@0xchain/token 1.1.0-beta.7 → 1.1.0-beta.70
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/LICENSE +21 -0
- package/dist/cookieSecure.d.ts +12 -0
- package/dist/cookieSecure.d.ts.map +1 -0
- package/dist/cookieStore.d.ts +34 -0
- package/dist/cookieStore.d.ts.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +253 -84
- package/dist/jwt.d.ts +10 -0
- package/dist/jwt.d.ts.map +1 -0
- package/package.json +11 -5
- package/dist/headers-tT97v9z0.js +0 -3787
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-present 0xchain
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 计算写 cookie 时的 secure 属性。
|
|
3
|
+
*
|
|
4
|
+
* 关键点:客户端(浏览器)以当前页面协议为准——https 页面就必须写 secure cookie,
|
|
5
|
+
* 否则会与服务端写入的 secure 同名 cookie 冲突,导航/刷新后客户端读不到。
|
|
6
|
+
* 这能让本地通过 https 代理调试时与线上行为一致。
|
|
7
|
+
*
|
|
8
|
+
* 服务端(无 window)无法感知页面协议,沿用 NODE_ENV==='production' 判断,
|
|
9
|
+
* 与既有线上行为保持一致。
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveCookieSecure(): boolean;
|
|
12
|
+
//# sourceMappingURL=cookieSecure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookieSecure.d.ts","sourceRoot":"","sources":["../src/cookieSecure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAU7C"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cookie 唯一真相源。
|
|
3
|
+
*
|
|
4
|
+
* 设计原则:domain / path / sameSite / secure 这套属性只在这里定义一次,
|
|
5
|
+
* set / get / remove 全部基于同一套属性。这样可以从机制上杜绝
|
|
6
|
+
* “写入带 secure、删除不带 secure 导致删不掉”这类属性漂移引发的
|
|
7
|
+
* cookie 时有时无问题。
|
|
8
|
+
*/
|
|
9
|
+
export declare const COOKIE_DOMAIN = ".ichatgo.ai";
|
|
10
|
+
export declare const COOKIE_PATH = "/";
|
|
11
|
+
export declare const COOKIE_SAME_SITE: "lax";
|
|
12
|
+
export declare const REFRESH_TOKEN_COOKIE_DAYS = 7;
|
|
13
|
+
export declare const DEFAULT_ACCESS_TOKEN_TTL_SECONDS = 3600;
|
|
14
|
+
export declare const RUNTIME_ENV: string;
|
|
15
|
+
/** 生产环境保持无后缀(兼容存量),其余环境按环境隔离 */
|
|
16
|
+
export declare const COOKIE_ENV_SUFFIX: string;
|
|
17
|
+
/**
|
|
18
|
+
* 生成环境作用域内的 cookie 名。
|
|
19
|
+
* 例:test 环境 `access_token` → `access_token__test`;生产环境保持 `access_token`。
|
|
20
|
+
* 幂等:已带后缀的名字不会重复追加。
|
|
21
|
+
*/
|
|
22
|
+
export declare function envCookieName(base: string): string;
|
|
23
|
+
/** js-cookie:number 表示「天数」,须用 Date 表示绝对过期时间 */
|
|
24
|
+
export declare function expiresFromSeconds(seconds: number): Date;
|
|
25
|
+
export declare const cookieStore: {
|
|
26
|
+
get(key: string): string;
|
|
27
|
+
set(key: string, value: string, expires: Date | number): void;
|
|
28
|
+
/**
|
|
29
|
+
* 删除必须与写入属性完全一致(domain/path/sameSite/secure),
|
|
30
|
+
* 否则浏览器无法命中目标 cookie,删除会“静默失败”。
|
|
31
|
+
*/
|
|
32
|
+
remove(key: string): void;
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=cookieStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookieStore.d.ts","sourceRoot":"","sources":["../src/cookieStore.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,gBAAgB,CAAA;AAC1C,eAAO,MAAM,WAAW,MAAM,CAAA;AAC9B,eAAO,MAAM,gBAAgB,EAAG,KAAc,CAAA;AAE9C,eAAO,MAAM,yBAAyB,IAAI,CAAA;AAC1C,eAAO,MAAM,gCAAgC,OAAO,CAAA;AAqBpD,eAAO,MAAM,WAAW,QAA2D,CAAA;AAEnF,gCAAgC;AAChC,eAAO,MAAM,iBAAiB,QAAyD,CAAA;AAEvF;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIlD;AAYD,+CAA+C;AAC/C,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAExD;AAED,eAAO,MAAM,WAAW;aACb,MAAM,GAAG,MAAM;aAGf,MAAM,SAAS,MAAM,WAAW,IAAI,GAAG,MAAM,GAAG,IAAI;IAG7D;;;OAGG;gBACS,MAAM,GAAG,IAAI;CAG1B,CAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server';
|
|
2
2
|
import { ITokenManager, ITokenManagerResponse } from './type';
|
|
3
|
+
export { decodeJwtPayload, isJwtExpired } from './jwt';
|
|
4
|
+
export { envCookieName, COOKIE_ENV_SUFFIX, RUNTIME_ENV, COOKIE_DOMAIN, } from './cookieStore';
|
|
3
5
|
/**
|
|
4
6
|
* 设置|更新token到cookie
|
|
5
7
|
* @param response NextResponse
|
|
@@ -8,7 +10,10 @@ import { ITokenManager, ITokenManagerResponse } from './type';
|
|
|
8
10
|
*/
|
|
9
11
|
export declare const setToken: (res: ITokenManagerResponse, response?: NextResponse | null) => NextResponse | null;
|
|
10
12
|
export declare const getToken: (key?: string) => string;
|
|
13
|
+
/** 兼容 OAuth 直出与 { data: token } 包装 */
|
|
14
|
+
export declare function normalizeTokenPayload(res: unknown): ITokenManagerResponse | null;
|
|
11
15
|
export declare const removeAllToken: () => void;
|
|
16
|
+
export declare const removeTokenByKey: (key?: string) => void;
|
|
12
17
|
export declare const isTokenExpired: () => Promise<boolean>;
|
|
13
18
|
declare const TokenManager: ITokenManager;
|
|
14
19
|
export default TokenManager;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;AAc9D,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AACvD,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,WAAW,EACX,aAAa,GACd,MAAM,eAAe,CAAC;AA+BvB;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,GACnB,KAAK,qBAAqB,EAC1B,WAAW,YAAY,GAAG,IAAI,KAC7B,YAAY,GAAG,IA0DjB,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,MAAM,MAAM,WAEpC,CAAC;AAEF,sCAAsC;AACtC,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,OAAO,GACX,qBAAqB,GAAG,IAAI,CAc9B;AAED,eAAO,MAAM,cAAc,YAM1B,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,SAE5C,CAAC;AAEF,eAAO,MAAM,cAAc,wBA6C1B,CAAC;AAEF,QAAA,MAAM,YAAY,EAAE,aAMnB,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,92 +1,261 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
1
|
+
import Cookies from "js-cookie";
|
|
2
|
+
function resolveCookieSecure() {
|
|
3
|
+
if (typeof window !== "undefined" && window.location) {
|
|
4
|
+
return window.location.protocol === "https:";
|
|
5
|
+
}
|
|
6
|
+
const authUrl = process.env.NEXT_PUBLIC_AUTH_URL || "";
|
|
7
|
+
const appUrl = process.env.NEXT_PUBLIC_APP_URL || "";
|
|
8
|
+
if (authUrl.startsWith("https://") || appUrl.startsWith("https://")) {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
return process.env.NODE_ENV === "production";
|
|
12
|
+
}
|
|
13
|
+
const COOKIE_DOMAIN = ".ichatgo.ai";
|
|
14
|
+
const COOKIE_PATH = "/";
|
|
15
|
+
const COOKIE_SAME_SITE = "lax";
|
|
16
|
+
const REFRESH_TOKEN_COOKIE_DAYS = 7;
|
|
17
|
+
const DEFAULT_ACCESS_TOKEN_TTL_SECONDS = 3600;
|
|
18
|
+
function normalizeRuntimeEnv(raw) {
|
|
19
|
+
const env = (raw || "").trim().toLowerCase();
|
|
20
|
+
if (!env || env === "prod" || env === "production") return "production";
|
|
21
|
+
return env;
|
|
22
|
+
}
|
|
23
|
+
const RUNTIME_ENV = normalizeRuntimeEnv(process.env.NEXT_PUBLIC_RUNTIME_ENV);
|
|
24
|
+
const COOKIE_ENV_SUFFIX = RUNTIME_ENV === "production" ? "" : `__${RUNTIME_ENV}`;
|
|
25
|
+
function envCookieName(base) {
|
|
26
|
+
if (!COOKIE_ENV_SUFFIX) return base;
|
|
27
|
+
if (base.endsWith(COOKIE_ENV_SUFFIX)) return base;
|
|
28
|
+
return `${base}${COOKIE_ENV_SUFFIX}`;
|
|
29
|
+
}
|
|
30
|
+
function baseAttributes() {
|
|
31
|
+
return {
|
|
32
|
+
domain: COOKIE_DOMAIN,
|
|
33
|
+
path: COOKIE_PATH,
|
|
34
|
+
sameSite: COOKIE_SAME_SITE,
|
|
35
|
+
secure: resolveCookieSecure()
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function expiresFromSeconds(seconds) {
|
|
39
|
+
return new Date(Date.now() + Math.max(seconds, 0) * 1e3);
|
|
40
|
+
}
|
|
41
|
+
const cookieStore = {
|
|
42
|
+
get(key) {
|
|
43
|
+
return Cookies.get(key) || "";
|
|
44
|
+
},
|
|
45
|
+
set(key, value, expires) {
|
|
46
|
+
Cookies.set(key, value, { ...baseAttributes(), expires });
|
|
47
|
+
},
|
|
48
|
+
/**
|
|
49
|
+
* 删除必须与写入属性完全一致(domain/path/sameSite/secure),
|
|
50
|
+
* 否则浏览器无法命中目标 cookie,删除会“静默失败”。
|
|
51
|
+
*/
|
|
52
|
+
remove(key) {
|
|
53
|
+
Cookies.remove(key, baseAttributes());
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
function base64UrlDecode(input) {
|
|
57
|
+
const normalized = input.replace(/-/g, "+").replace(/_/g, "/");
|
|
58
|
+
const padLength = (4 - normalized.length % 4) % 4;
|
|
59
|
+
const padded = normalized + "=".repeat(padLength);
|
|
60
|
+
if (typeof atob === "function") {
|
|
61
|
+
const binary = atob(padded);
|
|
62
|
+
const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
|
|
63
|
+
return new TextDecoder().decode(bytes);
|
|
64
|
+
}
|
|
65
|
+
return Buffer.from(padded, "base64").toString("utf8");
|
|
66
|
+
}
|
|
67
|
+
function decodeJwtPayload(token) {
|
|
68
|
+
if (!token) return null;
|
|
69
|
+
const parts = token.split(".");
|
|
70
|
+
if (parts.length < 2) return null;
|
|
71
|
+
try {
|
|
72
|
+
const payloadJson = base64UrlDecode(parts[1]);
|
|
73
|
+
return JSON.parse(payloadJson);
|
|
74
|
+
} catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function getJwtExpiryMs(token) {
|
|
79
|
+
const payload = decodeJwtPayload(token);
|
|
80
|
+
if (typeof payload?.exp === "number") {
|
|
81
|
+
return payload.exp * 1e3;
|
|
82
|
+
}
|
|
83
|
+
return void 0;
|
|
84
|
+
}
|
|
85
|
+
function isJwtExpired(payload, options) {
|
|
86
|
+
if (!payload?.exp) return false;
|
|
87
|
+
const skew = options?.skewSeconds ?? 15;
|
|
88
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
89
|
+
return payload.exp <= now + skew;
|
|
90
|
+
}
|
|
91
|
+
const cookieSetToken = (data) => {
|
|
92
|
+
const nextAccessToken = data?.access_token || getToken("access_token");
|
|
93
|
+
const nextRefreshToken = data?.refresh_token || getToken("refresh_token");
|
|
94
|
+
const nextIdToken = data?.id_token || getToken("id_token");
|
|
95
|
+
if (!nextAccessToken) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const expiresIn = data?.expires_in ?? DEFAULT_ACCESS_TOKEN_TTL_SECONDS;
|
|
99
|
+
const accessExpires = expiresFromSeconds(expiresIn);
|
|
100
|
+
cookieStore.set(envCookieName("access_token"), nextAccessToken, accessExpires);
|
|
101
|
+
if (nextRefreshToken) {
|
|
102
|
+
cookieStore.set(
|
|
103
|
+
envCookieName("refresh_token"),
|
|
104
|
+
nextRefreshToken,
|
|
105
|
+
REFRESH_TOKEN_COOKIE_DAYS
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
if (nextIdToken) {
|
|
109
|
+
cookieStore.set(envCookieName("id_token"), nextIdToken, accessExpires);
|
|
110
|
+
}
|
|
111
|
+
cookieStore.set(
|
|
112
|
+
envCookieName("token_expire"),
|
|
113
|
+
(Date.now() + expiresIn * 1e3).toString(),
|
|
114
|
+
accessExpires
|
|
115
|
+
);
|
|
116
|
+
};
|
|
117
|
+
const setToken = (res, response) => {
|
|
118
|
+
if (!response) {
|
|
119
|
+
cookieSetToken(res);
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
const nextAccessToken = res?.access_token;
|
|
123
|
+
const nextRefreshToken = res?.refresh_token;
|
|
124
|
+
const nextIdToken = res?.id_token;
|
|
125
|
+
const expiresIn = typeof res?.expires_in === "number" && res.expires_in > 0 ? res.expires_in : DEFAULT_ACCESS_TOKEN_TTL_SECONDS;
|
|
126
|
+
if (!nextAccessToken) {
|
|
127
|
+
return response;
|
|
128
|
+
}
|
|
129
|
+
const secure = resolveCookieSecure();
|
|
130
|
+
response.cookies.set(envCookieName("access_token"), nextAccessToken, {
|
|
131
|
+
httpOnly: false,
|
|
132
|
+
maxAge: expiresIn,
|
|
133
|
+
domain: COOKIE_DOMAIN,
|
|
134
|
+
sameSite: COOKIE_SAME_SITE,
|
|
135
|
+
secure,
|
|
136
|
+
path: COOKIE_PATH
|
|
27
137
|
});
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
maxAge: e == null ? void 0 : e.expires_in,
|
|
47
|
-
domain: o,
|
|
48
|
-
sameSite: s,
|
|
49
|
-
secure: c,
|
|
50
|
-
path: t
|
|
51
|
-
}), i.cookies.set("token_expire", (Date.now() + (e == null ? void 0 : e.expires_in) * 1e3).toString(), {
|
|
52
|
-
httpOnly: !1,
|
|
53
|
-
maxAge: e == null ? void 0 : e.expires_in,
|
|
54
|
-
domain: o,
|
|
55
|
-
sameSite: s,
|
|
56
|
-
secure: c,
|
|
57
|
-
path: t
|
|
138
|
+
if (nextRefreshToken) {
|
|
139
|
+
response.cookies.set(envCookieName("refresh_token"), nextRefreshToken, {
|
|
140
|
+
httpOnly: false,
|
|
141
|
+
maxAge: 60 * 60 * 24 * REFRESH_TOKEN_COOKIE_DAYS,
|
|
142
|
+
domain: COOKIE_DOMAIN,
|
|
143
|
+
sameSite: COOKIE_SAME_SITE,
|
|
144
|
+
secure,
|
|
145
|
+
path: COOKIE_PATH
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
if (nextIdToken) {
|
|
149
|
+
response.cookies.set(envCookieName("id_token"), nextIdToken, {
|
|
150
|
+
httpOnly: false,
|
|
151
|
+
maxAge: expiresIn,
|
|
152
|
+
domain: COOKIE_DOMAIN,
|
|
153
|
+
sameSite: COOKIE_SAME_SITE,
|
|
154
|
+
secure,
|
|
155
|
+
path: COOKIE_PATH
|
|
58
156
|
});
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
157
|
+
}
|
|
158
|
+
response.cookies.set(
|
|
159
|
+
envCookieName("token_expire"),
|
|
160
|
+
(Date.now() + expiresIn * 1e3).toString(),
|
|
161
|
+
{
|
|
162
|
+
httpOnly: false,
|
|
163
|
+
maxAge: expiresIn,
|
|
164
|
+
domain: COOKIE_DOMAIN,
|
|
165
|
+
sameSite: COOKIE_SAME_SITE,
|
|
166
|
+
secure,
|
|
167
|
+
path: COOKIE_PATH
|
|
168
|
+
}
|
|
169
|
+
);
|
|
170
|
+
return response;
|
|
171
|
+
};
|
|
172
|
+
const getToken = (key) => {
|
|
173
|
+
return cookieStore.get(envCookieName(key || "id_token"));
|
|
174
|
+
};
|
|
175
|
+
function normalizeTokenPayload(res) {
|
|
176
|
+
if (!res || typeof res !== "object") return null;
|
|
177
|
+
const payload = res;
|
|
178
|
+
if (typeof payload.access_token === "string") {
|
|
179
|
+
return payload;
|
|
180
|
+
}
|
|
181
|
+
const nested = payload.data;
|
|
182
|
+
if (nested && typeof nested === "object") {
|
|
183
|
+
const data = nested;
|
|
184
|
+
if (typeof data.access_token === "string") {
|
|
185
|
+
return data;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
const removeAllToken = () => {
|
|
191
|
+
cookieStore.remove(envCookieName("id_token"));
|
|
192
|
+
cookieStore.remove(envCookieName("access_token"));
|
|
193
|
+
cookieStore.remove(envCookieName("refresh_token"));
|
|
194
|
+
cookieStore.remove(envCookieName("sign_session"));
|
|
195
|
+
cookieStore.remove(envCookieName("token_expire"));
|
|
196
|
+
};
|
|
197
|
+
const removeTokenByKey = (key) => {
|
|
198
|
+
cookieStore.remove(envCookieName(key || "id_token"));
|
|
199
|
+
};
|
|
200
|
+
const isTokenExpired = async () => {
|
|
201
|
+
let t;
|
|
202
|
+
let refreshToken;
|
|
203
|
+
let accessToken;
|
|
204
|
+
if (typeof window === "undefined") {
|
|
70
205
|
try {
|
|
71
|
-
const { cookies
|
|
72
|
-
|
|
206
|
+
const { cookies } = await import("next/headers");
|
|
207
|
+
const nextCookies = await cookies();
|
|
208
|
+
const tokenExpire = nextCookies.get(envCookieName("token_expire"))?.value;
|
|
209
|
+
refreshToken = nextCookies.get(envCookieName("refresh_token"))?.value;
|
|
210
|
+
accessToken = nextCookies.get(envCookieName("access_token"))?.value;
|
|
211
|
+
t = tokenExpire ? Number(tokenExpire) : void 0;
|
|
73
212
|
} catch {
|
|
74
|
-
return
|
|
213
|
+
return false;
|
|
75
214
|
}
|
|
76
|
-
else
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
215
|
+
} else {
|
|
216
|
+
const rawExpire = cookieStore.get(envCookieName("token_expire"));
|
|
217
|
+
t = rawExpire ? Number(rawExpire) : void 0;
|
|
218
|
+
refreshToken = cookieStore.get(envCookieName("refresh_token"));
|
|
219
|
+
accessToken = cookieStore.get(envCookieName("access_token"));
|
|
220
|
+
}
|
|
221
|
+
const nearExpiry = (expireAt) => expireAt - Date.now() < 5 * 60 * 1e3;
|
|
222
|
+
if (accessToken) {
|
|
223
|
+
const jwtExpiry = getJwtExpiryMs(accessToken);
|
|
224
|
+
if (jwtExpiry) {
|
|
225
|
+
return nearExpiry(jwtExpiry);
|
|
226
|
+
}
|
|
227
|
+
if (t && !Number.isNaN(t)) {
|
|
228
|
+
return nearExpiry(t);
|
|
229
|
+
}
|
|
230
|
+
return Boolean(refreshToken);
|
|
231
|
+
}
|
|
232
|
+
if (refreshToken) {
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
if (t && !Number.isNaN(t)) {
|
|
236
|
+
return nearExpiry(t);
|
|
237
|
+
}
|
|
238
|
+
return false;
|
|
239
|
+
};
|
|
240
|
+
const TokenManager = {
|
|
241
|
+
setToken,
|
|
242
|
+
getToken,
|
|
243
|
+
removeAllToken,
|
|
244
|
+
removeTokenByKey,
|
|
245
|
+
isTokenExpired
|
|
85
246
|
};
|
|
86
247
|
export {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
248
|
+
COOKIE_DOMAIN,
|
|
249
|
+
COOKIE_ENV_SUFFIX,
|
|
250
|
+
RUNTIME_ENV,
|
|
251
|
+
decodeJwtPayload,
|
|
252
|
+
TokenManager as default,
|
|
253
|
+
envCookieName,
|
|
254
|
+
getToken,
|
|
255
|
+
isJwtExpired,
|
|
256
|
+
isTokenExpired,
|
|
257
|
+
normalizeTokenPayload,
|
|
258
|
+
removeAllToken,
|
|
259
|
+
removeTokenByKey,
|
|
260
|
+
setToken
|
|
92
261
|
};
|
package/dist/jwt.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type JwtPayload = Record<string, unknown> & {
|
|
2
|
+
exp?: number;
|
|
3
|
+
};
|
|
4
|
+
export declare function decodeJwtPayload(token?: string | null): JwtPayload | null;
|
|
5
|
+
/** JWT exp 字段转毫秒时间戳;无法解析时返回 undefined */
|
|
6
|
+
export declare function getJwtExpiryMs(token?: string | null): number | undefined;
|
|
7
|
+
export declare function isJwtExpired(payload: JwtPayload | null, options?: {
|
|
8
|
+
skewSeconds?: number;
|
|
9
|
+
}): boolean;
|
|
10
|
+
//# sourceMappingURL=jwt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../src/jwt.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IACjD,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAeF,wBAAgB,gBAAgB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,UAAU,GAAG,IAAI,CAUzE;AAED,yCAAyC;AACzC,wBAAgB,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAMxE;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,UAAU,GAAG,IAAI,EAC1B,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GACjC,OAAO,CAKT"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@0xchain/token",
|
|
3
|
-
"version": "1.1.0-beta.
|
|
3
|
+
"version": "1.1.0-beta.70",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -17,13 +17,19 @@
|
|
|
17
17
|
"dist",
|
|
18
18
|
"!**/*.tsbuildinfo"
|
|
19
19
|
],
|
|
20
|
+
"peerDependencies": {
|
|
21
|
+
"js-cookie": "3.0.5",
|
|
22
|
+
"next": "16.1.6"
|
|
23
|
+
},
|
|
20
24
|
"devDependencies": {
|
|
21
25
|
"@types/js-cookie": "3.0.6",
|
|
22
|
-
"@types/next": "9.0.0"
|
|
23
|
-
},
|
|
24
|
-
"dependencies": {
|
|
25
26
|
"js-cookie": "3.0.5",
|
|
26
|
-
"next": "
|
|
27
|
+
"next": "16.1.6"
|
|
28
|
+
},
|
|
29
|
+
"nx": {
|
|
30
|
+
"tags": [
|
|
31
|
+
"type:util"
|
|
32
|
+
]
|
|
27
33
|
},
|
|
28
34
|
"publishConfig": {
|
|
29
35
|
"access": "public"
|