zova-module-a-interceptor 5.0.0 → 5.1.0

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2016-present Zova
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.
package/dist/index.js ADDED
@@ -0,0 +1,181 @@
1
+ import { BeanInfo, BeanScopeBase, cast } from "zova";
2
+ import { BeanInterceptorBase, Interceptor, SymbolInterceptorBodyResponseFlag } from "zova-module-a-fetch";
3
+ import { $customKey } from "zova-core";
4
+ import { catchError } from "@cabloy/utils";
5
+ import { Scope } from "zova-module-a-bean";
6
+ //#region src/bean/interceptor.body.ts
7
+ var _dec$5, _dec2$5, _class$5;
8
+ var InterceptorBody = (_dec$5 = Interceptor({ dependencies: "a-interceptor:performAction" }), _dec2$5 = BeanInfo({ module: "a-interceptor" }), _dec$5(_class$5 = _dec2$5(_class$5 = class InterceptorBody extends BeanInterceptorBase {
9
+ async onResponse(response, _options, next) {
10
+ response = await next();
11
+ const contentType = response.headers["content-type"];
12
+ if (!contentType || !contentType.includes("application/json")) {
13
+ response[SymbolInterceptorBodyResponseFlag] = true;
14
+ return response;
15
+ }
16
+ if (response.data.code !== 0) {
17
+ const error = /* @__PURE__ */ new Error();
18
+ error.code = response.data.code;
19
+ error.message = response.data.message;
20
+ throw error;
21
+ }
22
+ return response.data.data ?? null;
23
+ }
24
+ async onResponseError(error, _options, next) {
25
+ error = await next();
26
+ if (!(error instanceof Error)) return error;
27
+ if (error.response) {
28
+ error.code = cast(error.response.data)?.code ?? error.response.status;
29
+ error.message = cast(error.response.data)?.message ?? error.response.statusText;
30
+ }
31
+ return error;
32
+ }
33
+ }) || _class$5) || _class$5);
34
+ //#endregion
35
+ //#region src/bean/interceptor.headers.ts
36
+ var _dec$4, _dec2$4, _class$4;
37
+ var InterceptorHeaders = (_dec$4 = Interceptor({ dependencies: "a-interceptor:mock" }), _dec2$4 = BeanInfo({ module: "a-interceptor" }), _dec$4(_class$4 = _dec2$4(_class$4 = class InterceptorHeaders extends BeanInterceptorBase {
38
+ async onRequest(config, options, next) {
39
+ const keyLocale = this.sys.env.APP_LOCALE_HEADER_KEY;
40
+ if (keyLocale && !config.headers[keyLocale]) config.headers[keyLocale] = this.app.meta.locale.current;
41
+ const keyTz = this.sys.env.APP_TZ_HEADER_KEY;
42
+ if (keyTz && !config.headers[keyTz]) config.headers[keyTz] = this.app.meta.locale.tz;
43
+ if (options.openapiSchema) config.headers[$customKey("x-vona-openapi-schema")] = true;
44
+ return next(config);
45
+ }
46
+ }) || _class$4) || _class$4);
47
+ //#endregion
48
+ //#region src/bean/interceptor.jwt.ts
49
+ var _dec$3, _dec2$3, _class$3;
50
+ var InterceptorJwt = (_dec$3 = Interceptor({ dependencies: "a-interceptor:headers" }), _dec2$3 = BeanInfo({ module: "a-interceptor" }), _dec$3(_class$3 = _dec2$3(_class$3 = class InterceptorJwt extends BeanInterceptorBase {
51
+ constructor(...args) {
52
+ super(...args);
53
+ this._beanJwtAdapter = void 0;
54
+ this._refreshAuthTokenPromise = void 0;
55
+ }
56
+ async __init__(_beanFetch, options) {
57
+ const beanFullName = (options.jwtAdapter || this.scope.config.jwtAdapter).replace(":", ".service.");
58
+ this._beanJwtAdapter = await this.app.bean._getBean(beanFullName, true);
59
+ }
60
+ async onRequest(config, options, next) {
61
+ try {
62
+ const accessToken = await this.prepareAccessToken(config, options.authToken);
63
+ if (accessToken) config.headers.Authorization = `Bearer ${accessToken}`;
64
+ } catch (error) {
65
+ error.config = config;
66
+ error.request = void 0;
67
+ error.response = void 0;
68
+ throw error;
69
+ }
70
+ return next(config);
71
+ }
72
+ async prepareAccessToken(config, authToken) {
73
+ if (!this.sys.config.api.jwt) return;
74
+ const authTokenCurrent = authToken ?? this.scope.config.authToken.default;
75
+ if (process.env.SERVER) config.headers[$customKey("x-vona-jwt-authtoken")] = typeof authTokenCurrent === "string" ? true : authTokenCurrent;
76
+ if (typeof authTokenCurrent === "string") return authTokenCurrent;
77
+ let jwtInfo = await this._beanJwtAdapter.getJwtInfo();
78
+ if (!jwtInfo) {
79
+ if (authToken === true) this.app.throw(401);
80
+ return;
81
+ }
82
+ if (process.env.SERVER || !jwtInfo.expireTime || jwtInfo.expireTime > Date.now()) {
83
+ if (!jwtInfo.accessToken) {
84
+ if (authToken === true) this.app.throw(401);
85
+ return;
86
+ }
87
+ return jwtInfo.accessToken;
88
+ }
89
+ if (!jwtInfo.refreshToken) {
90
+ if (authToken === true) this.app.throw(401);
91
+ return;
92
+ } else if (authToken === false) return;
93
+ jwtInfo = await this._refreshAuthToken(jwtInfo.refreshToken);
94
+ return jwtInfo.accessToken;
95
+ }
96
+ async _refreshAuthToken(refreshToken) {
97
+ if (!this._refreshAuthTokenPromise) this._refreshAuthTokenPromise = this._refreshAuthTokenInner(refreshToken);
98
+ return await this._refreshAuthTokenPromise;
99
+ }
100
+ async _refreshAuthTokenInner(refreshToken) {
101
+ try {
102
+ return await this._beanJwtAdapter.refreshAuthToken(refreshToken);
103
+ } finally {
104
+ this._refreshAuthTokenPromise = void 0;
105
+ }
106
+ }
107
+ }) || _class$3) || _class$3);
108
+ //#endregion
109
+ //#region src/bean/interceptor.mock.ts
110
+ var _dec$2, _dec2$2, _class$2;
111
+ var __ErrorsShouldBeMocked = [
112
+ "ECONNREFUSED",
113
+ "ERR_NETWORK",
114
+ "404"
115
+ ];
116
+ var InterceptorMock = (_dec$2 = Interceptor(), _dec2$2 = BeanInfo({ module: "a-interceptor" }), _dec$2(_class$2 = _dec2$2(_class$2 = class InterceptorMock extends BeanInterceptorBase {
117
+ async onResponseError(error, _options, next) {
118
+ if (!(error instanceof Error)) return next();
119
+ if (this.sys.env.MOCK_ENABLED === "true") {
120
+ if (process.env.DEV || process.env.PROD && this.sys.env.MOCK_BUILD === "true") {
121
+ if (__ErrorsShouldBeMocked.includes(String(error.code)) || error.status === 404) {
122
+ const config = error.config;
123
+ if (config.baseURL) {
124
+ let baseURL = `http://localhost:${process.env.DEV ? this.sys.env.DEV_SERVER_PORT : this.sys.env.MOCK_BUILD_PORT}`;
125
+ if (config.baseURL.endsWith(this.sys.env.API_PREFIX)) baseURL = `${baseURL}${this.sys.env.API_PREFIX}`;
126
+ if (config.baseURL !== baseURL && config.baseURL !== this.sys.env.API_PREFIX) {
127
+ const response = await this.$fetch.request(Object.assign({}, config, { baseURL }));
128
+ if (response && response[SymbolInterceptorBodyResponseFlag]) return response.data;
129
+ else return response;
130
+ }
131
+ }
132
+ }
133
+ }
134
+ }
135
+ return next();
136
+ }
137
+ }) || _class$2) || _class$2);
138
+ //#endregion
139
+ //#region src/bean/interceptor.performAction.ts
140
+ var _dec$1, _dec2$1, _class$1;
141
+ var InterceptorPerformAction = (_dec$1 = Interceptor({ dependencies: "a-interceptor:jwt" }), _dec2$1 = BeanInfo({ module: "a-interceptor" }), _dec$1(_class$1 = _dec2$1(_class$1 = class InterceptorPerformAction extends BeanInterceptorBase {
142
+ async onRequest(config, _options, next) {
143
+ if (process.env.CLIENT) return next();
144
+ const performAction = this.ctx.meta.$ssr.getPerformAction(config.baseURL);
145
+ if (!performAction) return next();
146
+ const data = {
147
+ method: config.method,
148
+ path: config.url,
149
+ query: config.params,
150
+ body: config.data,
151
+ headers: config.headers
152
+ };
153
+ const [result, error] = await catchError(() => {
154
+ return performAction(data);
155
+ });
156
+ if (error) {
157
+ cast(error).config = config;
158
+ throw error;
159
+ }
160
+ throw result;
161
+ }
162
+ }) || _class$1) || _class$1);
163
+ //#endregion
164
+ //#region src/config/config.ts
165
+ var config = (_sys) => {
166
+ return {
167
+ jwtAdapter: "home-api:jwtAdapter",
168
+ authToken: { default: true }
169
+ };
170
+ };
171
+ //#endregion
172
+ //#region src/.metadata/index.ts
173
+ /** config: end */
174
+ /** scope: begin */
175
+ var _dec, _dec2, _class;
176
+ var ScopeModuleAInterceptor = (_dec = Scope(), _dec2 = BeanInfo({ module: "a-interceptor" }), _dec(_class = _dec2(_class = class ScopeModuleAInterceptor extends BeanScopeBase {}) || _class) || _class);
177
+ /** scope: end */
178
+ //#endregion
179
+ export { InterceptorBody, InterceptorHeaders, InterceptorJwt, InterceptorMock, InterceptorPerformAction, ScopeModuleAInterceptor, config };
180
+
181
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/bean/interceptor.body.ts","../src/bean/interceptor.headers.ts","../src/bean/interceptor.jwt.ts","../src/bean/interceptor.mock.ts","../src/bean/interceptor.performAction.ts","../src/config/config.ts","../src/.metadata/index.ts"],"sourcesContent":["import type { AxiosError, AxiosResponse } from 'axios';\nimport type {\n IDecoratorInterceptorOptions,\n IInterceptorResponse,\n IInterceptorResponseError,\n NextInterceptorError,\n NextInterceptorResponse,\n} from 'zova-module-a-fetch';\n\nimport { cast } from 'zova';\nimport { BeanInterceptorBase, Interceptor, SymbolInterceptorBodyResponseFlag } from 'zova-module-a-fetch';\n\nexport interface IInterceptorOptionsBody extends IDecoratorInterceptorOptions {}\n\n@Interceptor<IInterceptorOptionsBody>({ dependencies: 'a-interceptor:performAction' })\nexport class InterceptorBody extends BeanInterceptorBase<IInterceptorOptionsBody> implements IInterceptorResponse, IInterceptorResponseError {\n async onResponse(response: AxiosResponse, _options: IInterceptorOptionsBody, next: NextInterceptorResponse): Promise<AxiosResponse> {\n response = await next();\n const contentType = response.headers['content-type'];\n if (!contentType || !contentType.includes('application/json')) {\n response[SymbolInterceptorBodyResponseFlag] = true;\n return response;\n }\n if (response.data.code !== 0) {\n const error = new Error();\n error.code = response.data.code;\n error.message = response.data.message;\n throw error;\n }\n // return data\n return response.data.data ?? null;\n }\n\n async onResponseError(error: AxiosError, _options: IInterceptorOptionsBody, next: NextInterceptorError): Promise<AxiosError> {\n error = await next();\n if (!(error instanceof Error)) return error;\n if (error.response) {\n error.code = cast(error.response.data)?.code ?? error.response.status;\n error.message = cast(error.response.data)?.message ?? error.response.statusText;\n }\n return error;\n }\n}\n","import { AxiosRequestConfig } from 'axios';\nimport { $customKey } from 'zova-core';\nimport { BeanInterceptorBase, IDecoratorInterceptorOptions, Interceptor, NextInterceptorRequest } from 'zova-module-a-fetch';\n\nexport interface IInterceptorOptionsHeaders extends IDecoratorInterceptorOptions {\n openapiSchema?: boolean;\n}\n\n@Interceptor<IInterceptorOptionsHeaders>({ dependencies: 'a-interceptor:mock' })\nexport class InterceptorHeaders extends BeanInterceptorBase<IInterceptorOptionsHeaders> {\n async onRequest(config: AxiosRequestConfig, options: IInterceptorOptionsHeaders, next: NextInterceptorRequest): Promise<AxiosRequestConfig> {\n // locale\n const keyLocale = this.sys.env.APP_LOCALE_HEADER_KEY;\n if (keyLocale && !config.headers![keyLocale]) {\n config.headers![keyLocale] = this.app.meta.locale.current;\n }\n // tz\n const keyTz = this.sys.env.APP_TZ_HEADER_KEY;\n if (keyTz && !config.headers![keyTz]) {\n config.headers![keyTz] = this.app.meta.locale.tz;\n }\n // openapi schema\n if (options.openapiSchema) {\n config.headers![$customKey('x-vona-openapi-schema')] = true;\n }\n // next\n return next(config);\n }\n}\n","import type { AxiosRequestConfig } from 'axios';\nimport type { BeanFetch, IDecoratorInterceptorOptions, IInterceptorRequest, NextInterceptorRequest } from 'zova-module-a-fetch';\n\nimport { $customKey } from 'zova-core';\nimport { BeanInterceptorBase, Interceptor } from 'zova-module-a-fetch';\n\nimport type { IJwtAdapter, IJwtInfo } from '../types/jwt.js';\n\nexport interface IInterceptorOptionsJwt extends IDecoratorInterceptorOptions {\n jwtAdapter?: string;\n authToken?: boolean | string;\n}\n\n@Interceptor<IInterceptorOptionsJwt>({ dependencies: 'a-interceptor:headers' })\nexport class InterceptorJwt extends BeanInterceptorBase<IInterceptorOptionsJwt> implements IInterceptorRequest {\n private _beanJwtAdapter: IJwtAdapter;\n private _refreshAuthTokenPromise?: Promise<IJwtInfo>;\n\n protected async __init__(_beanFetch: BeanFetch, options: IInterceptorOptionsJwt) {\n const jwtAdapter = options.jwtAdapter || this.scope.config.jwtAdapter;\n const beanFullName = jwtAdapter.replace(':', '.service.');\n // singleton\n this._beanJwtAdapter = await this.app.bean._getBean(beanFullName as any, true);\n }\n\n async onRequest(config: AxiosRequestConfig, options: IInterceptorOptionsJwt, next: NextInterceptorRequest): Promise<AxiosRequestConfig> {\n try {\n const accessToken = await this.prepareAccessToken(config, options.authToken);\n if (accessToken) {\n config.headers!.Authorization = `Bearer ${accessToken}`;\n }\n } catch (error: any) {\n error.config = config;\n error.request = undefined;\n error.response = undefined;\n throw error;\n }\n return next(config);\n }\n\n async prepareAccessToken(config: AxiosRequestConfig, authToken: string | boolean | undefined): Promise<string | undefined> {\n if (!this.sys.config.api.jwt) return;\n // use default in scope.config rather than IInterceptorOptionsJwt.options\n const authTokenCurrent = authToken ?? this.scope.config.authToken.default;\n // authToken = authToken ?? this.scope.config.authToken.default;\n if (process.env.SERVER) {\n config.headers![$customKey('x-vona-jwt-authtoken')] = typeof authTokenCurrent === 'string' ? true : authTokenCurrent;\n }\n // // authToken: false\n // if (authTokenCurrent === false) return;\n // authToken: string\n if (typeof authTokenCurrent === 'string') return authTokenCurrent;\n // if (typeof authToken === 'string') return authToken;\n // authToken: true\n let jwtInfo = await this._beanJwtAdapter.getJwtInfo();\n if (!jwtInfo) {\n if (authToken === true) {\n this.app.throw(401); // 401 rather than 403\n }\n return;\n }\n // accessToken\n if (process.env.SERVER || !jwtInfo.expireTime || jwtInfo.expireTime > Date.now()) {\n if (!jwtInfo.accessToken) {\n if (authToken === true) this.app.throw(401);\n return;\n }\n return jwtInfo.accessToken;\n }\n // refreshToken\n if (!jwtInfo.refreshToken) {\n if (authToken === true) this.app.throw(401);\n return;\n } else {\n if (authToken === false) {\n // need not refreshAuthToken, such as captcha.create\n return;\n }\n }\n jwtInfo = await this._refreshAuthToken(jwtInfo.refreshToken);\n return jwtInfo.accessToken;\n }\n\n private async _refreshAuthToken(refreshToken: string) {\n if (!this._refreshAuthTokenPromise) {\n this._refreshAuthTokenPromise = this._refreshAuthTokenInner(refreshToken);\n }\n return await this._refreshAuthTokenPromise;\n }\n\n private async _refreshAuthTokenInner(refreshToken: string) {\n try {\n return await this._beanJwtAdapter.refreshAuthToken(refreshToken);\n } finally {\n this._refreshAuthTokenPromise = undefined;\n }\n }\n}\n","import { AxiosError } from 'axios';\nimport {\n BeanInterceptorBase,\n IDecoratorInterceptorOptions,\n IInterceptorResponseError,\n Interceptor,\n NextInterceptorError,\n SymbolInterceptorBodyResponseFlag,\n} from 'zova-module-a-fetch';\n\nexport interface IInterceptorOptionsMock extends IDecoratorInterceptorOptions {}\n\n// not include: ERR_BAD_RESPONSE\nconst __ErrorsShouldBeMocked = ['ECONNREFUSED', 'ERR_NETWORK', '404'];\n\n@Interceptor<IInterceptorOptionsMock>()\nexport class InterceptorMock extends BeanInterceptorBase<IInterceptorOptionsMock> implements IInterceptorResponseError {\n async onResponseError(error: AxiosError, _options: IDecoratorInterceptorOptions, next: NextInterceptorError): Promise<AxiosError> {\n if (!(error instanceof Error)) return next();\n if (this.sys.env.MOCK_ENABLED === 'true') {\n if (process.env.DEV || (process.env.PROD && this.sys.env.MOCK_BUILD === 'true')) {\n if (__ErrorsShouldBeMocked.includes(String(error.code)) || error.status === 404) {\n const config = error.config!;\n if (config.baseURL) {\n const port = process.env.DEV ? this.sys.env.DEV_SERVER_PORT : this.sys.env.MOCK_BUILD_PORT;\n let baseURL = `http://localhost:${port}`;\n if (config.baseURL.endsWith(this.sys.env.API_PREFIX!)) {\n baseURL = `${baseURL}${this.sys.env.API_PREFIX}`;\n }\n if (config.baseURL !== baseURL && config.baseURL !== this.sys.env.API_PREFIX) {\n const response = await this.$fetch.request(Object.assign({}, config, { baseURL }));\n if (response && response[SymbolInterceptorBodyResponseFlag]) {\n return response.data;\n } else {\n return response as any;\n }\n }\n }\n }\n }\n }\n return next();\n }\n}\n","import { catchError } from '@cabloy/utils';\nimport { AxiosRequestConfig } from 'axios';\nimport { cast } from 'zova';\nimport { BeanInterceptorBase, IDecoratorInterceptorOptions, IInterceptorRequest, Interceptor, NextInterceptorRequest } from 'zova-module-a-fetch';\nimport { ISsrSitePerformActionOptions } from 'zova-module-a-ssr';\n\nexport interface IInterceptorOptionsPerformAction extends IDecoratorInterceptorOptions {}\n\n@Interceptor<IInterceptorOptionsPerformAction>({ dependencies: 'a-interceptor:jwt' })\nexport class InterceptorPerformAction extends BeanInterceptorBase<IInterceptorOptionsPerformAction> implements IInterceptorRequest {\n async onRequest(config: AxiosRequestConfig, _options: IInterceptorOptionsPerformAction, next: NextInterceptorRequest): Promise<AxiosRequestConfig> {\n if (process.env.CLIENT) return next();\n const performAction = this.ctx.meta.$ssr.getPerformAction(config.baseURL);\n if (!performAction) return next();\n const data: ISsrSitePerformActionOptions = {\n method: config.method as any,\n path: config.url!,\n query: config.params,\n body: config.data,\n headers: config.headers,\n };\n const [result, error] = await catchError(() => {\n return performAction(data);\n });\n if (error) {\n cast(error).config = config;\n throw error;\n }\n throw result;\n }\n}\n","import type { ZovaSys } from 'zova';\nimport type { IServiceRecord } from 'zova-module-a-bean';\n\nexport const config = (_sys: ZovaSys) => {\n return {\n jwtAdapter: 'home-api:jwtAdapter' as keyof IServiceRecord,\n authToken: {\n default: true,\n },\n };\n};\n","// eslint-disable\n/** interceptor: begin */\nexport * from '../bean/interceptor.body.js';\nexport * from '../bean/interceptor.headers.js';\nexport * from '../bean/interceptor.jwt.js';\nexport * from '../bean/interceptor.mock.js';\nexport * from '../bean/interceptor.performAction.js';\nimport { IInterceptorOptionsBody } from '../bean/interceptor.body.js';\nimport { IInterceptorOptionsHeaders } from '../bean/interceptor.headers.js';\nimport { IInterceptorOptionsJwt } from '../bean/interceptor.jwt.js';\nimport { IInterceptorOptionsMock } from '../bean/interceptor.mock.js';\nimport { IInterceptorOptionsPerformAction } from '../bean/interceptor.performAction.js';\nimport 'zova-module-a-fetch';\ndeclare module 'zova-module-a-fetch' {\n \n export interface IInterceptorRecord {\n 'a-interceptor:body': IInterceptorOptionsBody;\n'a-interceptor:headers': IInterceptorOptionsHeaders;\n'a-interceptor:jwt': IInterceptorOptionsJwt;\n'a-interceptor:mock': IInterceptorOptionsMock;\n'a-interceptor:performAction': IInterceptorOptionsPerformAction;\n }\n\n \n}\ndeclare module 'zova-module-a-interceptor' {\n \n export interface InterceptorBody {\n /** @internal */\n get scope(): ScopeModuleAInterceptor;\n }\n\n export interface InterceptorBody {\n get $beanFullName(): 'a-interceptor.interceptor.body';\n get $onionName(): 'a-interceptor:body';\n get $onionOptions(): IInterceptorOptionsBody;\n }\n\n export interface InterceptorHeaders {\n /** @internal */\n get scope(): ScopeModuleAInterceptor;\n }\n\n export interface InterceptorHeaders {\n get $beanFullName(): 'a-interceptor.interceptor.headers';\n get $onionName(): 'a-interceptor:headers';\n get $onionOptions(): IInterceptorOptionsHeaders;\n }\n\n export interface InterceptorJwt {\n /** @internal */\n get scope(): ScopeModuleAInterceptor;\n }\n\n export interface InterceptorJwt {\n get $beanFullName(): 'a-interceptor.interceptor.jwt';\n get $onionName(): 'a-interceptor:jwt';\n get $onionOptions(): IInterceptorOptionsJwt;\n }\n\n export interface InterceptorMock {\n /** @internal */\n get scope(): ScopeModuleAInterceptor;\n }\n\n export interface InterceptorMock {\n get $beanFullName(): 'a-interceptor.interceptor.mock';\n get $onionName(): 'a-interceptor:mock';\n get $onionOptions(): IInterceptorOptionsMock;\n }\n\n export interface InterceptorPerformAction {\n /** @internal */\n get scope(): ScopeModuleAInterceptor;\n }\n\n export interface InterceptorPerformAction {\n get $beanFullName(): 'a-interceptor.interceptor.performAction';\n get $onionName(): 'a-interceptor:performAction';\n get $onionOptions(): IInterceptorOptionsPerformAction;\n } \n}\n/** interceptor: end */\n/** interceptor: begin */\nimport { InterceptorBody } from '../bean/interceptor.body.js';\nimport { InterceptorHeaders } from '../bean/interceptor.headers.js';\nimport { InterceptorJwt } from '../bean/interceptor.jwt.js';\nimport { InterceptorMock } from '../bean/interceptor.mock.js';\nimport { InterceptorPerformAction } from '../bean/interceptor.performAction.js';\nimport 'zova';\ndeclare module 'zova' {\n export interface IBeanRecordLocal {\n 'a-interceptor.interceptor.body': InterceptorBody;\n'a-interceptor.interceptor.headers': InterceptorHeaders;\n'a-interceptor.interceptor.jwt': InterceptorJwt;\n'a-interceptor.interceptor.mock': InterceptorMock;\n'a-interceptor.interceptor.performAction': InterceptorPerformAction;\n }\n}\n/** interceptor: end */\n/** config: begin */\nexport * from '../config/config.js';\nimport { config } from '../config/config.js';\n/** config: end */\n/** scope: begin */\nimport { BeanScopeBase, type BeanScopeUtil, TypeModuleConfig } from 'zova';\nimport { Scope } from 'zova-module-a-bean';\n\n@Scope()\nexport class ScopeModuleAInterceptor extends BeanScopeBase {}\n\nexport interface ScopeModuleAInterceptor {\n util: BeanScopeUtil;\nconfig: TypeModuleConfig<typeof config>;\n}\n\nimport 'zova';\ndeclare module 'zova' {\n export interface IBeanScopeRecord {\n 'a-interceptor': ScopeModuleAInterceptor;\n }\n \n export interface IBeanScopeConfig {\n 'a-interceptor': ReturnType<typeof config>;\n }\n\n \n\n \n}\n \n/** scope: end */\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,37 +1,56 @@
1
1
  {
2
2
  "name": "zova-module-a-interceptor",
3
- "version": "5.0.0",
3
+ "version": "5.1.0",
4
+ "description": "",
5
+ "keywords": [
6
+ "Zova Module"
7
+ ],
8
+ "author": "",
9
+ "files": [
10
+ "dist",
11
+ "mock",
12
+ "src",
13
+ "icons",
14
+ "assets",
15
+ "rest"
16
+ ],
4
17
  "type": "module",
5
- "publishConfig": {
6
- "access": "public"
7
- },
8
18
  "exports": {
9
19
  ".": {
10
20
  "types": [
11
21
  "./src/index.ts",
12
22
  "./dist/index.d.ts"
13
23
  ],
14
- "development": "./src/index.ts",
15
- "import": "./dist/index.js",
16
- "default": "./src/index.ts"
24
+ "default": "./dist/index.js"
17
25
  },
18
- "./package.json": "./package.json"
26
+ "./*": "./*"
19
27
  },
20
- "description": "",
21
- "files": [
22
- "dist",
23
- "static",
24
- "typings"
25
- ],
26
28
  "scripts": {
27
- "build:front": "node ../../../../../scripts/egg-born-bin.js front-build-module",
28
- "build:backend": "node ../../../../../scripts/egg-born-bin.js backend-build-module",
29
- "build:all": "npm run build:front && npm run build:backend",
30
- "preversion": "npm run build:all && git add ."
29
+ "clean": "rimraf dist tsconfig.build.tsbuildinfo",
30
+ "tsc:publish": "npm run clean && zova :bin:buildModule --sourcemap",
31
+ "prepublishOnly": "npm run tsc:publish",
32
+ "prepack": "clean-package",
33
+ "postpack": "clean-package restore && npm run clean"
31
34
  },
32
- "keywords": [
33
- "Cabloy Module"
34
- ],
35
- "author": "zhennann",
36
- "dependencies": {}
35
+ "title": "a-interceptor",
36
+ "zovaModule": {
37
+ "onionsConfig": {
38
+ "interceptor": {
39
+ "body": {
40
+ "dependencies": "a-interceptor:performAction"
41
+ },
42
+ "headers": {
43
+ "dependencies": "a-interceptor:mock"
44
+ },
45
+ "jwt": {
46
+ "dependencies": "a-interceptor:headers"
47
+ },
48
+ "mock": {},
49
+ "performAction": {
50
+ "dependencies": "a-interceptor:jwt"
51
+ }
52
+ }
53
+ }
54
+ },
55
+ "gitHead": "bf1ceb4582381c74ba41ccf11b89d3b9e7b73628"
37
56
  }
@@ -0,0 +1,132 @@
1
+ // eslint-disable
2
+ /** interceptor: begin */
3
+ export * from '../bean/interceptor.body.js';
4
+ export * from '../bean/interceptor.headers.js';
5
+ export * from '../bean/interceptor.jwt.js';
6
+ export * from '../bean/interceptor.mock.js';
7
+ export * from '../bean/interceptor.performAction.js';
8
+ import { IInterceptorOptionsBody } from '../bean/interceptor.body.js';
9
+ import { IInterceptorOptionsHeaders } from '../bean/interceptor.headers.js';
10
+ import { IInterceptorOptionsJwt } from '../bean/interceptor.jwt.js';
11
+ import { IInterceptorOptionsMock } from '../bean/interceptor.mock.js';
12
+ import { IInterceptorOptionsPerformAction } from '../bean/interceptor.performAction.js';
13
+ import 'zova-module-a-fetch';
14
+ declare module 'zova-module-a-fetch' {
15
+
16
+ export interface IInterceptorRecord {
17
+ 'a-interceptor:body': IInterceptorOptionsBody;
18
+ 'a-interceptor:headers': IInterceptorOptionsHeaders;
19
+ 'a-interceptor:jwt': IInterceptorOptionsJwt;
20
+ 'a-interceptor:mock': IInterceptorOptionsMock;
21
+ 'a-interceptor:performAction': IInterceptorOptionsPerformAction;
22
+ }
23
+
24
+
25
+ }
26
+ declare module 'zova-module-a-interceptor' {
27
+
28
+ export interface InterceptorBody {
29
+ /** @internal */
30
+ get scope(): ScopeModuleAInterceptor;
31
+ }
32
+
33
+ export interface InterceptorBody {
34
+ get $beanFullName(): 'a-interceptor.interceptor.body';
35
+ get $onionName(): 'a-interceptor:body';
36
+ get $onionOptions(): IInterceptorOptionsBody;
37
+ }
38
+
39
+ export interface InterceptorHeaders {
40
+ /** @internal */
41
+ get scope(): ScopeModuleAInterceptor;
42
+ }
43
+
44
+ export interface InterceptorHeaders {
45
+ get $beanFullName(): 'a-interceptor.interceptor.headers';
46
+ get $onionName(): 'a-interceptor:headers';
47
+ get $onionOptions(): IInterceptorOptionsHeaders;
48
+ }
49
+
50
+ export interface InterceptorJwt {
51
+ /** @internal */
52
+ get scope(): ScopeModuleAInterceptor;
53
+ }
54
+
55
+ export interface InterceptorJwt {
56
+ get $beanFullName(): 'a-interceptor.interceptor.jwt';
57
+ get $onionName(): 'a-interceptor:jwt';
58
+ get $onionOptions(): IInterceptorOptionsJwt;
59
+ }
60
+
61
+ export interface InterceptorMock {
62
+ /** @internal */
63
+ get scope(): ScopeModuleAInterceptor;
64
+ }
65
+
66
+ export interface InterceptorMock {
67
+ get $beanFullName(): 'a-interceptor.interceptor.mock';
68
+ get $onionName(): 'a-interceptor:mock';
69
+ get $onionOptions(): IInterceptorOptionsMock;
70
+ }
71
+
72
+ export interface InterceptorPerformAction {
73
+ /** @internal */
74
+ get scope(): ScopeModuleAInterceptor;
75
+ }
76
+
77
+ export interface InterceptorPerformAction {
78
+ get $beanFullName(): 'a-interceptor.interceptor.performAction';
79
+ get $onionName(): 'a-interceptor:performAction';
80
+ get $onionOptions(): IInterceptorOptionsPerformAction;
81
+ }
82
+ }
83
+ /** interceptor: end */
84
+ /** interceptor: begin */
85
+ import { InterceptorBody } from '../bean/interceptor.body.js';
86
+ import { InterceptorHeaders } from '../bean/interceptor.headers.js';
87
+ import { InterceptorJwt } from '../bean/interceptor.jwt.js';
88
+ import { InterceptorMock } from '../bean/interceptor.mock.js';
89
+ import { InterceptorPerformAction } from '../bean/interceptor.performAction.js';
90
+ import 'zova';
91
+ declare module 'zova' {
92
+ export interface IBeanRecordLocal {
93
+ 'a-interceptor.interceptor.body': InterceptorBody;
94
+ 'a-interceptor.interceptor.headers': InterceptorHeaders;
95
+ 'a-interceptor.interceptor.jwt': InterceptorJwt;
96
+ 'a-interceptor.interceptor.mock': InterceptorMock;
97
+ 'a-interceptor.interceptor.performAction': InterceptorPerformAction;
98
+ }
99
+ }
100
+ /** interceptor: end */
101
+ /** config: begin */
102
+ export * from '../config/config.js';
103
+ import { config } from '../config/config.js';
104
+ /** config: end */
105
+ /** scope: begin */
106
+ import { BeanScopeBase, type BeanScopeUtil, TypeModuleConfig } from 'zova';
107
+ import { Scope } from 'zova-module-a-bean';
108
+
109
+ @Scope()
110
+ export class ScopeModuleAInterceptor extends BeanScopeBase {}
111
+
112
+ export interface ScopeModuleAInterceptor {
113
+ util: BeanScopeUtil;
114
+ config: TypeModuleConfig<typeof config>;
115
+ }
116
+
117
+ import 'zova';
118
+ declare module 'zova' {
119
+ export interface IBeanScopeRecord {
120
+ 'a-interceptor': ScopeModuleAInterceptor;
121
+ }
122
+
123
+ export interface IBeanScopeConfig {
124
+ 'a-interceptor': ReturnType<typeof config>;
125
+ }
126
+
127
+
128
+
129
+
130
+ }
131
+
132
+ /** scope: end */
@@ -0,0 +1,2 @@
1
+ export const __ThisModule__ = 'a-interceptor';
2
+ export { ScopeModuleAInterceptor as ScopeModule } from './index.js';
@@ -0,0 +1,43 @@
1
+ import type { AxiosError, AxiosResponse } from 'axios';
2
+ import type {
3
+ IDecoratorInterceptorOptions,
4
+ IInterceptorResponse,
5
+ IInterceptorResponseError,
6
+ NextInterceptorError,
7
+ NextInterceptorResponse,
8
+ } from 'zova-module-a-fetch';
9
+
10
+ import { cast } from 'zova';
11
+ import { BeanInterceptorBase, Interceptor, SymbolInterceptorBodyResponseFlag } from 'zova-module-a-fetch';
12
+
13
+ export interface IInterceptorOptionsBody extends IDecoratorInterceptorOptions {}
14
+
15
+ @Interceptor<IInterceptorOptionsBody>({ dependencies: 'a-interceptor:performAction' })
16
+ export class InterceptorBody extends BeanInterceptorBase<IInterceptorOptionsBody> implements IInterceptorResponse, IInterceptorResponseError {
17
+ async onResponse(response: AxiosResponse, _options: IInterceptorOptionsBody, next: NextInterceptorResponse): Promise<AxiosResponse> {
18
+ response = await next();
19
+ const contentType = response.headers['content-type'];
20
+ if (!contentType || !contentType.includes('application/json')) {
21
+ response[SymbolInterceptorBodyResponseFlag] = true;
22
+ return response;
23
+ }
24
+ if (response.data.code !== 0) {
25
+ const error = new Error();
26
+ error.code = response.data.code;
27
+ error.message = response.data.message;
28
+ throw error;
29
+ }
30
+ // return data
31
+ return response.data.data ?? null;
32
+ }
33
+
34
+ async onResponseError(error: AxiosError, _options: IInterceptorOptionsBody, next: NextInterceptorError): Promise<AxiosError> {
35
+ error = await next();
36
+ if (!(error instanceof Error)) return error;
37
+ if (error.response) {
38
+ error.code = cast(error.response.data)?.code ?? error.response.status;
39
+ error.message = cast(error.response.data)?.message ?? error.response.statusText;
40
+ }
41
+ return error;
42
+ }
43
+ }
@@ -0,0 +1,29 @@
1
+ import { AxiosRequestConfig } from 'axios';
2
+ import { $customKey } from 'zova-core';
3
+ import { BeanInterceptorBase, IDecoratorInterceptorOptions, Interceptor, NextInterceptorRequest } from 'zova-module-a-fetch';
4
+
5
+ export interface IInterceptorOptionsHeaders extends IDecoratorInterceptorOptions {
6
+ openapiSchema?: boolean;
7
+ }
8
+
9
+ @Interceptor<IInterceptorOptionsHeaders>({ dependencies: 'a-interceptor:mock' })
10
+ export class InterceptorHeaders extends BeanInterceptorBase<IInterceptorOptionsHeaders> {
11
+ async onRequest(config: AxiosRequestConfig, options: IInterceptorOptionsHeaders, next: NextInterceptorRequest): Promise<AxiosRequestConfig> {
12
+ // locale
13
+ const keyLocale = this.sys.env.APP_LOCALE_HEADER_KEY;
14
+ if (keyLocale && !config.headers![keyLocale]) {
15
+ config.headers![keyLocale] = this.app.meta.locale.current;
16
+ }
17
+ // tz
18
+ const keyTz = this.sys.env.APP_TZ_HEADER_KEY;
19
+ if (keyTz && !config.headers![keyTz]) {
20
+ config.headers![keyTz] = this.app.meta.locale.tz;
21
+ }
22
+ // openapi schema
23
+ if (options.openapiSchema) {
24
+ config.headers![$customKey('x-vona-openapi-schema')] = true;
25
+ }
26
+ // next
27
+ return next(config);
28
+ }
29
+ }
@@ -0,0 +1,98 @@
1
+ import type { AxiosRequestConfig } from 'axios';
2
+ import type { BeanFetch, IDecoratorInterceptorOptions, IInterceptorRequest, NextInterceptorRequest } from 'zova-module-a-fetch';
3
+
4
+ import { $customKey } from 'zova-core';
5
+ import { BeanInterceptorBase, Interceptor } from 'zova-module-a-fetch';
6
+
7
+ import type { IJwtAdapter, IJwtInfo } from '../types/jwt.js';
8
+
9
+ export interface IInterceptorOptionsJwt extends IDecoratorInterceptorOptions {
10
+ jwtAdapter?: string;
11
+ authToken?: boolean | string;
12
+ }
13
+
14
+ @Interceptor<IInterceptorOptionsJwt>({ dependencies: 'a-interceptor:headers' })
15
+ export class InterceptorJwt extends BeanInterceptorBase<IInterceptorOptionsJwt> implements IInterceptorRequest {
16
+ private _beanJwtAdapter: IJwtAdapter;
17
+ private _refreshAuthTokenPromise?: Promise<IJwtInfo>;
18
+
19
+ protected async __init__(_beanFetch: BeanFetch, options: IInterceptorOptionsJwt) {
20
+ const jwtAdapter = options.jwtAdapter || this.scope.config.jwtAdapter;
21
+ const beanFullName = jwtAdapter.replace(':', '.service.');
22
+ // singleton
23
+ this._beanJwtAdapter = await this.app.bean._getBean(beanFullName as any, true);
24
+ }
25
+
26
+ async onRequest(config: AxiosRequestConfig, options: IInterceptorOptionsJwt, next: NextInterceptorRequest): Promise<AxiosRequestConfig> {
27
+ try {
28
+ const accessToken = await this.prepareAccessToken(config, options.authToken);
29
+ if (accessToken) {
30
+ config.headers!.Authorization = `Bearer ${accessToken}`;
31
+ }
32
+ } catch (error: any) {
33
+ error.config = config;
34
+ error.request = undefined;
35
+ error.response = undefined;
36
+ throw error;
37
+ }
38
+ return next(config);
39
+ }
40
+
41
+ async prepareAccessToken(config: AxiosRequestConfig, authToken: string | boolean | undefined): Promise<string | undefined> {
42
+ if (!this.sys.config.api.jwt) return;
43
+ // use default in scope.config rather than IInterceptorOptionsJwt.options
44
+ const authTokenCurrent = authToken ?? this.scope.config.authToken.default;
45
+ // authToken = authToken ?? this.scope.config.authToken.default;
46
+ if (process.env.SERVER) {
47
+ config.headers![$customKey('x-vona-jwt-authtoken')] = typeof authTokenCurrent === 'string' ? true : authTokenCurrent;
48
+ }
49
+ // // authToken: false
50
+ // if (authTokenCurrent === false) return;
51
+ // authToken: string
52
+ if (typeof authTokenCurrent === 'string') return authTokenCurrent;
53
+ // if (typeof authToken === 'string') return authToken;
54
+ // authToken: true
55
+ let jwtInfo = await this._beanJwtAdapter.getJwtInfo();
56
+ if (!jwtInfo) {
57
+ if (authToken === true) {
58
+ this.app.throw(401); // 401 rather than 403
59
+ }
60
+ return;
61
+ }
62
+ // accessToken
63
+ if (process.env.SERVER || !jwtInfo.expireTime || jwtInfo.expireTime > Date.now()) {
64
+ if (!jwtInfo.accessToken) {
65
+ if (authToken === true) this.app.throw(401);
66
+ return;
67
+ }
68
+ return jwtInfo.accessToken;
69
+ }
70
+ // refreshToken
71
+ if (!jwtInfo.refreshToken) {
72
+ if (authToken === true) this.app.throw(401);
73
+ return;
74
+ } else {
75
+ if (authToken === false) {
76
+ // need not refreshAuthToken, such as captcha.create
77
+ return;
78
+ }
79
+ }
80
+ jwtInfo = await this._refreshAuthToken(jwtInfo.refreshToken);
81
+ return jwtInfo.accessToken;
82
+ }
83
+
84
+ private async _refreshAuthToken(refreshToken: string) {
85
+ if (!this._refreshAuthTokenPromise) {
86
+ this._refreshAuthTokenPromise = this._refreshAuthTokenInner(refreshToken);
87
+ }
88
+ return await this._refreshAuthTokenPromise;
89
+ }
90
+
91
+ private async _refreshAuthTokenInner(refreshToken: string) {
92
+ try {
93
+ return await this._beanJwtAdapter.refreshAuthToken(refreshToken);
94
+ } finally {
95
+ this._refreshAuthTokenPromise = undefined;
96
+ }
97
+ }
98
+ }
@@ -0,0 +1,44 @@
1
+ import { AxiosError } from 'axios';
2
+ import {
3
+ BeanInterceptorBase,
4
+ IDecoratorInterceptorOptions,
5
+ IInterceptorResponseError,
6
+ Interceptor,
7
+ NextInterceptorError,
8
+ SymbolInterceptorBodyResponseFlag,
9
+ } from 'zova-module-a-fetch';
10
+
11
+ export interface IInterceptorOptionsMock extends IDecoratorInterceptorOptions {}
12
+
13
+ // not include: ERR_BAD_RESPONSE
14
+ const __ErrorsShouldBeMocked = ['ECONNREFUSED', 'ERR_NETWORK', '404'];
15
+
16
+ @Interceptor<IInterceptorOptionsMock>()
17
+ export class InterceptorMock extends BeanInterceptorBase<IInterceptorOptionsMock> implements IInterceptorResponseError {
18
+ async onResponseError(error: AxiosError, _options: IDecoratorInterceptorOptions, next: NextInterceptorError): Promise<AxiosError> {
19
+ if (!(error instanceof Error)) return next();
20
+ if (this.sys.env.MOCK_ENABLED === 'true') {
21
+ if (process.env.DEV || (process.env.PROD && this.sys.env.MOCK_BUILD === 'true')) {
22
+ if (__ErrorsShouldBeMocked.includes(String(error.code)) || error.status === 404) {
23
+ const config = error.config!;
24
+ if (config.baseURL) {
25
+ const port = process.env.DEV ? this.sys.env.DEV_SERVER_PORT : this.sys.env.MOCK_BUILD_PORT;
26
+ let baseURL = `http://localhost:${port}`;
27
+ if (config.baseURL.endsWith(this.sys.env.API_PREFIX!)) {
28
+ baseURL = `${baseURL}${this.sys.env.API_PREFIX}`;
29
+ }
30
+ if (config.baseURL !== baseURL && config.baseURL !== this.sys.env.API_PREFIX) {
31
+ const response = await this.$fetch.request(Object.assign({}, config, { baseURL }));
32
+ if (response && response[SymbolInterceptorBodyResponseFlag]) {
33
+ return response.data;
34
+ } else {
35
+ return response as any;
36
+ }
37
+ }
38
+ }
39
+ }
40
+ }
41
+ }
42
+ return next();
43
+ }
44
+ }
@@ -0,0 +1,31 @@
1
+ import { catchError } from '@cabloy/utils';
2
+ import { AxiosRequestConfig } from 'axios';
3
+ import { cast } from 'zova';
4
+ import { BeanInterceptorBase, IDecoratorInterceptorOptions, IInterceptorRequest, Interceptor, NextInterceptorRequest } from 'zova-module-a-fetch';
5
+ import { ISsrSitePerformActionOptions } from 'zova-module-a-ssr';
6
+
7
+ export interface IInterceptorOptionsPerformAction extends IDecoratorInterceptorOptions {}
8
+
9
+ @Interceptor<IInterceptorOptionsPerformAction>({ dependencies: 'a-interceptor:jwt' })
10
+ export class InterceptorPerformAction extends BeanInterceptorBase<IInterceptorOptionsPerformAction> implements IInterceptorRequest {
11
+ async onRequest(config: AxiosRequestConfig, _options: IInterceptorOptionsPerformAction, next: NextInterceptorRequest): Promise<AxiosRequestConfig> {
12
+ if (process.env.CLIENT) return next();
13
+ const performAction = this.ctx.meta.$ssr.getPerformAction(config.baseURL);
14
+ if (!performAction) return next();
15
+ const data: ISsrSitePerformActionOptions = {
16
+ method: config.method as any,
17
+ path: config.url!,
18
+ query: config.params,
19
+ body: config.data,
20
+ headers: config.headers,
21
+ };
22
+ const [result, error] = await catchError(() => {
23
+ return performAction(data);
24
+ });
25
+ if (error) {
26
+ cast(error).config = config;
27
+ throw error;
28
+ }
29
+ throw result;
30
+ }
31
+ }
@@ -0,0 +1,11 @@
1
+ import type { ZovaSys } from 'zova';
2
+ import type { IServiceRecord } from 'zova-module-a-bean';
3
+
4
+ export const config = (_sys: ZovaSys) => {
5
+ return {
6
+ jwtAdapter: 'home-api:jwtAdapter' as keyof IServiceRecord,
7
+ authToken: {
8
+ default: true,
9
+ },
10
+ };
11
+ };
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './.metadata/index.js';
2
+ export * from './types/index.js';
@@ -0,0 +1 @@
1
+ export * from './jwt.js';
@@ -0,0 +1,11 @@
1
+ export interface IJwtAdapter {
2
+ getJwtInfo(): Promise<IJwtInfo | undefined>;
3
+ refreshAuthToken(refreshToken: string): Promise<IJwtInfo>;
4
+ }
5
+
6
+ export interface IJwtInfo {
7
+ accessToken: string;
8
+ refreshToken?: string;
9
+ expiresIn?: number;
10
+ expireTime?: number;
11
+ }
package/README.md DELETED
@@ -1 +0,0 @@
1
- # @cabloy/set