@lunora/ratelimit 1.0.0-alpha.17 → 1.0.0-alpha.18

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.d.mts CHANGED
@@ -183,6 +183,7 @@ declare class RateLimiter<Names extends string = string> {
183
183
  reset(name: Names, args?: {
184
184
  key?: string;
185
185
  }): Promise<void>;
186
+ private normalizeKey;
186
187
  private resolve;
187
188
  private run;
188
189
  }
package/dist/index.d.ts CHANGED
@@ -183,6 +183,7 @@ declare class RateLimiter<Names extends string = string> {
183
183
  reset(name: Names, args?: {
184
184
  key?: string;
185
185
  }): Promise<void>;
186
+ private normalizeKey;
186
187
  private resolve;
187
188
  private run;
188
189
  }
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{availableAt as o,evaluate as a}from"./packem_shared/availableAt-DITZ7jdT.mjs";import{default as i}from"./packem_shared/dbRateLimit-CrjZatIs.mjs";import{default as l}from"./packem_shared/RateLimitError-xJ2Iv-i7.mjs";import{rateLimit as x}from"./packem_shared/rateLimit-DLcwK-84.mjs";import{ratelimitPlugin as c}from"./packem_shared/ratelimitPlugin-D1QHZF9b.mjs";import{RateLimiter as b}from"./packem_shared/RateLimiter-uPXzD0St.mjs";import{createDbStore as u,createMemoryStore as L,createReadOnlyDbStore as n,createSqlStore as s}from"./packem_shared/createDbStore-CwJBMxDQ.mjs";const e="0.0.0";export{l as RateLimitError,b as RateLimiter,e as VERSION,o as availableAt,u as createDbStore,L as createMemoryStore,n as createReadOnlyDbStore,s as createSqlStore,i as dbRateLimit,a as evaluate,x as rateLimit,c as ratelimitPlugin};
1
+ import{availableAt as o,evaluate as a}from"./packem_shared/availableAt-BMlAt2U2.mjs";import{default as i}from"./packem_shared/dbRateLimit-e95-suu-.mjs";import{default as l}from"./packem_shared/RateLimitError-xJ2Iv-i7.mjs";import{rateLimit as x}from"./packem_shared/rateLimit-DLcwK-84.mjs";import{ratelimitPlugin as c}from"./packem_shared/ratelimitPlugin-D1QHZF9b.mjs";import{RateLimiter as b}from"./packem_shared/RateLimiter-CitqoGTI.mjs";import{createDbStore as u,createMemoryStore as L,createReadOnlyDbStore as n,createSqlStore as s}from"./packem_shared/createDbStore-CwJBMxDQ.mjs";const e="0.0.0";export{l as RateLimitError,b as RateLimiter,e as VERSION,o as availableAt,u as createDbStore,L as createMemoryStore,n as createReadOnlyDbStore,s as createSqlStore,i as dbRateLimit,a as evaluate,x as rateLimit,c as ratelimitPlugin};
@@ -0,0 +1 @@
1
+ import{LunoraError as n}from"@lunora/errors";import{availableAt as p,evaluate as N}from"./availableAt-BMlAt2U2.mjs";import w from"./RateLimitError-xJ2Iv-i7.mjs";import{createMemoryStore as g}from"./createDbStore-CwJBMxDQ.mjs";const y=(r,t)=>t===void 0?encodeURIComponent(r):`${encodeURIComponent(r)}:${encodeURIComponent(t)}`,b=(r,t)=>{let e=0;for(let i=0;i<r.length;i+=1)e=e*31+r.charCodeAt(i)|0;return Math.abs(e)%t},d=(r,t)=>t>1?{...r,capacity:(r.capacity??r.rate)/t,rate:r.rate/t}:r,I=(r,t,e)=>{const i=y(r,t);return e>1?Array.from({length:e},(o,s)=>`${i}#${String(s)}`):[i]},f=(r,t,e)=>{const i=y(r,t);return e>1?`${i}#${String(b(i,e))}`:i};class z{config;denyList;normalize;now;store;constructor(t){this.config=t.config,this.denyList=new Set(t.denyList),this.normalize=t.normalize??(e=>e),this.now=t.now??Date.now,this.store=t.store??g();for(const[e,i]of Object.entries(this.config)){if(i.shards!==void 0&&(!Number.isInteger(i.shards)||i.shards<1))throw new n("INTERNAL",`rate limit "${e}": shards must be a positive integer`);if(!Number.isFinite(i.period)||i.period<=0)throw new n("INTERNAL",`rate limit "${e}": period must be a positive number`);if(!Number.isFinite(i.rate)||i.rate<=0)throw new n("INTERNAL",`rate limit "${e}": rate must be a positive number`);if(i.capacity!==void 0&&(!Number.isFinite(i.capacity)||i.capacity<0))throw new n("INTERNAL",`rate limit "${e}": capacity must be a non-negative number`)}}async check(t,e={}){return this.run(t,e,!1)}async getValue(t,e={}){const i=this.resolve(t),o=i.shards??1,s=this.now(),a=this.normalizeKey(e.key),m=f(t,a,o),c=p(d(i,o),await this.store.get(m),s);return{config:i,ts:c.ts,value:c.value}}async limit(t,e={}){return this.run(t,e,!0)}async reset(t,e={}){const i=this.resolve(t).shards??1,o=this.normalizeKey(e.key);await Promise.all(I(t,o,i).map(s=>Promise.resolve(this.store.delete(s))))}normalizeKey(t){return t===void 0?void 0:this.normalize(t)}resolve(t){const e=this.config[t];if(!e)throw new n("INTERNAL",`rate limit "${t}" is not configured`);return e}async run(t,e,i){const o=this.resolve(t),s=this.normalizeKey(e.key);if(s!==void 0&&(this.denyList.has(s)||this.denyList.has(e.key))){const l={ok:!1,reason:"deny",retryAfter:Number.POSITIVE_INFINITY};if(e.throws)throw new w(l);return l}const a=e.count??1;if(!Number.isInteger(a)||a<=0)throw new n("INTERNAL",`rate limit "${t}": count must be a positive integer`);const m=o.shards??1,c=f(t,s,m),v=await this.store.get(c),{status:h,value:u}=N(d(o,m),v,{consume:i,count:a,now:this.now(),reserve:e.reserve??!1});if(u!==void 0&&await this.store.set(c,u),!h.ok&&e.throws)throw new w(h);return h}}export{z as RateLimiter};
@@ -0,0 +1 @@
1
+ import{LunoraError as M}from"@lunora/errors";const l=r=>r.capacity??r.rate,v=(r,e)=>{throw new M("INTERNAL",`@lunora/ratelimit: requested count ${String(r)} exceeds the limiter capacity ${String(e)}`)},f=(r,e,t)=>{const o=l(r),u=r.rate/r.period,n=e??{ts:t,value:o},a=Math.max(0,t-n.ts);return{available:Math.min(o,n.value+a*u),capacity:o,ratePerMs:u}},w=(r,e,t)=>{const o=r.start??0,u=o+Math.floor((t-o)/r.period)*r.period;if(!e||e.ts<u){let n=0;return e&&(e.value<0||r.capacity!==void 0)&&(n=e.value),{ts:u,value:Math.min(l(r),n+r.rate)}}return{ts:e.ts,value:e.value}},k=(r,e,t)=>{const o=r.start??0,u=o+Math.floor((t-o)/r.period)*r.period,n=t-u,a=(r.period-n)/r.period;let s=0,i=0;return e?.ts===u?(s=e.prev??0,i=e.value):e?.ts===u-r.period&&(s=e.value),{currentCount:i,elapsed:n,previousCount:s,weight:a,windowStart:u}},A=(r,e,t)=>{const{available:o,capacity:u,ratePerMs:n}=f(r,e,t.now);if(o>=t.count){const i={ts:t.now,value:o-t.count};return{status:{ok:!0,retryAfter:0},value:t.consume?i:void 0}}const a=t.count-o,s=Math.ceil(a/n);return t.consume&&t.reserve&&t.count<=u?{status:{ok:!0,retryAfter:s},value:{ts:t.now,value:o-t.count}}:(t.count>u&&v(t.count,u),{status:{ok:!1,reason:"rate",retryAfter:s},value:void 0})},b=(r,e,t)=>{const o=l(r),u=w(r,e,t.now);if(u.value>=t.count){const a={ts:u.ts,value:u.value-t.count};return{status:{ok:!0,retryAfter:0},value:t.consume?a:void 0}}const n=u.ts+r.period-t.now;return t.consume&&t.reserve&&t.count<=o?{status:{ok:!0,retryAfter:n},value:{ts:u.ts,value:u.value-t.count}}:(t.count>o&&v(t.count,o),{status:{ok:!1,reason:"rate",retryAfter:n},value:void 0})},g=(r,e,t)=>{const o=r.rate,{period:u}=r,{currentCount:n,elapsed:a,previousCount:s,weight:i,windowStart:h}=k(r,e,t.now),d=s*i+n+t.count<=o,p=()=>{const c=o-n-t.count;if(s>0&&c>=0)return Math.ceil(u-a-c*u/s);const m=o-t.count,y=n>0?Math.max(0,u-m*u/n):0;return Math.ceil(u-a+y)};if(d||t.consume&&t.reserve&&t.count<=o){const c={prev:s,ts:h,value:n+t.count};return{status:{ok:!0,retryAfter:d?0:p()},value:t.consume?c:void 0}}return t.count>o&&v(t.count,o),{status:{ok:!1,reason:"rate",retryAfter:p()},value:void 0}},x=(r,e,t)=>{if(r.kind==="token bucket")return{ts:t,value:f(r,e,t).available};if(r.kind==="sliding window"){const{currentCount:o,previousCount:u,weight:n,windowStart:a}=k(r,e,t);return{ts:a,value:Math.max(0,r.rate-(u*n+o))}}return w(r,e,t)},S=(r,e,t)=>r.kind==="token bucket"?A(r,e,t):r.kind==="sliding window"?g(r,e,t):b(r,e,t);export{x as availableAt,S as evaluate};
@@ -1 +1 @@
1
- import{rateLimit as a}from"./rateLimit-DLcwK-84.mjs";import{RateLimiter as i}from"./RateLimiter-uPXzD0St.mjs";import{createDbStore as m}from"./createDbStore-CwJBMxDQ.mjs";const p=(t,o,r={})=>a(e=>new i({config:t,store:m({db:e.db,...r.store})}),o,r);export{p as default};
1
+ import{rateLimit as a}from"./rateLimit-DLcwK-84.mjs";import{RateLimiter as i}from"./RateLimiter-CitqoGTI.mjs";import{createDbStore as m}from"./createDbStore-CwJBMxDQ.mjs";const p=(t,o,r={})=>a(e=>new i({config:t,store:m({db:e.db,...r.store})}),o,r);export{p as default};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/ratelimit",
3
- "version": "1.0.0-alpha.17",
3
+ "version": "1.0.0-alpha.18",
4
4
  "description": "Rate limiting: token-bucket / fixed-window / sliding-window algorithms, deny list, sharding, pluggable stores, and procedure middleware",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -46,7 +46,7 @@
46
46
  "access": "public"
47
47
  },
48
48
  "dependencies": {
49
- "@lunora/errors": "1.0.0-alpha.14"
49
+ "@lunora/errors": "1.0.0-alpha.15"
50
50
  },
51
51
  "engines": {
52
52
  "node": "^22.15.0 || >=24.11.0"
@@ -1 +0,0 @@
1
- import{LunoraError as n}from"@lunora/errors";import{availableAt as p,evaluate as N}from"./availableAt-DITZ7jdT.mjs";import d from"./RateLimitError-xJ2Iv-i7.mjs";import{createMemoryStore as g}from"./createDbStore-CwJBMxDQ.mjs";const v=(r,t)=>t===void 0?encodeURIComponent(r):`${encodeURIComponent(r)}:${encodeURIComponent(t)}`,b=(r,t)=>{let e=0;for(let i=0;i<r.length;i+=1)e=e*31+r.charCodeAt(i)|0;return Math.abs(e)%t},w=(r,t)=>t>1?{...r,capacity:(r.capacity??r.rate)/t,rate:r.rate/t}:r,I=(r,t,e)=>{const i=v(r,t);return e>1?Array.from({length:e},(o,s)=>`${i}#${String(s)}`):[i]},f=(r,t,e)=>{const i=v(r,t);return e>1?`${i}#${String(b(i,e))}`:i};class R{config;denyList;normalize;now;store;constructor(t){this.config=t.config,this.denyList=new Set(t.denyList),this.normalize=t.normalize??(e=>e),this.now=t.now??Date.now,this.store=t.store??g();for(const[e,i]of Object.entries(this.config)){if(i.shards!==void 0&&(!Number.isInteger(i.shards)||i.shards<1))throw new n("INTERNAL",`rate limit "${e}": shards must be a positive integer`);if(!Number.isFinite(i.period)||i.period<=0)throw new n("INTERNAL",`rate limit "${e}": period must be a positive number`);if(!Number.isFinite(i.rate)||i.rate<=0)throw new n("INTERNAL",`rate limit "${e}": rate must be a positive number`);if(i.capacity!==void 0&&(!Number.isFinite(i.capacity)||i.capacity<0))throw new n("INTERNAL",`rate limit "${e}": capacity must be a non-negative number`)}}async check(t,e={}){return this.run(t,e,!1)}async getValue(t,e={}){const i=this.resolve(t),o=i.shards??1,s=this.now(),a=e.key===void 0?void 0:this.normalize(e.key),m=f(t,a,o),c=p(w(i,o),await this.store.get(m),s);return{config:i,ts:c.ts,value:c.value}}async limit(t,e={}){return this.run(t,e,!0)}async reset(t,e={}){const i=this.resolve(t).shards??1,o=e.key===void 0?void 0:this.normalize(e.key);await Promise.all(I(t,o,i).map(s=>Promise.resolve(this.store.delete(s))))}resolve(t){const e=this.config[t];if(!e)throw new n("INTERNAL",`rate limit "${t}" is not configured`);return e}async run(t,e,i){const o=this.resolve(t),s=e.key===void 0?void 0:this.normalize(e.key);if(s!==void 0&&(this.denyList.has(s)||this.denyList.has(e.key))){const l={ok:!1,reason:"deny",retryAfter:Number.POSITIVE_INFINITY};if(e.throws)throw new d(l);return l}const a=e.count??1;if(!Number.isInteger(a)||a<=0)throw new n("INTERNAL",`rate limit "${t}": count must be a positive integer`);const m=o.shards??1,c=f(t,s,m),y=await this.store.get(c),{status:h,value:u}=N(w(o,m),y,{consume:i,count:a,now:this.now(),reserve:e.reserve??!1});if(u!==void 0&&await this.store.set(c,u),!h.ok&&e.throws)throw new d(h);return h}}export{R as RateLimiter};
@@ -1 +0,0 @@
1
- import{LunoraError as l}from"@lunora/errors";const v=r=>r.capacity??r.rate,p=(r,e,t)=>{const n=v(r),u=r.rate/r.period,o=e??{ts:t,value:n},a=Math.max(0,t-o.ts);return{available:Math.min(n,o.value+a*u),capacity:n,ratePerMs:u}},w=(r,e,t)=>{const n=r.start??0,u=n+Math.floor((t-n)/r.period)*r.period;if(!e||e.ts<u){let o=0;return e&&(e.value<0||r.capacity!==void 0)&&(o=e.value),{ts:u,value:Math.min(v(r),o+r.rate)}}return{ts:e.ts,value:e.value}},h=(r,e,t)=>{const n=r.start??0,u=n+Math.floor((t-n)/r.period)*r.period,o=t-u,a=(r.period-o)/r.period;let i=0,s=0;return e?.ts===u?(i=e.prev??0,s=e.value):e?.ts===u-r.period&&(i=e.value),{currentCount:s,elapsed:o,previousCount:i,weight:a,windowStart:u}},A=(r,e,t)=>{const{available:n,capacity:u,ratePerMs:o}=p(r,e,t.now);if(n>=t.count){const s={ts:t.now,value:n-t.count};return{status:{ok:!0,retryAfter:0},value:t.consume?s:void 0}}const a=t.count-n,i=Math.ceil(a/o);if(t.consume&&t.reserve&&t.count<=u)return{status:{ok:!0,retryAfter:i},value:{ts:t.now,value:n-t.count}};if(t.count>u)throw new l("INTERNAL",`@lunora/ratelimit: requested count ${String(t.count)} exceeds the limiter capacity ${String(u)}`);return{status:{ok:!1,reason:"rate",retryAfter:i},value:void 0}},M=(r,e,t)=>{const n=v(r),u=w(r,e,t.now);if(u.value>=t.count){const a={ts:u.ts,value:u.value-t.count};return{status:{ok:!0,retryAfter:0},value:t.consume?a:void 0}}const o=u.ts+r.period-t.now;if(t.consume&&t.reserve&&t.count<=n)return{status:{ok:!0,retryAfter:o},value:{ts:u.ts,value:u.value-t.count}};if(t.count>n)throw new l("INTERNAL",`@lunora/ratelimit: requested count ${String(t.count)} exceeds the limiter capacity ${String(n)}`);return{status:{ok:!1,reason:"rate",retryAfter:o},value:void 0}},g=(r,e,t)=>{const n=r.rate,{period:u}=r,{currentCount:o,elapsed:a,previousCount:i,weight:s,windowStart:m}=h(r,e,t.now),d=i*s+o+t.count<=n,f=()=>{const c=n-o-t.count;if(i>0&&c>=0)return Math.ceil(u-a-c*u/i);const k=n-t.count,y=o>0?Math.max(0,u-k*u/o):0;return Math.ceil(u-a+y)};if(d||t.consume&&t.reserve&&t.count<=n){const c={prev:i,ts:m,value:o+t.count};return{status:{ok:!0,retryAfter:d?0:f()},value:t.consume?c:void 0}}if(t.count>n)throw new l("INTERNAL",`@lunora/ratelimit: requested count ${String(t.count)} exceeds the limiter capacity ${String(n)}`);return{status:{ok:!1,reason:"rate",retryAfter:f()},value:void 0}},b=(r,e,t)=>{if(r.kind==="token bucket")return{ts:t,value:p(r,e,t).available};if(r.kind==="sliding window"){const{currentCount:n,previousCount:u,weight:o,windowStart:a}=h(r,e,t);return{ts:a,value:Math.max(0,r.rate-(u*o+n))}}return w(r,e,t)},x=(r,e,t)=>r.kind==="token bucket"?A(r,e,t):r.kind==="sliding window"?g(r,e,t):M(r,e,t);export{b as availableAt,x as evaluate};