npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dsh-whale-post-gate

v0.6.1

Published

配额与计费闸 + 回环闸(示例②的挂点) · Quota and billing gate + loop gate (example (2)'s socket)

Readme

dsh-whale-post-gate

English: gate README in English

配额与计费闸 + 回环闸(可换的挂点 —— 示例②)

  • 提供接口:whale.gate
  • 依赖接口:whale.types(可选)、whale.roster(可选,用于把"一个组"算成 1 单位)
  • 自测:node selftest.mjs(只看退出码:0 过/非 0 不过)

接口带 apiVersion;核心不认识任何成员名与类型标识 —— 名单与类型一律从接口取。

三道闸 + 配额(每道都写明为什么)

离线件豁免整套回环闸(2026-10-10 按设计文档移植;设计文档判据 29-31 +「今天的设计目标是 2026-10-06」): 三道闸拦的都是"别多叫醒人一次" —— 而离线件根本不叫醒任何人(它躺着等对方来收) ⇒ 拦它没有任何收益,只会把"想说的话"堵在发信人手里。 这正是"信只会晚到,不会不到":"闸"该拦的是代价**,不是表达。 ⚠️ 豁免的只是回环闸 —— 配额照旧(离线桶独立计);在线件一切照旧。

| # | 闸 | 拦什么 | |---|---|---| | ① | 纯回执拒发 | 正文去掉空白标点后只剩"收到/好的/谢谢" ⇒ 拒发(回执本该由收信方自动写 ack) | | ② | 同对回环闸 | 同一对(你→对方)在 pairWindowMs 内已发 pairMax 封 ⇒ 拒发,先合并成一封 | | ③ | 链深闸 | 带 re 的信按父信 hop 递推,到 hopMax 跳 ⇒ 拒发(链条必须落地成结论) | | ④ | 配额 | 分桶计额度;离线件独立计(按发信次数,1 次=1 条,组发不翻倍) | | ⑤ | 在线件小日上限(S8) | "手机"这类成员:每封在线件 = 叫醒它做一次满上下文推理(最贵的一步)⇒ 按 min(自报, 天花板) 拦;离线件不受这条限;--force 不豁免 |

接口

| 方法 | 一句话 | |---|---| | check(letter, ctx) | 拦不拦:'pass'/{ reject, reason } | | record(letter, targets) | 投递成功后才记账(被拦下的信不占额度) | | report({ as, days }) | 查账(只读) | | cfg/localDay()/quotaUnits() | 生效配置/日界/"这封算几个单位" |

配置

| 字段 | 默认 | 含义 | |---|---|---| | quota.onOver | 'reject' | 'reject' 拒发(退出码非 0、不落信箱)/'price' 照发但计费("闸是价格闸,不是封嘴闸") | | quota.dayBoundaryHour | 0 | 日界:0 = 自然日;写 9 = 早九点到次日早九点算一天 | | quota.types | direct 120/broadcast 45/club 60/offline 80 | 每桶 limit;离线桶可 perSend: true(按发信次数计) | | quota.defaultLimit | 120 | 没在表里的类型落这个桶(否则"注册一个新类型"在闸这层就不成立) | | quota.bucketRules | 不配 | 分桶规则(数组):[{ field, equals, bucket }] —— 从上往下第一个命中的赢;equals 不写 ⇒ "该字段有值就命中"。字段名与桶名全由配置给(本件里不出现任何具体名字)。不配 ⇒ 行为一字不变(离线走 offline、其余按 type) | | now(顶层) | 不配 | 时钟可注入:给一个有限数字(钉死时刻)或函数(() => ms)⇒ 台账的"哪一天"按它算(不配 ⇒ 真时间)。为什么要它:"生效时刻"这类规则("09:00 前按旧口径、到点后才分桶")必须能拿假时间测 —— 原来处处裸 Date.now() ⇒ 测不了 | | quota.defaultBucket | 不配 | 一条规则都没命中时落哪个桶(配了 bucketRules 才有意义 —— 必须有,否则"带新字段的信"会掉回 type 桶) | | quota.phoneFlag | 不配 | 谁是"手机"(属性名由配置给 —— 本件不认识任何具体名字):带此属性的收件人只算在线件的小日上限。不配 ⇒ 这道闸完全不启用 | | quota.phoneOnlineCap | 3 | 天花板:实际额度 = min(收件人自报的 onlineCapPerDay, 这个) —— "收件习惯由它自己声明,而声明只能更保守"(它能把上限调到 1,调不到天花板之上)。没自报 ⇒ 用天花板("没说" ≠ "可以一直叫醒它") | | loop.ackMaxBytes | 40 | 多长的正文才可能被当回执 | | loop.ackOnly | 中英回执词 | 中英都认(只认中文 ⇒ 英文回执成了绕过闸的后门) | | loop.pairWindowMs | 20 分钟 | 同对回环的时间窗 | | loop.pairMax | 3 | 同一对在这个窗内最多发几封 | | loop.hopMax | 3 | 链深上限 |

边界(两条老实话,免得下一个人把它当安全边界)

  • 链深闸不是安全边界 —— 它依赖回信人老实带 re,不带就重置。它是礼貌闸/省米闸。
  • --force 会整条绕过这三道闸(这是有意留的逃生门),但留痕:台账当日记 forced 计数。
  • 剔完组里没人 ⇒ 拒发(配额按组算时会遇到 —— 宁可拒发,也不发一封没有收件人的信)。

换掉它

想换一套计费口径(比如按字节计费、或者干脆不限额)⇒ 只换这一件, 核心与别的插件一行都不用动(它们只认 check/record/report/recount 这四个)。

对账(台账可以"验",不只是"信")

台账是基线 + 增量小文件,口径是「账可少不可多」(崩了可能漏记 ⇒ 对发信人有利,绝不双记)。 recount 是给"验"用的那一半:从文件系统重算一份按天的账,跟台账逐日逐桶比。 命令在 cli 里 —— whale-post reconcile --as <谁> [--days N] [--remote <根>] (用法见 packages/cli/README):一致 ⇒ 退出 0;有差 ⇒ 退出 3。

⚠️ 它能算的:letters/units/bytes/byBucket.<桶>.{letters, units}; 不能算的(文件里没有那些事实,命令会照实列出来):forced(force 是发送那一刻的选择)、 over/feeCent(取决于记账当时读到的已用量)、byPhone/recent(记账时属性与收据)。