@complex-suite/request
Advanced tools
| // request 包类型集中管理 | ||
| // 来源:src/{BaseRequest, Rule, Token}.ts | ||
| import type { messageType } from '@complex-suite/plugin' | ||
| // 来自 Token.ts | ||
| export type locationType = 'body' | 'header' | 'params' | ||
| // Token.ts 私有类型(不导出,仅供 TokenInitOption 使用) | ||
| type getValueType = () => unknown | ||
| type isExistType = (data: unknown) => boolean | ||
| type clearType = getValueType | ||
| type destroyType = clearType | ||
| export interface TokenInitOption { | ||
| value?: unknown | ||
| require?: boolean // 是否必选,必选则会在isExist返回不存在时失败,可能触发rule.login | ||
| location?: locationType // 位置 | ||
| time?: number // 本地缓存有效期 | ||
| session?: boolean // 本地缓存是否为session | ||
| getValue?: getValueType // 获取value函数实现,如存在此函数则不会直接从value中取值 | ||
| isExist?: isExistType // 判断数据是否存在,用户require判断和缓存获取判断 | ||
| clear?: clearType // 清除数据 | ||
| destroy?: destroyType // 销毁数据/会先触发清除数据 | ||
| } | ||
| // 来自 Rule.ts | ||
| export type tokenType = { | ||
| time?: number | ||
| session?: boolean | ||
| data?: Record<string, TokenInitOption> | ||
| refreshToken?: TokenInitOption | ||
| } | ||
| export interface responseType<D = any> { | ||
| status: 'success' | 'fail' | 'login' | 'refresh' | ||
| data: D | ||
| code?: number | string | ||
| msg?: string | ||
| err?: string | Error | Record<PropertyKey, unknown> | ||
| } | ||
| // Rule.ts 私有类型(不导出,仅供 RuleInitOption 使用) | ||
| type ruleFormatType<R = Record<PropertyKey, unknown>, L = Record<PropertyKey, unknown>> = (requestConfig: RequestConfig<R, L>) => void | ||
| type ruleParseType<R = Record<PropertyKey, unknown>, L = Record<PropertyKey, unknown>> = (response: R, requestConfig: RequestConfig<R, L>) => responseType | ||
| type loginType = (trigger: 'token' | 'refresh' | 'login') => Promise<unknown> | ||
| type refreshType = () => Promise<unknown> | ||
| export interface RuleInitOption<R = Record<PropertyKey, unknown>, L = Record<PropertyKey, unknown>> { | ||
| prop: string | ||
| token?: tokenType | ||
| format?: ruleFormatType<R, L> // 跟登录无关的参数在这里进行赋值,避免token过多导致的token失效后的连锁反应,注意此时的requestConfig已经经过了token的判断,data可能为formdata | ||
| parse: ruleParseType<R, L> // 格式化返回参数 | ||
| login: loginType // 登录操作,触发于token本地验证失败时\接口login\接口refresh成功后重新调用依然需要refresh时 | ||
| refresh: refreshType // 刷新操作,触发于请求提示refresh时 | ||
| formatUrl?: formatUrlType // 格式化对应URL | ||
| } | ||
| // 来自 BaseRequest.ts | ||
| export type formatUrlType = (url: string) => string | ||
| export interface RequestInitOption<R = Record<PropertyKey, unknown>, L = Record<PropertyKey, unknown>> { | ||
| baseUrl?: string | ||
| status?: Record<number, () => string> | ||
| formatUrl?: formatUrlType | ||
| rule: RuleInitOption<R, L> | ||
| } | ||
| export type methodType = 'get' | 'post' | 'delete' | 'put' | 'patch' | 'head' | 'options' | ||
| export type failType = 'internal' | 'server' | ||
| export type totalFailType = 'token' | failType | ||
| export type failOption = { | ||
| intercept?: totalFailType[] // 内部报错判断值 | ||
| content?: string | ||
| duration?: number | ||
| type?: messageType | ||
| title?: string | ||
| } | ||
| export type requestTrigger = 'login' | 'refresh' | ||
| export interface RequestConfig<_R = Record<PropertyKey, unknown>, L = Record<PropertyKey, unknown>> { | ||
| url: string // 请求地址 | ||
| method: methodType // 请求方式 | ||
| headers: Record<string, undefined | null | string | number | boolean> // Header头 | ||
| data: Record<PropertyKey, unknown> | FormData // Body体 | ||
| params: Record<PropertyKey, unknown> // query数据 | ||
| token: boolean | string[] // Token | ||
| format?: (finalConfig: L, trigger?: requestTrigger) => unknown // 对最终的数据做格式化处理,此数据为对应请求插件的参数而非Request的参数 | ||
| currentType: 'json' | 'form' // 当前数据类型 | ||
| targetType?: 'json' | 'form' // 目标数据类型=>初始化参数,后期无效 | ||
| responseType: 'json' | 'text' | 'blob' // 返回值类型,仅json进行格式化 | ||
| responseParse: boolean // 返回值解析判断,为否不解析 | ||
| fail: false | failOption | ||
| local?: L // 请求插件的单独参数 | ||
| } |
+8
-0
@@ -0,1 +1,9 @@ | ||
| ### 2.0.7 | ||
| - refactor: 状态消息改为函数形式,实现语言切换实时更新。 | ||
| - feat(locale): 导出消息类型并改用 vue-tsc 进行类型检查。 | ||
| - docs: 更新项目文档。 | ||
| ### 2.0.6 | ||
| - refactor: 将TypeScript类型导入语法升级为type关键字形式。 | ||
| ### 1.1.2 - 1.1.3 | ||
@@ -2,0 +10,0 @@ - refactor: 将TypeScript类型导入语法升级为type关键字形式 |
+8
-17
@@ -1,24 +0,15 @@ | ||
| import BaseRequest, { type RequestConfig, type RequestInitOption, type requestTrigger, type formatUrlType, type methodType, type failType, type totalFailType, type failOption } from './src/BaseRequest' | ||
| import Rule, { type responseType, type tokenType, type RuleInitOption } from './src/Rule' | ||
| import Token, { type TokenInitOption, type locationType } from './src/Token' | ||
| import BaseRequest from './src/BaseRequest' | ||
| import Rule from './src/Rule' | ||
| import Token from './src/Token' | ||
| import { requestLocale } from './src/locale' | ||
| import type { RequestMessages } from './src/locale' | ||
| export type * from './src/types' | ||
| export { | ||
| BaseRequest, | ||
| type RequestConfig, | ||
| type RequestInitOption, | ||
| type requestTrigger, | ||
| type formatUrlType, | ||
| type methodType, | ||
| type failType, | ||
| type totalFailType, | ||
| type failOption, | ||
| Rule, | ||
| type responseType, | ||
| type tokenType, | ||
| type RuleInitOption, | ||
| Token, | ||
| type TokenInitOption, | ||
| type locationType, | ||
| requestLocale | ||
| requestLocale, | ||
| type RequestMessages | ||
| } |
+4
-5
| { | ||
| "name": "@complex-suite/request", | ||
| "version": "2.0.6", | ||
| "version": "2.0.7", | ||
| "description": "a complex request", | ||
@@ -8,4 +8,3 @@ "type": "module", | ||
| "exports": { | ||
| ".": "./index.ts", | ||
| "./locale/en": "./src/locale/en.ts" | ||
| ".": "./index.ts" | ||
| }, | ||
@@ -17,4 +16,4 @@ "repository": { | ||
| "dependencies": { | ||
| "@complex-suite/plugin": "5.0.6", | ||
| "@complex-suite/utils": "3.0.6" | ||
| "@complex-suite/utils": "3.0.7", | ||
| "@complex-suite/plugin": "5.0.7" | ||
| }, | ||
@@ -21,0 +20,0 @@ "devDependencies": { |
+18
-65
@@ -5,33 +5,12 @@ import { _Data, jsonToForm } from "@complex-suite/utils" | ||
| import Rule from "./Rule" | ||
| import type { RuleInitOption, responseType } from "./Rule" | ||
| import { requestLocale } from "./locale" | ||
| import type { RequestMessages } from "./locale" | ||
| import type { formatUrlType, RequestInitOption, methodType, failType, totalFailType, failOption, requestTrigger, RequestConfig, responseType } from "./types" | ||
| type statusType = { | ||
| [prop: number]: string | ||
| [prop: number]: () => string | ||
| } | ||
| export type formatUrlType = (url: string) => string | ||
| export type { formatUrlType, RequestInitOption, methodType, failType, totalFailType, failOption, requestTrigger, RequestConfig } | ||
| export interface RequestInitOption<R = Record<PropertyKey, unknown>, L = Record<PropertyKey, unknown>> { | ||
| baseUrl?: string | ||
| status?: statusType | ||
| formatUrl?: formatUrlType | ||
| rule: RuleInitOption<R, L> | ||
| } | ||
| export type methodType = 'get' | 'post' | 'delete' | 'put' | 'patch' | 'head' | 'options' | ||
| export type failType = 'internal' | 'server' | ||
| export type totalFailType = 'token' | failType | ||
| export type failOption = { | ||
| intercept?: totalFailType[] // 内部报错判断值 | ||
| content?: string | ||
| duration?: number | ||
| type?: messageType | ||
| title?: string | ||
| } | ||
| const defaultFormatUrlWithBaseUrl = function(this: BaseRequest, url: string) { | ||
@@ -49,35 +28,17 @@ if (!url.startsWith('https://') && !url.startsWith('http://')) { | ||
| export type requestTrigger = 'login' | 'refresh' | ||
| export interface RequestConfig<_R = Record<PropertyKey, unknown>, L = Record<PropertyKey, unknown>> { | ||
| url: string // 请求地址 | ||
| method: methodType // 请求方式 | ||
| headers: Record<string, undefined | null | string | number | boolean> // Header头 | ||
| data: Record<PropertyKey, unknown> | FormData // Body体 | ||
| params: Record<PropertyKey, unknown> // query数据 | ||
| token: boolean | string[] // Token | ||
| format?: (finalConfig: L, trigger?: requestTrigger) => unknown // 对最终的数据做格式化处理,此数据为对应请求插件的参数而非Request的参数 | ||
| currentType: 'json' | 'form' // 当前数据类型 | ||
| targetType?: 'json' | 'form' // 目标数据类型=>初始化参数,后期无效 | ||
| responseType: 'json' | 'text' | 'blob' // 返回值类型,仅json进行格式化 | ||
| responseParse: boolean // 返回值解析判断,为否不解析 | ||
| fail: false | failOption | ||
| local?: L // 请求插件的单独参数 | ||
| } | ||
| abstract class BaseRequest<R = Record<PropertyKey, unknown>, L = Record<PropertyKey, unknown>> extends _Data { | ||
| static $name = 'BaseRequest' | ||
| static $formatConfig = { name: 'Request:BaseRequest', level: 5, recommend: false } | ||
| static $status = { | ||
| 400: 'status.400', | ||
| 403: 'status.403', | ||
| 404: 'status.404', | ||
| 405: 'status.405', | ||
| 408: 'status.408', | ||
| 410: 'status.410', | ||
| 500: 'status.500', | ||
| 502: 'status.502', | ||
| 503: 'status.503', | ||
| 504: 'status.504', | ||
| 505: 'status.505' | ||
| static $status: statusType = { | ||
| 400: () => requestLocale.t('status.400'), | ||
| 403: () => requestLocale.t('status.403'), | ||
| 404: () => requestLocale.t('status.404'), | ||
| 405: () => requestLocale.t('status.405'), | ||
| 408: () => requestLocale.t('status.408'), | ||
| 410: () => requestLocale.t('status.410'), | ||
| 500: () => requestLocale.t('status.500'), | ||
| 502: () => requestLocale.t('status.502'), | ||
| 503: () => requestLocale.t('status.503'), | ||
| 504: () => requestLocale.t('status.504'), | ||
| 505: () => requestLocale.t('status.505') | ||
| } | ||
@@ -117,13 +78,5 @@ static $contentType = { | ||
| this.baseUrl = initOption.baseUrl | ||
| // 翻译默认的 $status 键值,用户自定义值保持原样 | ||
| const translatedStatus: statusType = {} | ||
| const statusConfig = (this.constructor as typeof BaseRequest).$status | ||
| for (const code of Object.keys(statusConfig)) { | ||
| const key = statusConfig[code as unknown as keyof typeof statusConfig] as keyof RequestMessages & string | ||
| translatedStatus[code as unknown as number] = requestLocale.t(key) | ||
| } | ||
| this.status = { | ||
| ...translatedStatus, | ||
| ...initOption.status | ||
| } | ||
| // status 为函数表:每个 code 对应一个 () => string 函数,调用时实时翻译, | ||
| // 保证语言切换后实时更新 | ||
| this.status = { ...(this.constructor as typeof BaseRequest).$status, ...initOption.status } | ||
| this.formatUrl = this._getFormatUrl(initOption.formatUrl) | ||
@@ -130,0 +83,0 @@ this.rule = new Rule(initOption.rule) |
+2
-4
@@ -28,6 +28,4 @@ import type { LocalePack } from '@complex-suite/utils' | ||
| `Token rule for "${params.tokenName}" not found, getToken failed!`, | ||
| 'rule.refreshToken.setFail': | ||
| 'Token rule for refreshToken not found, setRefreshToken failed!', | ||
| 'rule.refreshToken.getFail': | ||
| 'Token rule for refreshToken not found, getRefreshToken failed!', | ||
| 'rule.refreshToken.setFail': 'Token rule for refreshToken not found, setRefreshToken failed!', | ||
| 'rule.refreshToken.getFail': 'Token rule for refreshToken not found, getRefreshToken failed!', | ||
| 'rule.token.clearFail': (params) => | ||
@@ -34,0 +32,0 @@ `Token rule for "${params.tokenName}" not found, clearToken failed!`, |
@@ -10,9 +10,9 @@ import { Locale } from '@complex-suite/utils' | ||
| * 【语言包按需加载/注册】构造时默认仅注册中文包。 | ||
| * 英文包 en 作为独立子路径导出(./locale/en),主入口不加载它,避免无谓的模块求值开销。 | ||
| * 需要英文时显式导入并注册: | ||
| * import en from '@complex-suite/request/locale/en' | ||
| * requestLocale.registerLocale(en) | ||
| * 英文包通过 registerLoader 注册动态加载器,setLocaleAsync 时自动按需 import。 | ||
| */ | ||
| const requestLocale = new Locale<RequestMessages>({ pack: zh, name: 'request' }) | ||
| /** 注册英文包动态加载器,setLocaleAsync 时自动触发按需加载 */ | ||
| requestLocale.registerLoader('en-US', () => import('./en').then(m => m.default)) | ||
| export { | ||
@@ -19,0 +19,0 @@ requestLocale, |
+2
-26
| import { _Data } from "@complex-suite/utils" | ||
| import Token from "./Token" | ||
| import type { TokenInitOption } from "./Token" | ||
| import type { RequestConfig } from "./BaseRequest" | ||
| import { requestLocale } from "./locale" | ||
| import type { tokenType, responseType, RuleInitOption, formatUrlType } from "./types" | ||
| export type tokenType = { | ||
| time?: number | ||
| session?: boolean | ||
| data?: Record<string, TokenInitOption> | ||
| refreshToken?: TokenInitOption | ||
| } | ||
| export type { tokenType, responseType, RuleInitOption } | ||
| export interface responseType<D = any> { | ||
| status: 'success' | 'fail' | 'login' | 'refresh' | ||
| data: D | ||
| code?: number | string | ||
| msg?: string | ||
| err?: string | Error | Record<PropertyKey, unknown> | ||
| } | ||
| type formatType<R = Record<PropertyKey, unknown>, L = Record<PropertyKey, unknown>> = (requestConfig: RequestConfig<R, L>) => void | ||
| type parseType<R = Record<PropertyKey, unknown>, L = Record<PropertyKey, unknown>> = (response: R, requestConfig: RequestConfig<R, L>) => responseType | ||
| type formatUrlType = (url: string) => string | ||
| type loginType = (trigger: 'token' | 'refresh' | 'login') => Promise<unknown> | ||
| type refreshType = () => Promise<unknown> | ||
| export interface RuleInitOption<R = Record<PropertyKey, unknown>, L = Record<PropertyKey, unknown>> { | ||
| prop: string | ||
| token?: tokenType | ||
| format?: formatType<R, L> // 跟登录无关的参数在这里进行赋值,避免token过多导致的token失效后的连锁反应,注意此时的requestConfig已经经过了token的判断,data可能为formdata | ||
| parse: parseType<R, L> // 格式化返回参数 | ||
| login: loginType // 登录操作,触发于token本地验证失败时\接口login\接口refresh成功后重新调用依然需要refresh时 | ||
| refresh: refreshType // 刷新操作,触发于请求提示refresh时 | ||
| formatUrl?: formatUrlType // 格式化对应URL | ||
| } | ||
| function defaultFormatUrl(url: string) { | ||
@@ -39,0 +15,0 @@ return url |
+3
-14
| import { isExist, storage, appendProp } from '@complex-suite/utils' | ||
| import type { RequestConfig } from './BaseRequest' | ||
| import type { locationType, TokenInitOption } from './types' | ||
| export type { locationType, TokenInitOption } | ||
| type getValueType = () => unknown | ||
@@ -10,16 +13,2 @@ type removeValueType = getValueType | ||
| export type locationType = 'body' | 'header' | 'params' | ||
| export interface TokenInitOption { | ||
| value?: unknown | ||
| require?: boolean // 是否必选,必选则会在isExist返回不存在时失败,可能触发rule.login | ||
| location?: locationType // 位置 | ||
| time?: number // 本地缓存有效期 | ||
| session?: boolean // 本地缓存是否为session | ||
| getValue?: getValueType // 获取value函数实现,如存在此函数则不会直接从value中取值 | ||
| isExist?: isExistType // 判断数据是否存在,用户require判断和缓存获取判断 | ||
| clear?: clearType // 清除数据 | ||
| destroy?: destroyType // 销毁数据/会先触发清除数据 | ||
| } | ||
| function setValue(this: Token, data: unknown, unSave?: boolean) { | ||
@@ -26,0 +15,0 @@ this.value = data |
+2
-0
| import { defineConfig } from 'vitest/config' | ||
| import { fileURLToPath } from 'node:url' | ||
| export default defineConfig({ | ||
| root: fileURLToPath(new URL('.', import.meta.url)), | ||
| test: { | ||
@@ -5,0 +7,0 @@ globals: true, |
46381
2.67%14
7.69%+ Added
+ Added
- Removed
- Removed
Updated
Updated