@longzai-intelligence-transport/http-adapter-react 0.1.0 → 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/dist/index.d.ts +103 -2
- package/dist/index.js +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SWRConfiguration, SWRResponse } from "swr";
|
|
2
|
-
import { ApiPaginatedListData, ApiResponse, CursorPaginatedResult, HttpClient, InferRouteBody, InferRouteParams, InferRouteQuery, InferRouteResponse, MockRequest, MockRequestContext, RouteDefinition, createConfigurableMockHttpClient, createDelayedMockHttpClient, createErrorMockHttpClient, createMockHttpClient, createRouteMock } from "@longzai-intelligence-transport/http-core";
|
|
2
|
+
import { ApiPaginatedListData, ApiResponse, CreateApiFunction, CsrfProvider, CursorPaginatedResult, HttpClient, InferRouteBody, InferRouteParams, InferRouteQuery, InferRouteResponse, MockRequest, MockRequestContext, RouteDefinition, StreamResponseRoute, TokenProvider, createConfigurableMockHttpClient, createDelayedMockHttpClient, createErrorMockHttpClient, createMockHttpClient, createRouteMock } from "@longzai-intelligence-transport/http-core";
|
|
3
3
|
import { SWRInfiniteConfiguration, SWRInfiniteResponse } from "swr/infinite";
|
|
4
4
|
|
|
5
5
|
//#region src/create-query-hook.factory.d.ts
|
|
@@ -265,4 +265,105 @@ type ExtractPageItem<T> = T extends ApiPaginatedListData<infer Item> ? Item : T
|
|
|
265
265
|
*/
|
|
266
266
|
declare function createInfiniteHook<TRoute extends RouteDefinition>(route: TRoute, client: HttpClient, options?: InfiniteHookOptions): InfiniteHookFunction<TRoute, ExtractPageItem<InferRouteResponse<TRoute>>>;
|
|
267
267
|
//#endregion
|
|
268
|
-
|
|
268
|
+
//#region src/stream-api-client.d.ts
|
|
269
|
+
/**
|
|
270
|
+
* 流式路由响应类型映射(react 场景:Blob)
|
|
271
|
+
*
|
|
272
|
+
* 将 core 层的 BinaryStreamMarker 映射为 Blob。
|
|
273
|
+
* 非流式路由映射为 never。
|
|
274
|
+
*
|
|
275
|
+
* @typeParam TRoute - 路由定义类型
|
|
276
|
+
*/
|
|
277
|
+
type InferStreamRouteResponse<TRoute extends RouteDefinition> = TRoute extends StreamResponseRoute ? Blob : never;
|
|
278
|
+
/**
|
|
279
|
+
* 流式下载函数签名
|
|
280
|
+
*
|
|
281
|
+
* 参数与 core GET 函数一致(基于 InferRouteParams / InferRouteQuery),
|
|
282
|
+
* 返回 Promise<Blob>。
|
|
283
|
+
*
|
|
284
|
+
* @typeParam TRoute - 路由定义类型
|
|
285
|
+
*/
|
|
286
|
+
type StreamDownloadFunction<TRoute extends RouteDefinition> = InferRouteParams<TRoute> extends undefined ? InferRouteQuery<TRoute> extends undefined ? () => Promise<InferStreamRouteResponse<TRoute>> : (query?: InferRouteQuery<TRoute>) => Promise<InferStreamRouteResponse<TRoute>> : InferRouteQuery<TRoute> extends undefined ? (params: InferRouteParams<TRoute>) => Promise<InferStreamRouteResponse<TRoute>> : (params: InferRouteParams<TRoute>, query?: InferRouteQuery<TRoute>) => Promise<InferStreamRouteResponse<TRoute>>;
|
|
287
|
+
/**
|
|
288
|
+
* react API mapped type
|
|
289
|
+
*
|
|
290
|
+
* 流式路由映射为 StreamDownloadFunction,JSON 路由映射为 core CreateApiFunction。
|
|
291
|
+
*
|
|
292
|
+
* @typeParam TRoutes - 路由定义集合类型
|
|
293
|
+
*/
|
|
294
|
+
type ReactApi<TRoutes extends Record<string, RouteDefinition>> = { [K in keyof TRoutes]: TRoutes[K] extends StreamResponseRoute ? StreamDownloadFunction<TRoutes[K]> : CreateApiFunction<TRoutes[K]> };
|
|
295
|
+
/**
|
|
296
|
+
* 流式 fetch 配置
|
|
297
|
+
*
|
|
298
|
+
* 提供 react 场景流式 fetch 所需的配置项(与 react 应用环境一致)。
|
|
299
|
+
*/
|
|
300
|
+
type StreamFetchConfig = {
|
|
301
|
+
/**
|
|
302
|
+
* API 基础 URL
|
|
303
|
+
*/
|
|
304
|
+
baseUrl: string;
|
|
305
|
+
/**
|
|
306
|
+
* 自定义请求头
|
|
307
|
+
*/
|
|
308
|
+
headers?: Record<string, string>;
|
|
309
|
+
/**
|
|
310
|
+
* Token 提供者(用于 Authorization 头)
|
|
311
|
+
*/
|
|
312
|
+
tokenProvider?: TokenProvider;
|
|
313
|
+
/**
|
|
314
|
+
* CSRF 提供者(用于 X-CSRF-Token 头)
|
|
315
|
+
*/
|
|
316
|
+
csrfProvider?: CsrfProvider;
|
|
317
|
+
/**
|
|
318
|
+
* 自定义 fetch 函数(依赖注入,测试时可 mock)
|
|
319
|
+
*
|
|
320
|
+
* 省略时用全局 fetch。
|
|
321
|
+
*/
|
|
322
|
+
fetch?: typeof fetch;
|
|
323
|
+
};
|
|
324
|
+
/**
|
|
325
|
+
* 创建流式下载函数
|
|
326
|
+
*
|
|
327
|
+
* 工厂模式:创建时绑定路由定义与配置,返回的函数发起 fetch 请求并返回 Blob。
|
|
328
|
+
* 错误路径(4xx/5xx)按 JSON 解析 ApiResponse 错误信封抛出。
|
|
329
|
+
*
|
|
330
|
+
* @typeParam TRoute - 流式路由定义类型
|
|
331
|
+
* @param route - 流式路由定义
|
|
332
|
+
* @param config - 流式 fetch 配置
|
|
333
|
+
* @returns 流式下载函数,返回 Promise<Blob>
|
|
334
|
+
* @throws {@link Error} 类型断言失败时抛出
|
|
335
|
+
*/
|
|
336
|
+
declare function createStreamDownloadFunction<TRoute extends StreamResponseRoute>(route: TRoute, config: StreamFetchConfig): StreamDownloadFunction<TRoute>;
|
|
337
|
+
/**
|
|
338
|
+
* 创建 react API 客户端 factory
|
|
339
|
+
*
|
|
340
|
+
* 返回的 factory 接受 routes 集合,生成 ReactApi:
|
|
341
|
+
* - JSON 路由:复用 core createApiClientFactory,走 HttpClient.request(JSON 解析 + safeParse)
|
|
342
|
+
* - 流式路由:走独立的 fetch + blob 路径,返回 Promise<Blob>
|
|
343
|
+
*
|
|
344
|
+
* react adapter 独立提供此能力,不依赖 preset-browser。react 应用(浏览器、React Native、
|
|
345
|
+
* Electron renderer)均可使用。
|
|
346
|
+
*
|
|
347
|
+
* @param client - core HttpClient(用于 JSON 路由)
|
|
348
|
+
* @param streamConfig - 流式 fetch 配置(baseUrl / headers / tokenProvider / csrfProvider)
|
|
349
|
+
* @returns API factory,接受 routes 返回 ReactApi
|
|
350
|
+
* @throws {@link Error} 类型断言失败时抛出
|
|
351
|
+
*
|
|
352
|
+
* @example
|
|
353
|
+
* ```typescript
|
|
354
|
+
* const factory = createReactApiClientFactory(client, {
|
|
355
|
+
* baseUrl: '/api',
|
|
356
|
+
* tokenProvider: { getToken: () => localStorage.getItem('token') },
|
|
357
|
+
* });
|
|
358
|
+
* const api = factory(orderRoutes);
|
|
359
|
+
*
|
|
360
|
+
* // JSON 路由:Promise<ApiResponse<Order>>
|
|
361
|
+
* const order = await api.detail({ id: '123' });
|
|
362
|
+
*
|
|
363
|
+
* // 流式路由:Promise<Blob>
|
|
364
|
+
* const blob = await api.downloadExport({ taskId: 'abc' });
|
|
365
|
+
* ```
|
|
366
|
+
*/
|
|
367
|
+
declare function createReactApiClientFactory(client: HttpClient, streamConfig: StreamFetchConfig): <TRoutes extends Record<string, RouteDefinition>>(routes: TRoutes) => ReactApi<TRoutes>;
|
|
368
|
+
//#endregion
|
|
369
|
+
export { type ExtractPageItem, type InferStreamRouteResponse, type InfiniteHookFunction, type InfiniteHookOptions, type InfiniteHookReturn, type InfinitePageData, type InfinitePaginationMode, type MockRequest, type MockRequestContext, type MutationHookFunction, type MutationHookReturn, type MutationTriggerArgs, type MutationTriggerNoArgs, type MutationTriggerWithBody, type MutationTriggerWithParams, type MutationTriggerWithParamsAndBody, type QueryHookFunction, type QueryHookNoParams, type QueryHookReturn, type QueryHookWithParams, type QueryHookWithParamsAndQuery, type QueryHookWithQuery, type ReactApi, type StreamDownloadFunction, type StreamFetchConfig, createConfigurableMockHttpClient, createDelayedMockHttpClient, createErrorMockHttpClient, createInfiniteHook, createMockHttpClient, createMutationHook, createQueryHook, createReactApiClientFactory, createRouteMock, createStreamDownloadFunction };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"swr";import{
|
|
1
|
+
import e from"swr";import{buildPath as t,createApiClientFactory as n,createConfigurableMockHttpClient as r,createDelayedMockHttpClient as i,createErrorMockHttpClient as a,createMockHttpClient as o,createRouteMock as s,isStreamRoute as c,isType as l}from"@longzai-intelligence-transport/http-core";import{useCallback as u,useState as d}from"react";import f from"swr/infinite";function p(e,t,n){let r=[e.method,e.path];return t&&r.push(t),n&&r.push(n),r}function m(e){return`params`in e&&e.params!==void 0}function h(e){return`query`in e&&e.query!==void 0}function g(t,n,r,i,a){return e(p(t,l(r)?r:void 0,l(i)?i:void 0),()=>n.request({route:t,params:l(r)?r:void 0,query:l(i)?i:void 0}),a)}function _(t,n,r,i){return e(p(t,l(r)?r:void 0),()=>n.request({route:t,params:l(r)?r:void 0}),i)}function v(t,n,r,i){return e(r?p(t,void 0,l(r)?r:void 0):null,()=>n.request({route:t,query:l(r)?r:void 0}),i)}function y(t,n,r){return e(p(t),()=>n.request({route:t}),r)}function b(e,t){let n=m(e),r=h(e);if(n&&r){let n=(n,r,i)=>g(e,t,n,r,i);if(l(n))return n}if(n){let n=(n,r)=>_(e,t,n,r);if(l(n))return n}if(r){let n=(n,r)=>v(e,t,n,r);if(l(n))return n}let i=n=>y(e,t,n);if(l(i))return i;throw Error(`无法创建 Query Hook:路由配置不合法`)}function x(e){return`params`in e&&e.params!==void 0}function S(e){return`body`in e&&e.body!==void 0}function C(e,t,n,r,i){if(n&&r){let[n,r]=i;return t.request({route:e,params:l(n)?n:void 0,body:l(r)?r:void 0})}if(n){let[n]=i;return t.request({route:e,params:l(n)?n:void 0})}if(r){let[n]=i;return t.request({route:e,body:l(n)?n:void 0})}return t.request({route:e})}function w(e,t){let n=x(e),r=S(e);return()=>{let[i,a]=d(!1),[o,s]=d(void 0),[c,l]=d(void 0);return{trigger:u(async(...i)=>{a(!0),l(void 0);try{let a=await C(e,t,n,r,i);return s(a),a}catch(e){let t=e instanceof Error?e:Error(String(e));throw l(t),t}finally{a(!1)}},[t]),isMutating:i,data:o,error:c,reset:u(()=>{a(!1),s(void 0),l(void 0)},[])}}}function T(e,t,n,r){let i=[e.method,e.path];return t&&i.push(t),r&&r.data&&`hasNextPage`in r.data&&!r.data.hasNextPage?null:(i.push({page:n+1}),i)}function E(e,t,n,r){let i=[e.method,e.path];if(t&&i.push(t),n&&n.data&&`hasMore`in n.data&&!n.data.hasMore)return null;let a=n?.data&&`nextCursor`in n.data?n.data.nextCursor:void 0;return i.push(a?{cursor:a,limit:r}:{limit:r}),i}function D(e,t,n,r){return async i=>{let a=i[n?2:1],o=await t.request({route:e,params:n&&l(r)?r:void 0,query:l(a)?a:void 0});return l(o)?o:{success:!1,data:null,message:`分页数据类型不匹配`,timestamp:Date.now()}}}function O(e,t,n){let r=`params`in e&&e.params!==void 0,i=n?.paginationMode??`page`,a=n?.defaultPageSize??20,o=(n,o)=>f((t,r)=>i===`page`?T(e,n,t,r):i===`cursor`?E(e,n,r,a):null,D(e,t,r,n),o);if(l(o))return o;throw Error(`无法创建 Infinite Hook:路由配置不合法`)}function k(e,n){let r=async(r,i)=>{let a=n.baseUrl+t(e.path,r,i),o={...n.headers};if(n.tokenProvider){let e=await n.tokenProvider.getToken();e!==null&&(o.Authorization=`Bearer ${e}`)}if(n.csrfProvider){let e=await n.csrfProvider.getToken();e!==null&&(o[`X-CSRF-Token`]=e)}let s=await(n.fetch??fetch)(a,{headers:o});if(!s.ok)throw await s.json();return s.blob()};if(l(r))return r;throw Error(`流式下载函数构建失败`)}function A(e,t){let r=n(e);return e=>{let n={...r(e)};for(let[r,i]of Object.entries(e))i&&c(i)&&(n[r]=k(i,t));if(l(n))return n;throw Error(`API 客户端构建失败`)}}export{r as createConfigurableMockHttpClient,i as createDelayedMockHttpClient,a as createErrorMockHttpClient,O as createInfiniteHook,o as createMockHttpClient,w as createMutationHook,b as createQueryHook,A as createReactApiClientFactory,s as createRouteMock,k as createStreamDownloadFunction};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@longzai-intelligence-transport/http-adapter-react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"adapter",
|
|
6
6
|
"hook",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"clean": "rimraf dist out .cache"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@longzai-intelligence-transport/http-core": "0.1.
|
|
41
|
+
"@longzai-intelligence-transport/http-core": "0.1.1"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@testing-library/react": "^16.3.2",
|