hoa 0.3.4 → 0.4.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/CHANGELOG.md +20 -0
- package/dist/cjs/lib/compose.cjs +2 -1
- package/dist/cjs/lib/utils.cjs +1 -0
- package/dist/cjs/request.cjs +22 -18
- package/dist/cjs/response.cjs +13 -6
- package/dist/esm/lib/compose.mjs +2 -1
- package/dist/esm/lib/utils.mjs +1 -0
- package/dist/esm/request.mjs +22 -18
- package/dist/esm/response.mjs +13 -6
- package/package.json +6 -6
- package/types/index.d.ts +25 -20
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
## v0.4.0 / 2026-05-09
|
|
2
|
+
|
|
3
|
+
- feat: add SKILL.md
|
|
4
|
+
- fix: improve Content-Length validation in request.length getter
|
|
5
|
+
- fix: normalize Content-Type in response.type getter with trim and lowercase
|
|
6
|
+
- fix: correct HTTP status code validation range from 100-1000 to 100-599
|
|
7
|
+
- fix: return empty string for empty query objects in stringifyQueryToString
|
|
8
|
+
- docs: clarify middleware array flattening behavior in compose function
|
|
9
|
+
- fix: export status code redirect empty mapping constants types
|
|
10
|
+
- fix(request): should clear search when set to null or undefined
|
|
11
|
+
- fix(response): should return null for invalid Content-Length header
|
|
12
|
+
- perf(response): hoist TextEncoder to a module-level singleton
|
|
13
|
+
- perf(request): hoist client IP header list to a module-level constant
|
|
14
|
+
- fix(types): rename HoaError to HttpErrorOptions for naming consistency
|
|
15
|
+
- chore(test): add content-length above 2 GB
|
|
16
|
+
|
|
17
|
+
## v0.3.5 / 2026-02-03
|
|
18
|
+
|
|
19
|
+
- hotfix: package.json exports
|
|
20
|
+
|
|
1
21
|
## v0.3.4 / 2026-01-26
|
|
2
22
|
|
|
3
23
|
- feat: use tsdown instead of tsup
|
package/dist/cjs/lib/compose.cjs
CHANGED
|
@@ -17,7 +17,8 @@ const composeSlim = (middlewares) => async (ctx, next) => {
|
|
|
17
17
|
};
|
|
18
18
|
/**
|
|
19
19
|
* Compose multiple middleware functions into one.
|
|
20
|
-
* Validates input, flattens nested arrays,
|
|
20
|
+
* Validates input, flattens one level of nested arrays,
|
|
21
|
+
* and returns a composed dispatcher.
|
|
21
22
|
*
|
|
22
23
|
* @param {HoaMiddleware[]|HoaMiddleware[][]} middlewares - Array of middleware functions or nested arrays
|
|
23
24
|
* @returns {HoaMiddleware} Composed middleware function
|
package/dist/cjs/lib/utils.cjs
CHANGED
|
@@ -24,6 +24,7 @@ function parseSearchParamsToQuery(searchParams) {
|
|
|
24
24
|
*/
|
|
25
25
|
function stringifyQueryToString(query) {
|
|
26
26
|
if (!query) return "";
|
|
27
|
+
if (Object.keys(query).length === 0) return "";
|
|
27
28
|
const params = new URLSearchParams();
|
|
28
29
|
for (const [key, value] of Object.entries(query)) if (Array.isArray(value)) value.forEach((v) => params.append(key, v ?? ""));
|
|
29
30
|
else params.append(key, value ?? "");
|
package/dist/cjs/request.cjs
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
const require_lib_utils = require('./lib/utils.cjs');
|
|
2
2
|
|
|
3
3
|
//#region src/request.js
|
|
4
|
+
const IP_HEADERS = [
|
|
5
|
+
"x-client-ip",
|
|
6
|
+
"x-forwarded-for",
|
|
7
|
+
"cf-connecting-ip",
|
|
8
|
+
"do-connecting-ip",
|
|
9
|
+
"fastly-client-ip",
|
|
10
|
+
"true-client-ip",
|
|
11
|
+
"x-real-ip",
|
|
12
|
+
"x-cluster-client-ip",
|
|
13
|
+
"x-forwarded",
|
|
14
|
+
"forwarded-for",
|
|
15
|
+
"forwarded",
|
|
16
|
+
"x-appengine-user-ip",
|
|
17
|
+
"cf-pseudo-ipv4"
|
|
18
|
+
];
|
|
4
19
|
/**
|
|
5
20
|
* @typedef {Object} ReqJSON
|
|
6
21
|
* @property {string} method - Request method
|
|
@@ -180,7 +195,7 @@ var HoaRequest = class {
|
|
|
180
195
|
* @public
|
|
181
196
|
*/
|
|
182
197
|
set search(val) {
|
|
183
|
-
this.url.search = val
|
|
198
|
+
this.url.search = val ?? "";
|
|
184
199
|
this._query = null;
|
|
185
200
|
}
|
|
186
201
|
/**
|
|
@@ -396,21 +411,7 @@ var HoaRequest = class {
|
|
|
396
411
|
* @public
|
|
397
412
|
*/
|
|
398
413
|
get ip() {
|
|
399
|
-
for (const header of
|
|
400
|
-
"x-client-ip",
|
|
401
|
-
"x-forwarded-for",
|
|
402
|
-
"cf-connecting-ip",
|
|
403
|
-
"do-connecting-ip",
|
|
404
|
-
"fastly-client-ip",
|
|
405
|
-
"true-client-ip",
|
|
406
|
-
"x-real-ip",
|
|
407
|
-
"x-cluster-client-ip",
|
|
408
|
-
"x-forwarded",
|
|
409
|
-
"forwarded-for",
|
|
410
|
-
"forwarded",
|
|
411
|
-
"x-appengine-user-ip",
|
|
412
|
-
"cf-pseudo-ipv4"
|
|
413
|
-
]) {
|
|
414
|
+
for (const header of IP_HEADERS) {
|
|
414
415
|
const value = this.get(header);
|
|
415
416
|
if (value) if (header === "x-forwarded-for" || header === "forwarded-for") {
|
|
416
417
|
const firstIp = value.split(",")[0]?.trim();
|
|
@@ -421,7 +422,7 @@ var HoaRequest = class {
|
|
|
421
422
|
}
|
|
422
423
|
/**
|
|
423
424
|
* Get the request content length from the Content-Length header.
|
|
424
|
-
* Returns
|
|
425
|
+
* Returns null if the header is missing, empty, or not a valid number.
|
|
425
426
|
*
|
|
426
427
|
* @returns {number|null} The content length in bytes, or null if not available
|
|
427
428
|
* @public
|
|
@@ -429,7 +430,10 @@ var HoaRequest = class {
|
|
|
429
430
|
get length() {
|
|
430
431
|
const len = this.get("Content-Length");
|
|
431
432
|
if (len == null) return null;
|
|
432
|
-
return
|
|
433
|
+
if (!/^\d+$/.test(len)) return null;
|
|
434
|
+
const n = Number(len);
|
|
435
|
+
if (!Number.isSafeInteger(n)) return null;
|
|
436
|
+
return n;
|
|
433
437
|
}
|
|
434
438
|
/**
|
|
435
439
|
* Get the request content type from the Content-Type header.
|
package/dist/cjs/response.cjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const require_lib_utils = require('./lib/utils.cjs');
|
|
2
2
|
|
|
3
3
|
//#region src/response.js
|
|
4
|
+
const encoder = new TextEncoder();
|
|
4
5
|
/**
|
|
5
6
|
* @typedef {Object} ResJSON
|
|
6
7
|
* @property {number} status - Response status code
|
|
@@ -142,7 +143,7 @@ var HoaResponse = class {
|
|
|
142
143
|
*/
|
|
143
144
|
set status(val) {
|
|
144
145
|
if (!Number.isInteger(val)) throw new TypeError("status code must be an integer");
|
|
145
|
-
if (val < 100 || val >
|
|
146
|
+
if (val < 100 || val > 599) throw new TypeError(`invalid status code: ${val}`);
|
|
146
147
|
this._status = val;
|
|
147
148
|
this._explicitStatus = true;
|
|
148
149
|
if (!this._explicitStatusText) this._statusText = require_lib_utils.statusTextMapping[val];
|
|
@@ -275,7 +276,7 @@ var HoaResponse = class {
|
|
|
275
276
|
get type() {
|
|
276
277
|
const type = this.get("Content-Type");
|
|
277
278
|
if (!type) return null;
|
|
278
|
-
return type.split(";", 1)[0];
|
|
279
|
+
return type.split(";", 1)[0].trim().toLowerCase();
|
|
279
280
|
}
|
|
280
281
|
/**
|
|
281
282
|
* Set the response Content-Type.
|
|
@@ -297,14 +298,20 @@ var HoaResponse = class {
|
|
|
297
298
|
* @public
|
|
298
299
|
*/
|
|
299
300
|
get length() {
|
|
300
|
-
|
|
301
|
+
const len = this.get("Content-Length");
|
|
302
|
+
if (len != null) {
|
|
303
|
+
if (!/^\d+$/.test(len)) return null;
|
|
304
|
+
const n = Number(len);
|
|
305
|
+
if (!Number.isSafeInteger(n)) return null;
|
|
306
|
+
return n;
|
|
307
|
+
}
|
|
301
308
|
if (this.body == null || this.body instanceof ReadableStream || this.body instanceof FormData || this.body instanceof Response) return null;
|
|
302
|
-
if (typeof this.body === "string") return
|
|
309
|
+
if (typeof this.body === "string") return encoder.encode(this.body).length;
|
|
303
310
|
if (this.body instanceof Blob) return this.body.size;
|
|
304
311
|
if (this.body instanceof ArrayBuffer) return this.body.byteLength;
|
|
305
312
|
if (ArrayBuffer.isView(this.body)) return this.body.byteLength;
|
|
306
|
-
if (this.body instanceof URLSearchParams) return
|
|
307
|
-
return
|
|
313
|
+
if (this.body instanceof URLSearchParams) return encoder.encode(this.body.toString()).length;
|
|
314
|
+
return encoder.encode(JSON.stringify(this.body)).length;
|
|
308
315
|
}
|
|
309
316
|
/**
|
|
310
317
|
* Set the response Content-Length header.
|
package/dist/esm/lib/compose.mjs
CHANGED
|
@@ -16,7 +16,8 @@ const composeSlim = (middlewares) => async (ctx, next) => {
|
|
|
16
16
|
};
|
|
17
17
|
/**
|
|
18
18
|
* Compose multiple middleware functions into one.
|
|
19
|
-
* Validates input, flattens nested arrays,
|
|
19
|
+
* Validates input, flattens one level of nested arrays,
|
|
20
|
+
* and returns a composed dispatcher.
|
|
20
21
|
*
|
|
21
22
|
* @param {HoaMiddleware[]|HoaMiddleware[][]} middlewares - Array of middleware functions or nested arrays
|
|
22
23
|
* @returns {HoaMiddleware} Composed middleware function
|
package/dist/esm/lib/utils.mjs
CHANGED
|
@@ -23,6 +23,7 @@ function parseSearchParamsToQuery(searchParams) {
|
|
|
23
23
|
*/
|
|
24
24
|
function stringifyQueryToString(query) {
|
|
25
25
|
if (!query) return "";
|
|
26
|
+
if (Object.keys(query).length === 0) return "";
|
|
26
27
|
const params = new URLSearchParams();
|
|
27
28
|
for (const [key, value] of Object.entries(query)) if (Array.isArray(value)) value.forEach((v) => params.append(key, v ?? ""));
|
|
28
29
|
else params.append(key, value ?? "");
|
package/dist/esm/request.mjs
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import { parseSearchParamsToQuery, stringifyQueryToString } from "./lib/utils.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/request.js
|
|
4
|
+
const IP_HEADERS = [
|
|
5
|
+
"x-client-ip",
|
|
6
|
+
"x-forwarded-for",
|
|
7
|
+
"cf-connecting-ip",
|
|
8
|
+
"do-connecting-ip",
|
|
9
|
+
"fastly-client-ip",
|
|
10
|
+
"true-client-ip",
|
|
11
|
+
"x-real-ip",
|
|
12
|
+
"x-cluster-client-ip",
|
|
13
|
+
"x-forwarded",
|
|
14
|
+
"forwarded-for",
|
|
15
|
+
"forwarded",
|
|
16
|
+
"x-appengine-user-ip",
|
|
17
|
+
"cf-pseudo-ipv4"
|
|
18
|
+
];
|
|
4
19
|
/**
|
|
5
20
|
* @typedef {Object} ReqJSON
|
|
6
21
|
* @property {string} method - Request method
|
|
@@ -180,7 +195,7 @@ var HoaRequest = class {
|
|
|
180
195
|
* @public
|
|
181
196
|
*/
|
|
182
197
|
set search(val) {
|
|
183
|
-
this.url.search = val
|
|
198
|
+
this.url.search = val ?? "";
|
|
184
199
|
this._query = null;
|
|
185
200
|
}
|
|
186
201
|
/**
|
|
@@ -396,21 +411,7 @@ var HoaRequest = class {
|
|
|
396
411
|
* @public
|
|
397
412
|
*/
|
|
398
413
|
get ip() {
|
|
399
|
-
for (const header of
|
|
400
|
-
"x-client-ip",
|
|
401
|
-
"x-forwarded-for",
|
|
402
|
-
"cf-connecting-ip",
|
|
403
|
-
"do-connecting-ip",
|
|
404
|
-
"fastly-client-ip",
|
|
405
|
-
"true-client-ip",
|
|
406
|
-
"x-real-ip",
|
|
407
|
-
"x-cluster-client-ip",
|
|
408
|
-
"x-forwarded",
|
|
409
|
-
"forwarded-for",
|
|
410
|
-
"forwarded",
|
|
411
|
-
"x-appengine-user-ip",
|
|
412
|
-
"cf-pseudo-ipv4"
|
|
413
|
-
]) {
|
|
414
|
+
for (const header of IP_HEADERS) {
|
|
414
415
|
const value = this.get(header);
|
|
415
416
|
if (value) if (header === "x-forwarded-for" || header === "forwarded-for") {
|
|
416
417
|
const firstIp = value.split(",")[0]?.trim();
|
|
@@ -421,7 +422,7 @@ var HoaRequest = class {
|
|
|
421
422
|
}
|
|
422
423
|
/**
|
|
423
424
|
* Get the request content length from the Content-Length header.
|
|
424
|
-
* Returns
|
|
425
|
+
* Returns null if the header is missing, empty, or not a valid number.
|
|
425
426
|
*
|
|
426
427
|
* @returns {number|null} The content length in bytes, or null if not available
|
|
427
428
|
* @public
|
|
@@ -429,7 +430,10 @@ var HoaRequest = class {
|
|
|
429
430
|
get length() {
|
|
430
431
|
const len = this.get("Content-Length");
|
|
431
432
|
if (len == null) return null;
|
|
432
|
-
return
|
|
433
|
+
if (!/^\d+$/.test(len)) return null;
|
|
434
|
+
const n = Number(len);
|
|
435
|
+
if (!Number.isSafeInteger(n)) return null;
|
|
436
|
+
return n;
|
|
433
437
|
}
|
|
434
438
|
/**
|
|
435
439
|
* Get the request content type from the Content-Type header.
|
package/dist/esm/response.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { commonTypeMapping, encodeUrl, statusEmptyMapping, statusRedirectMapping, statusTextMapping } from "./lib/utils.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/response.js
|
|
4
|
+
const encoder = new TextEncoder();
|
|
4
5
|
/**
|
|
5
6
|
* @typedef {Object} ResJSON
|
|
6
7
|
* @property {number} status - Response status code
|
|
@@ -142,7 +143,7 @@ var HoaResponse = class {
|
|
|
142
143
|
*/
|
|
143
144
|
set status(val) {
|
|
144
145
|
if (!Number.isInteger(val)) throw new TypeError("status code must be an integer");
|
|
145
|
-
if (val < 100 || val >
|
|
146
|
+
if (val < 100 || val > 599) throw new TypeError(`invalid status code: ${val}`);
|
|
146
147
|
this._status = val;
|
|
147
148
|
this._explicitStatus = true;
|
|
148
149
|
if (!this._explicitStatusText) this._statusText = statusTextMapping[val];
|
|
@@ -275,7 +276,7 @@ var HoaResponse = class {
|
|
|
275
276
|
get type() {
|
|
276
277
|
const type = this.get("Content-Type");
|
|
277
278
|
if (!type) return null;
|
|
278
|
-
return type.split(";", 1)[0];
|
|
279
|
+
return type.split(";", 1)[0].trim().toLowerCase();
|
|
279
280
|
}
|
|
280
281
|
/**
|
|
281
282
|
* Set the response Content-Type.
|
|
@@ -297,14 +298,20 @@ var HoaResponse = class {
|
|
|
297
298
|
* @public
|
|
298
299
|
*/
|
|
299
300
|
get length() {
|
|
300
|
-
|
|
301
|
+
const len = this.get("Content-Length");
|
|
302
|
+
if (len != null) {
|
|
303
|
+
if (!/^\d+$/.test(len)) return null;
|
|
304
|
+
const n = Number(len);
|
|
305
|
+
if (!Number.isSafeInteger(n)) return null;
|
|
306
|
+
return n;
|
|
307
|
+
}
|
|
301
308
|
if (this.body == null || this.body instanceof ReadableStream || this.body instanceof FormData || this.body instanceof Response) return null;
|
|
302
|
-
if (typeof this.body === "string") return
|
|
309
|
+
if (typeof this.body === "string") return encoder.encode(this.body).length;
|
|
303
310
|
if (this.body instanceof Blob) return this.body.size;
|
|
304
311
|
if (this.body instanceof ArrayBuffer) return this.body.byteLength;
|
|
305
312
|
if (ArrayBuffer.isView(this.body)) return this.body.byteLength;
|
|
306
|
-
if (this.body instanceof URLSearchParams) return
|
|
307
|
-
return
|
|
313
|
+
if (this.body instanceof URLSearchParams) return encoder.encode(this.body.toString()).length;
|
|
314
|
+
return encoder.encode(JSON.stringify(this.body)).length;
|
|
308
315
|
}
|
|
309
316
|
/**
|
|
310
317
|
* Set the response Content-Length header.
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hoa",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "A minimal web framework built on Web Standards",
|
|
5
|
-
"main": "./dist/cjs/hoa.
|
|
5
|
+
"main": "./dist/cjs/hoa.cjs",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"module": "./dist/esm/hoa.
|
|
7
|
+
"module": "./dist/esm/hoa.mjs",
|
|
8
8
|
"types": "./types/index.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
11
|
"types": "./types/index.d.ts",
|
|
12
|
-
"import": "./dist/esm/hoa.
|
|
13
|
-
"require": "./dist/cjs/hoa.
|
|
14
|
-
"default": "./dist/esm/hoa.
|
|
12
|
+
"import": "./dist/esm/hoa.mjs",
|
|
13
|
+
"require": "./dist/cjs/hoa.cjs",
|
|
14
|
+
"default": "./dist/esm/hoa.mjs"
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
package/types/index.d.ts
CHANGED
|
@@ -1,35 +1,28 @@
|
|
|
1
|
-
interface HoaAppJson {
|
|
1
|
+
export interface HoaAppJson {
|
|
2
2
|
name: string;
|
|
3
3
|
}
|
|
4
4
|
|
|
5
|
-
interface HoaContextJson {
|
|
5
|
+
export interface HoaContextJson {
|
|
6
6
|
app: HoaAppJson;
|
|
7
7
|
req: HoaRequestJson;
|
|
8
8
|
res: HoaResponseJson;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
interface HoaRequestJson {
|
|
11
|
+
export interface HoaRequestJson {
|
|
12
12
|
method: string;
|
|
13
13
|
url: string;
|
|
14
14
|
headers: Record<string, string>;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
interface HoaResponseJson {
|
|
17
|
+
export interface HoaResponseJson {
|
|
18
18
|
status: number;
|
|
19
19
|
statusText: string;
|
|
20
20
|
headers: Record<string, string>;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
interface HoaError {
|
|
24
|
-
message?: string;
|
|
25
|
-
cause?: unknown;
|
|
26
|
-
expose?: boolean;
|
|
27
|
-
headers?: Headers | Record<string, string> | Iterable<readonly [string, string]>;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
23
|
export type HoaExtension = (app: Hoa) => void;
|
|
31
24
|
|
|
32
|
-
export type HoaMiddleware = (ctx: HoaContext, next
|
|
25
|
+
export type HoaMiddleware = (ctx: HoaContext, next: () => Promise<void>) => Promise<void> | void;
|
|
33
26
|
|
|
34
27
|
export declare class Hoa {
|
|
35
28
|
constructor(options?: { name?: string });
|
|
@@ -61,8 +54,10 @@ export declare class HoaContext {
|
|
|
61
54
|
env?: any;
|
|
62
55
|
executionCtx?: any;
|
|
63
56
|
state: Record<string, any>;
|
|
64
|
-
throw(status: number, message?: string
|
|
65
|
-
|
|
57
|
+
throw(status: number, message?: string, options?: HttpErrorOptions): never;
|
|
58
|
+
throw(status: number, options: HttpErrorOptions): never;
|
|
59
|
+
assert<T>(value: T, status: number, message?: string, options?: HttpErrorOptions): asserts value is NonNullable<T>;
|
|
60
|
+
assert<T>(value: T, status: number, options: HttpErrorOptions): asserts value is NonNullable<T>;
|
|
66
61
|
onerror(err: unknown): Response;
|
|
67
62
|
toJSON(): HoaContextJson;
|
|
68
63
|
readonly response: Response;
|
|
@@ -139,7 +134,7 @@ export declare class HoaRequest {
|
|
|
139
134
|
toJSON(): HoaRequestJson;
|
|
140
135
|
}
|
|
141
136
|
|
|
142
|
-
type HoaResponseBody =
|
|
137
|
+
export type HoaResponseBody =
|
|
143
138
|
| string
|
|
144
139
|
| Blob
|
|
145
140
|
| ArrayBuffer
|
|
@@ -190,12 +185,16 @@ export declare class HoaResponse {
|
|
|
190
185
|
toJSON(): HoaResponseJson;
|
|
191
186
|
}
|
|
192
187
|
|
|
188
|
+
export interface HttpErrorOptions {
|
|
189
|
+
message?: string;
|
|
190
|
+
cause?: unknown;
|
|
191
|
+
expose?: boolean;
|
|
192
|
+
headers?: Headers | Record<string, string> | Iterable<readonly [string, string]>;
|
|
193
|
+
}
|
|
194
|
+
|
|
193
195
|
export declare class HttpError extends Error {
|
|
194
|
-
constructor(
|
|
195
|
-
|
|
196
|
-
message?: string | HoaError,
|
|
197
|
-
options?: HoaError
|
|
198
|
-
);
|
|
196
|
+
constructor(status: number, message?: string, options?: HttpErrorOptions);
|
|
197
|
+
constructor(status: number, options: HttpErrorOptions);
|
|
199
198
|
readonly name: string;
|
|
200
199
|
readonly status: number;
|
|
201
200
|
readonly statusCode: number;
|
|
@@ -207,4 +206,10 @@ export declare function compose(
|
|
|
207
206
|
middlewares: ReadonlyArray<HoaMiddleware> | ReadonlyArray<ReadonlyArray<HoaMiddleware>>
|
|
208
207
|
): HoaMiddleware;
|
|
209
208
|
|
|
209
|
+
export const statusTextMapping: Record<number, string>;
|
|
210
|
+
|
|
211
|
+
export const statusRedirectMapping: Record<number, boolean>;
|
|
212
|
+
|
|
213
|
+
export const statusEmptyMapping: Record<number, boolean>;
|
|
214
|
+
|
|
210
215
|
export default Hoa;
|