@perk-net/perk-pushplus-sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +17 -0
- package/README.md +334 -0
- package/dist/index.cjs +1283 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1208 -0
- package/dist/index.d.ts +1208 -0
- package/dist/index.global.js +1288 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.js +1241 -0
- package/dist/index.js.map +1 -0
- package/package.json +68 -0
- package/src/access-key-manager.ts +69 -0
- package/src/api/access-key-api.ts +35 -0
- package/src/api/base.ts +143 -0
- package/src/api/channel-api.ts +37 -0
- package/src/api/clawbot-api.ts +42 -0
- package/src/api/friend-api.ts +47 -0
- package/src/api/message-api.ts +109 -0
- package/src/api/message-token-api.ts +52 -0
- package/src/api/open-base.ts +54 -0
- package/src/api/open-message-api.ts +50 -0
- package/src/api/pre-api.ts +42 -0
- package/src/api/setting-api.ts +99 -0
- package/src/api/topic-api.ts +80 -0
- package/src/api/topic-user-api.ts +30 -0
- package/src/api/user-api.ts +34 -0
- package/src/api/webhook-api.ts +34 -0
- package/src/callback.ts +46 -0
- package/src/client.ts +143 -0
- package/src/config.ts +92 -0
- package/src/enums.ts +170 -0
- package/src/exception.ts +48 -0
- package/src/http.ts +117 -0
- package/src/index.ts +116 -0
- package/src/models.ts +580 -0
- package/src/rate-limit.ts +92 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { ResolvedPushPlusConfig } from './config';
|
|
2
|
+
import { ErrorCode } from './enums';
|
|
3
|
+
import { PushPlusError } from './exception';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 本地限流守卫:当 PushPlus 服务端返回 ErrorCode.RATE_LIMITED(code=900)时,
|
|
7
|
+
* 在内存里按 token 维度记录"解禁时间",期间任何发送类调用都会直接抛 PushPlusError,
|
|
8
|
+
* 不再发起 HTTP,避免继续打到上游浪费请求并加重账号限制。
|
|
9
|
+
*
|
|
10
|
+
* 对应官方文档建议:https://www.pushplus.plus/doc/guide/code.html
|
|
11
|
+
*
|
|
12
|
+
* 默认禁推到「次日 0 点」自动解禁;也可以通过 rateLimitCooldownMs 配置一个固定时长。
|
|
13
|
+
*
|
|
14
|
+
* 仅本地视角:服务端实际禁推时长可能与本地估算不同(文档示例为 2 天)。
|
|
15
|
+
*/
|
|
16
|
+
export class RateLimitGuard {
|
|
17
|
+
private readonly enabled: boolean;
|
|
18
|
+
private readonly cooldownMs: number;
|
|
19
|
+
private readonly blockedUntil = new Map<string, number>();
|
|
20
|
+
|
|
21
|
+
constructor(config: ResolvedPushPlusConfig) {
|
|
22
|
+
this.enabled = config.rateLimitGuardEnabled;
|
|
23
|
+
this.cooldownMs = config.rateLimitCooldownMs;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 在发起发送类请求前调用:若当前 token 处于限流期,直接抛 PushPlusError
|
|
28
|
+
* (code = ErrorCode.RATE_LIMITED),不会发起 HTTP。
|
|
29
|
+
*/
|
|
30
|
+
check(token: string | undefined | null): void {
|
|
31
|
+
if (!this.enabled) return;
|
|
32
|
+
const key = this.normalize(token);
|
|
33
|
+
if (!key) return;
|
|
34
|
+
const until = this.blockedUntil.get(key);
|
|
35
|
+
if (until == null) return;
|
|
36
|
+
const now = Date.now();
|
|
37
|
+
if (now < until) {
|
|
38
|
+
throw new PushPlusError(
|
|
39
|
+
`PushPlus 本地限流守卫:当前 token 已命中 code=900,` +
|
|
40
|
+
`在 ${new Date(until).toISOString()} 之前不再发起请求(请参考官方文档减少无用请求)`,
|
|
41
|
+
ErrorCode.RATE_LIMITED,
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
this.blockedUntil.delete(key);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 在收到服务端 code=900 后调用:登记限流状态,直到 cooldownUntil 到期。
|
|
49
|
+
*/
|
|
50
|
+
markBlocked(token: string | undefined | null): void {
|
|
51
|
+
if (!this.enabled) return;
|
|
52
|
+
const key = this.normalize(token);
|
|
53
|
+
if (!key) return;
|
|
54
|
+
const until = this.cooldownUntil(Date.now());
|
|
55
|
+
this.blockedUntil.set(key, until);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** 仅供测试或运维手动清除(例如已确认服务端解禁)。 */
|
|
59
|
+
clear(token: string | undefined | null): void {
|
|
60
|
+
const key = this.normalize(token);
|
|
61
|
+
if (key) this.blockedUntil.delete(key);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** 返回该 token 的解禁时间(毫秒时间戳);未被限流则为 null。 */
|
|
65
|
+
blockedUntilAt(token: string | undefined | null): number | null {
|
|
66
|
+
const key = this.normalize(token);
|
|
67
|
+
if (!key) return null;
|
|
68
|
+
const until = this.blockedUntil.get(key);
|
|
69
|
+
return until ?? null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 计算解禁时间:
|
|
74
|
+
* - cooldownMs > 0 时使用 now + cooldownMs;
|
|
75
|
+
* - 否则使用「系统默认时区的次日 0 点」。
|
|
76
|
+
*/
|
|
77
|
+
private cooldownUntil(now: number): number {
|
|
78
|
+
if (this.cooldownMs && this.cooldownMs > 0) {
|
|
79
|
+
return now + this.cooldownMs;
|
|
80
|
+
}
|
|
81
|
+
const d = new Date(now);
|
|
82
|
+
d.setHours(0, 0, 0, 0);
|
|
83
|
+
d.setDate(d.getDate() + 1);
|
|
84
|
+
return d.getTime();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private normalize(token: string | undefined | null): string | null {
|
|
88
|
+
if (token == null) return null;
|
|
89
|
+
const t = String(token).trim();
|
|
90
|
+
return t.length === 0 ? null : t;
|
|
91
|
+
}
|
|
92
|
+
}
|