@jcoder-stack/abp-react 0.2.0 → 0.3.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/dist/proxy.d.ts +11 -2
- package/dist/proxy.js +32 -3
- package/package.json +1 -1
package/dist/proxy.d.ts
CHANGED
|
@@ -4,11 +4,18 @@ import { A as Auth, d as OidcStrategy, b as Codec, C as CookieOptions } from './
|
|
|
4
4
|
import { A as ApplicationConfiguration } from './application-configuration-DhOZRqtz.js';
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* 请求正文。四种形状的共同点是**可重发**:401→刷新→重放与幂等重试都要把同一个 body 再发一次。
|
|
9
|
+
*
|
|
10
|
+
* `ReadableStream` 刻意不在其中。它只能消费一次,收下它会让上述两条路径静默退化成「重放一个
|
|
11
|
+
* 空正文」——上游看到的是内容缺失的请求而不是错误,最难查。要传流请先自行缓冲成字节。
|
|
12
|
+
*/
|
|
13
|
+
type AbpProxyBody = string | Uint8Array | ArrayBuffer | FormData;
|
|
7
14
|
interface AbpProxyRequest {
|
|
8
15
|
path: string;
|
|
9
16
|
method?: string;
|
|
10
17
|
headers?: Record<string, string>;
|
|
11
|
-
body?:
|
|
18
|
+
body?: AbpProxyBody;
|
|
12
19
|
/** 调用方的取消信号(如宿主的 `request.signal`);触发后当前尝试立即中止且不再重试。 */
|
|
13
20
|
signal?: AbortSignal;
|
|
14
21
|
}
|
|
@@ -49,6 +56,8 @@ declare function createAbpProxy(opts: {
|
|
|
49
56
|
};
|
|
50
57
|
/** 含重试与退避在内的总预算;默认不设,此时最坏耗时是 (retries+1)×timeoutMs 加退避。 */
|
|
51
58
|
totalTimeoutMs?: number;
|
|
59
|
+
/** 可测正文(字节/FormData)的上限,默认 10MB。字符串正文不参与判断,见 `measurableBodyBytes`。 */
|
|
60
|
+
maxBodyBytes?: number;
|
|
52
61
|
logger?: Logger;
|
|
53
62
|
}): AbpProxy;
|
|
54
63
|
|
|
@@ -224,4 +233,4 @@ type InstallExtraCaResult = "installed" | "already-installed" | "unsupported";
|
|
|
224
233
|
*/
|
|
225
234
|
declare function installExtraCa(caFile: string, caApi?: RuntimeCaApi): InstallExtraCaResult;
|
|
226
235
|
|
|
227
|
-
export { type AbpAuthEnv, type AbpAuthRuntimeOptions, type AbpCallRuntime, type AbpProxy, type AbpProxyAuth, AbpProxyError, type AbpProxyRequest, type AbpProxyResponse, type AppState, type AuthCookieConfig, type AuthCookieSettings, type AuthRuntime, CULTURE_COOKIE, DEFAULT_LOGIN_COOKIE, DEFAULT_LOGIN_COOKIE_MAX_AGE, DEFAULT_SESSION_COOKIE, DEFAULT_SESSION_COOKIE_MAX_AGE, type InstallExtraCaResult, SWITCH_COOKIE_MAX_AGE, TENANT_COOKIE, abpAuthEnvSchema, buildPolicyHeaders, callAbpWithSession, cookieAttributesOf, createAbpAuthRuntime, createAbpIdentityResolver, createAbpProxy, deriveIdentity, handleCallback, handleLogin, handleLogout, handleSetCulture, handleSetTenant, installExtraCa, loadAppState, resolveAbpAuthEnv, tlsTrustFailureCode, tlsTrustFailureMessage, upstreamUnreachableCode, upstreamUnreachableMessage };
|
|
236
|
+
export { type AbpAuthEnv, type AbpAuthRuntimeOptions, type AbpCallRuntime, type AbpProxy, type AbpProxyAuth, type AbpProxyBody, AbpProxyError, type AbpProxyRequest, type AbpProxyResponse, type AppState, type AuthCookieConfig, type AuthCookieSettings, type AuthRuntime, CULTURE_COOKIE, DEFAULT_LOGIN_COOKIE, DEFAULT_LOGIN_COOKIE_MAX_AGE, DEFAULT_SESSION_COOKIE, DEFAULT_SESSION_COOKIE_MAX_AGE, type InstallExtraCaResult, SWITCH_COOKIE_MAX_AGE, TENANT_COOKIE, abpAuthEnvSchema, buildPolicyHeaders, callAbpWithSession, cookieAttributesOf, createAbpAuthRuntime, createAbpIdentityResolver, createAbpProxy, deriveIdentity, handleCallback, handleLogin, handleLogout, handleSetCulture, handleSetTenant, installExtraCa, loadAppState, resolveAbpAuthEnv, tlsTrustFailureCode, tlsTrustFailureMessage, upstreamUnreachableCode, upstreamUnreachableMessage };
|
package/dist/proxy.js
CHANGED
|
@@ -289,12 +289,28 @@ function exposeHeaders(headers) {
|
|
|
289
289
|
}
|
|
290
290
|
return out;
|
|
291
291
|
}
|
|
292
|
-
function sanitizeHeaders(headers) {
|
|
292
|
+
function sanitizeHeaders(headers, body) {
|
|
293
293
|
if (headers === void 0) return {};
|
|
294
|
+
const dropContentType = typeof FormData !== "undefined" && body instanceof FormData;
|
|
294
295
|
return Object.fromEntries(
|
|
295
|
-
Object.entries(headers).filter(
|
|
296
|
+
Object.entries(headers).filter(
|
|
297
|
+
([key]) => FORWARDABLE.has(key.toLowerCase()) && !(dropContentType && key.toLowerCase() === "content-type")
|
|
298
|
+
)
|
|
296
299
|
);
|
|
297
300
|
}
|
|
301
|
+
var DEFAULT_MAX_BODY_BYTES = 10 * 1024 * 1024;
|
|
302
|
+
var isStreamLike = (body) => typeof body?.getReader === "function";
|
|
303
|
+
function measurableBodyBytes(body) {
|
|
304
|
+
if (body === void 0 || typeof body === "string") return null;
|
|
305
|
+
if (body instanceof ArrayBuffer) return body.byteLength;
|
|
306
|
+
if (ArrayBuffer.isView(body)) return body.byteLength;
|
|
307
|
+
let total = 0;
|
|
308
|
+
body.forEach((value, name) => {
|
|
309
|
+
total += name.length;
|
|
310
|
+
total += typeof value === "string" ? value.length : value.size;
|
|
311
|
+
});
|
|
312
|
+
return total;
|
|
313
|
+
}
|
|
298
314
|
var ABSOLUTE_OR_PROTOCOL_RELATIVE = /^([a-z][a-z0-9+.-]*:)?\/\//i;
|
|
299
315
|
function resolveTargetUrl(path, baseUrl) {
|
|
300
316
|
if (ABSOLUTE_OR_PROTOCOL_RELATIVE.test(path)) {
|
|
@@ -312,8 +328,18 @@ function createAbpProxy(opts) {
|
|
|
312
328
|
const fetchFn = opts.fetchFn ?? fetch;
|
|
313
329
|
const timeoutMs = opts.timeoutMs ?? 3e4;
|
|
314
330
|
const retries = opts.retry?.retries ?? 2;
|
|
331
|
+
const maxBodyBytes = opts.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
315
332
|
return {
|
|
316
333
|
async send(req, auth) {
|
|
334
|
+
if (isStreamLike(req.body)) {
|
|
335
|
+
throw new Error(
|
|
336
|
+
"abp proxy: a ReadableStream body cannot be replayed after a 401 refresh or an idempotent retry; buffer it into bytes first"
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
const bodyBytes = measurableBodyBytes(req.body);
|
|
340
|
+
if (bodyBytes !== null && bodyBytes > maxBodyBytes) {
|
|
341
|
+
throw new Error(`abp proxy: request body too large (${bodyBytes} > ${maxBodyBytes} bytes)`);
|
|
342
|
+
}
|
|
317
343
|
const method = (req.method ?? "GET").toUpperCase();
|
|
318
344
|
const maxRetries = IDEMPOTENT.has(method) ? retries : 0;
|
|
319
345
|
const url = resolveTargetUrl(req.path, opts.baseUrl);
|
|
@@ -336,9 +362,12 @@ function createAbpProxy(opts) {
|
|
|
336
362
|
res = await fetchFn(url, {
|
|
337
363
|
method,
|
|
338
364
|
headers: {
|
|
339
|
-
...sanitizeHeaders(req.headers),
|
|
365
|
+
...sanitizeHeaders(req.headers, req.body),
|
|
340
366
|
...session === null ? {} : { Authorization: `Bearer ${session.tokens.accessToken}` }
|
|
341
367
|
},
|
|
368
|
+
// AbpProxyBody 的四种形状运行时都是合法的 fetch 正文。TS 5.7 起 Uint8Array 带上了
|
|
369
|
+
// ArrayBufferLike 泛型参数,而 BodyInit 只认 ArrayBuffer 背衬的那支;把泛型参数写进
|
|
370
|
+
// 公开类型能消掉这次转换,但会反过来拒掉调用方最常写的裸 `Uint8Array` 标注。
|
|
342
371
|
body: req.body,
|
|
343
372
|
signal: AbortSignal.any([...stops, AbortSignal.timeout(timeoutMs)])
|
|
344
373
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jcoder-stack/abp-react",
|
|
3
3
|
"description": "Pure-React runtime for ABP backends: logging, ABP types with zod parsing, fetch client, auth sessions, the ABP proxy gateway, permissions, i18n, React providers/hooks, and TanStack Router guards — exported per domain via subpaths",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|