@shware/http 2.4.4 → 2.5.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/hono/handler.cjs +1 -5
- package/dist/hono/handler.cjs.map +1 -1
- package/dist/hono/handler.mjs +1 -5
- package/dist/hono/handler.mjs.map +1 -1
- package/dist/hono/index.cjs +3 -0
- package/dist/hono/index.cjs.map +1 -1
- package/dist/hono/index.d.cts +1 -0
- package/dist/hono/index.d.ts +1 -0
- package/dist/hono/index.mjs +2 -0
- package/dist/hono/index.mjs.map +1 -1
- package/dist/hono/rate-limit.cjs +121 -0
- package/dist/hono/rate-limit.cjs.map +1 -0
- package/dist/hono/rate-limit.d.cts +35 -0
- package/dist/hono/rate-limit.d.ts +35 -0
- package/dist/hono/rate-limit.mjs +95 -0
- package/dist/hono/rate-limit.mjs.map +1 -0
- package/dist/index.cjs +4 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +4 -4
- package/dist/index.mjs.map +1 -1
- package/dist/response.cjs +11 -11
- package/dist/response.cjs.map +1 -1
- package/dist/response.d.cts +3 -3
- package/dist/response.d.ts +3 -3
- package/dist/response.mjs +8 -8
- package/dist/response.mjs.map +1 -1
- package/package.json +1 -1
package/dist/hono/handler.cjs
CHANGED
|
@@ -39,13 +39,9 @@ function errorHandler(error, c) {
|
|
|
39
39
|
(d) => d["@type"] === import_detail.DetailType.BAD_REQUEST
|
|
40
40
|
);
|
|
41
41
|
if (badRequest) console.warn(servingData, badRequest);
|
|
42
|
+
console.error(servingData, error.body?.error);
|
|
42
43
|
return c.json(error.body, error.status);
|
|
43
44
|
}
|
|
44
|
-
if (error instanceof SyntaxError) {
|
|
45
|
-
if (/^Cannot convert .* to a BigInt$/.test(error.message)) {
|
|
46
|
-
return import_status.Status.invalidArgument(`Invalid number. ${error.message}`).response(details);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
45
|
if (isAxiosError(error)) {
|
|
50
46
|
console.error({
|
|
51
47
|
status: error.status,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hono/handler.ts"],"sourcesContent":["import type { Context } from 'hono';\nimport type { RequestIdVariables } from 'hono/request-id';\nimport type { Bindings, HTTPResponseError } from 'hono/types';\nimport type { ContentfulStatusCode } from 'hono/utils/http-status';\nimport { DetailType, Details } from '../error/detail';\nimport { Status, StatusError } from '../error/status';\n\nexport type Env = {\n Variables: RequestIdVariables;\n Bindings?: Bindings;\n};\n\ntype AxiosError = {\n code?: string;\n cause?: unknown;\n status?: number;\n message?: string;\n isAxiosError: boolean;\n response?: {\n data: unknown;\n status: number;\n statusText: string;\n headers: Record<string, string>;\n };\n config?: { url?: string; data?: unknown; method?: string; headers?: Record<string, string> };\n};\n\nexport function isAxiosError(payload: unknown): payload is AxiosError {\n return (\n payload !== null &&\n typeof payload === 'object' &&\n 'isAxiosError' in payload &&\n payload.isAxiosError === true\n );\n}\n\nexport function errorHandler<E extends Env = never>(\n error: Error | HTTPResponseError,\n c: Context<E>\n): Response | Promise<Response> {\n const requestId = c.get('requestId');\n const servingData = `${c.req.method}: ${c.req.path}`;\n const details = Details.new().requestInfo({ requestId, servingData });\n\n if (error instanceof StatusError) {\n error.body?.error?.details?.push(...details.list);\n const badRequest = error.body?.error?.details.find(\n (d) => d['@type'] === DetailType.BAD_REQUEST\n );\n if (badRequest) console.warn(servingData, badRequest);\n return c.json(error.body, error.status as ContentfulStatusCode);\n }\n\n if (
|
|
1
|
+
{"version":3,"sources":["../../src/hono/handler.ts"],"sourcesContent":["import type { Context } from 'hono';\nimport type { RequestIdVariables } from 'hono/request-id';\nimport type { Bindings, HTTPResponseError } from 'hono/types';\nimport type { ContentfulStatusCode } from 'hono/utils/http-status';\nimport { DetailType, Details } from '../error/detail';\nimport { Status, StatusError } from '../error/status';\n\nexport type Env = {\n Variables: RequestIdVariables;\n Bindings?: Bindings;\n};\n\ntype AxiosError = {\n code?: string;\n cause?: unknown;\n status?: number;\n message?: string;\n isAxiosError: boolean;\n response?: {\n data: unknown;\n status: number;\n statusText: string;\n headers: Record<string, string>;\n };\n config?: { url?: string; data?: unknown; method?: string; headers?: Record<string, string> };\n};\n\nexport function isAxiosError(payload: unknown): payload is AxiosError {\n return (\n payload !== null &&\n typeof payload === 'object' &&\n 'isAxiosError' in payload &&\n payload.isAxiosError === true\n );\n}\n\nexport function errorHandler<E extends Env = never>(\n error: Error | HTTPResponseError,\n c: Context<E>\n): Response | Promise<Response> {\n const requestId = c.get('requestId');\n const servingData = `${c.req.method}: ${c.req.path}`;\n const details = Details.new().requestInfo({ requestId, servingData });\n\n if (error instanceof StatusError) {\n error.body?.error?.details?.push(...details.list);\n const badRequest = error.body?.error?.details.find(\n (d) => d['@type'] === DetailType.BAD_REQUEST\n );\n if (badRequest) console.warn(servingData, badRequest);\n console.error(servingData, error.body?.error);\n return c.json(error.body, error.status as ContentfulStatusCode);\n }\n\n if (isAxiosError(error)) {\n console.error({\n status: error.status,\n message: error.message,\n request: {\n method: error.config?.method,\n url: error.config?.url,\n data: error.config?.data,\n },\n response: { data: error.response?.data },\n });\n return Status.internal('Axios error').response(details);\n }\n\n console.error(`Unknown error: ${servingData}`, error);\n return Status.internal('Unknown error').response(details);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,oBAAoC;AACpC,oBAAoC;AAsB7B,SAAS,aAAa,SAAyC;AACpE,SACE,YAAY,QACZ,OAAO,YAAY,YACnB,kBAAkB,WAClB,QAAQ,iBAAiB;AAE7B;AAEO,SAAS,aACd,OACA,GAC8B;AAC9B,QAAM,YAAY,EAAE,IAAI,WAAW;AACnC,QAAM,cAAc,GAAG,EAAE,IAAI,MAAM,KAAK,EAAE,IAAI,IAAI;AAClD,QAAM,UAAU,sBAAQ,IAAI,EAAE,YAAY,EAAE,WAAW,YAAY,CAAC;AAEpE,MAAI,iBAAiB,2BAAa;AAChC,UAAM,MAAM,OAAO,SAAS,KAAK,GAAG,QAAQ,IAAI;AAChD,UAAM,aAAa,MAAM,MAAM,OAAO,QAAQ;AAAA,MAC5C,CAAC,MAAM,EAAE,OAAO,MAAM,yBAAW;AAAA,IACnC;AACA,QAAI,WAAY,SAAQ,KAAK,aAAa,UAAU;AACpD,YAAQ,MAAM,aAAa,MAAM,MAAM,KAAK;AAC5C,WAAO,EAAE,KAAK,MAAM,MAAM,MAAM,MAA8B;AAAA,EAChE;AAEA,MAAI,aAAa,KAAK,GAAG;AACvB,YAAQ,MAAM;AAAA,MACZ,QAAQ,MAAM;AAAA,MACd,SAAS,MAAM;AAAA,MACf,SAAS;AAAA,QACP,QAAQ,MAAM,QAAQ;AAAA,QACtB,KAAK,MAAM,QAAQ;AAAA,QACnB,MAAM,MAAM,QAAQ;AAAA,MACtB;AAAA,MACA,UAAU,EAAE,MAAM,MAAM,UAAU,KAAK;AAAA,IACzC,CAAC;AACD,WAAO,qBAAO,SAAS,aAAa,EAAE,SAAS,OAAO;AAAA,EACxD;AAEA,UAAQ,MAAM,kBAAkB,WAAW,IAAI,KAAK;AACpD,SAAO,qBAAO,SAAS,eAAe,EAAE,SAAS,OAAO;AAC1D;","names":[]}
|
package/dist/hono/handler.mjs
CHANGED
|
@@ -14,13 +14,9 @@ function errorHandler(error, c) {
|
|
|
14
14
|
(d) => d["@type"] === DetailType.BAD_REQUEST
|
|
15
15
|
);
|
|
16
16
|
if (badRequest) console.warn(servingData, badRequest);
|
|
17
|
+
console.error(servingData, error.body?.error);
|
|
17
18
|
return c.json(error.body, error.status);
|
|
18
19
|
}
|
|
19
|
-
if (error instanceof SyntaxError) {
|
|
20
|
-
if (/^Cannot convert .* to a BigInt$/.test(error.message)) {
|
|
21
|
-
return Status.invalidArgument(`Invalid number. ${error.message}`).response(details);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
20
|
if (isAxiosError(error)) {
|
|
25
21
|
console.error({
|
|
26
22
|
status: error.status,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hono/handler.ts"],"sourcesContent":["import type { Context } from 'hono';\nimport type { RequestIdVariables } from 'hono/request-id';\nimport type { Bindings, HTTPResponseError } from 'hono/types';\nimport type { ContentfulStatusCode } from 'hono/utils/http-status';\nimport { DetailType, Details } from '../error/detail';\nimport { Status, StatusError } from '../error/status';\n\nexport type Env = {\n Variables: RequestIdVariables;\n Bindings?: Bindings;\n};\n\ntype AxiosError = {\n code?: string;\n cause?: unknown;\n status?: number;\n message?: string;\n isAxiosError: boolean;\n response?: {\n data: unknown;\n status: number;\n statusText: string;\n headers: Record<string, string>;\n };\n config?: { url?: string; data?: unknown; method?: string; headers?: Record<string, string> };\n};\n\nexport function isAxiosError(payload: unknown): payload is AxiosError {\n return (\n payload !== null &&\n typeof payload === 'object' &&\n 'isAxiosError' in payload &&\n payload.isAxiosError === true\n );\n}\n\nexport function errorHandler<E extends Env = never>(\n error: Error | HTTPResponseError,\n c: Context<E>\n): Response | Promise<Response> {\n const requestId = c.get('requestId');\n const servingData = `${c.req.method}: ${c.req.path}`;\n const details = Details.new().requestInfo({ requestId, servingData });\n\n if (error instanceof StatusError) {\n error.body?.error?.details?.push(...details.list);\n const badRequest = error.body?.error?.details.find(\n (d) => d['@type'] === DetailType.BAD_REQUEST\n );\n if (badRequest) console.warn(servingData, badRequest);\n return c.json(error.body, error.status as ContentfulStatusCode);\n }\n\n if (
|
|
1
|
+
{"version":3,"sources":["../../src/hono/handler.ts"],"sourcesContent":["import type { Context } from 'hono';\nimport type { RequestIdVariables } from 'hono/request-id';\nimport type { Bindings, HTTPResponseError } from 'hono/types';\nimport type { ContentfulStatusCode } from 'hono/utils/http-status';\nimport { DetailType, Details } from '../error/detail';\nimport { Status, StatusError } from '../error/status';\n\nexport type Env = {\n Variables: RequestIdVariables;\n Bindings?: Bindings;\n};\n\ntype AxiosError = {\n code?: string;\n cause?: unknown;\n status?: number;\n message?: string;\n isAxiosError: boolean;\n response?: {\n data: unknown;\n status: number;\n statusText: string;\n headers: Record<string, string>;\n };\n config?: { url?: string; data?: unknown; method?: string; headers?: Record<string, string> };\n};\n\nexport function isAxiosError(payload: unknown): payload is AxiosError {\n return (\n payload !== null &&\n typeof payload === 'object' &&\n 'isAxiosError' in payload &&\n payload.isAxiosError === true\n );\n}\n\nexport function errorHandler<E extends Env = never>(\n error: Error | HTTPResponseError,\n c: Context<E>\n): Response | Promise<Response> {\n const requestId = c.get('requestId');\n const servingData = `${c.req.method}: ${c.req.path}`;\n const details = Details.new().requestInfo({ requestId, servingData });\n\n if (error instanceof StatusError) {\n error.body?.error?.details?.push(...details.list);\n const badRequest = error.body?.error?.details.find(\n (d) => d['@type'] === DetailType.BAD_REQUEST\n );\n if (badRequest) console.warn(servingData, badRequest);\n console.error(servingData, error.body?.error);\n return c.json(error.body, error.status as ContentfulStatusCode);\n }\n\n if (isAxiosError(error)) {\n console.error({\n status: error.status,\n message: error.message,\n request: {\n method: error.config?.method,\n url: error.config?.url,\n data: error.config?.data,\n },\n response: { data: error.response?.data },\n });\n return Status.internal('Axios error').response(details);\n }\n\n console.error(`Unknown error: ${servingData}`, error);\n return Status.internal('Unknown error').response(details);\n}\n"],"mappings":";AAIA,SAAS,YAAY,eAAe;AACpC,SAAS,QAAQ,mBAAmB;AAsB7B,SAAS,aAAa,SAAyC;AACpE,SACE,YAAY,QACZ,OAAO,YAAY,YACnB,kBAAkB,WAClB,QAAQ,iBAAiB;AAE7B;AAEO,SAAS,aACd,OACA,GAC8B;AAC9B,QAAM,YAAY,EAAE,IAAI,WAAW;AACnC,QAAM,cAAc,GAAG,EAAE,IAAI,MAAM,KAAK,EAAE,IAAI,IAAI;AAClD,QAAM,UAAU,QAAQ,IAAI,EAAE,YAAY,EAAE,WAAW,YAAY,CAAC;AAEpE,MAAI,iBAAiB,aAAa;AAChC,UAAM,MAAM,OAAO,SAAS,KAAK,GAAG,QAAQ,IAAI;AAChD,UAAM,aAAa,MAAM,MAAM,OAAO,QAAQ;AAAA,MAC5C,CAAC,MAAM,EAAE,OAAO,MAAM,WAAW;AAAA,IACnC;AACA,QAAI,WAAY,SAAQ,KAAK,aAAa,UAAU;AACpD,YAAQ,MAAM,aAAa,MAAM,MAAM,KAAK;AAC5C,WAAO,EAAE,KAAK,MAAM,MAAM,MAAM,MAA8B;AAAA,EAChE;AAEA,MAAI,aAAa,KAAK,GAAG;AACvB,YAAQ,MAAM;AAAA,MACZ,QAAQ,MAAM;AAAA,MACd,SAAS,MAAM;AAAA,MACf,SAAS;AAAA,QACP,QAAQ,MAAM,QAAQ;AAAA,QACtB,KAAK,MAAM,QAAQ;AAAA,QACnB,MAAM,MAAM,QAAQ;AAAA,MACtB;AAAA,MACA,UAAU,EAAE,MAAM,MAAM,UAAU,KAAK;AAAA,IACzC,CAAC;AACD,WAAO,OAAO,SAAS,aAAa,EAAE,SAAS,OAAO;AAAA,EACxD;AAEA,UAAQ,MAAM,kBAAkB,WAAW,IAAI,KAAK;AACpD,SAAO,OAAO,SAAS,eAAe,EAAE,SAAS,OAAO;AAC1D;","names":[]}
|
package/dist/hono/index.cjs
CHANGED
|
@@ -25,6 +25,7 @@ __export(hono_exports, {
|
|
|
25
25
|
csrf: () => import_csrf.csrf,
|
|
26
26
|
errorHandler: () => import_handler.errorHandler,
|
|
27
27
|
geolocation: () => import_geolocation.geolocation,
|
|
28
|
+
rateLimit: () => import_rate_limit.rateLimit,
|
|
28
29
|
zValidator: () => import_validator.zValidator
|
|
29
30
|
});
|
|
30
31
|
module.exports = __toCommonJS(hono_exports);
|
|
@@ -33,6 +34,7 @@ var import_handler = require("./handler.cjs");
|
|
|
33
34
|
var import_geolocation = require("./geolocation.cjs");
|
|
34
35
|
var import_authorizer = require("./authorizer.cjs");
|
|
35
36
|
var import_csrf = require("./csrf.cjs");
|
|
37
|
+
var import_rate_limit = require("./rate-limit.cjs");
|
|
36
38
|
// Annotate the CommonJS export names for ESM import in node:
|
|
37
39
|
0 && (module.exports = {
|
|
38
40
|
authorizer,
|
|
@@ -40,6 +42,7 @@ var import_csrf = require("./csrf.cjs");
|
|
|
40
42
|
csrf,
|
|
41
43
|
errorHandler,
|
|
42
44
|
geolocation,
|
|
45
|
+
rateLimit,
|
|
43
46
|
zValidator
|
|
44
47
|
});
|
|
45
48
|
//# sourceMappingURL=index.cjs.map
|
package/dist/hono/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hono/index.ts"],"sourcesContent":["export { zValidator, bigintId } from './validator';\nexport { errorHandler } from './handler';\nexport { geolocation } from './geolocation';\nexport { authorizer, type AuthorizerConfig } from './authorizer';\nexport { csrf, type CSRFConfig, type CSRFIgnoreRule } from './csrf';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAAqC;AACrC,qBAA6B;AAC7B,yBAA4B;AAC5B,wBAAkD;AAClD,kBAA2D;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/hono/index.ts"],"sourcesContent":["export { zValidator, bigintId } from './validator';\nexport { errorHandler } from './handler';\nexport { geolocation } from './geolocation';\nexport { authorizer, type AuthorizerConfig } from './authorizer';\nexport { csrf, type CSRFConfig, type CSRFIgnoreRule } from './csrf';\nexport { rateLimit, type RateLimitOptions } from './rate-limit';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAAqC;AACrC,qBAA6B;AAC7B,yBAA4B;AAC5B,wBAAkD;AAClD,kBAA2D;AAC3D,wBAAiD;","names":[]}
|
package/dist/hono/index.d.cts
CHANGED
|
@@ -3,6 +3,7 @@ export { errorHandler } from './handler.cjs';
|
|
|
3
3
|
export { geolocation } from './geolocation.cjs';
|
|
4
4
|
export { AuthorizerConfig, authorizer } from './authorizer.cjs';
|
|
5
5
|
export { CSRFConfig, CSRFIgnoreRule, csrf } from './csrf.cjs';
|
|
6
|
+
export { RateLimitOptions, rateLimit } from './rate-limit.cjs';
|
|
6
7
|
import 'zod/mini';
|
|
7
8
|
import 'hono/utils/http-status';
|
|
8
9
|
import 'hono/validator';
|
package/dist/hono/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { errorHandler } from './handler.js';
|
|
|
3
3
|
export { geolocation } from './geolocation.js';
|
|
4
4
|
export { AuthorizerConfig, authorizer } from './authorizer.js';
|
|
5
5
|
export { CSRFConfig, CSRFIgnoreRule, csrf } from './csrf.js';
|
|
6
|
+
export { RateLimitOptions, rateLimit } from './rate-limit.js';
|
|
6
7
|
import 'zod/mini';
|
|
7
8
|
import 'hono/utils/http-status';
|
|
8
9
|
import 'hono/validator';
|
package/dist/hono/index.mjs
CHANGED
|
@@ -4,12 +4,14 @@ import { errorHandler } from "./handler.mjs";
|
|
|
4
4
|
import { geolocation } from "./geolocation.mjs";
|
|
5
5
|
import { authorizer } from "./authorizer.mjs";
|
|
6
6
|
import { csrf } from "./csrf.mjs";
|
|
7
|
+
import { rateLimit } from "./rate-limit.mjs";
|
|
7
8
|
export {
|
|
8
9
|
authorizer,
|
|
9
10
|
bigintId,
|
|
10
11
|
csrf,
|
|
11
12
|
errorHandler,
|
|
12
13
|
geolocation,
|
|
14
|
+
rateLimit,
|
|
13
15
|
zValidator
|
|
14
16
|
};
|
|
15
17
|
//# sourceMappingURL=index.mjs.map
|
package/dist/hono/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hono/index.ts"],"sourcesContent":["export { zValidator, bigintId } from './validator';\nexport { errorHandler } from './handler';\nexport { geolocation } from './geolocation';\nexport { authorizer, type AuthorizerConfig } from './authorizer';\nexport { csrf, type CSRFConfig, type CSRFIgnoreRule } from './csrf';\n"],"mappings":";AAAA,SAAS,YAAY,gBAAgB;AACrC,SAAS,oBAAoB;AAC7B,SAAS,mBAAmB;AAC5B,SAAS,kBAAyC;AAClD,SAAS,YAAkD;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/hono/index.ts"],"sourcesContent":["export { zValidator, bigintId } from './validator';\nexport { errorHandler } from './handler';\nexport { geolocation } from './geolocation';\nexport { authorizer, type AuthorizerConfig } from './authorizer';\nexport { csrf, type CSRFConfig, type CSRFIgnoreRule } from './csrf';\nexport { rateLimit, type RateLimitOptions } from './rate-limit';\n"],"mappings":";AAAA,SAAS,YAAY,gBAAgB;AACrC,SAAS,oBAAoB;AAC7B,SAAS,mBAAmB;AAC5B,SAAS,kBAAyC;AAClD,SAAS,YAAkD;AAC3D,SAAS,iBAAwC;","names":[]}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/hono/rate-limit.ts
|
|
21
|
+
var rate_limit_exports = {};
|
|
22
|
+
__export(rate_limit_exports, {
|
|
23
|
+
checkRateLimit: () => checkRateLimit,
|
|
24
|
+
rateLimit: () => rateLimit
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(rate_limit_exports);
|
|
27
|
+
var import_detail = require("../error/detail.cjs");
|
|
28
|
+
var import_status = require("../error/status.cjs");
|
|
29
|
+
var import_geolocation = require("./geolocation.cjs");
|
|
30
|
+
function calculateTokens(state, capacity, rate, now) {
|
|
31
|
+
if (!state) {
|
|
32
|
+
return { tokens: capacity, lastRefillTime: now };
|
|
33
|
+
}
|
|
34
|
+
const elapsed = (now - state.lastRefillTime) / 1e3;
|
|
35
|
+
const tokensToAdd = elapsed * rate;
|
|
36
|
+
const newTokens = Math.min(capacity, state.tokens + tokensToAdd);
|
|
37
|
+
return {
|
|
38
|
+
tokens: newTokens,
|
|
39
|
+
lastRefillTime: now
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function calculateResetTime(currentTokens, capacity, rate) {
|
|
43
|
+
if (currentTokens >= capacity) return 0;
|
|
44
|
+
return Math.ceil((capacity - currentTokens) / rate);
|
|
45
|
+
}
|
|
46
|
+
function calculateRetryAfter(currentTokens, requested, rate) {
|
|
47
|
+
if (currentTokens >= requested) return 0;
|
|
48
|
+
return Math.ceil((requested - currentTokens) / rate);
|
|
49
|
+
}
|
|
50
|
+
async function checkRateLimit(kv, identifier, options) {
|
|
51
|
+
const {
|
|
52
|
+
rate,
|
|
53
|
+
capacity,
|
|
54
|
+
requested = 1,
|
|
55
|
+
keyPrefix = "rate-limit:",
|
|
56
|
+
expiresIn = Math.max(3600, Math.ceil(capacity / rate * 2))
|
|
57
|
+
} = options;
|
|
58
|
+
const key = `${keyPrefix}${identifier}`;
|
|
59
|
+
const now = Date.now();
|
|
60
|
+
const stateStr = await kv.getItem(key);
|
|
61
|
+
const state = stateStr ? JSON.parse(stateStr) : null;
|
|
62
|
+
const { tokens: currentTokens, lastRefillTime } = calculateTokens(state, capacity, rate, now);
|
|
63
|
+
const allowed = currentTokens >= requested;
|
|
64
|
+
const newTokens = allowed ? currentTokens - requested : currentTokens;
|
|
65
|
+
const newState = { tokens: newTokens, lastRefillTime };
|
|
66
|
+
await kv.setItem(key, JSON.stringify(newState), expiresIn);
|
|
67
|
+
const result = {
|
|
68
|
+
allowed,
|
|
69
|
+
remaining: Math.floor(Math.max(0, newTokens)),
|
|
70
|
+
limit: capacity,
|
|
71
|
+
reset: calculateResetTime(newTokens, capacity, rate)
|
|
72
|
+
};
|
|
73
|
+
if (!allowed) {
|
|
74
|
+
result.retryAfter = calculateRetryAfter(currentTokens, requested, rate);
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
function rateLimit(options) {
|
|
79
|
+
const {
|
|
80
|
+
kv,
|
|
81
|
+
rate,
|
|
82
|
+
capacity,
|
|
83
|
+
requested = 1,
|
|
84
|
+
keyPrefix = "rate-limit:",
|
|
85
|
+
expiresIn = Math.max(3600, Math.ceil(capacity / rate * 2)),
|
|
86
|
+
getIdentifier,
|
|
87
|
+
onRateLimited,
|
|
88
|
+
skip
|
|
89
|
+
} = options;
|
|
90
|
+
return async (c, next) => {
|
|
91
|
+
if (skip && await skip(c)) {
|
|
92
|
+
return next();
|
|
93
|
+
}
|
|
94
|
+
const identifier = getIdentifier ? getIdentifier(c) : (0, import_geolocation.geolocation)(c).ip_address;
|
|
95
|
+
if (!identifier) return next();
|
|
96
|
+
const result = await checkRateLimit(kv, identifier, {
|
|
97
|
+
rate,
|
|
98
|
+
capacity,
|
|
99
|
+
requested,
|
|
100
|
+
keyPrefix,
|
|
101
|
+
expiresIn
|
|
102
|
+
});
|
|
103
|
+
c.header("X-RateLimit-Limit", String(result.limit));
|
|
104
|
+
c.header("X-RateLimit-Remaining", String(result.remaining));
|
|
105
|
+
c.header("X-RateLimit-Reset", String(result.reset));
|
|
106
|
+
if (!result.allowed) {
|
|
107
|
+
c.header("Retry-After", String(result.retryAfter ?? 1));
|
|
108
|
+
if (onRateLimited) return onRateLimited(c, result.retryAfter ?? 1);
|
|
109
|
+
const details = import_detail.Details.new().errorInfo({ reason: "RATE_LIMIT_EXCEEDED" }).retryInfo({ retryDelay: result.retryAfter ?? 1 });
|
|
110
|
+
const message = "Rate limit exceeded. Please try again later.";
|
|
111
|
+
return import_status.Status.resourceExhausted(message).response(details);
|
|
112
|
+
}
|
|
113
|
+
return next();
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
117
|
+
0 && (module.exports = {
|
|
118
|
+
checkRateLimit,
|
|
119
|
+
rateLimit
|
|
120
|
+
});
|
|
121
|
+
//# sourceMappingURL=rate-limit.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hono/rate-limit.ts"],"sourcesContent":["import type { Context, MiddlewareHandler } from 'hono';\nimport { Details } from '../error/detail';\nimport { Status } from '../error/status';\nimport { geolocation } from './geolocation';\n\nexport interface KV {\n setItem(key: string, value: string, expiresIn?: number): Promise<void>;\n getItem(key: string): Promise<string | null>;\n removeItem(key: string): Promise<void>;\n}\n\ninterface TokenBucketState {\n tokens: number;\n lastRefillTime: number;\n}\n\nexport interface RateLimitOptions {\n kv: KV;\n rate: number;\n capacity: number;\n requested?: number;\n keyPrefix?: string;\n expiresIn?: number;\n getIdentifier?: (c: Context) => string | undefined;\n onRateLimited?: (c: Context, retryAfter: number) => Response | Promise<Response>;\n skip?: (c: Context) => boolean | Promise<boolean>;\n}\n\nexport interface RateLimitResult {\n allowed: boolean;\n remaining: number;\n limit: number;\n reset: number;\n retryAfter?: number;\n}\n\nfunction calculateTokens(\n state: TokenBucketState | null,\n capacity: number,\n rate: number,\n now: number\n): { tokens: number; lastRefillTime: number } {\n if (!state) {\n return { tokens: capacity, lastRefillTime: now };\n }\n\n const elapsed = (now - state.lastRefillTime) / 1000;\n const tokensToAdd = elapsed * rate;\n const newTokens = Math.min(capacity, state.tokens + tokensToAdd);\n\n return {\n tokens: newTokens,\n lastRefillTime: now,\n };\n}\n\nfunction calculateResetTime(currentTokens: number, capacity: number, rate: number): number {\n if (currentTokens >= capacity) return 0;\n return Math.ceil((capacity - currentTokens) / rate);\n}\n\nfunction calculateRetryAfter(currentTokens: number, requested: number, rate: number): number {\n if (currentTokens >= requested) return 0;\n return Math.ceil((requested - currentTokens) / rate);\n}\n\nexport async function checkRateLimit(\n kv: KV,\n identifier: string,\n options: {\n rate: number;\n capacity: number;\n requested?: number;\n keyPrefix?: string;\n expiresIn?: number;\n }\n): Promise<RateLimitResult> {\n const {\n rate,\n capacity,\n requested = 1,\n keyPrefix = 'rate-limit:',\n expiresIn = Math.max(3600, Math.ceil((capacity / rate) * 2)),\n } = options;\n\n const key = `${keyPrefix}${identifier}`;\n const now = Date.now();\n\n const stateStr = await kv.getItem(key);\n const state: TokenBucketState | null = stateStr ? JSON.parse(stateStr) : null;\n\n const { tokens: currentTokens, lastRefillTime } = calculateTokens(state, capacity, rate, now);\n\n const allowed = currentTokens >= requested;\n const newTokens = allowed ? currentTokens - requested : currentTokens;\n\n const newState: TokenBucketState = { tokens: newTokens, lastRefillTime };\n await kv.setItem(key, JSON.stringify(newState), expiresIn);\n\n const result: RateLimitResult = {\n allowed,\n remaining: Math.floor(Math.max(0, newTokens)),\n limit: capacity,\n reset: calculateResetTime(newTokens, capacity, rate),\n };\n\n if (!allowed) {\n result.retryAfter = calculateRetryAfter(currentTokens, requested, rate);\n }\n\n return result;\n}\n\nexport function rateLimit(options: RateLimitOptions): MiddlewareHandler {\n const {\n kv,\n rate,\n capacity,\n requested = 1,\n keyPrefix = 'rate-limit:',\n expiresIn = Math.max(3600, Math.ceil((capacity / rate) * 2)),\n getIdentifier,\n onRateLimited,\n skip,\n } = options;\n\n return async (c, next) => {\n if (skip && (await skip(c))) {\n return next();\n }\n\n const identifier = getIdentifier ? getIdentifier(c) : geolocation(c).ip_address;\n if (!identifier) return next();\n\n const result = await checkRateLimit(kv, identifier, {\n rate,\n capacity,\n requested,\n keyPrefix,\n expiresIn,\n });\n\n c.header('X-RateLimit-Limit', String(result.limit));\n c.header('X-RateLimit-Remaining', String(result.remaining));\n c.header('X-RateLimit-Reset', String(result.reset));\n\n if (!result.allowed) {\n c.header('Retry-After', String(result.retryAfter ?? 1));\n if (onRateLimited) return onRateLimited(c, result.retryAfter ?? 1);\n\n const details = Details.new()\n .errorInfo({ reason: 'RATE_LIMIT_EXCEEDED' })\n .retryInfo({ retryDelay: result.retryAfter ?? 1 });\n\n const message = 'Rate limit exceeded. Please try again later.';\n return Status.resourceExhausted(message).response(details);\n }\n\n return next();\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Context, MiddlewareHandler } from 'hono';
|
|
2
|
+
|
|
3
|
+
interface KV {
|
|
4
|
+
setItem(key: string, value: string, expiresIn?: number): Promise<void>;
|
|
5
|
+
getItem(key: string): Promise<string | null>;
|
|
6
|
+
removeItem(key: string): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
interface RateLimitOptions {
|
|
9
|
+
kv: KV;
|
|
10
|
+
rate: number;
|
|
11
|
+
capacity: number;
|
|
12
|
+
requested?: number;
|
|
13
|
+
keyPrefix?: string;
|
|
14
|
+
expiresIn?: number;
|
|
15
|
+
getIdentifier?: (c: Context) => string | undefined;
|
|
16
|
+
onRateLimited?: (c: Context, retryAfter: number) => Response | Promise<Response>;
|
|
17
|
+
skip?: (c: Context) => boolean | Promise<boolean>;
|
|
18
|
+
}
|
|
19
|
+
interface RateLimitResult {
|
|
20
|
+
allowed: boolean;
|
|
21
|
+
remaining: number;
|
|
22
|
+
limit: number;
|
|
23
|
+
reset: number;
|
|
24
|
+
retryAfter?: number;
|
|
25
|
+
}
|
|
26
|
+
declare function checkRateLimit(kv: KV, identifier: string, options: {
|
|
27
|
+
rate: number;
|
|
28
|
+
capacity: number;
|
|
29
|
+
requested?: number;
|
|
30
|
+
keyPrefix?: string;
|
|
31
|
+
expiresIn?: number;
|
|
32
|
+
}): Promise<RateLimitResult>;
|
|
33
|
+
declare function rateLimit(options: RateLimitOptions): MiddlewareHandler;
|
|
34
|
+
|
|
35
|
+
export { type KV, type RateLimitOptions, type RateLimitResult, checkRateLimit, rateLimit };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Context, MiddlewareHandler } from 'hono';
|
|
2
|
+
|
|
3
|
+
interface KV {
|
|
4
|
+
setItem(key: string, value: string, expiresIn?: number): Promise<void>;
|
|
5
|
+
getItem(key: string): Promise<string | null>;
|
|
6
|
+
removeItem(key: string): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
interface RateLimitOptions {
|
|
9
|
+
kv: KV;
|
|
10
|
+
rate: number;
|
|
11
|
+
capacity: number;
|
|
12
|
+
requested?: number;
|
|
13
|
+
keyPrefix?: string;
|
|
14
|
+
expiresIn?: number;
|
|
15
|
+
getIdentifier?: (c: Context) => string | undefined;
|
|
16
|
+
onRateLimited?: (c: Context, retryAfter: number) => Response | Promise<Response>;
|
|
17
|
+
skip?: (c: Context) => boolean | Promise<boolean>;
|
|
18
|
+
}
|
|
19
|
+
interface RateLimitResult {
|
|
20
|
+
allowed: boolean;
|
|
21
|
+
remaining: number;
|
|
22
|
+
limit: number;
|
|
23
|
+
reset: number;
|
|
24
|
+
retryAfter?: number;
|
|
25
|
+
}
|
|
26
|
+
declare function checkRateLimit(kv: KV, identifier: string, options: {
|
|
27
|
+
rate: number;
|
|
28
|
+
capacity: number;
|
|
29
|
+
requested?: number;
|
|
30
|
+
keyPrefix?: string;
|
|
31
|
+
expiresIn?: number;
|
|
32
|
+
}): Promise<RateLimitResult>;
|
|
33
|
+
declare function rateLimit(options: RateLimitOptions): MiddlewareHandler;
|
|
34
|
+
|
|
35
|
+
export { type KV, type RateLimitOptions, type RateLimitResult, checkRateLimit, rateLimit };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// src/hono/rate-limit.ts
|
|
2
|
+
import { Details } from "../error/detail.mjs";
|
|
3
|
+
import { Status } from "../error/status.mjs";
|
|
4
|
+
import { geolocation } from "./geolocation.mjs";
|
|
5
|
+
function calculateTokens(state, capacity, rate, now) {
|
|
6
|
+
if (!state) {
|
|
7
|
+
return { tokens: capacity, lastRefillTime: now };
|
|
8
|
+
}
|
|
9
|
+
const elapsed = (now - state.lastRefillTime) / 1e3;
|
|
10
|
+
const tokensToAdd = elapsed * rate;
|
|
11
|
+
const newTokens = Math.min(capacity, state.tokens + tokensToAdd);
|
|
12
|
+
return {
|
|
13
|
+
tokens: newTokens,
|
|
14
|
+
lastRefillTime: now
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function calculateResetTime(currentTokens, capacity, rate) {
|
|
18
|
+
if (currentTokens >= capacity) return 0;
|
|
19
|
+
return Math.ceil((capacity - currentTokens) / rate);
|
|
20
|
+
}
|
|
21
|
+
function calculateRetryAfter(currentTokens, requested, rate) {
|
|
22
|
+
if (currentTokens >= requested) return 0;
|
|
23
|
+
return Math.ceil((requested - currentTokens) / rate);
|
|
24
|
+
}
|
|
25
|
+
async function checkRateLimit(kv, identifier, options) {
|
|
26
|
+
const {
|
|
27
|
+
rate,
|
|
28
|
+
capacity,
|
|
29
|
+
requested = 1,
|
|
30
|
+
keyPrefix = "rate-limit:",
|
|
31
|
+
expiresIn = Math.max(3600, Math.ceil(capacity / rate * 2))
|
|
32
|
+
} = options;
|
|
33
|
+
const key = `${keyPrefix}${identifier}`;
|
|
34
|
+
const now = Date.now();
|
|
35
|
+
const stateStr = await kv.getItem(key);
|
|
36
|
+
const state = stateStr ? JSON.parse(stateStr) : null;
|
|
37
|
+
const { tokens: currentTokens, lastRefillTime } = calculateTokens(state, capacity, rate, now);
|
|
38
|
+
const allowed = currentTokens >= requested;
|
|
39
|
+
const newTokens = allowed ? currentTokens - requested : currentTokens;
|
|
40
|
+
const newState = { tokens: newTokens, lastRefillTime };
|
|
41
|
+
await kv.setItem(key, JSON.stringify(newState), expiresIn);
|
|
42
|
+
const result = {
|
|
43
|
+
allowed,
|
|
44
|
+
remaining: Math.floor(Math.max(0, newTokens)),
|
|
45
|
+
limit: capacity,
|
|
46
|
+
reset: calculateResetTime(newTokens, capacity, rate)
|
|
47
|
+
};
|
|
48
|
+
if (!allowed) {
|
|
49
|
+
result.retryAfter = calculateRetryAfter(currentTokens, requested, rate);
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
function rateLimit(options) {
|
|
54
|
+
const {
|
|
55
|
+
kv,
|
|
56
|
+
rate,
|
|
57
|
+
capacity,
|
|
58
|
+
requested = 1,
|
|
59
|
+
keyPrefix = "rate-limit:",
|
|
60
|
+
expiresIn = Math.max(3600, Math.ceil(capacity / rate * 2)),
|
|
61
|
+
getIdentifier,
|
|
62
|
+
onRateLimited,
|
|
63
|
+
skip
|
|
64
|
+
} = options;
|
|
65
|
+
return async (c, next) => {
|
|
66
|
+
if (skip && await skip(c)) {
|
|
67
|
+
return next();
|
|
68
|
+
}
|
|
69
|
+
const identifier = getIdentifier ? getIdentifier(c) : geolocation(c).ip_address;
|
|
70
|
+
if (!identifier) return next();
|
|
71
|
+
const result = await checkRateLimit(kv, identifier, {
|
|
72
|
+
rate,
|
|
73
|
+
capacity,
|
|
74
|
+
requested,
|
|
75
|
+
keyPrefix,
|
|
76
|
+
expiresIn
|
|
77
|
+
});
|
|
78
|
+
c.header("X-RateLimit-Limit", String(result.limit));
|
|
79
|
+
c.header("X-RateLimit-Remaining", String(result.remaining));
|
|
80
|
+
c.header("X-RateLimit-Reset", String(result.reset));
|
|
81
|
+
if (!result.allowed) {
|
|
82
|
+
c.header("Retry-After", String(result.retryAfter ?? 1));
|
|
83
|
+
if (onRateLimited) return onRateLimited(c, result.retryAfter ?? 1);
|
|
84
|
+
const details = Details.new().errorInfo({ reason: "RATE_LIMIT_EXCEEDED" }).retryInfo({ retryDelay: result.retryAfter ?? 1 });
|
|
85
|
+
const message = "Rate limit exceeded. Please try again later.";
|
|
86
|
+
return Status.resourceExhausted(message).response(details);
|
|
87
|
+
}
|
|
88
|
+
return next();
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
export {
|
|
92
|
+
checkRateLimit,
|
|
93
|
+
rateLimit
|
|
94
|
+
};
|
|
95
|
+
//# sourceMappingURL=rate-limit.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hono/rate-limit.ts"],"sourcesContent":["import type { Context, MiddlewareHandler } from 'hono';\nimport { Details } from '../error/detail';\nimport { Status } from '../error/status';\nimport { geolocation } from './geolocation';\n\nexport interface KV {\n setItem(key: string, value: string, expiresIn?: number): Promise<void>;\n getItem(key: string): Promise<string | null>;\n removeItem(key: string): Promise<void>;\n}\n\ninterface TokenBucketState {\n tokens: number;\n lastRefillTime: number;\n}\n\nexport interface RateLimitOptions {\n kv: KV;\n rate: number;\n capacity: number;\n requested?: number;\n keyPrefix?: string;\n expiresIn?: number;\n getIdentifier?: (c: Context) => string | undefined;\n onRateLimited?: (c: Context, retryAfter: number) => Response | Promise<Response>;\n skip?: (c: Context) => boolean | Promise<boolean>;\n}\n\nexport interface RateLimitResult {\n allowed: boolean;\n remaining: number;\n limit: number;\n reset: number;\n retryAfter?: number;\n}\n\nfunction calculateTokens(\n state: TokenBucketState | null,\n capacity: number,\n rate: number,\n now: number\n): { tokens: number; lastRefillTime: number } {\n if (!state) {\n return { tokens: capacity, lastRefillTime: now };\n }\n\n const elapsed = (now - state.lastRefillTime) / 1000;\n const tokensToAdd = elapsed * rate;\n const newTokens = Math.min(capacity, state.tokens + tokensToAdd);\n\n return {\n tokens: newTokens,\n lastRefillTime: now,\n };\n}\n\nfunction calculateResetTime(currentTokens: number, capacity: number, rate: number): number {\n if (currentTokens >= capacity) return 0;\n return Math.ceil((capacity - currentTokens) / rate);\n}\n\nfunction calculateRetryAfter(currentTokens: number, requested: number, rate: number): number {\n if (currentTokens >= requested) return 0;\n return Math.ceil((requested - currentTokens) / rate);\n}\n\nexport async function checkRateLimit(\n kv: KV,\n identifier: string,\n options: {\n rate: number;\n capacity: number;\n requested?: number;\n keyPrefix?: string;\n expiresIn?: number;\n }\n): Promise<RateLimitResult> {\n const {\n rate,\n capacity,\n requested = 1,\n keyPrefix = 'rate-limit:',\n expiresIn = Math.max(3600, Math.ceil((capacity / rate) * 2)),\n } = options;\n\n const key = `${keyPrefix}${identifier}`;\n const now = Date.now();\n\n const stateStr = await kv.getItem(key);\n const state: TokenBucketState | null = stateStr ? JSON.parse(stateStr) : null;\n\n const { tokens: currentTokens, lastRefillTime } = calculateTokens(state, capacity, rate, now);\n\n const allowed = currentTokens >= requested;\n const newTokens = allowed ? currentTokens - requested : currentTokens;\n\n const newState: TokenBucketState = { tokens: newTokens, lastRefillTime };\n await kv.setItem(key, JSON.stringify(newState), expiresIn);\n\n const result: RateLimitResult = {\n allowed,\n remaining: Math.floor(Math.max(0, newTokens)),\n limit: capacity,\n reset: calculateResetTime(newTokens, capacity, rate),\n };\n\n if (!allowed) {\n result.retryAfter = calculateRetryAfter(currentTokens, requested, rate);\n }\n\n return result;\n}\n\nexport function rateLimit(options: RateLimitOptions): MiddlewareHandler {\n const {\n kv,\n rate,\n capacity,\n requested = 1,\n keyPrefix = 'rate-limit:',\n expiresIn = Math.max(3600, Math.ceil((capacity / rate) * 2)),\n getIdentifier,\n onRateLimited,\n skip,\n } = options;\n\n return async (c, next) => {\n if (skip && (await skip(c))) {\n return next();\n }\n\n const identifier = getIdentifier ? getIdentifier(c) : geolocation(c).ip_address;\n if (!identifier) return next();\n\n const result = await checkRateLimit(kv, identifier, {\n rate,\n capacity,\n requested,\n keyPrefix,\n expiresIn,\n });\n\n c.header('X-RateLimit-Limit', String(result.limit));\n c.header('X-RateLimit-Remaining', String(result.remaining));\n c.header('X-RateLimit-Reset', String(result.reset));\n\n if (!result.allowed) {\n c.header('Retry-After', String(result.retryAfter ?? 1));\n if (onRateLimited) return onRateLimited(c, result.retryAfter ?? 1);\n\n const details = Details.new()\n .errorInfo({ reason: 'RATE_LIMIT_EXCEEDED' })\n .retryInfo({ retryDelay: result.retryAfter ?? 1 });\n\n const message = 'Rate limit exceeded. Please try again later.';\n return Status.resourceExhausted(message).response(details);\n }\n\n return next();\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -35,9 +35,11 @@ __export(index_exports, {
|
|
|
35
35
|
DetailType: () => import_detail.DetailType,
|
|
36
36
|
Details: () => import_detail.Details,
|
|
37
37
|
ISO_3601_1: () => import_iso_3601_1.ISO_3601_1,
|
|
38
|
+
Items: () => import_response.Items,
|
|
38
39
|
LoginCanceledError: () => import_error.LoginCanceledError,
|
|
39
40
|
LoginTimeoutError: () => import_error.LoginTimeoutError,
|
|
40
41
|
MAX_LENGTH: () => MAX_LENGTH,
|
|
42
|
+
Pages: () => import_response.Pages,
|
|
41
43
|
PurchaseError: () => import_error.PurchaseError,
|
|
42
44
|
Status: () => import_status.Status,
|
|
43
45
|
StatusError: () => import_status.StatusError,
|
|
@@ -48,9 +50,7 @@ __export(index_exports, {
|
|
|
48
50
|
getNextPageParam: () => import_response.getNextPageParam,
|
|
49
51
|
getPreviousPageParam: () => import_response.getPreviousPageParam,
|
|
50
52
|
initialPageParam: () => import_response.initialPageParam,
|
|
51
|
-
items: () => import_response.items,
|
|
52
53
|
pageParamsSchema: () => import_response.pageParamsSchema,
|
|
53
|
-
pages: () => import_response.pages,
|
|
54
54
|
timing: () => import_timing.timing,
|
|
55
55
|
uid: () => import_snowflake.uid
|
|
56
56
|
});
|
|
@@ -71,9 +71,11 @@ var import_iso_3601_1 = require("./iso/iso_3601_1.cjs");
|
|
|
71
71
|
DetailType,
|
|
72
72
|
Details,
|
|
73
73
|
ISO_3601_1,
|
|
74
|
+
Items,
|
|
74
75
|
LoginCanceledError,
|
|
75
76
|
LoginTimeoutError,
|
|
76
77
|
MAX_LENGTH,
|
|
78
|
+
Pages,
|
|
77
79
|
PurchaseError,
|
|
78
80
|
Status,
|
|
79
81
|
StatusError,
|
|
@@ -84,9 +86,7 @@ var import_iso_3601_1 = require("./iso/iso_3601_1.cjs");
|
|
|
84
86
|
getNextPageParam,
|
|
85
87
|
getPreviousPageParam,
|
|
86
88
|
initialPageParam,
|
|
87
|
-
items,
|
|
88
89
|
pageParamsSchema,
|
|
89
|
-
pages,
|
|
90
90
|
timing,
|
|
91
91
|
uid
|
|
92
92
|
});
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @example\n * import { Details, Status } from '@repo/error';\n *\n * Status.adapter = () => new Error('Error');\n *\n * const details = Details.new()\n * .requestInfo({ requestId: '1234567890', servingData: '/v1/tests' })\n * .errorInfo({ reason: 'ACCOUNT_LOCKED' });\n *\n * throw Status.alreadyExists('xxx').error(details);\n */\n\nexport {\n LoginTimeoutError,\n LoginCanceledError,\n CheckoutCreateError,\n PurchaseError,\n} from './error/index';\nexport type {\n NetworkErrorReason,\n StatusErrorReason,\n AuthenticationErrorReason,\n ModerationErrorReason,\n MultipartErrorReason,\n AppErrorReason,\n ErrorReason,\n} from './error/reason';\nexport {\n DetailType,\n Details,\n type ErrorInfo,\n type RetryInfo,\n type DebugInfo,\n type QuotaFailure,\n type PreconditionFailure,\n type BadRequest,\n type RequestInfo,\n type ResourceInfo,\n type Help,\n type LocalizedMessage,\n type Detail,\n} from './error/detail';\nexport { Status, StatusError, type ErrorBody } from './error/status';\nexport { getErrorReason, getErrorMessage, getFieldViolations } from './error/parse';\nexport {\n
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @example\n * import { Details, Status } from '@repo/error';\n *\n * Status.adapter = () => new Error('Error');\n *\n * const details = Details.new()\n * .requestInfo({ requestId: '1234567890', servingData: '/v1/tests' })\n * .errorInfo({ reason: 'ACCOUNT_LOCKED' });\n *\n * throw Status.alreadyExists('xxx').error(details);\n */\n\nexport {\n LoginTimeoutError,\n LoginCanceledError,\n CheckoutCreateError,\n PurchaseError,\n} from './error/index';\nexport type {\n NetworkErrorReason,\n StatusErrorReason,\n AuthenticationErrorReason,\n ModerationErrorReason,\n MultipartErrorReason,\n AppErrorReason,\n ErrorReason,\n} from './error/reason';\nexport {\n DetailType,\n Details,\n type ErrorInfo,\n type RetryInfo,\n type DebugInfo,\n type QuotaFailure,\n type PreconditionFailure,\n type BadRequest,\n type RequestInfo,\n type ResourceInfo,\n type Help,\n type LocalizedMessage,\n type Detail,\n} from './error/detail';\nexport { Status, StatusError, type ErrorBody } from './error/status';\nexport { getErrorReason, getErrorMessage, getFieldViolations } from './error/parse';\nexport {\n Items,\n Pages,\n Cursor,\n pageParamsSchema,\n initialPageParam,\n getPreviousPageParam,\n getNextPageParam,\n} from './response';\nexport type {\n Empty,\n EntityId,\n Entity,\n Response,\n InitParams,\n NextParams,\n PrevParams,\n PageParams,\n ParentPageParams,\n Page,\n InfinitePageData,\n} from './response';\n\nexport { UidGenerator, uid } from './snowflake';\n\nexport * as MAX_LENGTH from './max-length/index';\nexport { timing } from './utils/timing';\nexport { ISO_3601_1, type ISO3166CountryCode } from './iso/iso_3601_1';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA,mBAKO;AAUP,oBAcO;AACP,oBAAoD;AACpD,mBAAoE;AACpE,sBAQO;AAeP,uBAAkC;AAElC,iBAA4B;AAC5B,oBAAuB;AACvB,wBAAoD;","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -3,7 +3,7 @@ export { AppErrorReason, AuthenticationErrorReason, ErrorReason, ModerationError
|
|
|
3
3
|
export { BadRequest, DebugInfo, Detail, DetailType, Details, ErrorInfo, Help, LocalizedMessage, PreconditionFailure, QuotaFailure, RequestInfo, ResourceInfo, RetryInfo } from './error/detail.cjs';
|
|
4
4
|
export { ErrorBody, Status, StatusError } from './error/status.cjs';
|
|
5
5
|
export { getErrorMessage, getErrorReason, getFieldViolations } from './error/parse.cjs';
|
|
6
|
-
export { Cursor, Empty, Entity, EntityId, InfinitePageData, InitParams, NextParams, Page, PageParams, ParentPageParams, PrevParams, Response, getNextPageParam, getPreviousPageParam, initialPageParam,
|
|
6
|
+
export { Cursor, Empty, Entity, EntityId, InfinitePageData, InitParams, Items, NextParams, Page, PageParams, Pages, ParentPageParams, PrevParams, Response, getNextPageParam, getPreviousPageParam, initialPageParam, pageParamsSchema } from './response.cjs';
|
|
7
7
|
export { UidGenerator, uid } from './snowflake.cjs';
|
|
8
8
|
export { i as MAX_LENGTH } from './index-BnPgRQDl.cjs';
|
|
9
9
|
export { timing } from './utils/timing.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export { AppErrorReason, AuthenticationErrorReason, ErrorReason, ModerationError
|
|
|
3
3
|
export { BadRequest, DebugInfo, Detail, DetailType, Details, ErrorInfo, Help, LocalizedMessage, PreconditionFailure, QuotaFailure, RequestInfo, ResourceInfo, RetryInfo } from './error/detail.js';
|
|
4
4
|
export { ErrorBody, Status, StatusError } from './error/status.js';
|
|
5
5
|
export { getErrorMessage, getErrorReason, getFieldViolations } from './error/parse.js';
|
|
6
|
-
export { Cursor, Empty, Entity, EntityId, InfinitePageData, InitParams, NextParams, Page, PageParams, ParentPageParams, PrevParams, Response, getNextPageParam, getPreviousPageParam, initialPageParam,
|
|
6
|
+
export { Cursor, Empty, Entity, EntityId, InfinitePageData, InitParams, Items, NextParams, Page, PageParams, Pages, ParentPageParams, PrevParams, Response, getNextPageParam, getPreviousPageParam, initialPageParam, pageParamsSchema } from './response.js';
|
|
7
7
|
export { UidGenerator, uid } from './snowflake.js';
|
|
8
8
|
export { i as MAX_LENGTH } from './index-BnPgRQDl.js';
|
|
9
9
|
export { timing } from './utils/timing.js';
|
package/dist/index.mjs
CHANGED
|
@@ -12,8 +12,8 @@ import {
|
|
|
12
12
|
import { Status, StatusError } from "./error/status.mjs";
|
|
13
13
|
import { getErrorReason, getErrorMessage, getFieldViolations } from "./error/parse.mjs";
|
|
14
14
|
import {
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
Items,
|
|
16
|
+
Pages,
|
|
17
17
|
Cursor,
|
|
18
18
|
pageParamsSchema,
|
|
19
19
|
initialPageParam,
|
|
@@ -30,9 +30,11 @@ export {
|
|
|
30
30
|
DetailType,
|
|
31
31
|
Details,
|
|
32
32
|
ISO_3601_1,
|
|
33
|
+
Items,
|
|
33
34
|
LoginCanceledError,
|
|
34
35
|
LoginTimeoutError,
|
|
35
36
|
MAX_LENGTH,
|
|
37
|
+
Pages,
|
|
36
38
|
PurchaseError,
|
|
37
39
|
Status,
|
|
38
40
|
StatusError,
|
|
@@ -43,9 +45,7 @@ export {
|
|
|
43
45
|
getNextPageParam,
|
|
44
46
|
getPreviousPageParam,
|
|
45
47
|
initialPageParam,
|
|
46
|
-
items,
|
|
47
48
|
pageParamsSchema,
|
|
48
|
-
pages,
|
|
49
49
|
timing,
|
|
50
50
|
uid
|
|
51
51
|
};
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @example\n * import { Details, Status } from '@repo/error';\n *\n * Status.adapter = () => new Error('Error');\n *\n * const details = Details.new()\n * .requestInfo({ requestId: '1234567890', servingData: '/v1/tests' })\n * .errorInfo({ reason: 'ACCOUNT_LOCKED' });\n *\n * throw Status.alreadyExists('xxx').error(details);\n */\n\nexport {\n LoginTimeoutError,\n LoginCanceledError,\n CheckoutCreateError,\n PurchaseError,\n} from './error/index';\nexport type {\n NetworkErrorReason,\n StatusErrorReason,\n AuthenticationErrorReason,\n ModerationErrorReason,\n MultipartErrorReason,\n AppErrorReason,\n ErrorReason,\n} from './error/reason';\nexport {\n DetailType,\n Details,\n type ErrorInfo,\n type RetryInfo,\n type DebugInfo,\n type QuotaFailure,\n type PreconditionFailure,\n type BadRequest,\n type RequestInfo,\n type ResourceInfo,\n type Help,\n type LocalizedMessage,\n type Detail,\n} from './error/detail';\nexport { Status, StatusError, type ErrorBody } from './error/status';\nexport { getErrorReason, getErrorMessage, getFieldViolations } from './error/parse';\nexport {\n
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @example\n * import { Details, Status } from '@repo/error';\n *\n * Status.adapter = () => new Error('Error');\n *\n * const details = Details.new()\n * .requestInfo({ requestId: '1234567890', servingData: '/v1/tests' })\n * .errorInfo({ reason: 'ACCOUNT_LOCKED' });\n *\n * throw Status.alreadyExists('xxx').error(details);\n */\n\nexport {\n LoginTimeoutError,\n LoginCanceledError,\n CheckoutCreateError,\n PurchaseError,\n} from './error/index';\nexport type {\n NetworkErrorReason,\n StatusErrorReason,\n AuthenticationErrorReason,\n ModerationErrorReason,\n MultipartErrorReason,\n AppErrorReason,\n ErrorReason,\n} from './error/reason';\nexport {\n DetailType,\n Details,\n type ErrorInfo,\n type RetryInfo,\n type DebugInfo,\n type QuotaFailure,\n type PreconditionFailure,\n type BadRequest,\n type RequestInfo,\n type ResourceInfo,\n type Help,\n type LocalizedMessage,\n type Detail,\n} from './error/detail';\nexport { Status, StatusError, type ErrorBody } from './error/status';\nexport { getErrorReason, getErrorMessage, getFieldViolations } from './error/parse';\nexport {\n Items,\n Pages,\n Cursor,\n pageParamsSchema,\n initialPageParam,\n getPreviousPageParam,\n getNextPageParam,\n} from './response';\nexport type {\n Empty,\n EntityId,\n Entity,\n Response,\n InitParams,\n NextParams,\n PrevParams,\n PageParams,\n ParentPageParams,\n Page,\n InfinitePageData,\n} from './response';\n\nexport { UidGenerator, uid } from './snowflake';\n\nexport * as MAX_LENGTH from './max-length/index';\nexport { timing } from './utils/timing';\nexport { ISO_3601_1, type ISO3166CountryCode } from './iso/iso_3601_1';\n"],"mappings":";AAaA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAUP;AAAA,EACE;AAAA,EACA;AAAA,OAYK;AACP,SAAS,QAAQ,mBAAmC;AACpD,SAAS,gBAAgB,iBAAiB,0BAA0B;AACpE;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAeP,SAAS,cAAc,WAAW;AAElC,YAAY,gBAAgB;AAC5B,SAAS,cAAc;AACvB,SAAS,kBAA2C;","names":[]}
|
package/dist/response.cjs
CHANGED
|
@@ -21,12 +21,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var response_exports = {};
|
|
22
22
|
__export(response_exports, {
|
|
23
23
|
Cursor: () => Cursor,
|
|
24
|
+
Items: () => Items,
|
|
25
|
+
Pages: () => Pages,
|
|
24
26
|
getNextPageParam: () => getNextPageParam,
|
|
25
27
|
getPreviousPageParam: () => getPreviousPageParam,
|
|
26
28
|
initialPageParam: () => initialPageParam,
|
|
27
|
-
|
|
28
|
-
pageParamsSchema: () => pageParamsSchema,
|
|
29
|
-
pages: () => pages
|
|
29
|
+
pageParamsSchema: () => pageParamsSchema
|
|
30
30
|
});
|
|
31
31
|
module.exports = __toCommonJS(response_exports);
|
|
32
32
|
var import_utils = require("@shware/utils");
|
|
@@ -68,7 +68,7 @@ function getPreviousPageParam(first) {
|
|
|
68
68
|
function getNextPageParam(last) {
|
|
69
69
|
return (0, import_utils.hasText)(last.paging.next) ? { next: last.paging.next } : null;
|
|
70
70
|
}
|
|
71
|
-
var
|
|
71
|
+
var Pages = {
|
|
72
72
|
flatten(data) {
|
|
73
73
|
return data.pages.flatMap((page) => page.data);
|
|
74
74
|
},
|
|
@@ -96,10 +96,10 @@ var pages = {
|
|
|
96
96
|
append(item) {
|
|
97
97
|
return (data) => {
|
|
98
98
|
if (!data) return data;
|
|
99
|
-
const
|
|
100
|
-
const last =
|
|
99
|
+
const pages = data.pages;
|
|
100
|
+
const last = pages[pages.length - 1];
|
|
101
101
|
if (!last) return { ...data, pages: [{ data: [item], paging: {} }] };
|
|
102
|
-
return { ...data, pages: [...
|
|
102
|
+
return { ...data, pages: [...pages.slice(0, -1), { ...last, data: [...last.data, item] }] };
|
|
103
103
|
};
|
|
104
104
|
},
|
|
105
105
|
update(updater, predicate) {
|
|
@@ -133,7 +133,7 @@ var pages = {
|
|
|
133
133
|
return this.remove((item) => item.id === id);
|
|
134
134
|
}
|
|
135
135
|
};
|
|
136
|
-
var
|
|
136
|
+
var Items = {
|
|
137
137
|
push(newItems) {
|
|
138
138
|
return (data) => {
|
|
139
139
|
if (!data) return newItems;
|
|
@@ -208,11 +208,11 @@ var items = {
|
|
|
208
208
|
// Annotate the CommonJS export names for ESM import in node:
|
|
209
209
|
0 && (module.exports = {
|
|
210
210
|
Cursor,
|
|
211
|
+
Items,
|
|
212
|
+
Pages,
|
|
211
213
|
getNextPageParam,
|
|
212
214
|
getPreviousPageParam,
|
|
213
215
|
initialPageParam,
|
|
214
|
-
|
|
215
|
-
pageParamsSchema,
|
|
216
|
-
pages
|
|
216
|
+
pageParamsSchema
|
|
217
217
|
});
|
|
218
218
|
//# sourceMappingURL=response.cjs.map
|
package/dist/response.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/response.ts"],"sourcesContent":["import { hasText } from '@shware/utils';\nimport { _default, coerce, int, maximum, minimum, object, optional, string } from 'zod/mini';\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport type Empty = {};\nexport type EntityId = string | number;\nexport type Entity = { id: EntityId };\n\nexport type Response<T = never> = { data: T };\n\nexport type InitParams = { limit: number; parent?: string };\nexport type NextParams = { limit: number; parent?: string; next: string };\nexport type PrevParams = { limit: number; parent?: string; prev: string };\nexport type PageParams = { limit: number; prev?: string; next?: string };\nexport type ParentPageParams = { limit: number; parent: string; prev?: string; next?: string };\nexport type Page<T = never> = { data: T[]; paging: { next?: string; prev?: string } };\n\nexport function pageParamsSchema(max = 100, defaultLimit = 20) {\n return object({\n limit: _default(coerce.number().check(int(), minimum(1), maximum(max)), defaultLimit),\n prev: optional(string()),\n next: optional(string()),\n });\n}\n\nexport const Cursor = {\n of(\n prev: bigint | number | string | undefined,\n next: bigint | number | string | undefined\n ): Page['paging'] {\n return {\n prev: prev ? this.encode(prev) : undefined,\n next: next ? this.encode(next) : undefined,\n };\n },\n empty(): Page['paging'] {\n return { prev: undefined, next: undefined };\n },\n encode(id: bigint | number | string | undefined): string | undefined {\n if (!id) return undefined;\n return Buffer.from(id.toString(), 'utf-8').toString('base64');\n },\n decode<T extends 'bigint' | 'number' | 'string' = 'bigint'>(\n token: string,\n type: T = 'bigint' as T\n ): T extends 'bigint' ? bigint : T extends 'number' ? number : string {\n const value = Buffer.from(token, 'base64').toString('utf-8');\n if (type === 'bigint')\n return BigInt(value) as T extends 'bigint' ? bigint : T extends 'number' ? number : string;\n if (type === 'number')\n return Number(value) as T extends 'bigint' ? bigint : T extends 'number' ? number : string;\n return value as T extends 'bigint' ? bigint : T extends 'number' ? number : string;\n },\n};\n\nexport const initialPageParam: Page['paging'] = {};\n\nexport function getPreviousPageParam<T = never>(first: Page<T>): Page['paging'] | null {\n return hasText(first.paging.prev) ? { prev: first.paging.prev } : null;\n}\n\nexport function getNextPageParam<T = never>(last: Page<T>): Page['paging'] | null {\n return hasText(last.paging.next) ? { next: last.paging.next } : null;\n}\n\nexport type InfinitePageData<T> = {\n pages: Array<Page<T>>;\n pageParams: Array<Page['paging']>;\n};\n\nexport const pages = {\n flatten<T>(data: InfinitePageData<T>): T[] {\n return data.pages.flatMap((page) => page.data);\n },\n dedupe<T extends Entity>(data: InfinitePageData<T>): T[] {\n const seen = new Set<EntityId>();\n const result: T[] = [];\n for (const page of data.pages) {\n for (const item of page.data) {\n if (!seen.has(item.id)) {\n seen.add(item.id);\n result.push(item);\n }\n }\n }\n return result;\n },\n prepend<T>(item: T) {\n return (data: InfinitePageData<T> | undefined): InfinitePageData<T> | undefined => {\n if (!data) return data;\n const [first, ...rest] = data.pages;\n if (!first) return { ...data, pages: [{ data: [item], paging: {} }] };\n return { ...data, pages: [{ ...first, data: [item, ...first.data] }, ...rest] };\n };\n },\n append<T>(item: T) {\n return (data: InfinitePageData<T> | undefined): InfinitePageData<T> | undefined => {\n if (!data) return data;\n const pages = data.pages;\n const last = pages[pages.length - 1];\n if (!last) return { ...data, pages: [{ data: [item], paging: {} }] };\n return { ...data, pages: [...pages.slice(0, -1), { ...last, data: [...last.data, item] }] };\n };\n },\n update<T>(updater: T, predicate: (item: T) => boolean) {\n return (data: InfinitePageData<T> | undefined): InfinitePageData<T> | undefined => {\n if (!data) return data;\n return {\n ...data,\n pages: data.pages.map((page) => ({\n ...page,\n data: page.data.map((item) => (predicate(item) ? updater : item)),\n })),\n };\n };\n },\n updateById<T extends Entity>(updated: T) {\n return this.update<T>(updated, (item) => item.id === updated.id);\n },\n remove<T>(predicate: (item: T) => boolean) {\n return (data: InfinitePageData<T> | undefined): InfinitePageData<T> | undefined => {\n if (!data) return data;\n return {\n ...data,\n pages: data.pages.map((page) => ({\n ...page,\n data: page.data.filter((item) => !predicate(item)),\n })),\n };\n };\n },\n removeById<T extends Entity>(id: EntityId) {\n return this.remove<T>((item) => item.id === id);\n },\n};\n\nexport const items = {\n push<T>(newItems: T[]) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return newItems;\n return [...data, ...newItems];\n };\n },\n unshift<T>(newItems: T[]) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return newItems;\n return [...newItems, ...data];\n };\n },\n pushAndDedupe<T extends Entity>(newItems: T[]) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return newItems;\n const seen = new Set<EntityId>();\n const result: T[] = [];\n for (const item of data) {\n if (!seen.has(item.id)) {\n seen.add(item.id);\n result.push(item);\n }\n }\n for (const item of newItems) {\n if (!seen.has(item.id)) {\n seen.add(item.id);\n result.push(item);\n }\n }\n return result;\n };\n },\n unshiftAndDedupe<T extends Entity>(newItems: T[]) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return newItems;\n const seen = new Set<EntityId>();\n const result: T[] = [];\n for (const item of newItems) {\n if (!seen.has(item.id)) {\n seen.add(item.id);\n result.push(item);\n }\n }\n for (const item of data) {\n if (!seen.has(item.id)) {\n seen.add(item.id);\n result.push(item);\n }\n }\n return result;\n };\n },\n update<T>(updater: T, predicate: (item: T) => boolean) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return data;\n return data.map((item) => (predicate(item) ? updater : item));\n };\n },\n updateById<T extends Entity>(updated: T) {\n return this.update<T>(updated, (item) => item.id === updated.id);\n },\n remove<T>(predicate: (item: T) => boolean) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return data;\n return data.filter((item) => !predicate(item));\n };\n },\n removeById<T extends Entity>(id: EntityId) {\n return this.remove<T>((item) => item.id === id);\n },\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAwB;AACxB,kBAAkF;AAgB3E,SAAS,iBAAiB,MAAM,KAAK,eAAe,IAAI;AAC7D,aAAO,oBAAO;AAAA,IACZ,WAAO,sBAAS,mBAAO,OAAO,EAAE,UAAM,iBAAI,OAAG,qBAAQ,CAAC,OAAG,qBAAQ,GAAG,CAAC,GAAG,YAAY;AAAA,IACpF,UAAM,0BAAS,oBAAO,CAAC;AAAA,IACvB,UAAM,0BAAS,oBAAO,CAAC;AAAA,EACzB,CAAC;AACH;AAEO,IAAM,SAAS;AAAA,EACpB,GACE,MACA,MACgB;AAChB,WAAO;AAAA,MACL,MAAM,OAAO,KAAK,OAAO,IAAI,IAAI;AAAA,MACjC,MAAM,OAAO,KAAK,OAAO,IAAI,IAAI;AAAA,IACnC;AAAA,EACF;AAAA,EACA,QAAwB;AACtB,WAAO,EAAE,MAAM,QAAW,MAAM,OAAU;AAAA,EAC5C;AAAA,EACA,OAAO,IAA8D;AACnE,QAAI,CAAC,GAAI,QAAO;AAChB,WAAO,OAAO,KAAK,GAAG,SAAS,GAAG,OAAO,EAAE,SAAS,QAAQ;AAAA,EAC9D;AAAA,EACA,OACE,OACA,OAAU,UAC0D;AACpE,UAAM,QAAQ,OAAO,KAAK,OAAO,QAAQ,EAAE,SAAS,OAAO;AAC3D,QAAI,SAAS;AACX,aAAO,OAAO,KAAK;AACrB,QAAI,SAAS;AACX,aAAO,OAAO,KAAK;AACrB,WAAO;AAAA,EACT;AACF;AAEO,IAAM,mBAAmC,CAAC;AAE1C,SAAS,qBAAgC,OAAuC;AACrF,aAAO,sBAAQ,MAAM,OAAO,IAAI,IAAI,EAAE,MAAM,MAAM,OAAO,KAAK,IAAI;AACpE;AAEO,SAAS,iBAA4B,MAAsC;AAChF,aAAO,sBAAQ,KAAK,OAAO,IAAI,IAAI,EAAE,MAAM,KAAK,OAAO,KAAK,IAAI;AAClE;AAOO,IAAM,QAAQ;AAAA,EACnB,QAAW,MAAgC;AACzC,WAAO,KAAK,MAAM,QAAQ,CAAC,SAAS,KAAK,IAAI;AAAA,EAC/C;AAAA,EACA,OAAyB,MAAgC;AACvD,UAAM,OAAO,oBAAI,IAAc;AAC/B,UAAM,SAAc,CAAC;AACrB,eAAW,QAAQ,KAAK,OAAO;AAC7B,iBAAW,QAAQ,KAAK,MAAM;AAC5B,YAAI,CAAC,KAAK,IAAI,KAAK,EAAE,GAAG;AACtB,eAAK,IAAI,KAAK,EAAE;AAChB,iBAAO,KAAK,IAAI;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EACA,QAAW,MAAS;AAClB,WAAO,CAAC,SAA2E;AACjF,UAAI,CAAC,KAAM,QAAO;AAClB,YAAM,CAAC,OAAO,GAAG,IAAI,IAAI,KAAK;AAC9B,UAAI,CAAC,MAAO,QAAO,EAAE,GAAG,MAAM,OAAO,CAAC,EAAE,MAAM,CAAC,IAAI,GAAG,QAAQ,CAAC,EAAE,CAAC,EAAE;AACpE,aAAO,EAAE,GAAG,MAAM,OAAO,CAAC,EAAE,GAAG,OAAO,MAAM,CAAC,MAAM,GAAG,MAAM,IAAI,EAAE,GAAG,GAAG,IAAI,EAAE;AAAA,IAChF;AAAA,EACF;AAAA,EACA,OAAU,MAAS;AACjB,WAAO,CAAC,SAA2E;AACjF,UAAI,CAAC,KAAM,QAAO;AAClB,YAAMA,SAAQ,KAAK;AACnB,YAAM,OAAOA,OAAMA,OAAM,SAAS,CAAC;AACnC,UAAI,CAAC,KAAM,QAAO,EAAE,GAAG,MAAM,OAAO,CAAC,EAAE,MAAM,CAAC,IAAI,GAAG,QAAQ,CAAC,EAAE,CAAC,EAAE;AACnE,aAAO,EAAE,GAAG,MAAM,OAAO,CAAC,GAAGA,OAAM,MAAM,GAAG,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,GAAG,KAAK,MAAM,IAAI,EAAE,CAAC,EAAE;AAAA,IAC5F;AAAA,EACF;AAAA,EACA,OAAU,SAAY,WAAiC;AACrD,WAAO,CAAC,SAA2E;AACjF,UAAI,CAAC,KAAM,QAAO;AAClB,aAAO;AAAA,QACL,GAAG;AAAA,QACH,OAAO,KAAK,MAAM,IAAI,CAAC,UAAU;AAAA,UAC/B,GAAG;AAAA,UACH,MAAM,KAAK,KAAK,IAAI,CAAC,SAAU,UAAU,IAAI,IAAI,UAAU,IAAK;AAAA,QAClE,EAAE;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AAAA,EACA,WAA6B,SAAY;AACvC,WAAO,KAAK,OAAU,SAAS,CAAC,SAAS,KAAK,OAAO,QAAQ,EAAE;AAAA,EACjE;AAAA,EACA,OAAU,WAAiC;AACzC,WAAO,CAAC,SAA2E;AACjF,UAAI,CAAC,KAAM,QAAO;AAClB,aAAO;AAAA,QACL,GAAG;AAAA,QACH,OAAO,KAAK,MAAM,IAAI,CAAC,UAAU;AAAA,UAC/B,GAAG;AAAA,UACH,MAAM,KAAK,KAAK,OAAO,CAAC,SAAS,CAAC,UAAU,IAAI,CAAC;AAAA,QACnD,EAAE;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AAAA,EACA,WAA6B,IAAc;AACzC,WAAO,KAAK,OAAU,CAAC,SAAS,KAAK,OAAO,EAAE;AAAA,EAChD;AACF;AAEO,IAAM,QAAQ;AAAA,EACnB,KAAQ,UAAe;AACrB,WAAO,CAAC,SAA2C;AACjD,UAAI,CAAC,KAAM,QAAO;AAClB,aAAO,CAAC,GAAG,MAAM,GAAG,QAAQ;AAAA,IAC9B;AAAA,EACF;AAAA,EACA,QAAW,UAAe;AACxB,WAAO,CAAC,SAA2C;AACjD,UAAI,CAAC,KAAM,QAAO;AAClB,aAAO,CAAC,GAAG,UAAU,GAAG,IAAI;AAAA,IAC9B;AAAA,EACF;AAAA,EACA,cAAgC,UAAe;AAC7C,WAAO,CAAC,SAA2C;AACjD,UAAI,CAAC,KAAM,QAAO;AAClB,YAAM,OAAO,oBAAI,IAAc;AAC/B,YAAM,SAAc,CAAC;AACrB,iBAAW,QAAQ,MAAM;AACvB,YAAI,CAAC,KAAK,IAAI,KAAK,EAAE,GAAG;AACtB,eAAK,IAAI,KAAK,EAAE;AAChB,iBAAO,KAAK,IAAI;AAAA,QAClB;AAAA,MACF;AACA,iBAAW,QAAQ,UAAU;AAC3B,YAAI,CAAC,KAAK,IAAI,KAAK,EAAE,GAAG;AACtB,eAAK,IAAI,KAAK,EAAE;AAChB,iBAAO,KAAK,IAAI;AAAA,QAClB;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,iBAAmC,UAAe;AAChD,WAAO,CAAC,SAA2C;AACjD,UAAI,CAAC,KAAM,QAAO;AAClB,YAAM,OAAO,oBAAI,IAAc;AAC/B,YAAM,SAAc,CAAC;AACrB,iBAAW,QAAQ,UAAU;AAC3B,YAAI,CAAC,KAAK,IAAI,KAAK,EAAE,GAAG;AACtB,eAAK,IAAI,KAAK,EAAE;AAChB,iBAAO,KAAK,IAAI;AAAA,QAClB;AAAA,MACF;AACA,iBAAW,QAAQ,MAAM;AACvB,YAAI,CAAC,KAAK,IAAI,KAAK,EAAE,GAAG;AACtB,eAAK,IAAI,KAAK,EAAE;AAChB,iBAAO,KAAK,IAAI;AAAA,QAClB;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,OAAU,SAAY,WAAiC;AACrD,WAAO,CAAC,SAA2C;AACjD,UAAI,CAAC,KAAM,QAAO;AAClB,aAAO,KAAK,IAAI,CAAC,SAAU,UAAU,IAAI,IAAI,UAAU,IAAK;AAAA,IAC9D;AAAA,EACF;AAAA,EACA,WAA6B,SAAY;AACvC,WAAO,KAAK,OAAU,SAAS,CAAC,SAAS,KAAK,OAAO,QAAQ,EAAE;AAAA,EACjE;AAAA,EACA,OAAU,WAAiC;AACzC,WAAO,CAAC,SAA2C;AACjD,UAAI,CAAC,KAAM,QAAO;AAClB,aAAO,KAAK,OAAO,CAAC,SAAS,CAAC,UAAU,IAAI,CAAC;AAAA,IAC/C;AAAA,EACF;AAAA,EACA,WAA6B,IAAc;AACzC,WAAO,KAAK,OAAU,CAAC,SAAS,KAAK,OAAO,EAAE;AAAA,EAChD;AACF;","names":["pages"]}
|
|
1
|
+
{"version":3,"sources":["../src/response.ts"],"sourcesContent":["import { hasText } from '@shware/utils';\nimport { _default, coerce, int, maximum, minimum, object, optional, string } from 'zod/mini';\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport type Empty = {};\nexport type EntityId = string | number;\nexport type Entity = { id: EntityId };\n\nexport type Response<T = never> = { data: T };\n\nexport type InitParams = { limit: number; parent?: string };\nexport type NextParams = { limit: number; parent?: string; next: string };\nexport type PrevParams = { limit: number; parent?: string; prev: string };\nexport type PageParams = { limit: number; prev?: string; next?: string };\nexport type ParentPageParams = { limit: number; parent: string; prev?: string; next?: string };\nexport type Page<T = never> = { data: T[]; paging: { next?: string; prev?: string } };\n\nexport function pageParamsSchema(max = 100, defaultLimit = 20) {\n return object({\n limit: _default(coerce.number().check(int(), minimum(1), maximum(max)), defaultLimit),\n prev: optional(string()),\n next: optional(string()),\n });\n}\n\nexport const Cursor = {\n of(\n prev: bigint | number | string | undefined,\n next: bigint | number | string | undefined\n ): Page['paging'] {\n return {\n prev: prev ? this.encode(prev) : undefined,\n next: next ? this.encode(next) : undefined,\n };\n },\n empty(): Page['paging'] {\n return { prev: undefined, next: undefined };\n },\n encode(id: bigint | number | string | undefined): string | undefined {\n if (!id) return undefined;\n return Buffer.from(id.toString(), 'utf-8').toString('base64');\n },\n decode<T extends 'bigint' | 'number' | 'string' = 'bigint'>(\n token: string,\n type: T = 'bigint' as T\n ): T extends 'bigint' ? bigint : T extends 'number' ? number : string {\n const value = Buffer.from(token, 'base64').toString('utf-8');\n if (type === 'bigint')\n return BigInt(value) as T extends 'bigint' ? bigint : T extends 'number' ? number : string;\n if (type === 'number')\n return Number(value) as T extends 'bigint' ? bigint : T extends 'number' ? number : string;\n return value as T extends 'bigint' ? bigint : T extends 'number' ? number : string;\n },\n};\n\nexport const initialPageParam: Page['paging'] = {};\n\nexport function getPreviousPageParam<T = never>(first: Page<T>): Page['paging'] | null {\n return hasText(first.paging.prev) ? { prev: first.paging.prev } : null;\n}\n\nexport function getNextPageParam<T = never>(last: Page<T>): Page['paging'] | null {\n return hasText(last.paging.next) ? { next: last.paging.next } : null;\n}\n\nexport type InfinitePageData<T> = {\n pages: Array<Page<T>>;\n pageParams: Array<Page['paging']>;\n};\n\nexport const Pages = {\n flatten<T>(data: InfinitePageData<T>): T[] {\n return data.pages.flatMap((page) => page.data);\n },\n dedupe<T extends Entity>(data: InfinitePageData<T>): T[] {\n const seen = new Set<EntityId>();\n const result: T[] = [];\n for (const page of data.pages) {\n for (const item of page.data) {\n if (!seen.has(item.id)) {\n seen.add(item.id);\n result.push(item);\n }\n }\n }\n return result;\n },\n prepend<T>(item: T) {\n return (data: InfinitePageData<T> | undefined): InfinitePageData<T> | undefined => {\n if (!data) return data;\n const [first, ...rest] = data.pages;\n if (!first) return { ...data, pages: [{ data: [item], paging: {} }] };\n return { ...data, pages: [{ ...first, data: [item, ...first.data] }, ...rest] };\n };\n },\n append<T>(item: T) {\n return (data: InfinitePageData<T> | undefined): InfinitePageData<T> | undefined => {\n if (!data) return data;\n const pages = data.pages;\n const last = pages[pages.length - 1];\n if (!last) return { ...data, pages: [{ data: [item], paging: {} }] };\n return { ...data, pages: [...pages.slice(0, -1), { ...last, data: [...last.data, item] }] };\n };\n },\n update<T>(updater: T, predicate: (item: T) => boolean) {\n return (data: InfinitePageData<T> | undefined): InfinitePageData<T> | undefined => {\n if (!data) return data;\n return {\n ...data,\n pages: data.pages.map((page) => ({\n ...page,\n data: page.data.map((item) => (predicate(item) ? updater : item)),\n })),\n };\n };\n },\n updateById<T extends Entity>(updated: T) {\n return this.update<T>(updated, (item) => item.id === updated.id);\n },\n remove<T>(predicate: (item: T) => boolean) {\n return (data: InfinitePageData<T> | undefined): InfinitePageData<T> | undefined => {\n if (!data) return data;\n return {\n ...data,\n pages: data.pages.map((page) => ({\n ...page,\n data: page.data.filter((item) => !predicate(item)),\n })),\n };\n };\n },\n removeById<T extends Entity>(id: EntityId) {\n return this.remove<T>((item) => item.id === id);\n },\n};\n\nexport const Items = {\n push<T>(newItems: T[]) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return newItems;\n return [...data, ...newItems];\n };\n },\n unshift<T>(newItems: T[]) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return newItems;\n return [...newItems, ...data];\n };\n },\n pushAndDedupe<T extends Entity>(newItems: T[]) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return newItems;\n const seen = new Set<EntityId>();\n const result: T[] = [];\n for (const item of data) {\n if (!seen.has(item.id)) {\n seen.add(item.id);\n result.push(item);\n }\n }\n for (const item of newItems) {\n if (!seen.has(item.id)) {\n seen.add(item.id);\n result.push(item);\n }\n }\n return result;\n };\n },\n unshiftAndDedupe<T extends Entity>(newItems: T[]) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return newItems;\n const seen = new Set<EntityId>();\n const result: T[] = [];\n for (const item of newItems) {\n if (!seen.has(item.id)) {\n seen.add(item.id);\n result.push(item);\n }\n }\n for (const item of data) {\n if (!seen.has(item.id)) {\n seen.add(item.id);\n result.push(item);\n }\n }\n return result;\n };\n },\n update<T>(updater: T, predicate: (item: T) => boolean) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return data;\n return data.map((item) => (predicate(item) ? updater : item));\n };\n },\n updateById<T extends Entity>(updated: T) {\n return this.update<T>(updated, (item) => item.id === updated.id);\n },\n remove<T>(predicate: (item: T) => boolean) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return data;\n return data.filter((item) => !predicate(item));\n };\n },\n removeById<T extends Entity>(id: EntityId) {\n return this.remove<T>((item) => item.id === id);\n },\n};\n"],"mappings":"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","names":[]}
|
package/dist/response.d.cts
CHANGED
|
@@ -59,7 +59,7 @@ type InfinitePageData<T> = {
|
|
|
59
59
|
pages: Array<Page<T>>;
|
|
60
60
|
pageParams: Array<Page['paging']>;
|
|
61
61
|
};
|
|
62
|
-
declare const
|
|
62
|
+
declare const Pages: {
|
|
63
63
|
flatten<T>(data: InfinitePageData<T>): T[];
|
|
64
64
|
dedupe<T extends Entity>(data: InfinitePageData<T>): T[];
|
|
65
65
|
prepend<T>(item: T): (data: InfinitePageData<T> | undefined) => InfinitePageData<T> | undefined;
|
|
@@ -69,7 +69,7 @@ declare const pages: {
|
|
|
69
69
|
remove<T>(predicate: (item: T) => boolean): (data: InfinitePageData<T> | undefined) => InfinitePageData<T> | undefined;
|
|
70
70
|
removeById<T extends Entity>(id: EntityId): (data: InfinitePageData<T> | undefined) => InfinitePageData<T> | undefined;
|
|
71
71
|
};
|
|
72
|
-
declare const
|
|
72
|
+
declare const Items: {
|
|
73
73
|
push<T>(newItems: T[]): (data: T[] | undefined) => T[] | undefined;
|
|
74
74
|
unshift<T>(newItems: T[]): (data: T[] | undefined) => T[] | undefined;
|
|
75
75
|
pushAndDedupe<T extends Entity>(newItems: T[]): (data: T[] | undefined) => T[] | undefined;
|
|
@@ -80,4 +80,4 @@ declare const items: {
|
|
|
80
80
|
removeById<T extends Entity>(id: EntityId): (data: T[] | undefined) => T[] | undefined;
|
|
81
81
|
};
|
|
82
82
|
|
|
83
|
-
export { Cursor, type Empty, type Entity, type EntityId, type InfinitePageData, type InitParams, type NextParams, type Page, type PageParams, type ParentPageParams, type PrevParams, type Response, getNextPageParam, getPreviousPageParam, initialPageParam,
|
|
83
|
+
export { Cursor, type Empty, type Entity, type EntityId, type InfinitePageData, type InitParams, Items, type NextParams, type Page, type PageParams, Pages, type ParentPageParams, type PrevParams, type Response, getNextPageParam, getPreviousPageParam, initialPageParam, pageParamsSchema };
|
package/dist/response.d.ts
CHANGED
|
@@ -59,7 +59,7 @@ type InfinitePageData<T> = {
|
|
|
59
59
|
pages: Array<Page<T>>;
|
|
60
60
|
pageParams: Array<Page['paging']>;
|
|
61
61
|
};
|
|
62
|
-
declare const
|
|
62
|
+
declare const Pages: {
|
|
63
63
|
flatten<T>(data: InfinitePageData<T>): T[];
|
|
64
64
|
dedupe<T extends Entity>(data: InfinitePageData<T>): T[];
|
|
65
65
|
prepend<T>(item: T): (data: InfinitePageData<T> | undefined) => InfinitePageData<T> | undefined;
|
|
@@ -69,7 +69,7 @@ declare const pages: {
|
|
|
69
69
|
remove<T>(predicate: (item: T) => boolean): (data: InfinitePageData<T> | undefined) => InfinitePageData<T> | undefined;
|
|
70
70
|
removeById<T extends Entity>(id: EntityId): (data: InfinitePageData<T> | undefined) => InfinitePageData<T> | undefined;
|
|
71
71
|
};
|
|
72
|
-
declare const
|
|
72
|
+
declare const Items: {
|
|
73
73
|
push<T>(newItems: T[]): (data: T[] | undefined) => T[] | undefined;
|
|
74
74
|
unshift<T>(newItems: T[]): (data: T[] | undefined) => T[] | undefined;
|
|
75
75
|
pushAndDedupe<T extends Entity>(newItems: T[]): (data: T[] | undefined) => T[] | undefined;
|
|
@@ -80,4 +80,4 @@ declare const items: {
|
|
|
80
80
|
removeById<T extends Entity>(id: EntityId): (data: T[] | undefined) => T[] | undefined;
|
|
81
81
|
};
|
|
82
82
|
|
|
83
|
-
export { Cursor, type Empty, type Entity, type EntityId, type InfinitePageData, type InitParams, type NextParams, type Page, type PageParams, type ParentPageParams, type PrevParams, type Response, getNextPageParam, getPreviousPageParam, initialPageParam,
|
|
83
|
+
export { Cursor, type Empty, type Entity, type EntityId, type InfinitePageData, type InitParams, Items, type NextParams, type Page, type PageParams, Pages, type ParentPageParams, type PrevParams, type Response, getNextPageParam, getPreviousPageParam, initialPageParam, pageParamsSchema };
|
package/dist/response.mjs
CHANGED
|
@@ -38,7 +38,7 @@ function getPreviousPageParam(first) {
|
|
|
38
38
|
function getNextPageParam(last) {
|
|
39
39
|
return hasText(last.paging.next) ? { next: last.paging.next } : null;
|
|
40
40
|
}
|
|
41
|
-
var
|
|
41
|
+
var Pages = {
|
|
42
42
|
flatten(data) {
|
|
43
43
|
return data.pages.flatMap((page) => page.data);
|
|
44
44
|
},
|
|
@@ -66,10 +66,10 @@ var pages = {
|
|
|
66
66
|
append(item) {
|
|
67
67
|
return (data) => {
|
|
68
68
|
if (!data) return data;
|
|
69
|
-
const
|
|
70
|
-
const last =
|
|
69
|
+
const pages = data.pages;
|
|
70
|
+
const last = pages[pages.length - 1];
|
|
71
71
|
if (!last) return { ...data, pages: [{ data: [item], paging: {} }] };
|
|
72
|
-
return { ...data, pages: [...
|
|
72
|
+
return { ...data, pages: [...pages.slice(0, -1), { ...last, data: [...last.data, item] }] };
|
|
73
73
|
};
|
|
74
74
|
},
|
|
75
75
|
update(updater, predicate) {
|
|
@@ -103,7 +103,7 @@ var pages = {
|
|
|
103
103
|
return this.remove((item) => item.id === id);
|
|
104
104
|
}
|
|
105
105
|
};
|
|
106
|
-
var
|
|
106
|
+
var Items = {
|
|
107
107
|
push(newItems) {
|
|
108
108
|
return (data) => {
|
|
109
109
|
if (!data) return newItems;
|
|
@@ -177,11 +177,11 @@ var items = {
|
|
|
177
177
|
};
|
|
178
178
|
export {
|
|
179
179
|
Cursor,
|
|
180
|
+
Items,
|
|
181
|
+
Pages,
|
|
180
182
|
getNextPageParam,
|
|
181
183
|
getPreviousPageParam,
|
|
182
184
|
initialPageParam,
|
|
183
|
-
|
|
184
|
-
pageParamsSchema,
|
|
185
|
-
pages
|
|
185
|
+
pageParamsSchema
|
|
186
186
|
};
|
|
187
187
|
//# sourceMappingURL=response.mjs.map
|
package/dist/response.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/response.ts"],"sourcesContent":["import { hasText } from '@shware/utils';\nimport { _default, coerce, int, maximum, minimum, object, optional, string } from 'zod/mini';\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport type Empty = {};\nexport type EntityId = string | number;\nexport type Entity = { id: EntityId };\n\nexport type Response<T = never> = { data: T };\n\nexport type InitParams = { limit: number; parent?: string };\nexport type NextParams = { limit: number; parent?: string; next: string };\nexport type PrevParams = { limit: number; parent?: string; prev: string };\nexport type PageParams = { limit: number; prev?: string; next?: string };\nexport type ParentPageParams = { limit: number; parent: string; prev?: string; next?: string };\nexport type Page<T = never> = { data: T[]; paging: { next?: string; prev?: string } };\n\nexport function pageParamsSchema(max = 100, defaultLimit = 20) {\n return object({\n limit: _default(coerce.number().check(int(), minimum(1), maximum(max)), defaultLimit),\n prev: optional(string()),\n next: optional(string()),\n });\n}\n\nexport const Cursor = {\n of(\n prev: bigint | number | string | undefined,\n next: bigint | number | string | undefined\n ): Page['paging'] {\n return {\n prev: prev ? this.encode(prev) : undefined,\n next: next ? this.encode(next) : undefined,\n };\n },\n empty(): Page['paging'] {\n return { prev: undefined, next: undefined };\n },\n encode(id: bigint | number | string | undefined): string | undefined {\n if (!id) return undefined;\n return Buffer.from(id.toString(), 'utf-8').toString('base64');\n },\n decode<T extends 'bigint' | 'number' | 'string' = 'bigint'>(\n token: string,\n type: T = 'bigint' as T\n ): T extends 'bigint' ? bigint : T extends 'number' ? number : string {\n const value = Buffer.from(token, 'base64').toString('utf-8');\n if (type === 'bigint')\n return BigInt(value) as T extends 'bigint' ? bigint : T extends 'number' ? number : string;\n if (type === 'number')\n return Number(value) as T extends 'bigint' ? bigint : T extends 'number' ? number : string;\n return value as T extends 'bigint' ? bigint : T extends 'number' ? number : string;\n },\n};\n\nexport const initialPageParam: Page['paging'] = {};\n\nexport function getPreviousPageParam<T = never>(first: Page<T>): Page['paging'] | null {\n return hasText(first.paging.prev) ? { prev: first.paging.prev } : null;\n}\n\nexport function getNextPageParam<T = never>(last: Page<T>): Page['paging'] | null {\n return hasText(last.paging.next) ? { next: last.paging.next } : null;\n}\n\nexport type InfinitePageData<T> = {\n pages: Array<Page<T>>;\n pageParams: Array<Page['paging']>;\n};\n\nexport const pages = {\n flatten<T>(data: InfinitePageData<T>): T[] {\n return data.pages.flatMap((page) => page.data);\n },\n dedupe<T extends Entity>(data: InfinitePageData<T>): T[] {\n const seen = new Set<EntityId>();\n const result: T[] = [];\n for (const page of data.pages) {\n for (const item of page.data) {\n if (!seen.has(item.id)) {\n seen.add(item.id);\n result.push(item);\n }\n }\n }\n return result;\n },\n prepend<T>(item: T) {\n return (data: InfinitePageData<T> | undefined): InfinitePageData<T> | undefined => {\n if (!data) return data;\n const [first, ...rest] = data.pages;\n if (!first) return { ...data, pages: [{ data: [item], paging: {} }] };\n return { ...data, pages: [{ ...first, data: [item, ...first.data] }, ...rest] };\n };\n },\n append<T>(item: T) {\n return (data: InfinitePageData<T> | undefined): InfinitePageData<T> | undefined => {\n if (!data) return data;\n const pages = data.pages;\n const last = pages[pages.length - 1];\n if (!last) return { ...data, pages: [{ data: [item], paging: {} }] };\n return { ...data, pages: [...pages.slice(0, -1), { ...last, data: [...last.data, item] }] };\n };\n },\n update<T>(updater: T, predicate: (item: T) => boolean) {\n return (data: InfinitePageData<T> | undefined): InfinitePageData<T> | undefined => {\n if (!data) return data;\n return {\n ...data,\n pages: data.pages.map((page) => ({\n ...page,\n data: page.data.map((item) => (predicate(item) ? updater : item)),\n })),\n };\n };\n },\n updateById<T extends Entity>(updated: T) {\n return this.update<T>(updated, (item) => item.id === updated.id);\n },\n remove<T>(predicate: (item: T) => boolean) {\n return (data: InfinitePageData<T> | undefined): InfinitePageData<T> | undefined => {\n if (!data) return data;\n return {\n ...data,\n pages: data.pages.map((page) => ({\n ...page,\n data: page.data.filter((item) => !predicate(item)),\n })),\n };\n };\n },\n removeById<T extends Entity>(id: EntityId) {\n return this.remove<T>((item) => item.id === id);\n },\n};\n\nexport const items = {\n push<T>(newItems: T[]) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return newItems;\n return [...data, ...newItems];\n };\n },\n unshift<T>(newItems: T[]) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return newItems;\n return [...newItems, ...data];\n };\n },\n pushAndDedupe<T extends Entity>(newItems: T[]) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return newItems;\n const seen = new Set<EntityId>();\n const result: T[] = [];\n for (const item of data) {\n if (!seen.has(item.id)) {\n seen.add(item.id);\n result.push(item);\n }\n }\n for (const item of newItems) {\n if (!seen.has(item.id)) {\n seen.add(item.id);\n result.push(item);\n }\n }\n return result;\n };\n },\n unshiftAndDedupe<T extends Entity>(newItems: T[]) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return newItems;\n const seen = new Set<EntityId>();\n const result: T[] = [];\n for (const item of newItems) {\n if (!seen.has(item.id)) {\n seen.add(item.id);\n result.push(item);\n }\n }\n for (const item of data) {\n if (!seen.has(item.id)) {\n seen.add(item.id);\n result.push(item);\n }\n }\n return result;\n };\n },\n update<T>(updater: T, predicate: (item: T) => boolean) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return data;\n return data.map((item) => (predicate(item) ? updater : item));\n };\n },\n updateById<T extends Entity>(updated: T) {\n return this.update<T>(updated, (item) => item.id === updated.id);\n },\n remove<T>(predicate: (item: T) => boolean) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return data;\n return data.filter((item) => !predicate(item));\n };\n },\n removeById<T extends Entity>(id: EntityId) {\n return this.remove<T>((item) => item.id === id);\n },\n};\n"],"mappings":"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","names":["pages"]}
|
|
1
|
+
{"version":3,"sources":["../src/response.ts"],"sourcesContent":["import { hasText } from '@shware/utils';\nimport { _default, coerce, int, maximum, minimum, object, optional, string } from 'zod/mini';\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport type Empty = {};\nexport type EntityId = string | number;\nexport type Entity = { id: EntityId };\n\nexport type Response<T = never> = { data: T };\n\nexport type InitParams = { limit: number; parent?: string };\nexport type NextParams = { limit: number; parent?: string; next: string };\nexport type PrevParams = { limit: number; parent?: string; prev: string };\nexport type PageParams = { limit: number; prev?: string; next?: string };\nexport type ParentPageParams = { limit: number; parent: string; prev?: string; next?: string };\nexport type Page<T = never> = { data: T[]; paging: { next?: string; prev?: string } };\n\nexport function pageParamsSchema(max = 100, defaultLimit = 20) {\n return object({\n limit: _default(coerce.number().check(int(), minimum(1), maximum(max)), defaultLimit),\n prev: optional(string()),\n next: optional(string()),\n });\n}\n\nexport const Cursor = {\n of(\n prev: bigint | number | string | undefined,\n next: bigint | number | string | undefined\n ): Page['paging'] {\n return {\n prev: prev ? this.encode(prev) : undefined,\n next: next ? this.encode(next) : undefined,\n };\n },\n empty(): Page['paging'] {\n return { prev: undefined, next: undefined };\n },\n encode(id: bigint | number | string | undefined): string | undefined {\n if (!id) return undefined;\n return Buffer.from(id.toString(), 'utf-8').toString('base64');\n },\n decode<T extends 'bigint' | 'number' | 'string' = 'bigint'>(\n token: string,\n type: T = 'bigint' as T\n ): T extends 'bigint' ? bigint : T extends 'number' ? number : string {\n const value = Buffer.from(token, 'base64').toString('utf-8');\n if (type === 'bigint')\n return BigInt(value) as T extends 'bigint' ? bigint : T extends 'number' ? number : string;\n if (type === 'number')\n return Number(value) as T extends 'bigint' ? bigint : T extends 'number' ? number : string;\n return value as T extends 'bigint' ? bigint : T extends 'number' ? number : string;\n },\n};\n\nexport const initialPageParam: Page['paging'] = {};\n\nexport function getPreviousPageParam<T = never>(first: Page<T>): Page['paging'] | null {\n return hasText(first.paging.prev) ? { prev: first.paging.prev } : null;\n}\n\nexport function getNextPageParam<T = never>(last: Page<T>): Page['paging'] | null {\n return hasText(last.paging.next) ? { next: last.paging.next } : null;\n}\n\nexport type InfinitePageData<T> = {\n pages: Array<Page<T>>;\n pageParams: Array<Page['paging']>;\n};\n\nexport const Pages = {\n flatten<T>(data: InfinitePageData<T>): T[] {\n return data.pages.flatMap((page) => page.data);\n },\n dedupe<T extends Entity>(data: InfinitePageData<T>): T[] {\n const seen = new Set<EntityId>();\n const result: T[] = [];\n for (const page of data.pages) {\n for (const item of page.data) {\n if (!seen.has(item.id)) {\n seen.add(item.id);\n result.push(item);\n }\n }\n }\n return result;\n },\n prepend<T>(item: T) {\n return (data: InfinitePageData<T> | undefined): InfinitePageData<T> | undefined => {\n if (!data) return data;\n const [first, ...rest] = data.pages;\n if (!first) return { ...data, pages: [{ data: [item], paging: {} }] };\n return { ...data, pages: [{ ...first, data: [item, ...first.data] }, ...rest] };\n };\n },\n append<T>(item: T) {\n return (data: InfinitePageData<T> | undefined): InfinitePageData<T> | undefined => {\n if (!data) return data;\n const pages = data.pages;\n const last = pages[pages.length - 1];\n if (!last) return { ...data, pages: [{ data: [item], paging: {} }] };\n return { ...data, pages: [...pages.slice(0, -1), { ...last, data: [...last.data, item] }] };\n };\n },\n update<T>(updater: T, predicate: (item: T) => boolean) {\n return (data: InfinitePageData<T> | undefined): InfinitePageData<T> | undefined => {\n if (!data) return data;\n return {\n ...data,\n pages: data.pages.map((page) => ({\n ...page,\n data: page.data.map((item) => (predicate(item) ? updater : item)),\n })),\n };\n };\n },\n updateById<T extends Entity>(updated: T) {\n return this.update<T>(updated, (item) => item.id === updated.id);\n },\n remove<T>(predicate: (item: T) => boolean) {\n return (data: InfinitePageData<T> | undefined): InfinitePageData<T> | undefined => {\n if (!data) return data;\n return {\n ...data,\n pages: data.pages.map((page) => ({\n ...page,\n data: page.data.filter((item) => !predicate(item)),\n })),\n };\n };\n },\n removeById<T extends Entity>(id: EntityId) {\n return this.remove<T>((item) => item.id === id);\n },\n};\n\nexport const Items = {\n push<T>(newItems: T[]) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return newItems;\n return [...data, ...newItems];\n };\n },\n unshift<T>(newItems: T[]) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return newItems;\n return [...newItems, ...data];\n };\n },\n pushAndDedupe<T extends Entity>(newItems: T[]) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return newItems;\n const seen = new Set<EntityId>();\n const result: T[] = [];\n for (const item of data) {\n if (!seen.has(item.id)) {\n seen.add(item.id);\n result.push(item);\n }\n }\n for (const item of newItems) {\n if (!seen.has(item.id)) {\n seen.add(item.id);\n result.push(item);\n }\n }\n return result;\n };\n },\n unshiftAndDedupe<T extends Entity>(newItems: T[]) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return newItems;\n const seen = new Set<EntityId>();\n const result: T[] = [];\n for (const item of newItems) {\n if (!seen.has(item.id)) {\n seen.add(item.id);\n result.push(item);\n }\n }\n for (const item of data) {\n if (!seen.has(item.id)) {\n seen.add(item.id);\n result.push(item);\n }\n }\n return result;\n };\n },\n update<T>(updater: T, predicate: (item: T) => boolean) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return data;\n return data.map((item) => (predicate(item) ? updater : item));\n };\n },\n updateById<T extends Entity>(updated: T) {\n return this.update<T>(updated, (item) => item.id === updated.id);\n },\n remove<T>(predicate: (item: T) => boolean) {\n return (data: T[] | undefined): T[] | undefined => {\n if (!data) return data;\n return data.filter((item) => !predicate(item));\n };\n },\n removeById<T extends Entity>(id: EntityId) {\n return this.remove<T>((item) => item.id === id);\n },\n};\n"],"mappings":"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","names":[]}
|