• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

supabase / edge-runtime / 22624253961

03 Mar 2026 01:03PM UTC coverage: 53.14% (+0.8%) from 52.383%
22624253961

push

github

web-flow
feat: add request-local rate limiter (#670)

* feat: add request-local rate limiter

* chore: update `global.d.ts`

* stamp: apply suggestion 2

* stamp: abort check first

* stamp: 🤨

132 of 167 new or added lines in 8 files covered. (79.04%)

42 existing lines in 3 files now uncovered.

19327 of 36370 relevant lines covered (53.14%)

7320.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/cli/src/flags.rs
1
use std::net::SocketAddr;
2
use std::path::PathBuf;
3

4
use clap::arg;
5
use clap::builder::BoolishValueParser;
6
use clap::builder::FalseyValueParser;
7
use clap::builder::TypedValueParser;
8
use clap::crate_version;
9
use clap::value_parser;
10
use clap::ArgAction;
11
use clap::ArgGroup;
12
use clap::Command;
13
use clap::ValueEnum;
14
use deno::deno_telemetry;
15
use deno_facade::Checksum;
16

17
#[derive(ValueEnum, Default, Clone, Copy)]
18
#[repr(u8)]
19
pub(super) enum EszipV2ChecksumKind {
20
  #[default]
21
  NoChecksum = 0,
22
  Sha256 = 1,
23
  XxHash3 = 2,
24
}
25

26
impl From<EszipV2ChecksumKind> for Option<Checksum> {
27
  fn from(value: EszipV2ChecksumKind) -> Self {
×
28
    Checksum::from_u8(value as u8)
×
29
  }
×
30
}
31

32
#[derive(ValueEnum, Clone, Copy)]
33
pub(super) enum OtelKind {
34
  Main,
35
  Event,
36
}
37

38
#[derive(ValueEnum, Default, Clone, Copy)]
39
pub(super) enum OtelConsoleConfig {
40
  #[default]
41
  Ignore,
42
  Capture,
43
  Replace,
44
}
45

46
impl From<OtelConsoleConfig> for deno_telemetry::OtelConsoleConfig {
47
  fn from(value: OtelConsoleConfig) -> Self {
×
48
    match value {
×
49
      OtelConsoleConfig::Ignore => Self::Ignore,
×
50
      OtelConsoleConfig::Capture => Self::Capture,
×
51
      OtelConsoleConfig::Replace => Self::Replace,
×
52
    }
53
  }
×
54
}
55

56
pub(super) fn get_cli() -> Command {
×
57
  Command::new(env!("CARGO_BIN_NAME"))
×
58
    .about(env!("CARGO_PKG_DESCRIPTION"))
×
59
    .version(format!(
×
60
      "{}\ndeno {} ({}, {})",
×
61
      crate_version!(),
×
62
      deno::version(),
×
63
      env!("PROFILE"),
×
64
      env!("TARGET")
×
65
    ))
×
66
    .arg_required_else_help(true)
×
67
    .arg(
×
68
      arg!(-v --verbose "Use verbose output")
×
69
        .conflicts_with("quiet")
×
70
        .global(true)
×
71
        .action(ArgAction::SetTrue),
×
72
    )
×
73
    .arg(
×
74
      arg!(-q --quiet "Do not print any log messages")
×
75
        .conflicts_with("verbose")
×
76
        .global(true)
×
77
        .action(ArgAction::SetTrue),
×
78
    )
×
79
    .arg(
×
80
      arg!(--"log-source")
×
81
        .help("Include source file and line in log messages")
×
82
        .global(true)
×
83
        .action(ArgAction::SetTrue),
×
84
    )
×
85
    .subcommand(get_start_command())
×
86
    .subcommand(get_bundle_command())
×
87
    .subcommand(get_unbundle_command())
×
88
}
×
89

90
fn get_start_command() -> Command {
×
91
  Command::new("start")
×
92
    .about("Start the server")
×
93
    .arg(
×
94
      arg!(-i --ip <HOST>)
×
95
        .help("Host IP address to listen on")
×
96
        .default_value("0.0.0.0"),
×
97
    )
×
98
    .arg(
×
99
      arg!(-p --port <PORT>)
×
100
        .help("Port to listen on")
×
101
        .env("EDGE_RUNTIME_PORT")
×
102
        .default_value("9000")
×
103
        .value_parser(value_parser!(u16)),
×
104
    )
×
105
    .arg(
×
106
      arg!(--tls[PORT])
×
107
        .env("EDGE_RUNTIME_TLS")
×
108
        .num_args(0..=1)
×
109
        .default_missing_value("443")
×
110
        .value_parser(value_parser!(u16))
×
111
        .requires("key")
×
112
        .requires("cert"),
×
113
    )
×
114
    .arg(
×
115
      arg!(--key <Path>)
×
116
        .help("Path to PEM-encoded key to be used to TLS")
×
117
        .env("EDGE_RUNTIME_TLS_KEY_PATH")
×
118
        .value_parser(value_parser!(PathBuf)),
×
119
    )
×
120
    .arg(
×
121
      arg!(--cert <Path>)
×
122
        .help("Path to PEM-encoded X.509 certificate to be used to TLS")
×
123
        .env("EDGE_RUNTIME_TLS_CERT_PATH")
×
124
        .value_parser(value_parser!(PathBuf)),
×
125
    )
×
126
    .arg(
×
127
      arg!(--"main-service" <DIR>)
×
128
        .help("Path to main service directory or eszip")
×
129
        .default_value("examples/main"),
×
130
    )
×
131
    .arg(
×
132
      arg!(--"disable-module-cache")
×
133
        .help("Disable using module cache")
×
134
        .default_value("false")
×
135
        .value_parser(FalseyValueParser::new()),
×
136
    )
×
137
    .arg(arg!(--"event-worker" <Path>).help("Path to event worker directory"))
×
138
    .arg(
×
139
      arg!(--"main-entrypoint" <Path>)
×
140
        .help("Path to entrypoint in main service (only for eszips)"),
×
141
    )
×
142
    .arg(
×
143
      arg!(--"events-entrypoint" <Path>)
×
144
        .help("Path to entrypoint in events worker (only for eszips)"),
×
145
    )
×
146
    .arg(
×
147
      arg!(--"policy" <POLICY>)
×
148
        .help("Policy to enforce in the worker pool")
×
149
        .default_value("per_worker")
×
150
        .value_parser(["per_worker", "per_request", "oneshot"]),
×
151
    )
×
152
    .arg(
×
153
      arg!(--"graceful-exit-timeout"[SECONDS])
×
154
        .help(concat!(
×
155
          "Maximum time in seconds that can wait for workers before ",
×
156
          "terminating forcibly. If providing zero value, the runtime will ",
×
157
          "not try a graceful exit."
×
158
        ))
×
159
        // NOTE(Nyannyacha): Default timeout value follows the
×
160
        // value[1] defined in moby.
×
161
        //
×
162
        // [1]: https://github.com/moby/moby/blob/master/daemon/config/config.go#L45-L47
×
163
        .default_value("15")
×
164
        .value_parser(value_parser!(u64).range(..u64::MAX)),
×
165
    )
×
166
    .arg(
×
167
      arg!(--"event-worker-exit-timeout"[SECONDS])
×
168
        .help(concat!(
×
169
          "Maximum time in seconds that can wait for the event worker before ",
×
170
          "terminating forcibly. (graceful exit)"
×
171
        ))
×
172
        .default_value("10")
×
173
        .value_parser(value_parser!(u64).range(..u64::MAX)),
×
174
    )
×
175
    .arg(
×
176
      arg!(
×
177
        --"experimental-graceful-exit-keepalive-deadline-ratio"
×
178
        <PERCENTAGE>
179
      )
180
      .help(concat!(
×
181
        "(Experimental) Maximum period of time that incoming requests ",
×
182
        "can be processed over a pre-established keep-alive HTTP connection. ",
×
183
        "This is specified as a percentage of the `--graceful-exit-timeout` ",
×
184
        "value. The percentage cannot be greater than 95."
×
185
      ))
×
186
      .value_parser(value_parser!(u64).range(..=95)),
×
187
    )
×
188
    .arg(
×
189
      arg!(--"max-parallelism" <COUNT>)
×
190
        .help(concat!(
×
191
          "Maximum count of workers that can exist in the worker pool ",
×
192
          "simultaneously"
×
193
        ))
×
194
        .value_parser(
×
195
          // NOTE: Acceptable bounds were chosen arbitrarily.
×
196
          value_parser!(u32)
×
197
            .range(1..9999)
×
198
            .map(|it| -> usize { it as usize }),
×
199
        ),
×
200
    )
×
201
    .arg(
×
202
      arg!(--"request-wait-timeout" <MILLISECONDS>)
×
203
        .help(concat!(
×
204
          "Maximum time in milliseconds that can wait to establish a ",
×
205
          "connection with a worker"
×
206
        ))
×
207
        .default_value("10000")
×
208
        .value_parser(value_parser!(u64)),
×
209
    )
×
210
    .arg(
×
211
      arg!(--"main-worker-request-idle-timeout" <MILLISECONDS>)
×
212
        .help(concat!(
×
213
          "Maximum time in milliseconds that can be waited from when a ",
×
214
          "worker takes over the request (disabled by default)"
×
215
        ))
×
216
        .value_parser(value_parser!(u64)),
×
217
    )
×
218
    .arg(
×
219
      arg!(--"user-worker-request-idle-timeout" <MILLISECONDS>)
×
220
        .help(concat!(
×
221
          "Maximum time in milliseconds that can be waited from when a ",
×
222
          "worker takes over the request (disabled by default)"
×
223
        ))
×
224
        .value_parser(value_parser!(u64)),
×
225
    )
×
226
    .arg(
×
227
      arg!(--"request-read-timeout" <MILLISECONDS>)
×
228
        .help(concat!(
×
229
          "Maximum time in milliseconds that can be waited from when the ",
×
230
          "connection is accepted until the request body is fully read ",
×
231
          "(disabled by default)"
×
232
        ))
×
233
        .value_parser(value_parser!(u64)),
×
234
    )
×
NEW
235
    .arg(
×
NEW
236
      arg!(--"rate-limit-table-cleanup-interval" <SECONDS>)
×
NEW
237
        .help(concat!(
×
NEW
238
          "Interval in seconds between sweeps of the outbound rate-limit ",
×
NEW
239
          "table to remove expired entries (default: 60)"
×
NEW
240
        ))
×
NEW
241
        .default_value("60")
×
NEW
242
        .value_parser(value_parser!(u64)),
×
NEW
243
    )
×
244
    .arg(
×
245
      arg!(--"inspect"[HOST_AND_PORT])
×
246
        .help("Activate inspector on host:port")
×
247
        .num_args(0..=1)
×
248
        .value_parser(value_parser!(SocketAddr))
×
249
        .require_equals(true)
×
250
        .default_missing_value("127.0.0.1:9229"),
×
251
    )
×
252
    .arg(
×
253
      arg!(--"inspect-brk"[HOST_AND_PORT])
×
254
        .help(concat!(
×
255
          "Activate inspector on host:port, wait for debugger to connect ",
×
256
          "and break at the start of user script"
×
257
        ))
×
258
        .num_args(0..=1)
×
259
        .value_parser(value_parser!(SocketAddr))
×
260
        .require_equals(true)
×
261
        .default_missing_value("127.0.0.1:9229"),
×
262
    )
×
263
    .arg(
×
264
      arg!(--"inspect-wait"[HOST_AND_PORT])
×
265
        .help(concat!(
×
266
          "Activate inspector on host:port and wait for debugger to ",
×
267
          "connect before running user code"
×
268
        ))
×
269
        .num_args(0..=1)
×
270
        .value_parser(value_parser!(SocketAddr))
×
271
        .require_equals(true)
×
272
        .default_missing_value("127.0.0.1:9229"),
×
273
    )
×
274
    .group(ArgGroup::new("inspector").args([
×
275
      "inspect",
×
276
      "inspect-brk",
×
277
      "inspect-wait",
×
278
    ]))
×
279
    .arg(
×
280
      arg!(--"inspect-main")
×
281
        .help("Allow creating inspector for main worker")
×
282
        .requires("inspector")
×
283
        .action(ArgAction::SetTrue),
×
284
    )
×
285
    .arg(
×
286
      arg!(--"static" <Path>)
×
287
        .help("Glob pattern for static files to be included")
×
288
        .action(ArgAction::Append),
×
289
    )
×
290
    .arg(
×
291
      arg!(--"tcp-nodelay"[BOOL])
×
292
        .help("Disables Nagle's algorithm")
×
293
        .num_args(0..=1)
×
294
        .value_parser(BoolishValueParser::new())
×
295
        .require_equals(true)
×
296
        .default_value("true")
×
297
        .default_missing_value("true"),
×
298
    )
×
299
    .arg(
×
300
      arg!(--"request-buffer-size" <BYTES>)
×
301
        .help(concat!(
×
302
          "The buffer size of the stream that is used to forward a request ",
×
303
          "to the worker"
×
304
        ))
×
305
        .value_parser(value_parser!(u64))
×
306
        .default_value("16384"),
×
307
    )
×
308
    .arg(
×
309
      arg!(--"dispatch-beforeunload-wall-clock-ratio" <PERCENTAGE>)
×
310
        .value_parser(value_parser!(u8).range(..=99))
×
311
        .default_value("90"),
×
312
    )
×
313
    .arg(
×
314
      arg!(--"dispatch-beforeunload-cpu-ratio" <PERCENTAGE>)
×
315
        .value_parser(value_parser!(u8).range(..=99))
×
316
        .default_value("90"),
×
317
    )
×
318
    .arg(
×
319
      arg!(--"dispatch-beforeunload-memory-ratio" <PERCENTAGE>)
×
320
        .value_parser(value_parser!(u8).range(..=99))
×
321
        .default_value("90"),
×
322
    )
×
323
    .arg(
×
324
      arg!(--"enable-otel")
×
325
        .help("Enable OpenTelemetry in the main and event workers")
×
326
        .value_delimiter(',')
×
327
        .value_parser(value_parser!(OtelKind))
×
328
        .num_args(0..=1)
×
329
        .default_missing_value("main,event")
×
330
        .action(ArgAction::Append),
×
331
    )
×
332
    .arg(
×
333
      arg!(--"otel-console" <MODE>)
×
334
        // .env("OTEL_DENO_CONSOLE")
335
        .help("Configure console auto instrumentation for OpenTelemetry Logs")
×
336
        .value_parser(value_parser!(OtelConsoleConfig)),
×
337
    )
×
338
}
×
339

340
fn get_bundle_command() -> Command {
×
341
  Command::new("bundle")
×
342
    .about(concat!(
×
343
      "Creates an 'eszip' file that can be executed by the EdgeRuntime. ",
×
344
      "Such file contains all the modules in contained in a single binary."
×
345
    ))
×
346
    .arg(
×
347
      arg!(--"output" <DIR>)
×
348
        .help("Path to output eszip file")
×
349
        .default_value("bin.eszip"),
×
350
    )
×
351
    .arg(
×
352
      arg!(--"entrypoint" <Path>)
×
353
        .help("Path to entrypoint to bundle as an eszip")
×
354
        .required(true),
×
355
    )
×
356
    .arg(
×
357
      arg!(--"static" <Path>)
×
358
        .help("Glob pattern for static files to be included")
×
359
        .action(ArgAction::Append),
×
360
    )
×
361
    .arg(
×
362
      arg!(--"import-map" <Path>).help("(DEPRECATED) Path to import map file"),
×
363
    )
×
364
    .arg(
×
365
      arg!(--"decorator" <TYPE>)
×
366
        .help(concat!(
×
367
          "(DEPRECATED) Type of decorator to use on the main worker and event worker. ",
×
368
          "If not specified, the decorator feature is disabled."
×
369
        ))
×
370
        .value_parser(["tc39", "typescript", "typescript_with_metadata"]),
×
371
    )
×
372
    .arg(
×
373
      arg!(--"checksum" <KIND>)
×
374
        .env("EDGE_RUNTIME_BUNDLE_CHECKSUM")
×
375
        .help("Hash function to use when checksum the contents")
×
376
        .value_parser(value_parser!(EszipV2ChecksumKind)),
×
377
    )
×
378
    .arg(
×
379
      arg!(--"disable-module-cache")
×
380
        .help("Disable using module cache")
×
381
        .default_value("false")
×
382
        .value_parser(FalseyValueParser::new()),
×
383
    )
×
384
    .arg(
×
385
      arg!(--"timeout" <SECONDS>)
×
386
        .help("Maximum time in seconds that can be waited for the bundle to complete.")
×
387
        .value_parser(value_parser!(u64).range(..u64::MAX))
×
388
    )
×
389
}
×
390

391
fn get_unbundle_command() -> Command {
×
392
  Command::new("unbundle")
×
393
    .about("Unbundles an .eszip file into the specified directory")
×
394
    .arg(
×
395
      arg!(--"output" <DIR>)
×
396
        .help("Path to extract the ESZIP content")
×
397
        .default_value("./"),
×
398
    )
×
399
    .arg(
×
400
      arg!(--"eszip" <Path>)
×
401
        .help("Path of eszip to extract")
×
402
        .required(true),
×
403
    )
×
404
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc