fix(scheduler): NOTIFICATION_HOURS 通配符 "*" 被 padStart 误处理为 "0*"

本地 wrangler dev 测试时发现:用户配置 "*" 后,inWindow 始终判定 false,
反而比 v2 不能用。

根因:v3 scheduler 对配置数组无脑 padStart(2,'0'),把 '*' 变成 '0*'。

修复 src/services/scheduler.js:normalize 时仅对纯数字 padStart;
'*' / 'ALL' 保持原样。

测试 tests/services/scheduler.test.js:新增 "场景5:通配符不应被 padStart"
确保回归。

171 测试全绿。

发现自我们 @ 2026-05-24 19:11 在本地 dev 环境实测中。
This commit is contained in:
wangwangit
2026-05-24 19:13:06 +08:00
parent d3066dfc5e
commit a1fe2dcbf4
3 changed files with 65 additions and 1 deletions

View File

@@ -60,7 +60,15 @@ export async function checkExpiringSubscriptions(env) {
const now = getNowInTimezone(timezone);
const normalizedHours = Array.isArray(config.NOTIFICATION_HOURS)
? config.NOTIFICATION_HOURS.map((h) => String(h).padStart(2, '0'))
? config.NOTIFICATION_HOURS
.map((h) => String(h).trim())
.filter((h) => h.length > 0)
.map((h) => {
const up = h.toUpperCase();
if (up === '*' || up === 'ALL') return '*';
// 仅对纯数字做两位补齐;'*' 之类通配符保持原样
return /^\d+$/.test(h) ? h.padStart(2, '0') : up;
})
: [];
const inWindow =
normalizedHours.length === 0 ||

View File

@@ -193,6 +193,35 @@ describe('scheduler v3 - 时区 + 通知时段', () => {
expect(fetchSpy).toHaveBeenCalledTimes(1); // 只发了一次
});
it('场景5NOTIFICATION_HOURS=["*"] 通配符不应被 padStart 误处理为 "0*"', async () => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-05-24T00:00:00.000Z'));
await setConfig({
JWT_SECRET: 's',
TIMEZONE: 'Asia/Shanghai',
NOTIFICATION_HOURS: ['*'],
ENABLED_NOTIFIERS: ['telegram'],
TG_BOT_TOKEN: 'B',
TG_CHAT_ID: 'C'
});
await subRepo.save(env, {
id: 's-wc',
name: 'WC',
isActive: true,
autoRenew: false,
expiryDate: '2026-05-25T03:00:00.000Z'
});
await remindersRepo.replaceForSubscription(env, 's-wc', [
remindersRepo.normalizeRule({ type: 'before_expiry', value: 1, unit: 'days' })
]);
mockTelegramOk();
const log = await checkExpiringSubscriptions(env);
expect(log.inWindow).toBe(true);
expect(log.configuredHours).toEqual(['*']);
expect(log.sentCount).toBe(1);
});
});
describe('scheduler v3 - 自动续订', () => {

27
wrangler.dev.toml Normal file
View File

@@ -0,0 +1,27 @@
# 本地开发专用配置v3
#
# 用法npx wrangler dev --config wrangler.dev.toml
#
# 与 wrangler.toml 的差异:
# - 内联了一个 KV 命名空间假 ID让 miniflare 模拟 KV 时不再报"未绑定"
# - 不动主 wrangler.toml避免与 npm run setup 自动写入的 KV 块冲突
name = "subscription-manager-dev"
main = "src/index.js"
compatibility_date = "2024-09-23"
compatibility_flags = ["nodejs_compat"]
# 本地用的占位 KVminiflare 会自动用 .wrangler/state 下的本地 KV 文件
[[kv_namespaces]]
binding = "SUBSCRIPTIONS_KV"
id = "local-dev-kv-placeholder"
preview_id = "local-dev-kv-preview"
[assets]
directory = "./public"
binding = "ASSETS"
[triggers]
crons = ["0 * * * *"]
[vars]
ENVIRONMENT = "development"