1- import SCRIPT_RATELIMIT_OBJECT from "worker:ratelimit/ratelimit" ;
1+ import SCRIPT_RATELIMIT_CLIENT from "worker:ratelimit/ratelimit" ;
2+ import SCRIPT_RATELIMIT_OBJECT from "worker:ratelimit/ratelimit-object" ;
23import { z } from "zod" ;
3- import { ProxyNodeBinding } from "../shared" ;
4- import type { Worker_Binding } from "../../runtime" ;
4+ import { kVoid } from "../../runtime" ;
5+ import { SharedBindings } from "../../workers" ;
6+ import {
7+ getMiniflareObjectBindings ,
8+ getUserBindingServiceName ,
9+ objectEntryWorker ,
10+ ProxyNodeBinding ,
11+ SERVICE_LOOPBACK ,
12+ } from "../shared" ;
13+ import type {
14+ Service ,
15+ Worker_Binding ,
16+ Worker_Binding_DurableObjectNamespaceDesignator ,
17+ } from "../../runtime" ;
518import type { Plugin } from "../shared" ;
619
720export enum PeriodType {
@@ -14,7 +27,7 @@ export const RatelimitConfigSchema = z.object({
1427 limit : z . number ( ) . gt ( 0 ) ,
1528
1629 // may relax this to be any number in the future
17- period : z . nativeEnum ( PeriodType ) . optional ( ) ,
30+ period : z . nativeEnum ( PeriodType ) . optional ( ) . default ( PeriodType . MINUTE ) ,
1831 } ) ,
1932} ) ;
2033export const RatelimitOptionsSchema = z . object ( {
@@ -24,6 +37,12 @@ export const RatelimitOptionsSchema = z.object({
2437export const RATELIMIT_PLUGIN_NAME = "ratelimit" ;
2538const SERVICE_RATELIMIT_PREFIX = `${ RATELIMIT_PLUGIN_NAME } ` ;
2639const SERVICE_RATELIMIT_MODULE = `cloudflare-internal:${ SERVICE_RATELIMIT_PREFIX } :module` ;
40+ const RATELIMIT_ENTRY_SERVICE_PREFIX = `${ RATELIMIT_PLUGIN_NAME } :ns` ;
41+ const RATELIMIT_OBJECT_CLASS_NAME = "RateLimiterObject" ;
42+ const RATELIMIT_OBJECT : Worker_Binding_DurableObjectNamespaceDesignator = {
43+ serviceName : RATELIMIT_ENTRY_SERVICE_PREFIX ,
44+ className : RATELIMIT_OBJECT_CLASS_NAME ,
45+ } ;
2746
2847function buildJsonBindings ( bindings : Record < string , any > ) : Worker_Binding [ ] {
2948 return Object . entries ( bindings ) . map ( ( [ name , value ] ) => ( {
@@ -44,11 +63,21 @@ export const RATELIMIT_PLUGIN: Plugin<typeof RatelimitOptionsSchema> = {
4463 name,
4564 wrapped : {
4665 moduleName : SERVICE_RATELIMIT_MODULE ,
47- innerBindings : buildJsonBindings ( {
48- namespaceId : name ,
49- limit : config . simple . limit ,
50- period : config . simple . period ,
51- } ) ,
66+ innerBindings : [
67+ {
68+ name : "fetcher" ,
69+ service : {
70+ name : getUserBindingServiceName (
71+ RATELIMIT_ENTRY_SERVICE_PREFIX ,
72+ name
73+ ) ,
74+ } ,
75+ } ,
76+ ...buildJsonBindings ( {
77+ limit : config . simple . limit ,
78+ period : config . simple . period ,
79+ } ) ,
80+ ] ,
5281 } ,
5382 } )
5483 ) ;
@@ -65,8 +94,46 @@ export const RATELIMIT_PLUGIN: Plugin<typeof RatelimitOptionsSchema> = {
6594 ] )
6695 ) ;
6796 } ,
68- async getServices ( ) {
69- return [ ] ;
97+ async getServices ( { options, unsafeStickyBlobs } ) {
98+ if ( ! options . ratelimits ) {
99+ return [ ] ;
100+ }
101+ const names = Object . keys ( options . ratelimits ) ;
102+ const services = names . map < Service > ( ( name ) => ( {
103+ name : getUserBindingServiceName ( RATELIMIT_ENTRY_SERVICE_PREFIX , name ) ,
104+ worker : objectEntryWorker ( RATELIMIT_OBJECT , name ) ,
105+ } ) ) ;
106+
107+ const uniqueKey = `miniflare-${ RATELIMIT_OBJECT_CLASS_NAME } ` ;
108+ services . push ( {
109+ name : RATELIMIT_ENTRY_SERVICE_PREFIX ,
110+ worker : {
111+ compatibilityDate : "2023-07-24" ,
112+ compatibilityFlags : [ "nodejs_compat" , "experimental" ] ,
113+ modules : [
114+ {
115+ name : "ratelimit-object.worker.js" ,
116+ esModule : SCRIPT_RATELIMIT_OBJECT ( ) ,
117+ } ,
118+ ] ,
119+ durableObjectNamespaces : [
120+ { className : RATELIMIT_OBJECT_CLASS_NAME , uniqueKey } ,
121+ ] ,
122+ // Counters are only ever needed for the lifetime of the Miniflare
123+ // process, never persisted across restarts (matching the previous
124+ // purely in-memory implementation).
125+ durableObjectStorage : { inMemory : kVoid } ,
126+ bindings : [
127+ {
128+ name : SharedBindings . MAYBE_SERVICE_LOOPBACK ,
129+ service : { name : SERVICE_LOOPBACK } ,
130+ } ,
131+ ...getMiniflareObjectBindings ( unsafeStickyBlobs ) ,
132+ ] ,
133+ } ,
134+ } ) ;
135+
136+ return services ;
70137 } ,
71138 getExtensions ( { options } ) {
72139 if ( ! options . some ( ( o ) => o . ratelimits ) ) {
@@ -77,7 +144,7 @@ export const RATELIMIT_PLUGIN: Plugin<typeof RatelimitOptionsSchema> = {
77144 modules : [
78145 {
79146 name : SERVICE_RATELIMIT_MODULE ,
80- esModule : SCRIPT_RATELIMIT_OBJECT ( ) ,
147+ esModule : SCRIPT_RATELIMIT_CLIENT ( ) ,
81148 internal : true ,
82149 } ,
83150 ] ,
0 commit comments