iota-fetch 0.0.4 → 0.1.1

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/README.md CHANGED
@@ -1,92 +1,206 @@
1
- ### 安装
2
-
3
- ```tex
4
- npm install iota-fetch
5
- ```
6
-
7
- ### 使用 ①
8
-
9
- ```js
10
- import createFetch from "iota-fetch"
11
-
12
- // requestConfig 请求配置项 同axios config
13
- const requestConfig = {};
14
-
15
- // 请求拦截
16
- function requestIntercept() {
17
- let intercept = (config) => {
18
- // 在发送请求之前做些什么
19
- return config;
20
- }
21
- let error = (error) => {
22
- // 对请求错误做些什么
23
- return Promise.reject(error);
24
- }
25
- return [intercept, error]
26
- }
27
-
28
- // 相应拦截
29
- function responseIntercept() {
30
- let intercept = (response) => {
31
- // 2xx 范围内的状态码都会触发该函数。
32
- console.log(response, "响应拦截器")
33
- return response;
34
- }
35
- let error = () => {
36
- // 超出 2xx 范围的状态码都会触发该函数。
37
- return Promise.reject(error);
38
- }
39
- return [intercept, error]
40
- }
41
-
42
- let { fetch } = createFetch({ requestIntercept, responseIntercept, requestConfig })
43
- ```
44
-
45
- ### 使用
46
-
47
- ```tsx
48
- import createFetch from "iota-fetch"
49
-
50
- // requestConfig 请求配置项 同axios config
51
- const requestConfig = {};
52
-
53
- //loading -> loading.show() loading.hide()
54
- const { fetch, instance } = createFetch({ requestConfig, loading})
55
-
56
- // fetch 请求方法 fetch.get fetch.post fetch.put ...
57
- // 创建的axios 实例 instance 添加拦截器
58
-
59
- // 添加请求拦截器
60
- instance.interceptors.request.use(function (config) {
61
- // 在发送请求之前做些什么
62
- return config;
63
- }, function (error) {
64
- // 对请求错误做些什么
65
- return Promise.reject(error);
66
- });
67
-
68
- // 添加响应拦截器
69
- instance.interceptors.response.use(function (response) {
70
- // 2xx 范围内的状态码都会触发该函数。
71
- return response;
72
- }, function (error) {
73
- // 超出 2xx 范围的状态码都会触发该函数。
74
- return Promise.reject(error);
75
- });
76
-
77
- export default fetch;
78
- ```
79
-
80
-
81
-
82
- ### 取消请求
83
-
84
- ```js
85
- import { requestQueue } from "iota-fetch"
86
- // requestQueue 有一个队列用于请求未响应的队列
87
-
88
- // getQueue() 获取队列
89
- // createMapKey(method, path, data) 生成map key // 参数 data传入口会序列化
90
- // abortive(key) map key取消请求的key
91
- // removeResAll() 取消队列中所有的请求
92
- ```
1
+ # iota-fetch
2
+
3
+ 一个基于 **axios** 的二次封装请求库,提供统一的 `get/post/delete/put/patch` 调用方式,并内置**请求队列**能力(可按 key 中断单个请求或中断全部请求)。支持自定义 axios 默认配置、请求/响应拦截器,以及可选的 loading 显示/隐藏钩子。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm i iota-fetch axios
9
+ ```
10
+
11
+ > 本项目本身依赖 `axios`,如果你在业务工程里已安装 axios,可按你的依赖管理策略处理(避免重复安装/版本冲突)。
12
+
13
+ ## 快速开始
14
+
15
+ ```ts
16
+ import { createFetch } from "iota-fetch";
17
+
18
+ const fetch = createFetch({
19
+ requestConfig: {
20
+ baseURL: "https://api.example.com",
21
+ headers: {
22
+ "Content-Type": "application/json;charset=utf-8",
23
+ },
24
+ },
25
+ });
26
+
27
+ // GET:第二个参数会作为 query params
28
+ const list = await fetch.get("/items", { page: 1, pageSize: 10 });
29
+
30
+ // POST:第二个参数会作为 body data
31
+ const created = await fetch.post("/items", { name: "foo" });
32
+ ```
33
+
34
+ ## API
35
+
36
+ ### `createFetch(options)`
37
+
38
+ 创建一个包含 `get/post/delete/put/patch` 的请求对象。
39
+
40
+ #### 参数 `options`
41
+
42
+ - **`requestConfig`**: `CreateAxiosDefaults`
43
+ - axios 实例默认配置(如 `baseURL`、`timeout`、`headers` 等)
44
+ - **`requestIntercept?`**: `() => { onFulfilled, onRejected }`
45
+ - 请求拦截器工厂函数(内部会 `instance.interceptors.request.use(...)`)
46
+ - **`responseIntercept?`**: `() => { onFulfilled, onRejected }`
47
+ - 响应拦截器工厂函数(内部会 `instance.interceptors.response.use(...)`)
48
+ - **`loading?`**: `{ show(): void; hide(): void }`
49
+ - 传入后可配合单次请求的 `config.loading` 控制显示/隐藏
50
+
51
+ #### 返回值
52
+
53
+ 返回 `fetch` 对象:
54
+
55
+ - **`fetch.get(url, data?, config?)`**
56
+ - **`fetch.delete(url, data?, config?)`**
57
+ - **`fetch.post(url, data?, config?)`**
58
+ - **`fetch.put(url, data?, config?)`**
59
+ - **`fetch.patch(url, data?, config?)`**
60
+
61
+ 其中:
62
+ - `url: string`
63
+ - `data?: any`
64
+ - `config?: AxiosRequestConfig & { loading?: boolean }`
65
+
66
+ 行为规则:
67
+ - `get/delete`:`data` 会被放到 `params`
68
+ - `post/put/patch`:`data` 会被放到 `data`
69
+ - 返回值:默认 `Promise<R>`,内部 `resolve(res.data)`
70
+
71
+ ### 拦截器示例
72
+
73
+ ```ts
74
+ import type { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from "axios";
75
+ import { createFetch } from "iota-fetch";
76
+
77
+ const fetch = createFetch({
78
+ requestConfig: { baseURL: "https://api.example.com" },
79
+ requestIntercept: () => ({
80
+ onFulfilled: (config: InternalAxiosRequestConfig) => {
81
+ config.headers.set("X-Token", "your-token");
82
+ return config;
83
+ },
84
+ onRejected: (error: AxiosError) => Promise.reject(error),
85
+ }),
86
+ responseIntercept: () => ({
87
+ onFulfilled: (resp: AxiosResponse) => resp,
88
+ onRejected: (error: AxiosError) => Promise.reject(error),
89
+ }),
90
+ });
91
+ ```
92
+
93
+ ### Loading 示例
94
+
95
+ ```ts
96
+ import { createFetch } from "iota-fetch";
97
+
98
+ const loading = {
99
+ show: () => console.log("loading show"),
100
+ hide: () => console.log("loading hide"),
101
+ };
102
+
103
+ const fetch = createFetch({
104
+ requestConfig: { baseURL: "https://api.example.com" },
105
+ loading,
106
+ });
107
+
108
+ // 只有当 config.loading 为 true 才会触发 show/hide
109
+ await fetch.get("/items", { page: 1 }, { loading: true });
110
+ ```
111
+
112
+ ## 请求队列与取消请求
113
+
114
+ 包对外导出 `requestQueue`,内部用 `AbortController` 管理请求。
115
+
116
+ ```ts
117
+ import { requestQueue } from "iota-fetch";
118
+
119
+ // 获取当前队列(Map<key, AbortController>)
120
+ const q = requestQueue.getQueue();
121
+ ```
122
+
123
+ ### key 规则
124
+
125
+ key 默认由以下规则生成:
126
+
127
+ 1. 基础部分:`method + "-" + url`
128
+ 2. 数据部分:如果存在 `data`,则对其进行以下处理:
129
+ - 递归排序对象键
130
+ - 清洗数据(过滤 `undefined` 和函数)
131
+ - 将处理后的数据转换为 JSON 字符串
132
+ - 使用 MD5 生成哈希值
133
+ 3. 最终 key:`基础部分 + "-" + MD5哈希值`
134
+
135
+ 这样处理的好处是:
136
+ - 相同的请求参数(无论顺序如何)会生成相同的 key
137
+ - 避免了复杂参数导致 key 过长的问题
138
+ - 提高了 key 的唯一性和安全性
139
+
140
+ 你也可以手动生成:
141
+
142
+ ```ts
143
+ const key = requestQueue.createKey("get", "/items", { page: 1 });
144
+ ```
145
+
146
+ 示例:
147
+ ```ts
148
+ // 以下两个请求会生成相同的 key
149
+ const key1 = requestQueue.createKey("get", "/items", { page: 1, size: 10 });
150
+ const key2 = requestQueue.createKey("get", "/items", { size: 10, page: 1 });
151
+
152
+ // 输出示例:"get-/items-5f4dcc3b5aa765d61d8327deb882cf99"
153
+ ```
154
+
155
+ ### 中断单个请求
156
+
157
+ ```ts
158
+ requestQueue.abortive(key);
159
+ ```
160
+
161
+ ### 中断所有请求
162
+
163
+ ```ts
164
+ requestQueue.removeResAll();
165
+ ```
166
+
167
+ ### 同 key 自动取消旧请求(内置行为)
168
+
169
+ 当发起新请求时,如果队列里已存在同一个 key,会先取消旧请求再登记新请求(避免相同请求并发造成的覆盖与浪费)。
170
+
171
+ > 注意:是否算“同一个请求”取决于 key(包含 `method/url/data` 的 JSON 字符串)。
172
+
173
+ ## 开发与构建
174
+
175
+ ```bash
176
+ # 构建产物到 lib/(CJS + ESM + d.ts)
177
+ npm run build
178
+
179
+ # 开发模式(watch + 本地静态服务 + livereload)
180
+ npm run start
181
+
182
+ # 自动发布脚本(检查代码更新、npm 登录状态、版本管理)
183
+ npm run release
184
+ ```
185
+
186
+ 构建输出(默认):
187
+ - `lib/bundle.cjs.js`
188
+ - `lib/bundle.esm.js`
189
+ - `lib/main.d.ts`
190
+
191
+ ## 发布流程
192
+
193
+ 1. 运行 `npm run release` 启动发布流程
194
+ 2. 脚本会检查代码是否有更新
195
+ 3. 检查 npm 是否登录
196
+ 4. 显示当前版本和仓库版本
197
+ 5. 选择版本升级类型(小版本/中版本/大版本)
198
+ 6. 执行构建和发布
199
+ 7. 显示远程包的最新版本
200
+
201
+ ## 版本管理
202
+
203
+ - **小版本**:修复 bug,向后兼容
204
+ - **中版本**:添加新功能,向后兼容
205
+ - **大版本**:不向后兼容的变更
206
+
@@ -0,0 +1,6 @@
1
+ import type { FetchSturt, Loading, Options } from "./models";
2
+ declare const createFetch: ({ requestConfig, requestIntercept, responseIntercept, loading, }: Options & {
3
+ loading?: Loading;
4
+ }) => FetchSturt;
5
+ export { createFetch };
6
+ //# sourceMappingURL=fetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/axios/fetch.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAa,UAAU,EAAY,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAElF,QAAA,MAAM,WAAW,GAAI,kEAKlB,OAAO,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,eAiBjC,CAAC;AAEF,OAAO,EAAE,WAAW,EAAE,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { AxiosInstance } from "axios";
2
+ import { Loading, RequestConfig } from "./models";
3
+ declare const fetchData: <D, R = Record<string, any> | any>(instance: AxiosInstance, { url, method, data, config }: RequestConfig<D>, loading?: Loading) => Promise<R>;
4
+ export default fetchData;
5
+ //# sourceMappingURL=fetchFun.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetchFun.d.ts","sourceRoot":"","sources":["../../src/axios/fetchFun.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAsB,MAAM,OAAO,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGlD,QAAA,MAAM,SAAS,GAAI,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EACjD,UAAU,aAAa,EACvB,+BAA+B,aAAa,CAAC,CAAC,CAAC,EAC/C,UAAU,OAAO,KAChB,OAAO,CAAC,CAAC,CAoCX,CAAC;AAEF,eAAe,SAAS,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { type AxiosInstance } from "axios";
2
+ import { Options } from "./models";
3
+ declare const createInstance: ({ requestConfig, requestIntercept, responseIntercept }: Options) => AxiosInstance;
4
+ export default createInstance;
5
+ //# sourceMappingURL=instance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instance.d.ts","sourceRoot":"","sources":["../../src/axios/instance.ts"],"names":[],"mappings":"AAAA,OAAc,EAAE,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,QAAA,MAAM,cAAc,GAAI,wDAAwD,OAAO,KAAG,aAkBzF,CAAC;AAEF,eAAe,cAAc,CAAC"}
@@ -0,0 +1,32 @@
1
+ import type { AxiosError, AxiosRequestConfig, AxiosResponse, CreateAxiosDefaults, InternalAxiosRequestConfig, Method } from "axios";
2
+ export interface Options {
3
+ requestConfig: CreateAxiosDefaults;
4
+ requestIntercept?: () => {
5
+ onFulfilled: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig;
6
+ onRejected: (error: AxiosError) => Promise<AxiosError>;
7
+ };
8
+ responseIntercept?: () => {
9
+ onFulfilled: (response: AxiosResponse) => AxiosResponse;
10
+ onRejected: (error: AxiosError) => Promise<AxiosError>;
11
+ };
12
+ }
13
+ export type ConfigPorps = {
14
+ loading?: boolean;
15
+ } & AxiosRequestConfig;
16
+ export interface RequestConfig<D = any> {
17
+ url: string;
18
+ method: Method;
19
+ data?: D;
20
+ loading?: boolean;
21
+ config?: ConfigPorps;
22
+ }
23
+ export type Loading = {
24
+ show: () => void;
25
+ hide: () => void;
26
+ };
27
+ export type FuncName = "get" | "post" | "delete" | "put" | "patch";
28
+ export type FetchFunc = {
29
+ <D = any, R = Record<string, any>>(url: string, data?: D, config?: ConfigPorps): Promise<R>;
30
+ };
31
+ export type FetchSturt = Record<FuncName, FetchFunc>;
32
+ //# sourceMappingURL=models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/axios/models.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,0BAA0B,EAC1B,MAAM,EACP,MAAM,OAAO,CAAC;AAEf,MAAM,WAAW,OAAO;IACtB,aAAa,EAAE,mBAAmB,CAAC;IAEnC,gBAAgB,CAAC,EAAE,MAAM;QACvB,WAAW,EAAE,CAAC,MAAM,EAAE,0BAA0B,KAAK,0BAA0B,CAAC;QAChF,UAAU,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;KACxD,CAAC;IAEF,iBAAiB,CAAC,EAAE,MAAM;QACxB,WAAW,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,aAAa,CAAC;QACxD,UAAU,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;KACxD,CAAC;CACH;AAED,MAAM,MAAM,WAAW,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,kBAAkB,CAAC;AAErE,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,GAAG;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC;AAGF,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,OAAO,CAAC;AAEnE,MAAM,MAAM,SAAS,GAAG;IACtB,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAC7F,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC"}
@@ -0,0 +1,16 @@
1
+ declare class RequestQueue {
2
+ private static instance;
3
+ private queue;
4
+ constructor();
5
+ private sortObjectKeys;
6
+ getQueue(): Map<string, AbortController>;
7
+ createKey<T>(method: string, path: string, data?: T): string;
8
+ setQueue(key: string, controller: AbortController): void;
9
+ deleteQueue(key: string): void;
10
+ hasQueue(key: string): boolean;
11
+ abortive(key: string): void;
12
+ removeResAll(): void;
13
+ }
14
+ declare let requestQueue: RequestQueue;
15
+ export { requestQueue };
16
+ //# sourceMappingURL=requestQueue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requestQueue.d.ts","sourceRoot":"","sources":["../../src/axios/requestQueue.ts"],"names":[],"mappings":"AAEA,cAAM,YAAY;IAChB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAe;IACtC,OAAO,CAAC,KAAK,CAA+B;;IAe5C,OAAO,CAAC,cAAc;IAkBf,QAAQ,IAAI,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC;IAKxC,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,GAAG,MAAM;IAU5D,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe;IAKjD,WAAW,CAAC,GAAG,EAAE,MAAM;IAKvB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAK9B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAO3B,YAAY,IAAI,IAAI;CAI5B;AAED,QAAA,IAAI,YAAY,cAAqB,CAAC;AAEtC,OAAO,EAAE,YAAY,EAAE,CAAC"}