@jcoder-stack/abp-react 0.2.1 → 0.3.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/proxy.d.ts +11 -2
- package/dist/proxy.js +34 -4
- 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
|
@@ -260,6 +260,7 @@ var AbpProxyError = class extends Error {
|
|
|
260
260
|
};
|
|
261
261
|
var IDEMPOTENT = /* @__PURE__ */ new Set(["GET", "HEAD", "OPTIONS"]);
|
|
262
262
|
var isRetryableStatus = (status) => status >= 500 || status === 429;
|
|
263
|
+
var utf8KeepingBom = new TextDecoder("utf-8", { ignoreBOM: true });
|
|
263
264
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
264
265
|
var discardBody = (res) => res.body?.cancel().catch(() => {
|
|
265
266
|
});
|
|
@@ -289,12 +290,28 @@ function exposeHeaders(headers) {
|
|
|
289
290
|
}
|
|
290
291
|
return out;
|
|
291
292
|
}
|
|
292
|
-
function sanitizeHeaders(headers) {
|
|
293
|
+
function sanitizeHeaders(headers, body) {
|
|
293
294
|
if (headers === void 0) return {};
|
|
295
|
+
const dropContentType = typeof FormData !== "undefined" && body instanceof FormData;
|
|
294
296
|
return Object.fromEntries(
|
|
295
|
-
Object.entries(headers).filter(
|
|
297
|
+
Object.entries(headers).filter(
|
|
298
|
+
([key]) => FORWARDABLE.has(key.toLowerCase()) && !(dropContentType && key.toLowerCase() === "content-type")
|
|
299
|
+
)
|
|
296
300
|
);
|
|
297
301
|
}
|
|
302
|
+
var DEFAULT_MAX_BODY_BYTES = 10 * 1024 * 1024;
|
|
303
|
+
var isStreamLike = (body) => typeof body?.getReader === "function";
|
|
304
|
+
function measurableBodyBytes(body) {
|
|
305
|
+
if (body === void 0 || typeof body === "string") return null;
|
|
306
|
+
if (body instanceof ArrayBuffer) return body.byteLength;
|
|
307
|
+
if (ArrayBuffer.isView(body)) return body.byteLength;
|
|
308
|
+
let total = 0;
|
|
309
|
+
body.forEach((value, name) => {
|
|
310
|
+
total += name.length;
|
|
311
|
+
total += typeof value === "string" ? value.length : value.size;
|
|
312
|
+
});
|
|
313
|
+
return total;
|
|
314
|
+
}
|
|
298
315
|
var ABSOLUTE_OR_PROTOCOL_RELATIVE = /^([a-z][a-z0-9+.-]*:)?\/\//i;
|
|
299
316
|
function resolveTargetUrl(path, baseUrl) {
|
|
300
317
|
if (ABSOLUTE_OR_PROTOCOL_RELATIVE.test(path)) {
|
|
@@ -312,8 +329,18 @@ function createAbpProxy(opts) {
|
|
|
312
329
|
const fetchFn = opts.fetchFn ?? fetch;
|
|
313
330
|
const timeoutMs = opts.timeoutMs ?? 3e4;
|
|
314
331
|
const retries = opts.retry?.retries ?? 2;
|
|
332
|
+
const maxBodyBytes = opts.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
315
333
|
return {
|
|
316
334
|
async send(req, auth) {
|
|
335
|
+
if (isStreamLike(req.body)) {
|
|
336
|
+
throw new Error(
|
|
337
|
+
"abp proxy: a ReadableStream body cannot be replayed after a 401 refresh or an idempotent retry; buffer it into bytes first"
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
const bodyBytes = measurableBodyBytes(req.body);
|
|
341
|
+
if (bodyBytes !== null && bodyBytes > maxBodyBytes) {
|
|
342
|
+
throw new Error(`abp proxy: request body too large (${bodyBytes} > ${maxBodyBytes} bytes)`);
|
|
343
|
+
}
|
|
317
344
|
const method = (req.method ?? "GET").toUpperCase();
|
|
318
345
|
const maxRetries = IDEMPOTENT.has(method) ? retries : 0;
|
|
319
346
|
const url = resolveTargetUrl(req.path, opts.baseUrl);
|
|
@@ -336,9 +363,12 @@ function createAbpProxy(opts) {
|
|
|
336
363
|
res = await fetchFn(url, {
|
|
337
364
|
method,
|
|
338
365
|
headers: {
|
|
339
|
-
...sanitizeHeaders(req.headers),
|
|
366
|
+
...sanitizeHeaders(req.headers, req.body),
|
|
340
367
|
...session === null ? {} : { Authorization: `Bearer ${session.tokens.accessToken}` }
|
|
341
368
|
},
|
|
369
|
+
// AbpProxyBody 的四种形状运行时都是合法的 fetch 正文。TS 5.7 起 Uint8Array 带上了
|
|
370
|
+
// ArrayBufferLike 泛型参数,而 BodyInit 只认 ArrayBuffer 背衬的那支;把泛型参数写进
|
|
371
|
+
// 公开类型能消掉这次转换,但会反过来拒掉调用方最常写的裸 `Uint8Array` 标注。
|
|
342
372
|
body: req.body,
|
|
343
373
|
signal: AbortSignal.any([...stops, AbortSignal.timeout(timeoutMs)])
|
|
344
374
|
});
|
|
@@ -385,7 +415,7 @@ function createAbpProxy(opts) {
|
|
|
385
415
|
return {
|
|
386
416
|
status: res.status,
|
|
387
417
|
headers: exposeHeaders(res.headers),
|
|
388
|
-
body: isText ? await res.
|
|
418
|
+
body: isText ? utf8KeepingBom.decode(await res.arrayBuffer()) : await res.arrayBuffer(),
|
|
389
419
|
setCookies
|
|
390
420
|
};
|
|
391
421
|
}
|
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.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|