@sproutboat/runtime 0.4.0 → 0.5.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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @sproutboat/runtime
2
2
 
3
+ ## 0.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Rate limiter (baronunread/sproutboat#69): `env.<NAME>.limit({ key })` now
8
+ returns `{ success, resetAt }`. `resetAt` is epoch milliseconds for when the
9
+ fixed window rolls and the counter clears, returned on every call (hit or
10
+ miss), so a rejection can carry an accurate `Retry-After`:
11
+ `Math.ceil((resetAt - Date.now()) / 1000)`. The `ratelimit.check` op already
12
+ had `windowStart` and `period` in hand; it just stopped discarding them.
13
+ Additive: existing callers reading only `success` are unaffected.
14
+
3
15
  ## 0.4.0
4
16
 
5
17
  ### Minor Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sproutboat/runtime",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -1106,9 +1106,11 @@ globalThis.__sbInstallBindings = function (target, bindings) {
1106
1106
  target[b.binding] = __sbMakeDONamespace(b.binding, b.className);
1107
1107
  }
1108
1108
 
1109
- // #69 — env.<NAME>.limit({ key }) -> { success }. Fixed window: at most
1110
- // `limit` calls per `period` seconds for a given key. limit/period travel in
1111
- // the message so the op stays stateless (the transport has no config).
1109
+ // #69 — env.<NAME>.limit({ key }) -> { success, resetAt }. Fixed window: at
1110
+ // most `limit` calls per `period` seconds for a given key. limit/period
1111
+ // travel in the message so the op stays stateless (the transport has no
1112
+ // config). `resetAt` is epoch ms when the window rolls and the count clears,
1113
+ // so a 429 can send `Retry-After: ceil((resetAt - Date.now()) / 1000)`.
1112
1114
  // Returns sync like the other shims (CF's is a Promise; the runtime is sync).
1113
1115
  for (let i = 0; i < (bindings.ratelimiters || []).length; i++) {
1114
1116
  const rl = bindings.ratelimiters[i];
@@ -1116,7 +1118,7 @@ globalThis.__sbInstallBindings = function (target, bindings) {
1116
1118
  limit(options) {
1117
1119
  const key = options && options.key != null ? String(options.key) : "";
1118
1120
  const r = __sbRpc("ratelimit.check", { name: rl.binding, key, limit: rl.limit, period: rl.period });
1119
- return { success: !!r.success };
1121
+ return { success: !!r.success, resetAt: Number(r.resetAt) || 0 };
1120
1122
  },
1121
1123
  };
1122
1124
  }
@@ -1539,7 +1539,7 @@ function __sbEmbeddedDispatch(msg) {
1539
1539
  [String(msg.name), String(msg.key == null ? "" : msg.key), windowStart],
1540
1540
  );
1541
1541
  const count = r.rows.length ? Number(r.rows[0][0]) : 1;
1542
- return { ok: true, success: count <= limit };
1542
+ return { ok: true, success: count <= limit, resetAt: (windowStart + period) * 1000 };
1543
1543
  }
1544
1544
 
1545
1545
  throw new Error("unknown op: " + op);