@shware/http 0.3.0 → 0.3.2
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/index.cjs +6 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.mjs +4 -0
- package/dist/index.mjs.map +1 -1
- package/dist/utils/invariant.cjs +37 -0
- package/dist/utils/invariant.cjs.map +1 -0
- package/dist/utils/invariant.d.cts +3 -0
- package/dist/utils/invariant.d.ts +3 -0
- package/dist/utils/invariant.mjs +12 -0
- package/dist/utils/invariant.mjs.map +1 -0
- package/dist/utils/token-bucket.cjs +73 -0
- package/dist/utils/token-bucket.cjs.map +1 -0
- package/dist/utils/token-bucket.d.cts +20 -0
- package/dist/utils/token-bucket.d.ts +20 -0
- package/dist/utils/token-bucket.mjs +48 -0
- package/dist/utils/token-bucket.mjs.map +1 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -21,7 +21,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
// src/index.ts
|
|
22
22
|
var index_exports = {};
|
|
23
23
|
__export(index_exports, {
|
|
24
|
+
TokenBucket: () => import_token_bucket.TokenBucket,
|
|
24
25
|
hasText: () => import_string.hasText,
|
|
26
|
+
invariant: () => import_invariant.invariant,
|
|
25
27
|
timing: () => import_timing.timing,
|
|
26
28
|
verifyStandardWebhook: () => import_webhook.verifyStandardWebhook
|
|
27
29
|
});
|
|
@@ -34,9 +36,13 @@ __reExport(index_exports, require("./response.cjs"), module.exports);
|
|
|
34
36
|
var import_string = require("./utils/string.cjs");
|
|
35
37
|
var import_timing = require("./utils/timing.cjs");
|
|
36
38
|
var import_webhook = require("./webhook.cjs");
|
|
39
|
+
var import_invariant = require("./utils/invariant.cjs");
|
|
40
|
+
var import_token_bucket = require("./utils/token-bucket.cjs");
|
|
37
41
|
// Annotate the CommonJS export names for ESM import in node:
|
|
38
42
|
0 && (module.exports = {
|
|
43
|
+
TokenBucket,
|
|
39
44
|
hasText,
|
|
45
|
+
invariant,
|
|
40
46
|
timing,
|
|
41
47
|
verifyStandardWebhook,
|
|
42
48
|
...require("./detail.cjs"),
|
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 type {\n NetworkErrorReason,\n StatusErrorReason,\n AuthenticationErrorReason,\n ModerationErrorReason,\n MultipartErrorReason,\n AppErrorReason,\n ErrorReason,\n} from './reason';\n\nexport * from './detail';\nexport * from './status';\nexport * from './vaild';\nexport * from './snowflake';\nexport * from './response';\nexport { hasText } from './utils/string';\nexport { timing } from './utils/timing';\nexport { verifyStandardWebhook } from './webhook';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuBA,0BAAc,yBAvBd;AAwBA,0BAAc,yBAxBd;AAyBA,0BAAc,wBAzBd;AA0BA,0BAAc,4BA1Bd;AA2BA,0BAAc,2BA3Bd;AA4BA,oBAAwB;AACxB,oBAAuB;AACvB,qBAAsC;","names":[]}
|
|
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 type {\n NetworkErrorReason,\n StatusErrorReason,\n AuthenticationErrorReason,\n ModerationErrorReason,\n MultipartErrorReason,\n AppErrorReason,\n ErrorReason,\n} from './reason';\n\nexport * from './detail';\nexport * from './status';\nexport * from './vaild';\nexport * from './snowflake';\nexport * from './response';\nexport { hasText } from './utils/string';\nexport { timing } from './utils/timing';\nexport { verifyStandardWebhook } from './webhook';\nexport { invariant } from './utils/invariant';\nexport { TokenBucket, type TokenBucketOptions } from './utils/token-bucket';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuBA,0BAAc,yBAvBd;AAwBA,0BAAc,yBAxBd;AAyBA,0BAAc,wBAzBd;AA0BA,0BAAc,4BA1Bd;AA2BA,0BAAc,2BA3Bd;AA4BA,oBAAwB;AACxB,oBAAuB;AACvB,qBAAsC;AACtC,uBAA0B;AAC1B,0BAAqD;","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -7,4 +7,6 @@ export { Cursor, Empty, Entity, EntityId, InitParams, NextParams, PageParams, Pa
|
|
|
7
7
|
export { hasText } from './utils/string.cjs';
|
|
8
8
|
export { timing } from './utils/timing.cjs';
|
|
9
9
|
export { verifyStandardWebhook } from './webhook.cjs';
|
|
10
|
+
export { invariant } from './utils/invariant.cjs';
|
|
11
|
+
export { TokenBucket, TokenBucketOptions } from './utils/token-bucket.cjs';
|
|
10
12
|
import 'zod/v4';
|
package/dist/index.d.ts
CHANGED
|
@@ -7,4 +7,6 @@ export { Cursor, Empty, Entity, EntityId, InitParams, NextParams, PageParams, Pa
|
|
|
7
7
|
export { hasText } from './utils/string.js';
|
|
8
8
|
export { timing } from './utils/timing.js';
|
|
9
9
|
export { verifyStandardWebhook } from './webhook.js';
|
|
10
|
+
export { invariant } from './utils/invariant.js';
|
|
11
|
+
export { TokenBucket, TokenBucketOptions } from './utils/token-bucket.js';
|
|
10
12
|
import 'zod/v4';
|
package/dist/index.mjs
CHANGED
|
@@ -7,8 +7,12 @@ export * from "./response.mjs";
|
|
|
7
7
|
import { hasText } from "./utils/string.mjs";
|
|
8
8
|
import { timing } from "./utils/timing.mjs";
|
|
9
9
|
import { verifyStandardWebhook } from "./webhook.mjs";
|
|
10
|
+
import { invariant } from "./utils/invariant.mjs";
|
|
11
|
+
import { TokenBucket } from "./utils/token-bucket.mjs";
|
|
10
12
|
export {
|
|
13
|
+
TokenBucket,
|
|
11
14
|
hasText,
|
|
15
|
+
invariant,
|
|
12
16
|
timing,
|
|
13
17
|
verifyStandardWebhook
|
|
14
18
|
};
|
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 type {\n NetworkErrorReason,\n StatusErrorReason,\n AuthenticationErrorReason,\n ModerationErrorReason,\n MultipartErrorReason,\n AppErrorReason,\n ErrorReason,\n} from './reason';\n\nexport * from './detail';\nexport * from './status';\nexport * from './vaild';\nexport * from './snowflake';\nexport * from './response';\nexport { hasText } from './utils/string';\nexport { timing } from './utils/timing';\nexport { verifyStandardWebhook } from './webhook';\n"],"mappings":";AAuBA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,eAAe;AACxB,SAAS,cAAc;AACvB,SAAS,6BAA6B;","names":[]}
|
|
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 type {\n NetworkErrorReason,\n StatusErrorReason,\n AuthenticationErrorReason,\n ModerationErrorReason,\n MultipartErrorReason,\n AppErrorReason,\n ErrorReason,\n} from './reason';\n\nexport * from './detail';\nexport * from './status';\nexport * from './vaild';\nexport * from './snowflake';\nexport * from './response';\nexport { hasText } from './utils/string';\nexport { timing } from './utils/timing';\nexport { verifyStandardWebhook } from './webhook';\nexport { invariant } from './utils/invariant';\nexport { TokenBucket, type TokenBucketOptions } from './utils/token-bucket';\n"],"mappings":";AAuBA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,eAAe;AACxB,SAAS,cAAc;AACvB,SAAS,6BAA6B;AACtC,SAAS,iBAAiB;AAC1B,SAAS,mBAA4C;","names":[]}
|
|
@@ -0,0 +1,37 @@
|
|
|
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/utils/invariant.ts
|
|
21
|
+
var invariant_exports = {};
|
|
22
|
+
__export(invariant_exports, {
|
|
23
|
+
invariant: () => invariant
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(invariant_exports);
|
|
26
|
+
var prefix = "Invariant failed";
|
|
27
|
+
function invariant(condition, message) {
|
|
28
|
+
if (condition) return;
|
|
29
|
+
const provided = typeof message === "function" ? message() : message;
|
|
30
|
+
const value = provided ? `${prefix}: ${provided}` : prefix;
|
|
31
|
+
throw new Error(value);
|
|
32
|
+
}
|
|
33
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
34
|
+
0 && (module.exports = {
|
|
35
|
+
invariant
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=invariant.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/invariant.ts"],"sourcesContent":["const prefix = 'Invariant failed';\n\nexport function invariant(condition: any, message?: string | (() => string)): asserts condition {\n if (condition) return;\n const provided: string | undefined = typeof message === 'function' ? message() : message;\n const value: string = provided ? `${prefix}: ${provided}` : prefix;\n throw new Error(value);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAM,SAAS;AAER,SAAS,UAAU,WAAgB,SAAsD;AAC9F,MAAI,UAAW;AACf,QAAM,WAA+B,OAAO,YAAY,aAAa,QAAQ,IAAI;AACjF,QAAM,QAAgB,WAAW,GAAG,MAAM,KAAK,QAAQ,KAAK;AAC5D,QAAM,IAAI,MAAM,KAAK;AACvB;","names":[]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// src/utils/invariant.ts
|
|
2
|
+
var prefix = "Invariant failed";
|
|
3
|
+
function invariant(condition, message) {
|
|
4
|
+
if (condition) return;
|
|
5
|
+
const provided = typeof message === "function" ? message() : message;
|
|
6
|
+
const value = provided ? `${prefix}: ${provided}` : prefix;
|
|
7
|
+
throw new Error(value);
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
invariant
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=invariant.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/invariant.ts"],"sourcesContent":["const prefix = 'Invariant failed';\n\nexport function invariant(condition: any, message?: string | (() => string)): asserts condition {\n if (condition) return;\n const provided: string | undefined = typeof message === 'function' ? message() : message;\n const value: string = provided ? `${prefix}: ${provided}` : prefix;\n throw new Error(value);\n}\n"],"mappings":";AAAA,IAAM,SAAS;AAER,SAAS,UAAU,WAAgB,SAAsD;AAC9F,MAAI,UAAW;AACf,QAAM,WAA+B,OAAO,YAAY,aAAa,QAAQ,IAAI;AACjF,QAAM,QAAgB,WAAW,GAAG,MAAM,KAAK,QAAQ,KAAK;AAC5D,QAAM,IAAI,MAAM,KAAK;AACvB;","names":[]}
|
|
@@ -0,0 +1,73 @@
|
|
|
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/utils/token-bucket.ts
|
|
21
|
+
var token_bucket_exports = {};
|
|
22
|
+
__export(token_bucket_exports, {
|
|
23
|
+
TokenBucket: () => TokenBucket
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(token_bucket_exports);
|
|
26
|
+
var INTERVAL_MAP = {
|
|
27
|
+
second: 1e3,
|
|
28
|
+
minute: 60 * 1e3,
|
|
29
|
+
hour: 60 * 60 * 1e3,
|
|
30
|
+
day: 24 * 60 * 60 * 1e3
|
|
31
|
+
};
|
|
32
|
+
var TokenBucket = class {
|
|
33
|
+
rate;
|
|
34
|
+
capacity;
|
|
35
|
+
requested;
|
|
36
|
+
timer;
|
|
37
|
+
tokens;
|
|
38
|
+
constructor({ rate, capacity, requested, interval = "second" }) {
|
|
39
|
+
if (rate <= 0) throw new Error("rate must be greater than 0");
|
|
40
|
+
if (capacity <= 0) throw new Error("capacity must be greater than 0");
|
|
41
|
+
if (requested <= 0) throw new Error("requested must be greater than 0");
|
|
42
|
+
if (requested > capacity) throw new Error("requested must be less than or equal to capacity");
|
|
43
|
+
this.rate = rate;
|
|
44
|
+
this.capacity = capacity;
|
|
45
|
+
this.requested = requested;
|
|
46
|
+
this.tokens = capacity;
|
|
47
|
+
this.timer = setInterval(() => {
|
|
48
|
+
if (this.tokens < this.capacity) {
|
|
49
|
+
const tokens = this.tokens + this.rate;
|
|
50
|
+
this.tokens = Math.min(tokens, this.capacity);
|
|
51
|
+
}
|
|
52
|
+
}, INTERVAL_MAP[interval]);
|
|
53
|
+
}
|
|
54
|
+
wait(ms) {
|
|
55
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
56
|
+
}
|
|
57
|
+
async removeTokens() {
|
|
58
|
+
while (this.tokens < this.requested) {
|
|
59
|
+
const ms = Math.ceil(1e3 * (this.requested - this.tokens) / this.rate);
|
|
60
|
+
await this.wait(ms);
|
|
61
|
+
}
|
|
62
|
+
this.tokens -= this.requested;
|
|
63
|
+
return this.tokens;
|
|
64
|
+
}
|
|
65
|
+
destroy() {
|
|
66
|
+
clearInterval(this.timer);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
70
|
+
0 && (module.exports = {
|
|
71
|
+
TokenBucket
|
|
72
|
+
});
|
|
73
|
+
//# sourceMappingURL=token-bucket.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/token-bucket.ts"],"sourcesContent":["type Interval = 'second' | 'minute' | 'hour' | 'day';\n\nconst INTERVAL_MAP: Record<Interval, number> = {\n second: 1000,\n minute: 60 * 1000,\n hour: 60 * 60 * 1000,\n day: 24 * 60 * 60 * 1000,\n};\n\nexport interface TokenBucketOptions {\n rate: number;\n capacity: number;\n requested: number;\n interval?: Interval;\n}\n\nexport class TokenBucket {\n readonly rate: number;\n readonly capacity: number;\n readonly requested: number;\n private readonly timer: number | NodeJS.Timeout;\n private tokens: number;\n\n constructor({ rate, capacity, requested, interval = 'second' }: TokenBucketOptions) {\n if (rate <= 0) throw new Error('rate must be greater than 0');\n if (capacity <= 0) throw new Error('capacity must be greater than 0');\n if (requested <= 0) throw new Error('requested must be greater than 0');\n if (requested > capacity) throw new Error('requested must be less than or equal to capacity');\n\n this.rate = rate;\n this.capacity = capacity;\n this.requested = requested;\n this.tokens = capacity;\n this.timer = setInterval(() => {\n if (this.tokens < this.capacity) {\n const tokens = this.tokens + this.rate;\n this.tokens = Math.min(tokens, this.capacity);\n }\n }, INTERVAL_MAP[interval]);\n }\n\n private wait(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n async removeTokens(): Promise<number> {\n while (this.tokens < this.requested) {\n const ms = Math.ceil((1000 * (this.requested - this.tokens)) / this.rate);\n await this.wait(ms);\n }\n this.tokens -= this.requested;\n return this.tokens;\n }\n\n destroy() {\n clearInterval(this.timer);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,IAAM,eAAyC;AAAA,EAC7C,QAAQ;AAAA,EACR,QAAQ,KAAK;AAAA,EACb,MAAM,KAAK,KAAK;AAAA,EAChB,KAAK,KAAK,KAAK,KAAK;AACtB;AASO,IAAM,cAAN,MAAkB;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACQ;AAAA,EACT;AAAA,EAER,YAAY,EAAE,MAAM,UAAU,WAAW,WAAW,SAAS,GAAuB;AAClF,QAAI,QAAQ,EAAG,OAAM,IAAI,MAAM,6BAA6B;AAC5D,QAAI,YAAY,EAAG,OAAM,IAAI,MAAM,iCAAiC;AACpE,QAAI,aAAa,EAAG,OAAM,IAAI,MAAM,kCAAkC;AACtE,QAAI,YAAY,SAAU,OAAM,IAAI,MAAM,kDAAkD;AAE5F,SAAK,OAAO;AACZ,SAAK,WAAW;AAChB,SAAK,YAAY;AACjB,SAAK,SAAS;AACd,SAAK,QAAQ,YAAY,MAAM;AAC7B,UAAI,KAAK,SAAS,KAAK,UAAU;AAC/B,cAAM,SAAS,KAAK,SAAS,KAAK;AAClC,aAAK,SAAS,KAAK,IAAI,QAAQ,KAAK,QAAQ;AAAA,MAC9C;AAAA,IACF,GAAG,aAAa,QAAQ,CAAC;AAAA,EAC3B;AAAA,EAEQ,KAAK,IAA2B;AACtC,WAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAAA,EACzD;AAAA,EAEA,MAAM,eAAgC;AACpC,WAAO,KAAK,SAAS,KAAK,WAAW;AACnC,YAAM,KAAK,KAAK,KAAM,OAAQ,KAAK,YAAY,KAAK,UAAW,KAAK,IAAI;AACxE,YAAM,KAAK,KAAK,EAAE;AAAA,IACpB;AACA,SAAK,UAAU,KAAK;AACpB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,UAAU;AACR,kBAAc,KAAK,KAAK;AAAA,EAC1B;AACF;","names":[]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type Interval = 'second' | 'minute' | 'hour' | 'day';
|
|
2
|
+
interface TokenBucketOptions {
|
|
3
|
+
rate: number;
|
|
4
|
+
capacity: number;
|
|
5
|
+
requested: number;
|
|
6
|
+
interval?: Interval;
|
|
7
|
+
}
|
|
8
|
+
declare class TokenBucket {
|
|
9
|
+
readonly rate: number;
|
|
10
|
+
readonly capacity: number;
|
|
11
|
+
readonly requested: number;
|
|
12
|
+
private readonly timer;
|
|
13
|
+
private tokens;
|
|
14
|
+
constructor({ rate, capacity, requested, interval }: TokenBucketOptions);
|
|
15
|
+
private wait;
|
|
16
|
+
removeTokens(): Promise<number>;
|
|
17
|
+
destroy(): void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { TokenBucket, type TokenBucketOptions };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type Interval = 'second' | 'minute' | 'hour' | 'day';
|
|
2
|
+
interface TokenBucketOptions {
|
|
3
|
+
rate: number;
|
|
4
|
+
capacity: number;
|
|
5
|
+
requested: number;
|
|
6
|
+
interval?: Interval;
|
|
7
|
+
}
|
|
8
|
+
declare class TokenBucket {
|
|
9
|
+
readonly rate: number;
|
|
10
|
+
readonly capacity: number;
|
|
11
|
+
readonly requested: number;
|
|
12
|
+
private readonly timer;
|
|
13
|
+
private tokens;
|
|
14
|
+
constructor({ rate, capacity, requested, interval }: TokenBucketOptions);
|
|
15
|
+
private wait;
|
|
16
|
+
removeTokens(): Promise<number>;
|
|
17
|
+
destroy(): void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { TokenBucket, type TokenBucketOptions };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// src/utils/token-bucket.ts
|
|
2
|
+
var INTERVAL_MAP = {
|
|
3
|
+
second: 1e3,
|
|
4
|
+
minute: 60 * 1e3,
|
|
5
|
+
hour: 60 * 60 * 1e3,
|
|
6
|
+
day: 24 * 60 * 60 * 1e3
|
|
7
|
+
};
|
|
8
|
+
var TokenBucket = class {
|
|
9
|
+
rate;
|
|
10
|
+
capacity;
|
|
11
|
+
requested;
|
|
12
|
+
timer;
|
|
13
|
+
tokens;
|
|
14
|
+
constructor({ rate, capacity, requested, interval = "second" }) {
|
|
15
|
+
if (rate <= 0) throw new Error("rate must be greater than 0");
|
|
16
|
+
if (capacity <= 0) throw new Error("capacity must be greater than 0");
|
|
17
|
+
if (requested <= 0) throw new Error("requested must be greater than 0");
|
|
18
|
+
if (requested > capacity) throw new Error("requested must be less than or equal to capacity");
|
|
19
|
+
this.rate = rate;
|
|
20
|
+
this.capacity = capacity;
|
|
21
|
+
this.requested = requested;
|
|
22
|
+
this.tokens = capacity;
|
|
23
|
+
this.timer = setInterval(() => {
|
|
24
|
+
if (this.tokens < this.capacity) {
|
|
25
|
+
const tokens = this.tokens + this.rate;
|
|
26
|
+
this.tokens = Math.min(tokens, this.capacity);
|
|
27
|
+
}
|
|
28
|
+
}, INTERVAL_MAP[interval]);
|
|
29
|
+
}
|
|
30
|
+
wait(ms) {
|
|
31
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
32
|
+
}
|
|
33
|
+
async removeTokens() {
|
|
34
|
+
while (this.tokens < this.requested) {
|
|
35
|
+
const ms = Math.ceil(1e3 * (this.requested - this.tokens) / this.rate);
|
|
36
|
+
await this.wait(ms);
|
|
37
|
+
}
|
|
38
|
+
this.tokens -= this.requested;
|
|
39
|
+
return this.tokens;
|
|
40
|
+
}
|
|
41
|
+
destroy() {
|
|
42
|
+
clearInterval(this.timer);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
export {
|
|
46
|
+
TokenBucket
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=token-bucket.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/token-bucket.ts"],"sourcesContent":["type Interval = 'second' | 'minute' | 'hour' | 'day';\n\nconst INTERVAL_MAP: Record<Interval, number> = {\n second: 1000,\n minute: 60 * 1000,\n hour: 60 * 60 * 1000,\n day: 24 * 60 * 60 * 1000,\n};\n\nexport interface TokenBucketOptions {\n rate: number;\n capacity: number;\n requested: number;\n interval?: Interval;\n}\n\nexport class TokenBucket {\n readonly rate: number;\n readonly capacity: number;\n readonly requested: number;\n private readonly timer: number | NodeJS.Timeout;\n private tokens: number;\n\n constructor({ rate, capacity, requested, interval = 'second' }: TokenBucketOptions) {\n if (rate <= 0) throw new Error('rate must be greater than 0');\n if (capacity <= 0) throw new Error('capacity must be greater than 0');\n if (requested <= 0) throw new Error('requested must be greater than 0');\n if (requested > capacity) throw new Error('requested must be less than or equal to capacity');\n\n this.rate = rate;\n this.capacity = capacity;\n this.requested = requested;\n this.tokens = capacity;\n this.timer = setInterval(() => {\n if (this.tokens < this.capacity) {\n const tokens = this.tokens + this.rate;\n this.tokens = Math.min(tokens, this.capacity);\n }\n }, INTERVAL_MAP[interval]);\n }\n\n private wait(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n async removeTokens(): Promise<number> {\n while (this.tokens < this.requested) {\n const ms = Math.ceil((1000 * (this.requested - this.tokens)) / this.rate);\n await this.wait(ms);\n }\n this.tokens -= this.requested;\n return this.tokens;\n }\n\n destroy() {\n clearInterval(this.timer);\n }\n}\n"],"mappings":";AAEA,IAAM,eAAyC;AAAA,EAC7C,QAAQ;AAAA,EACR,QAAQ,KAAK;AAAA,EACb,MAAM,KAAK,KAAK;AAAA,EAChB,KAAK,KAAK,KAAK,KAAK;AACtB;AASO,IAAM,cAAN,MAAkB;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACQ;AAAA,EACT;AAAA,EAER,YAAY,EAAE,MAAM,UAAU,WAAW,WAAW,SAAS,GAAuB;AAClF,QAAI,QAAQ,EAAG,OAAM,IAAI,MAAM,6BAA6B;AAC5D,QAAI,YAAY,EAAG,OAAM,IAAI,MAAM,iCAAiC;AACpE,QAAI,aAAa,EAAG,OAAM,IAAI,MAAM,kCAAkC;AACtE,QAAI,YAAY,SAAU,OAAM,IAAI,MAAM,kDAAkD;AAE5F,SAAK,OAAO;AACZ,SAAK,WAAW;AAChB,SAAK,YAAY;AACjB,SAAK,SAAS;AACd,SAAK,QAAQ,YAAY,MAAM;AAC7B,UAAI,KAAK,SAAS,KAAK,UAAU;AAC/B,cAAM,SAAS,KAAK,SAAS,KAAK;AAClC,aAAK,SAAS,KAAK,IAAI,QAAQ,KAAK,QAAQ;AAAA,MAC9C;AAAA,IACF,GAAG,aAAa,QAAQ,CAAC;AAAA,EAC3B;AAAA,EAEQ,KAAK,IAA2B;AACtC,WAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAAA,EACzD;AAAA,EAEA,MAAM,eAAgC;AACpC,WAAO,KAAK,SAAS,KAAK,WAAW;AACnC,YAAM,KAAK,KAAK,KAAM,OAAQ,KAAK,YAAY,KAAK,UAAW,KAAK,IAAI;AACxE,YAAM,KAAK,KAAK,EAAE;AAAA,IACpB;AACA,SAAK,UAAU,KAAK;AACpB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,UAAU;AACR,kBAAc,KAAK,KAAK;AAAA,EAC1B;AACF;","names":[]}
|