jax-hono 1.0.2 → 1.0.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/bin/jax.js +0 -0
- package/build/generate-registry.ts +2 -1
- package/index.ts +2 -0
- package/middleware/jwt.ts +41 -25
- package/package.json +5 -3
- package/plugins/config.ts +3 -3
- package/plugins/session/index.ts +84 -18
- package/types/config.ts +3 -7
package/bin/jax.js
CHANGED
|
File without changes
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'
|
|
2
2
|
import { cwd } from 'node:process'
|
|
3
3
|
import { basename, join, parse, relative } from 'node:path'
|
|
4
|
-
import { ensureGeneratedDir, generatedDir, projectDir } from './generated-path'
|
|
4
|
+
import { ensureGeneratedDir, generatedDir, packageDir, projectDir } from './generated-path'
|
|
5
5
|
|
|
6
6
|
const srcDir = join(cwd(), 'src')
|
|
7
7
|
const moduleExtensions = new Set(['.ts', '.js', '.mjs', '.cjs'])
|
|
@@ -575,6 +575,7 @@ function serializePluginOptions(options: unknown) {
|
|
|
575
575
|
|
|
576
576
|
function generatePluginContextRegistry() {
|
|
577
577
|
const enabledPlugins = mergePluginConfig([
|
|
578
|
+
{ filePath: join(packageDir, 'plugins/config.ts'), config: readPluginConfig(join(packageDir, 'plugins/config.ts')) },
|
|
578
579
|
{ filePath: join(srcDir, 'config/plugin.ts'), config: readPluginConfig(join(srcDir, 'config/plugin.ts')) },
|
|
579
580
|
])
|
|
580
581
|
const imports = enabledPlugins.map(([name, item]) => {
|
package/index.ts
CHANGED
package/middleware/jwt.ts
CHANGED
|
@@ -1,62 +1,78 @@
|
|
|
1
|
-
import config from
|
|
2
|
-
import jwt from
|
|
3
|
-
import type { Context, MiddlewareHandler, Next } from
|
|
1
|
+
import config from "../config";
|
|
2
|
+
import jwt from "jsonwebtoken";
|
|
3
|
+
import type { Context, MiddlewareHandler, Next } from "hono";
|
|
4
4
|
|
|
5
|
-
type JwtAuthOptions<
|
|
5
|
+
type JwtAuthOptions<
|
|
6
|
+
TPayload extends Record<string, any> = Record<string, any>,
|
|
7
|
+
> = {
|
|
6
8
|
secretSuffix: string;
|
|
7
9
|
stateKey: string;
|
|
8
10
|
validate?: (payload: TPayload, c: Context) => boolean | Promise<boolean>;
|
|
9
11
|
resolveState?: (payload: TPayload, c: Context) => unknown | Promise<unknown>;
|
|
10
12
|
};
|
|
11
13
|
|
|
12
|
-
function createJwtAuth<
|
|
13
|
-
|
|
14
|
-
): MiddlewareHandler {
|
|
14
|
+
function createJwtAuth<
|
|
15
|
+
TPayload extends Record<string, any> = Record<string, any>,
|
|
16
|
+
>(options: JwtAuthOptions<TPayload>): MiddlewareHandler {
|
|
15
17
|
return async (c, next) => {
|
|
16
|
-
const session = c.
|
|
17
|
-
const sessionData = session.get(
|
|
18
|
+
const session = c.var.session;
|
|
19
|
+
const sessionData = await session.get();
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
console.log("sessionData", sessionData);
|
|
22
|
+
|
|
23
|
+
// if (sessionData && sessionData[options.stateKey]) {
|
|
24
|
+
// c.state[options.stateKey] = sessionData[options.stateKey];
|
|
25
|
+
// await next();
|
|
26
|
+
// return;
|
|
27
|
+
// }
|
|
28
|
+
|
|
29
|
+
// const session = c.get('session');
|
|
30
|
+
// const sessionData = session.get(options.stateKey);
|
|
31
|
+
|
|
32
|
+
// if (sessionData) {
|
|
33
|
+
// c.state[options.stateKey] = sessionData;
|
|
34
|
+
// await next();
|
|
35
|
+
// }
|
|
24
36
|
|
|
25
37
|
const token = getAuthorizationToken(c);
|
|
26
38
|
|
|
27
39
|
if (!token) {
|
|
28
|
-
return c.json({ code: 401, msg:
|
|
40
|
+
return c.json({ code: 401, msg: "请先登录" });
|
|
29
41
|
}
|
|
30
42
|
|
|
31
43
|
try {
|
|
32
44
|
const payload = jwt.verify(
|
|
33
45
|
token,
|
|
34
|
-
(config as any).jwt.secret + options.secretSuffix
|
|
46
|
+
(config as any).jwt.secret + options.secretSuffix,
|
|
35
47
|
) as TPayload;
|
|
36
|
-
const valid = options.validate
|
|
48
|
+
const valid = options.validate
|
|
49
|
+
? await options.validate(payload, c)
|
|
50
|
+
: true;
|
|
37
51
|
|
|
38
52
|
if (!valid) {
|
|
39
|
-
return c.json({ code: 401, msg:
|
|
53
|
+
return c.json({ code: 401, msg: "请重新登录" });
|
|
40
54
|
}
|
|
41
55
|
|
|
42
|
-
const stateValue = options.resolveState
|
|
56
|
+
const stateValue = options.resolveState
|
|
57
|
+
? await options.resolveState(payload, c)
|
|
58
|
+
: payload;
|
|
43
59
|
|
|
44
60
|
if (!stateValue) {
|
|
45
|
-
return c.json({ code: 401, msg:
|
|
61
|
+
return c.json({ code: 401, msg: "请重新登录" });
|
|
46
62
|
}
|
|
47
63
|
|
|
48
64
|
c.state[options.stateKey] = stateValue;
|
|
49
65
|
|
|
50
66
|
await next();
|
|
51
67
|
} catch {
|
|
52
|
-
return c.json({ code: 401, msg:
|
|
68
|
+
return c.json({ code: 401, msg: "请重新登录" });
|
|
53
69
|
}
|
|
54
70
|
};
|
|
55
71
|
}
|
|
56
72
|
|
|
57
73
|
function createOptionalAuth(auth: MiddlewareHandler): MiddlewareHandler {
|
|
58
74
|
return async (c, next) => {
|
|
59
|
-
if (!c.req.header(
|
|
75
|
+
if (!c.req.header("authorization")) {
|
|
60
76
|
await next();
|
|
61
77
|
return;
|
|
62
78
|
}
|
|
@@ -66,10 +82,10 @@ function createOptionalAuth(auth: MiddlewareHandler): MiddlewareHandler {
|
|
|
66
82
|
}
|
|
67
83
|
|
|
68
84
|
function getAuthorizationToken(c: Context) {
|
|
69
|
-
const authorization = c.req.header(
|
|
85
|
+
const authorization = c.req.header("authorization") ?? "";
|
|
70
86
|
|
|
71
|
-
return authorization.startsWith(
|
|
72
|
-
? authorization.slice(
|
|
87
|
+
return authorization.startsWith("Bearer ")
|
|
88
|
+
? authorization.slice("Bearer ".length)
|
|
73
89
|
: authorization;
|
|
74
90
|
}
|
|
75
91
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jax-hono",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Lightweight framework layer on top of Hono, built for Bun",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.ts",
|
|
@@ -82,10 +82,10 @@
|
|
|
82
82
|
},
|
|
83
83
|
"dependencies": {
|
|
84
84
|
"@hono/session": "^0.2.1",
|
|
85
|
-
"cac": "^7.0.0"
|
|
86
|
-
"hono": "^4.12.27"
|
|
85
|
+
"cac": "^7.0.0"
|
|
87
86
|
},
|
|
88
87
|
"peerDependencies": {
|
|
88
|
+
"hono": "^4.12.27",
|
|
89
89
|
"dayjs": "*",
|
|
90
90
|
"deepmerge": "^4.3.1",
|
|
91
91
|
"dotenv": "^17.4.2",
|
|
@@ -95,9 +95,11 @@
|
|
|
95
95
|
},
|
|
96
96
|
"devDependencies": {
|
|
97
97
|
"@types/bun": "^1.3.14",
|
|
98
|
+
"@types/jsonwebtoken": "^9.0.10",
|
|
98
99
|
"dayjs": "^1.11.21",
|
|
99
100
|
"deepmerge": "^4.3.1",
|
|
100
101
|
"dotenv": "^17.4.2",
|
|
102
|
+
"hono": "^4.12.27",
|
|
101
103
|
"jsonwebtoken": "^9.0.3",
|
|
102
104
|
"minimist": "^1.2.8",
|
|
103
105
|
"mongoose": "^8.24.1"
|
package/plugins/config.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { definePluginConfig } from
|
|
1
|
+
import { definePluginConfig } from "../helpers/config";
|
|
2
2
|
|
|
3
3
|
export default definePluginConfig({
|
|
4
4
|
session: {
|
|
5
5
|
enable: true,
|
|
6
|
-
package:
|
|
7
|
-
}
|
|
6
|
+
package: "jax-hono/plugins/session",
|
|
7
|
+
},
|
|
8
8
|
});
|
package/plugins/session/index.ts
CHANGED
|
@@ -1,20 +1,86 @@
|
|
|
1
|
-
import { useSession, useSessionStorage } from '@hono/session'
|
|
2
|
-
import type {
|
|
3
|
-
import {
|
|
4
|
-
import { definePlugin } from '../define'
|
|
1
|
+
import { useSession, useSessionStorage } from '@hono/session';
|
|
2
|
+
import type { Session, SessionData, SessionOptions, Storage } from '@hono/session';
|
|
3
|
+
import type { Context } from 'hono';
|
|
4
|
+
import { definePlugin } from '../define';
|
|
5
|
+
|
|
6
|
+
export type JaxSessionData = SessionData;
|
|
7
|
+
|
|
8
|
+
export type SessionStorageFactory<Data extends SessionData = JaxSessionData> = (
|
|
9
|
+
c: Context
|
|
10
|
+
) => Storage<Data>;
|
|
11
|
+
|
|
12
|
+
export type SessionPluginOptions<Data extends SessionData = JaxSessionData> =
|
|
13
|
+
SessionOptions<Data> & {
|
|
14
|
+
/**
|
|
15
|
+
* Optional backing storage. When omitted, @hono/session keeps session data
|
|
16
|
+
* inside the encrypted cookie.
|
|
17
|
+
*/
|
|
18
|
+
storage?: Storage<Data> | SessionStorageFactory<Data>;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
declare module 'hono' {
|
|
22
|
+
interface ContextVariableMap {
|
|
23
|
+
session: Session<JaxSessionData>;
|
|
24
|
+
sessionStorage?: Storage<JaxSessionData>;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const DEFAULT_SESSION_DURATION = {
|
|
29
|
+
// 会话的有效时间以秒为单位。超过该时间后,会话将失效,需要重新认证才能继续使用。
|
|
30
|
+
absolute: 60 * 60 * 24 * 7 // 7天
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const DEFAULT_SESSION_OPTIONS: SessionPluginOptions = {
|
|
34
|
+
secret: 'jax-session',
|
|
35
|
+
duration: DEFAULT_SESSION_DURATION
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
function isSessionPluginOptions(options: unknown): options is SessionPluginOptions {
|
|
39
|
+
return Boolean(options && typeof options === 'object' && !Array.isArray(options));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function resolveSessionOptions(config: unknown, options: unknown): SessionPluginOptions {
|
|
43
|
+
const configOptions = readConfigSessionOptions(config);
|
|
44
|
+
const pluginOptions = isSessionPluginOptions(options) ? options : {};
|
|
45
|
+
const duration: NonNullable<SessionPluginOptions['duration']> = {
|
|
46
|
+
absolute: DEFAULT_SESSION_DURATION.absolute,
|
|
47
|
+
...configOptions.duration,
|
|
48
|
+
...pluginOptions.duration
|
|
49
|
+
};
|
|
50
|
+
const { storage, ...sessionOptions } = {
|
|
51
|
+
...DEFAULT_SESSION_OPTIONS,
|
|
52
|
+
...configOptions,
|
|
53
|
+
...pluginOptions,
|
|
54
|
+
duration
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
...sessionOptions,
|
|
59
|
+
storage
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function readConfigSessionOptions(config: unknown): SessionPluginOptions {
|
|
64
|
+
if (!config || typeof config !== 'object' || Array.isArray(config)) {
|
|
65
|
+
return {};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const session = (config as { session?: unknown }).session;
|
|
69
|
+
|
|
70
|
+
return isSessionPluginOptions(session) ? session : {};
|
|
71
|
+
}
|
|
5
72
|
|
|
6
73
|
export default definePlugin({
|
|
7
|
-
setup(ctx) {
|
|
8
|
-
ctx.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
})
|
|
74
|
+
setup(ctx, options) {
|
|
75
|
+
const { storage, ...sessionOptions } = resolveSessionOptions(ctx.config, options);
|
|
76
|
+
|
|
77
|
+
if (storage) {
|
|
78
|
+
ctx.app.use(useSessionStorage(storage));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
ctx.app.use(useSession(sessionOptions));
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
export type { Session, SessionData, SessionOptions, Storage };
|
|
86
|
+
export { useSession, useSessionStorage };
|
package/types/config.ts
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
|
+
import type { SessionPluginOptions } from '../plugins/session';
|
|
2
|
+
|
|
1
3
|
export type JaxConfig = {
|
|
2
4
|
rootDir: string;
|
|
3
5
|
port: number;
|
|
4
6
|
env: string;
|
|
5
7
|
|
|
6
|
-
session?:
|
|
7
|
-
secret?: string;
|
|
8
|
-
duration?: {
|
|
9
|
-
absolute: number;
|
|
10
|
-
inactivity?: number;
|
|
11
|
-
};
|
|
12
|
-
};
|
|
8
|
+
session?: SessionPluginOptions;
|
|
13
9
|
};
|