@readyfor/api-client-base 1.22.0-pr1284.dc25e7e → 1.22.1-pr1285.b385439
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/{utils/headersInit.mjs → apiClientConfigStore-CNRWwVM3.mjs} +40 -1
- package/dist/index.mjs +146 -9
- package/dist/react/index.mjs +61 -3
- package/package.json +1 -1
- package/dist/apiClientConfigStore.mjs +0 -10
- package/dist/apiError.mjs +0 -71
- package/dist/fetcher.mjs +0 -63
- package/dist/react/ApiClientConfigProvider.mjs +0 -23
- package/dist/react/swr.mjs +0 -26
- package/dist/react/useApiClientConfig.mjs +0 -20
- package/dist/requestUrl.mjs +0 -13
- package/dist/store.mjs +0 -21
- package/dist/types.mjs +0 -1
- package/dist/utils/requestInit.mjs +0 -15
- package/dist/zod.mjs +0 -7
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
//#region src/store.ts
|
|
2
|
+
const createStore = (initialState) => {
|
|
3
|
+
let state = initialState;
|
|
4
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
5
|
+
const getState = () => state;
|
|
6
|
+
const setState = (fn) => {
|
|
7
|
+
state = fn(state);
|
|
8
|
+
listeners.forEach((listener) => listener());
|
|
9
|
+
};
|
|
10
|
+
const subscribe = (listener) => {
|
|
11
|
+
listeners.add(listener);
|
|
12
|
+
return () => listeners.delete(listener);
|
|
13
|
+
};
|
|
14
|
+
return {
|
|
15
|
+
getState,
|
|
16
|
+
setState,
|
|
17
|
+
subscribe
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
1
21
|
//#region src/utils/headersInit.ts
|
|
2
22
|
/**
|
|
3
23
|
* 二つのHeadersInitの情報を元に、新たなHeadersInitを作成する
|
|
@@ -44,4 +64,23 @@ const toHeadersInit = (headers) => {
|
|
|
44
64
|
return result;
|
|
45
65
|
};
|
|
46
66
|
//#endregion
|
|
47
|
-
|
|
67
|
+
//#region src/utils/requestInit.ts
|
|
68
|
+
/**
|
|
69
|
+
* 第一引数と第二引数のequestInitをマージした新たなRequestInitを返す。
|
|
70
|
+
* 同じフィールドが存在する場合、第二引数の値で上書きされる。
|
|
71
|
+
* ただし、`headers`フィールドに関しては、`base`と`override`両方に有効なHeadersInitがある場合に限り、
|
|
72
|
+
* `mergeHeadersInit`を使用してヘッダーの内容をマージする
|
|
73
|
+
*/
|
|
74
|
+
const mergeRequestInit = ({ headers: baseHeaders, ...base }, { headers: overrideHeaders, ...override }) => ({
|
|
75
|
+
...base,
|
|
76
|
+
...override,
|
|
77
|
+
headers: baseHeaders === void 0 ? overrideHeaders : overrideHeaders === void 0 ? baseHeaders : mergeHeadersInit(baseHeaders, overrideHeaders)
|
|
78
|
+
});
|
|
79
|
+
const store = globalThis[Symbol.for("@readyfor/api-client-base/config")] ??= createStore({});
|
|
80
|
+
const setApiClientConfig = (config) => store.setState(() => config);
|
|
81
|
+
const buildRequestInitWithDefaultConfig = (customRequestInit = {}) => {
|
|
82
|
+
const { defaultRequestInit = {} } = store.getState();
|
|
83
|
+
return mergeRequestInit(defaultRequestInit, customRequestInit);
|
|
84
|
+
};
|
|
85
|
+
//#endregion
|
|
86
|
+
export { mergeHeadersInit as a, mergeRequestInit as i, setApiClientConfig as n, toHeadersInit as o, store as r, createStore as s, buildRequestInitWithDefaultConfig as t };
|
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,147 @@
|
|
|
1
|
-
import { createStore } from "./
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import { a as mergeHeadersInit, i as mergeRequestInit, n as setApiClientConfig, o as toHeadersInit, r as store, s as createStore, t as buildRequestInitWithDefaultConfig } from "./apiClientConfigStore-CNRWwVM3.mjs";
|
|
2
|
+
import qs from "qs";
|
|
3
|
+
//#region src/zod.ts
|
|
4
|
+
const schemaForType = () => (arg) => {
|
|
5
|
+
return arg;
|
|
6
|
+
};
|
|
7
|
+
const isZodError = (obj) => obj !== null && typeof obj === "object" && obj.constructor.name === "ZodError";
|
|
8
|
+
//#endregion
|
|
9
|
+
//#region src/apiError.ts
|
|
10
|
+
const errorStatusCode = {
|
|
11
|
+
MOVED_PERMANENTLY: 301,
|
|
12
|
+
FOUND: 302,
|
|
13
|
+
BAD_REQUEST: 400,
|
|
14
|
+
UNAUTHORIZED: 401,
|
|
15
|
+
FORBIDDEN: 403,
|
|
16
|
+
NOT_FOUND: 404,
|
|
17
|
+
CONFLICT: 409,
|
|
18
|
+
PAYLOAD_TOO_LARGE: 413,
|
|
19
|
+
NETWORK_ERROR: 418,
|
|
20
|
+
UNPROCESSABLE_ENTITY: 422,
|
|
21
|
+
INTERNAL_SERVER_ERROR: 500,
|
|
22
|
+
BAD_GATEWAY: 502,
|
|
23
|
+
SERVER_UNAVAILABLE: 503,
|
|
24
|
+
GATEWAY_TIMEOUT: 504,
|
|
25
|
+
ZOD_ERROR: 901,
|
|
26
|
+
UNHANDLED_ERROR: 999
|
|
27
|
+
};
|
|
28
|
+
const errorTitle = {
|
|
29
|
+
301: "ページが移動されています",
|
|
30
|
+
302: "ページが一時的に移動されています",
|
|
31
|
+
400: "リクエストが不正です",
|
|
32
|
+
401: "ログインしてください",
|
|
33
|
+
403: "不正なトークンです",
|
|
34
|
+
404: "ページが見つかりませんでした",
|
|
35
|
+
409: "編集内容が競合しています",
|
|
36
|
+
413: "通信に失敗しました",
|
|
37
|
+
418: "通信に失敗しました",
|
|
38
|
+
422: "データが不正です",
|
|
39
|
+
500: "サーバーでエラーが起きました",
|
|
40
|
+
502: "サーバーでエラーが起きました",
|
|
41
|
+
503: "メンテナンス中です",
|
|
42
|
+
504: "通信に失敗しました",
|
|
43
|
+
901: "問題が発生しました",
|
|
44
|
+
999: "サーバーでエラーが起きました"
|
|
45
|
+
};
|
|
46
|
+
var HTTPError = class extends Error {
|
|
47
|
+
status;
|
|
48
|
+
body;
|
|
49
|
+
constructor(status, body) {
|
|
50
|
+
super(errorTitle[status]);
|
|
51
|
+
this.name = "HTTPError";
|
|
52
|
+
this.status = status;
|
|
53
|
+
this.body = body;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* duck typing で HTTPError の status を判定する。
|
|
58
|
+
* pnpm の strict isolation により instanceof HTTPError が
|
|
59
|
+
* 別バージョンのクラスと一致しないケースがあるため、
|
|
60
|
+
* プロパティベースで判定する。
|
|
61
|
+
*/
|
|
62
|
+
const isHttpErrorWithStatus = (error, status) => error instanceof Error && "status" in error && error.status === status;
|
|
63
|
+
const getHttpErrorBody = (error) => error instanceof Error && "body" in error ? error.body : void 0;
|
|
64
|
+
const getHttpErrorBodyReason = (body) => {
|
|
65
|
+
if (body !== null && typeof body === "object" && "reason" in body) {
|
|
66
|
+
const reason = body.reason;
|
|
67
|
+
return typeof reason === "string" ? reason : void 0;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const getErrorStatus = (response) => {
|
|
71
|
+
if (response instanceof Object && "status" in response && typeof response["status"] === "number") {
|
|
72
|
+
const status = Number(response["status"]);
|
|
73
|
+
return Object.values(errorStatusCode).includes(status) ? status : 999;
|
|
74
|
+
}
|
|
75
|
+
if (isZodError(response)) return errorStatusCode.ZOD_ERROR;
|
|
76
|
+
};
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region src/fetcher.ts
|
|
79
|
+
const defaultRequestInit = { credentials: "include" };
|
|
80
|
+
const createJsonFetcher = (schema, customRequestInit = {}) => (input, requestInit = {}) => fetch(input, mergeRequestInit(defaultRequestInit, mergeRequestInit(customRequestInit, requestInit))).then(async (res) => {
|
|
81
|
+
const text = await res.text();
|
|
82
|
+
const body = text ? JSON.parse(text) : {};
|
|
83
|
+
if (res.ok) return body;
|
|
84
|
+
throw new HTTPError(Object.values(errorStatusCode).includes(res.status) ? res.status : 999, body);
|
|
85
|
+
}).catch((error) => {
|
|
86
|
+
store.getState().onError?.(error);
|
|
87
|
+
throw error;
|
|
88
|
+
}).then((parsedResponse) => {
|
|
89
|
+
const result = schema.safeParse(parsedResponse);
|
|
90
|
+
const config = store.getState();
|
|
91
|
+
if (result.success) return result.data;
|
|
92
|
+
if (config.showsSchemaParseError) console.error(result.error);
|
|
93
|
+
if (config.forceDeserializeResponse) {
|
|
94
|
+
config.onFailedDeserializeResponse(input, result.error);
|
|
95
|
+
return parsedResponse;
|
|
96
|
+
}
|
|
97
|
+
throw result.error;
|
|
98
|
+
});
|
|
99
|
+
const createTextFetcher = (customRequestInit = {}) => (input, requestInit = {}) => fetch(input, mergeRequestInit(defaultRequestInit, mergeRequestInit(customRequestInit, requestInit))).then(async (res) => {
|
|
100
|
+
const body = await res.text();
|
|
101
|
+
if (res.ok) return body;
|
|
102
|
+
throw new HTTPError(Object.values(errorStatusCode).includes(res.status) ? res.status : 999, body);
|
|
103
|
+
}).catch((error) => {
|
|
104
|
+
store.getState().onError?.(error);
|
|
105
|
+
throw error;
|
|
106
|
+
});
|
|
107
|
+
const createBlobFetcher = (customRequestInit = {}) => (input, requestInit = {}) => fetch(input, mergeRequestInit(defaultRequestInit, mergeRequestInit(customRequestInit, requestInit))).then(async (res) => {
|
|
108
|
+
const body = await res.blob();
|
|
109
|
+
if (res.ok) return {
|
|
110
|
+
body,
|
|
111
|
+
headers: res.headers
|
|
112
|
+
};
|
|
113
|
+
throw new HTTPError(Object.values(errorStatusCode).includes(res.status) ? res.status : 999, body);
|
|
114
|
+
}).catch((error) => {
|
|
115
|
+
store.getState().onError?.(error);
|
|
116
|
+
throw error;
|
|
117
|
+
});
|
|
118
|
+
const createFileOrBlobFetcher = (customRequestInit = {}) => (input, requestInit = {}) => fetch(input, mergeRequestInit(defaultRequestInit, mergeRequestInit(customRequestInit, requestInit))).then(async (res) => {
|
|
119
|
+
const body = await res.blob();
|
|
120
|
+
if (res.ok) return {
|
|
121
|
+
body,
|
|
122
|
+
headers: res.headers
|
|
123
|
+
};
|
|
124
|
+
throw new HTTPError(Object.values(errorStatusCode).includes(res.status) ? res.status : 999, body);
|
|
125
|
+
}).catch((error) => {
|
|
126
|
+
store.getState().onError?.(error);
|
|
127
|
+
throw error;
|
|
128
|
+
});
|
|
129
|
+
const createVoidFetcher = (customRequestInit = {}) => (input, requestInit = {}) => fetch(input, mergeRequestInit(defaultRequestInit, mergeRequestInit(customRequestInit, requestInit))).then(async (res) => {
|
|
130
|
+
if (res.ok) return;
|
|
131
|
+
throw new HTTPError(Object.values(errorStatusCode).includes(res.status) ? res.status : 999, await res.text());
|
|
132
|
+
}).catch((error) => {
|
|
133
|
+
store.getState().onError?.(error);
|
|
134
|
+
throw error;
|
|
135
|
+
});
|
|
136
|
+
//#endregion
|
|
137
|
+
//#region src/requestUrl.ts
|
|
138
|
+
function __internal__requestUrl(...args) {
|
|
139
|
+
const config = store.getState();
|
|
140
|
+
const rawPath = args[0];
|
|
141
|
+
const params = args[1] || {};
|
|
142
|
+
const query = args[2];
|
|
143
|
+
const path = (config.hostName ? typeof config.hostName === "string" ? config.hostName : config.hostName(rawPath) : "") + Object.entries(params).reduce((path, [key, value]) => path.replace(`{${key}}`, String(value)), rawPath);
|
|
144
|
+
return query ? `${path}?${qs.stringify(query)}` : path;
|
|
145
|
+
}
|
|
146
|
+
//#endregion
|
|
10
147
|
export { HTTPError, __internal__requestUrl, buildRequestInitWithDefaultConfig, createBlobFetcher, createFileOrBlobFetcher, createJsonFetcher, createStore, createTextFetcher, createVoidFetcher, errorStatusCode, errorTitle, getErrorStatus, getHttpErrorBody, getHttpErrorBodyReason, isHttpErrorWithStatus, isZodError, mergeHeadersInit, mergeRequestInit, schemaForType, setApiClientConfig, store, toHeadersInit };
|
package/dist/react/index.mjs
CHANGED
|
@@ -1,4 +1,62 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { i as mergeRequestInit, r as store } from "../apiClientConfigStore-CNRWwVM3.mjs";
|
|
2
|
+
import { createContext, useContext, useEffect, useMemo, useRef } from "react";
|
|
3
|
+
import { SWRConfig } from "swr";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import { useSyncExternalStore } from "use-sync-external-store/shim/index.js";
|
|
6
|
+
import { useSyncExternalStoreWithSelector } from "use-sync-external-store/shim/with-selector.js";
|
|
7
|
+
//#region src/react/swr.ts
|
|
8
|
+
/**
|
|
9
|
+
* requestのfetchを中断させるためのmiddleware
|
|
10
|
+
*
|
|
11
|
+
* 同一hookにおいて、keyが更新されるなどにより、一つ前のrequestが返る前に再度fetchが行われる場合がある
|
|
12
|
+
* その場合、一つ前のfetchが戻ってきた値がそのまま捨てられるため、responseに時間がかかるAPIの場合、純粋な負荷増加に繋がってしまう
|
|
13
|
+
* そのため、最新のrequestのみを返すように、一つ前のrequestをabortする
|
|
14
|
+
*/
|
|
15
|
+
const abortMiddleware = (useSWRNext) => (key, fetcher, config) => {
|
|
16
|
+
const ctrlRef = useRef(void 0);
|
|
17
|
+
return useSWRNext(key, fetcher ? (key, params) => {
|
|
18
|
+
ctrlRef.current?.abort();
|
|
19
|
+
ctrlRef.current = new AbortController();
|
|
20
|
+
return fetcher(key, {
|
|
21
|
+
...params,
|
|
22
|
+
signal: ctrlRef.current.signal
|
|
23
|
+
});
|
|
24
|
+
} : fetcher, config);
|
|
25
|
+
};
|
|
26
|
+
const createSwrConfig = (config) => ({
|
|
27
|
+
...config,
|
|
28
|
+
use: [...config?.use ?? [], abortMiddleware]
|
|
29
|
+
});
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/react/ApiClientConfigProvider.tsx
|
|
32
|
+
const ApiClientConfigContext = createContext(store);
|
|
33
|
+
const ApiClientConfigProvider = (props) => {
|
|
34
|
+
const { swr, ...config } = props.config;
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
store.setState(() => config);
|
|
37
|
+
}, [config]);
|
|
38
|
+
return /* @__PURE__ */ jsx(ApiClientConfigContext.Provider, {
|
|
39
|
+
value: store,
|
|
40
|
+
children: /* @__PURE__ */ jsx(SWRConfig, {
|
|
41
|
+
value: createSwrConfig(swr),
|
|
42
|
+
children: props.children
|
|
43
|
+
})
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
const useApiClientConfigContext = () => useContext(ApiClientConfigContext) || store;
|
|
47
|
+
//#endregion
|
|
48
|
+
//#region src/react/useApiClientConfig.ts
|
|
49
|
+
const useApiClientConfig = () => {
|
|
50
|
+
const store = useApiClientConfigContext();
|
|
51
|
+
return useSyncExternalStore(store.subscribe, store.getState, store.getState);
|
|
52
|
+
};
|
|
53
|
+
const useApiClientConfigWithSelector = (selector) => {
|
|
54
|
+
const store = useApiClientConfigContext();
|
|
55
|
+
return useSyncExternalStoreWithSelector(store.subscribe, store.getState, store.getState, selector);
|
|
56
|
+
};
|
|
57
|
+
const useRequestInit = (customRequestInit = {}) => {
|
|
58
|
+
const { defaultRequestInit = {} } = useApiClientConfig();
|
|
59
|
+
return useMemo(() => mergeRequestInit(defaultRequestInit, customRequestInit), [defaultRequestInit, customRequestInit]);
|
|
60
|
+
};
|
|
61
|
+
//#endregion
|
|
4
62
|
export { ApiClientConfigProvider, createSwrConfig, useApiClientConfig, useApiClientConfigContext, useApiClientConfigWithSelector, useRequestInit };
|
package/package.json
CHANGED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { createStore } from "./store.mjs";
|
|
2
|
-
import { mergeRequestInit } from "./utils/requestInit.mjs";
|
|
3
|
-
const store = globalThis[Symbol.for("@readyfor/api-client-base/config")] ??= createStore({});
|
|
4
|
-
const setApiClientConfig = (config) => store.setState(() => config);
|
|
5
|
-
const buildRequestInitWithDefaultConfig = (customRequestInit = {}) => {
|
|
6
|
-
const { defaultRequestInit = {} } = store.getState();
|
|
7
|
-
return mergeRequestInit(defaultRequestInit, customRequestInit);
|
|
8
|
-
};
|
|
9
|
-
//#endregion
|
|
10
|
-
export { buildRequestInitWithDefaultConfig, setApiClientConfig, store };
|
package/dist/apiError.mjs
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { isZodError } from "./zod.mjs";
|
|
2
|
-
//#region src/apiError.ts
|
|
3
|
-
const errorStatusCode = {
|
|
4
|
-
MOVED_PERMANENTLY: 301,
|
|
5
|
-
FOUND: 302,
|
|
6
|
-
BAD_REQUEST: 400,
|
|
7
|
-
UNAUTHORIZED: 401,
|
|
8
|
-
FORBIDDEN: 403,
|
|
9
|
-
NOT_FOUND: 404,
|
|
10
|
-
CONFLICT: 409,
|
|
11
|
-
PAYLOAD_TOO_LARGE: 413,
|
|
12
|
-
NETWORK_ERROR: 418,
|
|
13
|
-
UNPROCESSABLE_ENTITY: 422,
|
|
14
|
-
INTERNAL_SERVER_ERROR: 500,
|
|
15
|
-
BAD_GATEWAY: 502,
|
|
16
|
-
SERVER_UNAVAILABLE: 503,
|
|
17
|
-
GATEWAY_TIMEOUT: 504,
|
|
18
|
-
ZOD_ERROR: 901,
|
|
19
|
-
UNHANDLED_ERROR: 999
|
|
20
|
-
};
|
|
21
|
-
const errorTitle = {
|
|
22
|
-
301: "ページが移動されています",
|
|
23
|
-
302: "ページが一時的に移動されています",
|
|
24
|
-
400: "リクエストが不正です",
|
|
25
|
-
401: "ログインしてください",
|
|
26
|
-
403: "不正なトークンです",
|
|
27
|
-
404: "ページが見つかりませんでした",
|
|
28
|
-
409: "編集内容が競合しています",
|
|
29
|
-
413: "通信に失敗しました",
|
|
30
|
-
418: "通信に失敗しました",
|
|
31
|
-
422: "データが不正です",
|
|
32
|
-
500: "サーバーでエラーが起きました",
|
|
33
|
-
502: "サーバーでエラーが起きました",
|
|
34
|
-
503: "メンテナンス中です",
|
|
35
|
-
504: "通信に失敗しました",
|
|
36
|
-
901: "問題が発生しました",
|
|
37
|
-
999: "サーバーでエラーが起きました"
|
|
38
|
-
};
|
|
39
|
-
var HTTPError = class extends Error {
|
|
40
|
-
status;
|
|
41
|
-
body;
|
|
42
|
-
constructor(status, body) {
|
|
43
|
-
super(errorTitle[status]);
|
|
44
|
-
this.name = "HTTPError";
|
|
45
|
-
this.status = status;
|
|
46
|
-
this.body = body;
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
/**
|
|
50
|
-
* duck typing で HTTPError の status を判定する。
|
|
51
|
-
* pnpm の strict isolation により instanceof HTTPError が
|
|
52
|
-
* 別バージョンのクラスと一致しないケースがあるため、
|
|
53
|
-
* プロパティベースで判定する。
|
|
54
|
-
*/
|
|
55
|
-
const isHttpErrorWithStatus = (error, status) => error instanceof Error && "status" in error && error.status === status;
|
|
56
|
-
const getHttpErrorBody = (error) => error instanceof Error && "body" in error ? error.body : void 0;
|
|
57
|
-
const getHttpErrorBodyReason = (body) => {
|
|
58
|
-
if (body !== null && typeof body === "object" && "reason" in body) {
|
|
59
|
-
const reason = body.reason;
|
|
60
|
-
return typeof reason === "string" ? reason : void 0;
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
const getErrorStatus = (response) => {
|
|
64
|
-
if (response instanceof Object && "status" in response && typeof response["status"] === "number") {
|
|
65
|
-
const status = Number(response["status"]);
|
|
66
|
-
return Object.values(errorStatusCode).includes(status) ? status : 999;
|
|
67
|
-
}
|
|
68
|
-
if (isZodError(response)) return errorStatusCode.ZOD_ERROR;
|
|
69
|
-
};
|
|
70
|
-
//#endregion
|
|
71
|
-
export { HTTPError, errorStatusCode, errorTitle, getErrorStatus, getHttpErrorBody, getHttpErrorBodyReason, isHttpErrorWithStatus };
|
package/dist/fetcher.mjs
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { mergeRequestInit } from "./utils/requestInit.mjs";
|
|
2
|
-
import { store } from "./apiClientConfigStore.mjs";
|
|
3
|
-
import { HTTPError, errorStatusCode } from "./apiError.mjs";
|
|
4
|
-
//#region src/fetcher.ts
|
|
5
|
-
const defaultRequestInit = { credentials: "include" };
|
|
6
|
-
const createJsonFetcher = (schema, customRequestInit = {}) => (input, requestInit = {}) => fetch(input, mergeRequestInit(defaultRequestInit, mergeRequestInit(customRequestInit, requestInit))).then(async (res) => {
|
|
7
|
-
const text = await res.text();
|
|
8
|
-
const body = text ? JSON.parse(text) : {};
|
|
9
|
-
if (res.ok) return body;
|
|
10
|
-
throw new HTTPError(Object.values(errorStatusCode).includes(res.status) ? res.status : 999, body);
|
|
11
|
-
}).catch((error) => {
|
|
12
|
-
store.getState().onError?.(error);
|
|
13
|
-
throw error;
|
|
14
|
-
}).then((parsedResponse) => {
|
|
15
|
-
const result = schema.safeParse(parsedResponse);
|
|
16
|
-
const config = store.getState();
|
|
17
|
-
if (result.success) return result.data;
|
|
18
|
-
if (config.showsSchemaParseError) console.error(result.error);
|
|
19
|
-
if (config.forceDeserializeResponse) {
|
|
20
|
-
config.onFailedDeserializeResponse(input, result.error);
|
|
21
|
-
return parsedResponse;
|
|
22
|
-
}
|
|
23
|
-
throw result.error;
|
|
24
|
-
});
|
|
25
|
-
const createTextFetcher = (customRequestInit = {}) => (input, requestInit = {}) => fetch(input, mergeRequestInit(defaultRequestInit, mergeRequestInit(customRequestInit, requestInit))).then(async (res) => {
|
|
26
|
-
const body = await res.text();
|
|
27
|
-
if (res.ok) return body;
|
|
28
|
-
throw new HTTPError(Object.values(errorStatusCode).includes(res.status) ? res.status : 999, body);
|
|
29
|
-
}).catch((error) => {
|
|
30
|
-
store.getState().onError?.(error);
|
|
31
|
-
throw error;
|
|
32
|
-
});
|
|
33
|
-
const createBlobFetcher = (customRequestInit = {}) => (input, requestInit = {}) => fetch(input, mergeRequestInit(defaultRequestInit, mergeRequestInit(customRequestInit, requestInit))).then(async (res) => {
|
|
34
|
-
const body = await res.blob();
|
|
35
|
-
if (res.ok) return {
|
|
36
|
-
body,
|
|
37
|
-
headers: res.headers
|
|
38
|
-
};
|
|
39
|
-
throw new HTTPError(Object.values(errorStatusCode).includes(res.status) ? res.status : 999, body);
|
|
40
|
-
}).catch((error) => {
|
|
41
|
-
store.getState().onError?.(error);
|
|
42
|
-
throw error;
|
|
43
|
-
});
|
|
44
|
-
const createFileOrBlobFetcher = (customRequestInit = {}) => (input, requestInit = {}) => fetch(input, mergeRequestInit(defaultRequestInit, mergeRequestInit(customRequestInit, requestInit))).then(async (res) => {
|
|
45
|
-
const body = await res.blob();
|
|
46
|
-
if (res.ok) return {
|
|
47
|
-
body,
|
|
48
|
-
headers: res.headers
|
|
49
|
-
};
|
|
50
|
-
throw new HTTPError(Object.values(errorStatusCode).includes(res.status) ? res.status : 999, body);
|
|
51
|
-
}).catch((error) => {
|
|
52
|
-
store.getState().onError?.(error);
|
|
53
|
-
throw error;
|
|
54
|
-
});
|
|
55
|
-
const createVoidFetcher = (customRequestInit = {}) => (input, requestInit = {}) => fetch(input, mergeRequestInit(defaultRequestInit, mergeRequestInit(customRequestInit, requestInit))).then(async (res) => {
|
|
56
|
-
if (res.ok) return;
|
|
57
|
-
throw new HTTPError(Object.values(errorStatusCode).includes(res.status) ? res.status : 999, await res.text());
|
|
58
|
-
}).catch((error) => {
|
|
59
|
-
store.getState().onError?.(error);
|
|
60
|
-
throw error;
|
|
61
|
-
});
|
|
62
|
-
//#endregion
|
|
63
|
-
export { createBlobFetcher, createFileOrBlobFetcher, createJsonFetcher, createTextFetcher, createVoidFetcher };
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { store } from "../apiClientConfigStore.mjs";
|
|
2
|
-
import { createSwrConfig } from "./swr.mjs";
|
|
3
|
-
import { createContext, useContext, useEffect } from "react";
|
|
4
|
-
import { SWRConfig } from "swr";
|
|
5
|
-
import { jsx } from "react/jsx-runtime";
|
|
6
|
-
//#region src/react/ApiClientConfigProvider.tsx
|
|
7
|
-
const ApiClientConfigContext = createContext(store);
|
|
8
|
-
const ApiClientConfigProvider = (props) => {
|
|
9
|
-
const { swr, ...config } = props.config;
|
|
10
|
-
useEffect(() => {
|
|
11
|
-
store.setState(() => config);
|
|
12
|
-
}, [config]);
|
|
13
|
-
return /* @__PURE__ */ jsx(ApiClientConfigContext.Provider, {
|
|
14
|
-
value: store,
|
|
15
|
-
children: /* @__PURE__ */ jsx(SWRConfig, {
|
|
16
|
-
value: createSwrConfig(swr),
|
|
17
|
-
children: props.children
|
|
18
|
-
})
|
|
19
|
-
});
|
|
20
|
-
};
|
|
21
|
-
const useApiClientConfigContext = () => useContext(ApiClientConfigContext) || store;
|
|
22
|
-
//#endregion
|
|
23
|
-
export { ApiClientConfigProvider, useApiClientConfigContext };
|
package/dist/react/swr.mjs
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { useRef } from "react";
|
|
2
|
-
//#region src/react/swr.ts
|
|
3
|
-
/**
|
|
4
|
-
* requestのfetchを中断させるためのmiddleware
|
|
5
|
-
*
|
|
6
|
-
* 同一hookにおいて、keyが更新されるなどにより、一つ前のrequestが返る前に再度fetchが行われる場合がある
|
|
7
|
-
* その場合、一つ前のfetchが戻ってきた値がそのまま捨てられるため、responseに時間がかかるAPIの場合、純粋な負荷増加に繋がってしまう
|
|
8
|
-
* そのため、最新のrequestのみを返すように、一つ前のrequestをabortする
|
|
9
|
-
*/
|
|
10
|
-
const abortMiddleware = (useSWRNext) => (key, fetcher, config) => {
|
|
11
|
-
const ctrlRef = useRef(void 0);
|
|
12
|
-
return useSWRNext(key, fetcher ? (key, params) => {
|
|
13
|
-
ctrlRef.current?.abort();
|
|
14
|
-
ctrlRef.current = new AbortController();
|
|
15
|
-
return fetcher(key, {
|
|
16
|
-
...params,
|
|
17
|
-
signal: ctrlRef.current.signal
|
|
18
|
-
});
|
|
19
|
-
} : fetcher, config);
|
|
20
|
-
};
|
|
21
|
-
const createSwrConfig = (config) => ({
|
|
22
|
-
...config,
|
|
23
|
-
use: [...config?.use ?? [], abortMiddleware]
|
|
24
|
-
});
|
|
25
|
-
//#endregion
|
|
26
|
-
export { createSwrConfig };
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { mergeRequestInit } from "../utils/requestInit.mjs";
|
|
2
|
-
import { useApiClientConfigContext } from "./ApiClientConfigProvider.mjs";
|
|
3
|
-
import { useMemo } from "react";
|
|
4
|
-
import { useSyncExternalStore } from "use-sync-external-store/shim/index.js";
|
|
5
|
-
import { useSyncExternalStoreWithSelector } from "use-sync-external-store/shim/with-selector.js";
|
|
6
|
-
//#region src/react/useApiClientConfig.ts
|
|
7
|
-
const useApiClientConfig = () => {
|
|
8
|
-
const store = useApiClientConfigContext();
|
|
9
|
-
return useSyncExternalStore(store.subscribe, store.getState, store.getState);
|
|
10
|
-
};
|
|
11
|
-
const useApiClientConfigWithSelector = (selector) => {
|
|
12
|
-
const store = useApiClientConfigContext();
|
|
13
|
-
return useSyncExternalStoreWithSelector(store.subscribe, store.getState, store.getState, selector);
|
|
14
|
-
};
|
|
15
|
-
const useRequestInit = (customRequestInit = {}) => {
|
|
16
|
-
const { defaultRequestInit = {} } = useApiClientConfig();
|
|
17
|
-
return useMemo(() => mergeRequestInit(defaultRequestInit, customRequestInit), [defaultRequestInit, customRequestInit]);
|
|
18
|
-
};
|
|
19
|
-
//#endregion
|
|
20
|
-
export { useApiClientConfig, useApiClientConfigWithSelector, useRequestInit };
|
package/dist/requestUrl.mjs
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { store } from "./apiClientConfigStore.mjs";
|
|
2
|
-
import qs from "qs";
|
|
3
|
-
//#region src/requestUrl.ts
|
|
4
|
-
function __internal__requestUrl(...args) {
|
|
5
|
-
const config = store.getState();
|
|
6
|
-
const rawPath = args[0];
|
|
7
|
-
const params = args[1] || {};
|
|
8
|
-
const query = args[2];
|
|
9
|
-
const path = (config.hostName ? typeof config.hostName === "string" ? config.hostName : config.hostName(rawPath) : "") + Object.entries(params).reduce((path, [key, value]) => path.replace(`{${key}}`, String(value)), rawPath);
|
|
10
|
-
return query ? `${path}?${qs.stringify(query)}` : path;
|
|
11
|
-
}
|
|
12
|
-
//#endregion
|
|
13
|
-
export { __internal__requestUrl };
|
package/dist/store.mjs
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
//#region src/store.ts
|
|
2
|
-
const createStore = (initialState) => {
|
|
3
|
-
let state = initialState;
|
|
4
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
5
|
-
const getState = () => state;
|
|
6
|
-
const setState = (fn) => {
|
|
7
|
-
state = fn(state);
|
|
8
|
-
listeners.forEach((listener) => listener());
|
|
9
|
-
};
|
|
10
|
-
const subscribe = (listener) => {
|
|
11
|
-
listeners.add(listener);
|
|
12
|
-
return () => listeners.delete(listener);
|
|
13
|
-
};
|
|
14
|
-
return {
|
|
15
|
-
getState,
|
|
16
|
-
setState,
|
|
17
|
-
subscribe
|
|
18
|
-
};
|
|
19
|
-
};
|
|
20
|
-
//#endregion
|
|
21
|
-
export { createStore };
|
package/dist/types.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { mergeHeadersInit } from "./headersInit.mjs";
|
|
2
|
-
//#region src/utils/requestInit.ts
|
|
3
|
-
/**
|
|
4
|
-
* 第一引数と第二引数のequestInitをマージした新たなRequestInitを返す。
|
|
5
|
-
* 同じフィールドが存在する場合、第二引数の値で上書きされる。
|
|
6
|
-
* ただし、`headers`フィールドに関しては、`base`と`override`両方に有効なHeadersInitがある場合に限り、
|
|
7
|
-
* `mergeHeadersInit`を使用してヘッダーの内容をマージする
|
|
8
|
-
*/
|
|
9
|
-
const mergeRequestInit = ({ headers: baseHeaders, ...base }, { headers: overrideHeaders, ...override }) => ({
|
|
10
|
-
...base,
|
|
11
|
-
...override,
|
|
12
|
-
headers: baseHeaders === void 0 ? overrideHeaders : overrideHeaders === void 0 ? baseHeaders : mergeHeadersInit(baseHeaders, overrideHeaders)
|
|
13
|
-
});
|
|
14
|
-
//#endregion
|
|
15
|
-
export { mergeRequestInit };
|
package/dist/zod.mjs
DELETED