@dangao/bun-server 0.2.0 → 0.3.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.
@@ -95,6 +95,12 @@ export declare class Context {
95
95
  * @returns 头值
96
96
  */
97
97
  getHeader(key: string): string | null;
98
+ /**
99
+ * 获取客户端 IP 地址
100
+ * 优先从 X-Forwarded-For 头获取(代理场景),否则从连接信息获取
101
+ * @returns 客户端 IP 地址
102
+ */
103
+ getClientIp(): string;
98
104
  /**
99
105
  * 设置响应头
100
106
  * @param key - 头名称
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/core/context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAGjD;;;GAGG;AACH,qBAAa,OAAO;IAClB;;OAEG;IACH,SAAgB,OAAO,EAAE,OAAO,CAAC;IAEjC;;OAEG;IACI,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAE3B;;OAEG;IACH,SAAgB,GAAG,EAAE,GAAG,CAAC;IAEzB;;OAEG;IACH,SAAgB,MAAM,EAAE,MAAM,CAAC;IAE/B;;OAEG;IACH,SAAgB,IAAI,EAAE,MAAM,CAAC;IAE7B;;OAEG;IACH,SAAgB,KAAK,EAAE,eAAe,CAAC;IAEvC;;OAEG;IACI,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAM;IAE3C;;OAEG;IACH,SAAgB,OAAO,EAAE,OAAO,CAAC;IAEjC;;OAEG;IACI,eAAe,EAAE,OAAO,CAAC;IAEhC;;OAEG;IACI,UAAU,EAAE,MAAM,CAAO;IAEhC;;OAEG;IACI,KAAK,EAAE,gBAAgB,EAAE,CAAM;IAEtC;;OAEG;IACH,OAAO,CAAC,KAAK,CAAC,CAAU;IAExB;;OAEG;IACH,OAAO,CAAC,WAAW,CAAkB;gBAElB,OAAO,EAAE,OAAO;IAUnC;;;OAGG;IACU,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAQxC;;;OAGG;IACH,IAAW,IAAI,IAAI,OAAO,CAEzB;IAED;;;OAGG;IACH,IAAW,IAAI,CAAC,IAAI,EAAE,OAAO,EAG5B;IAED;;;;OAIG;IACI,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAI3C;;;OAGG;IACI,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAQ5C;;;;OAIG;IACI,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIhD;;;;OAIG;IACI,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAI5C;;;;OAIG;IACI,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAIlD;;;OAGG;IACI,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIpC;;;;;OAKG;IACI,cAAc,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,QAAQ;CA2BrE"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/core/context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAGjD;;;GAGG;AACH,qBAAa,OAAO;IAClB;;OAEG;IACH,SAAgB,OAAO,EAAE,OAAO,CAAC;IAEjC;;OAEG;IACI,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAE3B;;OAEG;IACH,SAAgB,GAAG,EAAE,GAAG,CAAC;IAEzB;;OAEG;IACH,SAAgB,MAAM,EAAE,MAAM,CAAC;IAE/B;;OAEG;IACH,SAAgB,IAAI,EAAE,MAAM,CAAC;IAE7B;;OAEG;IACH,SAAgB,KAAK,EAAE,eAAe,CAAC;IAEvC;;OAEG;IACI,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAM;IAE3C;;OAEG;IACH,SAAgB,OAAO,EAAE,OAAO,CAAC;IAEjC;;OAEG;IACI,eAAe,EAAE,OAAO,CAAC;IAEhC;;OAEG;IACI,UAAU,EAAE,MAAM,CAAO;IAEhC;;OAEG;IACI,KAAK,EAAE,gBAAgB,EAAE,CAAM;IAEtC;;OAEG;IACH,OAAO,CAAC,KAAK,CAAC,CAAU;IAExB;;OAEG;IACH,OAAO,CAAC,WAAW,CAAkB;gBAElB,OAAO,EAAE,OAAO;IAUnC;;;OAGG;IACU,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAQxC;;;OAGG;IACH,IAAW,IAAI,IAAI,OAAO,CAEzB;IAED;;;OAGG;IACH,IAAW,IAAI,CAAC,IAAI,EAAE,OAAO,EAG5B;IAED;;;;OAIG;IACI,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAI3C;;;OAGG;IACI,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAQ5C;;;;OAIG;IACI,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIhD;;;;OAIG;IACI,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAI5C;;;;OAIG;IACI,WAAW,IAAI,MAAM;IAmB5B;;;;OAIG;IACI,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAIlD;;;OAGG;IACI,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIpC;;;;;OAKG;IACI,cAAc,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,QAAQ;CA2BrE"}
package/dist/index.d.ts CHANGED
@@ -12,9 +12,9 @@ export { Injectable, Inject } from './di/decorators';
12
12
  export { Lifecycle, type ProviderConfig, type DependencyMetadata } from './di/types';
13
13
  export { Module, type ModuleMetadata, type ModuleProvider, type ModuleClass, } from './di/module';
14
14
  export { ModuleRegistry } from './di/module-registry';
15
- export { UseMiddleware, MiddlewarePipeline } from './middleware';
15
+ export { UseMiddleware, RateLimit, MiddlewarePipeline } from './middleware';
16
16
  export type { Middleware, NextFunction } from './middleware';
17
- export { createLoggerMiddleware, createRequestLoggingMiddleware, createErrorHandlingMiddleware, createCorsMiddleware, createFileUploadMiddleware, createStaticFileMiddleware, } from './middleware/builtin';
17
+ export { createLoggerMiddleware, createRequestLoggingMiddleware, createErrorHandlingMiddleware, createCorsMiddleware, createFileUploadMiddleware, createStaticFileMiddleware, createRateLimitMiddleware, createTokenKeyGenerator, createUserKeyGenerator, type RateLimitOptions, type RateLimitStore, } from './middleware/builtin';
18
18
  export { Validate, IsString, IsNumber, IsEmail, IsOptional, MinLength, ValidationError, type ValidationIssue, } from './validation';
19
19
  export { HttpException, BadRequestException, UnauthorizedException, ForbiddenException, NotFoundException, InternalServerErrorException, ExceptionFilterRegistry, type ExceptionFilter, } from './error';
20
20
  export { WebSocketGateway, OnOpen, OnMessage, OnClose, WebSocketGatewayRegistry, type WebSocketConnectionData, } from './websocket';
@@ -23,6 +23,7 @@ export { SwaggerExtension, SwaggerModule, SwaggerGenerator, createSwaggerUIMiddl
23
23
  export { SecurityModule, SecurityContextHolder, AuthenticationManager, RoleBasedAccessDecisionManager, JwtAuthenticationProvider, OAuth2AuthenticationProvider, createSecurityFilter, type SecurityModuleConfig, type SecurityConfig, type SecurityContext, type Authentication, type AuthenticationProvider, type AuthenticationRequest, type Principal, type Credentials, type AccessDecisionManager, } from './security';
24
24
  export { ConfigModule, ConfigService, CONFIG_SERVICE_TOKEN, type ConfigModuleOptions, } from './config';
25
25
  export { HealthModule, type HealthIndicator, type HealthIndicatorResult, type HealthStatus, type HealthModuleOptions, HEALTH_INDICATORS_TOKEN, HEALTH_OPTIONS_TOKEN, } from './health';
26
+ export { MetricsModule, MetricsCollector, PrometheusFormatter, createHttpMetricsMiddleware, METRICS_SERVICE_TOKEN, METRICS_OPTIONS_TOKEN, type MetricsModuleOptions, type MetricType, type MetricLabels, type MetricValue, type MetricDataPoint, type CustomMetric, } from './metrics';
26
27
  export { JWTUtil, OAuth2Service, OAuth2Controller, Auth, getAuthMetadata, requiresAuth, checkRoles, OAUTH2_SERVICE_TOKEN, JWT_UTIL_TOKEN, type JWTConfig, type JWTPayload, type OAuth2Client, type OAuth2AuthorizationRequest, type OAuth2TokenRequest, type OAuth2TokenResponse, type UserInfo, type AuthContext, type AuthConfig, } from './auth';
27
28
  export { PerformanceHarness, StressTester, type BenchmarkResult, type StressResult, } from './testing/harness';
28
29
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -525,6 +525,17 @@ class Context {
525
525
  getHeader(key) {
526
526
  return this.headers.get(key);
527
527
  }
528
+ getClientIp() {
529
+ const forwardedFor = this.getHeader("X-Forwarded-For");
530
+ if (forwardedFor) {
531
+ return forwardedFor.split(",")[0].trim();
532
+ }
533
+ const realIp = this.getHeader("X-Real-IP");
534
+ if (realIp) {
535
+ return realIp.trim();
536
+ }
537
+ return "unknown";
538
+ }
528
539
  setHeader(key, value) {
529
540
  this.responseHeaders.set(key, value);
530
541
  }
@@ -1325,6 +1336,112 @@ function getRouteMetadata(target) {
1325
1336
  }
1326
1337
  // src/middleware/decorators.ts
1327
1338
  import"reflect-metadata";
1339
+
1340
+ // src/middleware/builtin/rate-limit.ts
1341
+ class MemoryRateLimitStore {
1342
+ store = new Map;
1343
+ async get(key) {
1344
+ const entry = this.store.get(key);
1345
+ if (!entry) {
1346
+ return 0;
1347
+ }
1348
+ if (Date.now() > entry.resetTime) {
1349
+ this.store.delete(key);
1350
+ return 0;
1351
+ }
1352
+ return entry.count;
1353
+ }
1354
+ async increment(key, windowMs) {
1355
+ const now = Date.now();
1356
+ const entry = this.store.get(key);
1357
+ if (!entry || now > entry.resetTime) {
1358
+ const resetTime = now + windowMs;
1359
+ this.store.set(key, { count: 1, resetTime });
1360
+ return 1;
1361
+ }
1362
+ entry.count++;
1363
+ return entry.count;
1364
+ }
1365
+ async reset(key) {
1366
+ this.store.delete(key);
1367
+ }
1368
+ cleanup() {
1369
+ const now = Date.now();
1370
+ for (const [key, entry] of this.store.entries()) {
1371
+ if (now > entry.resetTime) {
1372
+ this.store.delete(key);
1373
+ }
1374
+ }
1375
+ }
1376
+ }
1377
+ function defaultKeyGenerator(context) {
1378
+ return `rate-limit:${context.getClientIp()}`;
1379
+ }
1380
+ function createRateLimitMiddleware(options) {
1381
+ const {
1382
+ max,
1383
+ windowMs = 60000,
1384
+ store = new MemoryRateLimitStore,
1385
+ keyGenerator = defaultKeyGenerator,
1386
+ skipSuccessfulRequests = false,
1387
+ skipFailedRequests = false,
1388
+ message = "Too Many Requests",
1389
+ statusCode = 429,
1390
+ standardHeaders = true,
1391
+ legacyHeaders = true
1392
+ } = options;
1393
+ return async (context, next) => {
1394
+ const key = await keyGenerator(context);
1395
+ const currentCount = await store.increment(key, windowMs);
1396
+ const remaining = Math.max(0, max - currentCount);
1397
+ const resetTime = Date.now() + windowMs;
1398
+ if (standardHeaders) {
1399
+ context.setHeader("RateLimit-Limit", max.toString());
1400
+ context.setHeader("RateLimit-Remaining", remaining.toString());
1401
+ context.setHeader("RateLimit-Reset", Math.ceil(resetTime / 1000).toString());
1402
+ }
1403
+ if (legacyHeaders) {
1404
+ context.setHeader("X-RateLimit-Limit", max.toString());
1405
+ context.setHeader("X-RateLimit-Remaining", remaining.toString());
1406
+ context.setHeader("X-RateLimit-Reset", Math.ceil(resetTime / 1000).toString());
1407
+ }
1408
+ if (currentCount > max) {
1409
+ context.setStatus(statusCode);
1410
+ return context.createResponse({
1411
+ error: message,
1412
+ retryAfter: Math.ceil(windowMs / 1000)
1413
+ });
1414
+ }
1415
+ const response = await next();
1416
+ const shouldSkip = skipSuccessfulRequests && response.status >= 200 && response.status < 300 || skipFailedRequests && response.status >= 400;
1417
+ if (shouldSkip) {
1418
+ const current = await store.get(key);
1419
+ if (current > 0) {}
1420
+ }
1421
+ return response;
1422
+ };
1423
+ }
1424
+ function createTokenKeyGenerator(tokenHeader = "Authorization") {
1425
+ return (context) => {
1426
+ const token = context.getHeader(tokenHeader);
1427
+ if (token) {
1428
+ const tokenValue = token.startsWith("Bearer ") ? token.substring(7) : token;
1429
+ return `rate-limit:token:${tokenValue}`;
1430
+ }
1431
+ return defaultKeyGenerator(context);
1432
+ };
1433
+ }
1434
+ function createUserKeyGenerator(getUserId) {
1435
+ return (context) => {
1436
+ const userId = getUserId(context);
1437
+ if (userId) {
1438
+ return `rate-limit:user:${userId}`;
1439
+ }
1440
+ return defaultKeyGenerator(context);
1441
+ };
1442
+ }
1443
+
1444
+ // src/middleware/decorators.ts
1328
1445
  var CLASS_MIDDLEWARE_METADATA_KEY = Symbol("middleware:class");
1329
1446
  var METHOD_MIDDLEWARE_METADATA_KEY = Symbol("middleware:method");
1330
1447
  function appendMiddlewareMetadata(target, propertyKey, middlewares) {
@@ -1344,6 +1461,12 @@ function UseMiddleware(...middlewares) {
1344
1461
  appendMiddlewareMetadata(propertyKey === undefined ? target : target, propertyKey, middlewares);
1345
1462
  };
1346
1463
  }
1464
+ function RateLimit(options) {
1465
+ return function(target, propertyKey) {
1466
+ const middleware = createRateLimitMiddleware(options);
1467
+ appendMiddlewareMetadata(target, propertyKey, [middleware]);
1468
+ };
1469
+ }
1347
1470
  function getClassMiddlewares(constructor) {
1348
1471
  return Reflect.getMetadata(CLASS_MIDDLEWARE_METADATA_KEY, constructor) || [];
1349
1472
  }
@@ -3489,6 +3612,297 @@ HealthModule = __legacyDecorateClassTS([
3489
3612
  providers: []
3490
3613
  })
3491
3614
  ], HealthModule);
3615
+ // src/metrics/collector.ts
3616
+ class MetricsCollector {
3617
+ counters = new Map;
3618
+ gauges = new Map;
3619
+ histograms = new Map;
3620
+ customMetrics = [];
3621
+ registerCustomMetric(metric) {
3622
+ this.customMetrics.push(metric);
3623
+ }
3624
+ incrementCounter(name, labels, value = 1) {
3625
+ const key = this.getKey(name, labels);
3626
+ const counterMap = this.counters.get(name) || new Map;
3627
+ const current = counterMap.get(key) || 0;
3628
+ counterMap.set(key, current + value);
3629
+ this.counters.set(name, counterMap);
3630
+ }
3631
+ setGauge(name, labels, value) {
3632
+ const key = this.getKey(name, labels);
3633
+ const gaugeMap = this.gauges.get(name) || new Map;
3634
+ gaugeMap.set(key, value);
3635
+ this.gauges.set(name, gaugeMap);
3636
+ }
3637
+ observeHistogram(name, labels, value) {
3638
+ const key = this.getKey(name, labels);
3639
+ const histogramMap = this.histograms.get(name) || new Map;
3640
+ const values = histogramMap.get(key) || [];
3641
+ values.push(value);
3642
+ histogramMap.set(key, values);
3643
+ this.histograms.set(name, histogramMap);
3644
+ }
3645
+ async getAllDataPoints() {
3646
+ const dataPoints = [];
3647
+ for (const [name, counterMap] of this.counters.entries()) {
3648
+ for (const [key, value] of counterMap.entries()) {
3649
+ const labels = this.parseKey(key);
3650
+ dataPoints.push({
3651
+ name,
3652
+ type: "counter",
3653
+ value,
3654
+ labels: labels && Object.keys(labels).length > 0 ? labels : undefined
3655
+ });
3656
+ }
3657
+ }
3658
+ for (const [name, gaugeMap] of this.gauges.entries()) {
3659
+ for (const [key, value] of gaugeMap.entries()) {
3660
+ const labels = this.parseKey(key);
3661
+ dataPoints.push({
3662
+ name,
3663
+ type: "gauge",
3664
+ value,
3665
+ labels: labels && Object.keys(labels).length > 0 ? labels : undefined
3666
+ });
3667
+ }
3668
+ }
3669
+ for (const [name, histogramMap] of this.histograms.entries()) {
3670
+ for (const [key, values] of histogramMap.entries()) {
3671
+ const labels = this.parseKey(key);
3672
+ const sum = values.reduce((a, b) => a + b, 0);
3673
+ const count = values.length;
3674
+ const buckets = this.calculateBuckets(values);
3675
+ dataPoints.push({
3676
+ name: `${name}_sum`,
3677
+ type: "histogram",
3678
+ value: sum,
3679
+ labels: labels && Object.keys(labels).length > 0 ? labels : undefined
3680
+ });
3681
+ dataPoints.push({
3682
+ name: `${name}_count`,
3683
+ type: "histogram",
3684
+ value: count,
3685
+ labels: labels && Object.keys(labels).length > 0 ? labels : undefined
3686
+ });
3687
+ for (const [bucket, bucketCount] of Object.entries(buckets)) {
3688
+ dataPoints.push({
3689
+ name: `${name}_bucket`,
3690
+ type: "histogram",
3691
+ value: bucketCount,
3692
+ labels: {
3693
+ ...labels,
3694
+ le: bucket
3695
+ }
3696
+ });
3697
+ }
3698
+ }
3699
+ }
3700
+ for (const metric of this.customMetrics) {
3701
+ try {
3702
+ const value = await metric.getValue();
3703
+ dataPoints.push({
3704
+ name: metric.name,
3705
+ type: metric.type,
3706
+ value,
3707
+ help: metric.help
3708
+ });
3709
+ } catch (error) {
3710
+ console.error(`Failed to collect custom metric ${metric.name}:`, error);
3711
+ }
3712
+ }
3713
+ return dataPoints;
3714
+ }
3715
+ reset() {
3716
+ this.counters.clear();
3717
+ this.gauges.clear();
3718
+ this.histograms.clear();
3719
+ }
3720
+ getKey(name, labels) {
3721
+ if (!labels || Object.keys(labels).length === 0) {
3722
+ return "";
3723
+ }
3724
+ const sortedLabels = Object.keys(labels).sort().map((key) => `${key}="${labels[key]}"`).join(",");
3725
+ return `{${sortedLabels}}`;
3726
+ }
3727
+ parseKey(key) {
3728
+ if (!key || key === "") {
3729
+ return;
3730
+ }
3731
+ const labels = {};
3732
+ const match = key.match(/\{([^}]+)\}/);
3733
+ if (match) {
3734
+ const labelPairs = match[1].split(",");
3735
+ for (const pair of labelPairs) {
3736
+ const [k, v] = pair.split("=");
3737
+ if (k && v) {
3738
+ labels[k.trim()] = v.trim().replace(/^"|"$/g, "");
3739
+ }
3740
+ }
3741
+ }
3742
+ return Object.keys(labels).length > 0 ? labels : undefined;
3743
+ }
3744
+ calculateBuckets(values) {
3745
+ const defaultBuckets = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10];
3746
+ const buckets = {};
3747
+ for (const bucket of defaultBuckets) {
3748
+ buckets[bucket.toString()] = values.filter((v) => v <= bucket).length;
3749
+ }
3750
+ buckets["+Inf"] = values.length;
3751
+ return buckets;
3752
+ }
3753
+ }
3754
+
3755
+ // src/metrics/prometheus.ts
3756
+ class PrometheusFormatter {
3757
+ format(dataPoints) {
3758
+ const lines = [];
3759
+ const metricGroups = this.groupByMetricName(dataPoints);
3760
+ for (const [metricName, points] of metricGroups.entries()) {
3761
+ const help = points[0]?.help;
3762
+ if (help) {
3763
+ lines.push(`# HELP ${metricName} ${help}`);
3764
+ }
3765
+ const type = points[0]?.type;
3766
+ if (type) {
3767
+ lines.push(`# TYPE ${metricName} ${type}`);
3768
+ }
3769
+ for (const point of points) {
3770
+ const labelString = this.formatLabels(point.labels);
3771
+ const line = labelString ? `${point.name}${labelString} ${point.value}` : `${point.name} ${point.value}`;
3772
+ lines.push(line);
3773
+ }
3774
+ lines.push("");
3775
+ }
3776
+ return lines.join(`
3777
+ `);
3778
+ }
3779
+ groupByMetricName(dataPoints) {
3780
+ const groups = new Map;
3781
+ for (const point of dataPoints) {
3782
+ const name = point.name;
3783
+ const existing = groups.get(name) || [];
3784
+ existing.push(point);
3785
+ groups.set(name, existing);
3786
+ }
3787
+ return groups;
3788
+ }
3789
+ formatLabels(labels) {
3790
+ if (!labels || Object.keys(labels).length === 0) {
3791
+ return "";
3792
+ }
3793
+ const labelPairs = Object.keys(labels).sort().map((key) => `${key}="${this.escapeLabelValue(labels[key])}"`).join(",");
3794
+ return `{${labelPairs}}`;
3795
+ }
3796
+ escapeLabelValue(value) {
3797
+ return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n");
3798
+ }
3799
+ }
3800
+
3801
+ // src/metrics/types.ts
3802
+ var METRICS_SERVICE_TOKEN = Symbol("@dangao/bun-server:metrics:service");
3803
+ var METRICS_OPTIONS_TOKEN = Symbol("@dangao/bun-server:metrics:options");
3804
+
3805
+ // src/metrics/controller.ts
3806
+ class MetricsController {
3807
+ collector;
3808
+ options;
3809
+ formatter;
3810
+ constructor(collector, options) {
3811
+ this.collector = collector;
3812
+ this.options = options;
3813
+ this.formatter = new PrometheusFormatter;
3814
+ }
3815
+ async metrics() {
3816
+ const dataPoints = await this.collector.getAllDataPoints();
3817
+ const prometheusText = this.formatter.format(dataPoints);
3818
+ return new Response(prometheusText, {
3819
+ headers: {
3820
+ "Content-Type": "text/plain; version=0.0.4; charset=utf-8"
3821
+ }
3822
+ });
3823
+ }
3824
+ }
3825
+ __legacyDecorateClassTS([
3826
+ GET("/metrics"),
3827
+ __legacyMetadataTS("design:type", Function),
3828
+ __legacyMetadataTS("design:paramtypes", []),
3829
+ __legacyMetadataTS("design:returntype", typeof Promise === "undefined" ? Object : Promise)
3830
+ ], MetricsController.prototype, "metrics", null);
3831
+ MetricsController = __legacyDecorateClassTS([
3832
+ Controller("/"),
3833
+ __legacyDecorateParamTS(0, Inject(METRICS_SERVICE_TOKEN)),
3834
+ __legacyDecorateParamTS(1, Inject(METRICS_OPTIONS_TOKEN)),
3835
+ __legacyMetadataTS("design:paramtypes", [
3836
+ typeof MetricsCollector === "undefined" ? Object : MetricsCollector,
3837
+ typeof MetricsModuleOptions === "undefined" ? Object : MetricsModuleOptions
3838
+ ])
3839
+ ], MetricsController);
3840
+
3841
+ // src/metrics/metrics-module.ts
3842
+ class MetricsModule {
3843
+ static forRoot(options = {}) {
3844
+ const providers2 = [];
3845
+ const collector = new MetricsCollector;
3846
+ if (options.customMetrics) {
3847
+ for (const metric of options.customMetrics) {
3848
+ collector.registerCustomMetric(metric);
3849
+ }
3850
+ }
3851
+ providers2.push({
3852
+ provide: METRICS_SERVICE_TOKEN,
3853
+ useValue: collector
3854
+ }, {
3855
+ provide: METRICS_OPTIONS_TOKEN,
3856
+ useValue: options
3857
+ }, MetricsCollector);
3858
+ const existingMetadata = Reflect.getMetadata(MODULE_METADATA_KEY, MetricsModule) || {};
3859
+ const metadata = {
3860
+ ...existingMetadata,
3861
+ controllers: [...existingMetadata.controllers || [], MetricsController],
3862
+ providers: [...existingMetadata.providers || [], ...providers2],
3863
+ exports: [
3864
+ ...existingMetadata.exports || [],
3865
+ METRICS_SERVICE_TOKEN,
3866
+ MetricsCollector
3867
+ ]
3868
+ };
3869
+ Reflect.defineMetadata(MODULE_METADATA_KEY, metadata, MetricsModule);
3870
+ return MetricsModule;
3871
+ }
3872
+ }
3873
+ MetricsModule = __legacyDecorateClassTS([
3874
+ Module({
3875
+ controllers: [MetricsController],
3876
+ providers: []
3877
+ })
3878
+ ], MetricsModule);
3879
+ // src/metrics/middleware.ts
3880
+ function createHttpMetricsMiddleware(collector) {
3881
+ return async (context2, next) => {
3882
+ const startTime = Date.now();
3883
+ const response = await next();
3884
+ const duration = Date.now() - startTime;
3885
+ const durationSeconds = duration / 1000;
3886
+ const method = context2.method;
3887
+ const path = context2.path;
3888
+ const statusCode = response.status;
3889
+ collector.incrementCounter("http_requests_total", {
3890
+ method,
3891
+ path,
3892
+ status: statusCode.toString()
3893
+ });
3894
+ collector.observeHistogram("http_request_duration_seconds", {
3895
+ method,
3896
+ path,
3897
+ status: statusCode.toString()
3898
+ }, durationSeconds);
3899
+ collector.observeHistogram("http_request_duration_seconds_summary", {
3900
+ method,
3901
+ path
3902
+ }, durationSeconds);
3903
+ return response;
3904
+ };
3905
+ }
3492
3906
  // src/testing/harness.ts
3493
3907
  import { performance as performance2 } from "perf_hooks";
3494
3908
 
@@ -3552,11 +3966,15 @@ class StressTester {
3552
3966
  export {
3553
3967
  requiresAuth,
3554
3968
  getAuthMetadata,
3969
+ createUserKeyGenerator,
3970
+ createTokenKeyGenerator,
3555
3971
  createSwaggerUIMiddleware,
3556
3972
  createStaticFileMiddleware,
3557
3973
  createSecurityFilter,
3558
3974
  createRequestLoggingMiddleware,
3975
+ createRateLimitMiddleware,
3559
3976
  createLoggerMiddleware,
3977
+ createHttpMetricsMiddleware,
3560
3978
  createFileUploadMiddleware,
3561
3979
  createErrorHandlingMiddleware,
3562
3980
  createCorsMiddleware,
@@ -3579,7 +3997,9 @@ export {
3579
3997
  RoleBasedAccessDecisionManager,
3580
3998
  ResponseBuilder,
3581
3999
  RequestWrapper,
4000
+ RateLimit,
3582
4001
  Query,
4002
+ PrometheusFormatter,
3583
4003
  PerformanceHarness,
3584
4004
  ParamBinder,
3585
4005
  Param,
@@ -3598,6 +4018,10 @@ export {
3598
4018
  Module,
3599
4019
  MinLength,
3600
4020
  MiddlewarePipeline,
4021
+ MetricsModule,
4022
+ MetricsCollector,
4023
+ METRICS_SERVICE_TOKEN,
4024
+ METRICS_OPTIONS_TOKEN,
3601
4025
  LoggerModule,
3602
4026
  LoggerExtension,
3603
4027
  LogLevel2 as LogLevel,
@@ -0,0 +1,47 @@
1
+ import type { CustomMetric, MetricDataPoint, MetricLabels } from './types';
2
+ /**
3
+ * 指标收集器
4
+ */
5
+ export declare class MetricsCollector {
6
+ private counters;
7
+ private gauges;
8
+ private histograms;
9
+ private customMetrics;
10
+ /**
11
+ * 注册自定义指标
12
+ */
13
+ registerCustomMetric(metric: CustomMetric): void;
14
+ /**
15
+ * 增加计数器
16
+ */
17
+ incrementCounter(name: string, labels?: MetricLabels, value?: number): void;
18
+ /**
19
+ * 设置仪表值
20
+ */
21
+ setGauge(name: string, labels: MetricLabels | undefined, value: number): void;
22
+ /**
23
+ * 观察直方图值
24
+ */
25
+ observeHistogram(name: string, labels: MetricLabels | undefined, value: number): void;
26
+ /**
27
+ * 获取所有指标数据点
28
+ */
29
+ getAllDataPoints(): Promise<MetricDataPoint[]>;
30
+ /**
31
+ * 重置所有指标
32
+ */
33
+ reset(): void;
34
+ /**
35
+ * 生成标签键
36
+ */
37
+ private getKey;
38
+ /**
39
+ * 解析标签键
40
+ */
41
+ private parseKey;
42
+ /**
43
+ * 计算直方图桶
44
+ */
45
+ private calculateBuckets;
46
+ }
47
+ //# sourceMappingURL=collector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../../src/metrics/collector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,eAAe,EACf,YAAY,EAGb,MAAM,SAAS,CAAC;AAEjB;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAA+C;IAC/D,OAAO,CAAC,MAAM,CAA+C;IAC7D,OAAO,CAAC,UAAU,CAAiD;IACnE,OAAO,CAAC,aAAa,CAAsB;IAE3C;;OAEG;IACI,oBAAoB,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAIvD;;OAEG;IACI,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,EAAE,KAAK,GAAE,MAAU,GAAG,IAAI;IAQrF;;OAEG;IACI,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAOpF;;OAEG;IACI,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAS5F;;OAEG;IACU,gBAAgB,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IAuF3D;;OAEG;IACI,KAAK,IAAI,IAAI;IAMpB;;OAEG;IACH,OAAO,CAAC,MAAM;IAYd;;OAEG;IACH,OAAO,CAAC,QAAQ;IAmBhB;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAYzB"}
@@ -0,0 +1,17 @@
1
+ import { MetricsCollector } from './collector';
2
+ import { type MetricsModuleOptions } from './types';
3
+ /**
4
+ * Metrics 控制器
5
+ * 提供 `/metrics` 端点用于 Prometheus 指标导出
6
+ */
7
+ export declare class MetricsController {
8
+ private readonly collector;
9
+ private readonly options?;
10
+ private readonly formatter;
11
+ constructor(collector: MetricsCollector, options?: MetricsModuleOptions | undefined);
12
+ /**
13
+ * 获取 Prometheus 格式的指标
14
+ */
15
+ metrics(): Promise<Response>;
16
+ }
17
+ //# sourceMappingURL=controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/metrics/controller.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAgD,KAAK,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAElG;;;GAGG;AACH,qBACa,iBAAiB;IAK1B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAE1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;IAN3B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsB;gBAI7B,SAAS,EAAE,gBAAgB,EAE3B,OAAO,CAAC,EAAE,oBAAoB,YAAA;IAKjD;;OAEG;IAEU,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC;CAU1C"}
@@ -0,0 +1,7 @@
1
+ export { MetricsModule } from './metrics-module';
2
+ export { MetricsCollector } from './collector';
3
+ export { PrometheusFormatter } from './prometheus';
4
+ export { MetricsController } from './controller';
5
+ export { createHttpMetricsMiddleware } from './middleware';
6
+ export { METRICS_SERVICE_TOKEN, METRICS_OPTIONS_TOKEN, type MetricsModuleOptions, type MetricType, type MetricLabels, type MetricValue, type MetricDataPoint, type CustomMetric, } from './types';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,KAAK,oBAAoB,EACzB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,YAAY,GAClB,MAAM,SAAS,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { MetricsModuleOptions } from './types';
2
+ export declare class MetricsModule {
3
+ /**
4
+ * 创建指标监控模块
5
+ * @param options - 模块配置
6
+ */
7
+ static forRoot(options?: MetricsModuleOptions): typeof MetricsModule;
8
+ }
9
+ //# sourceMappingURL=metrics-module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics-module.d.ts","sourceRoot":"","sources":["../../src/metrics/metrics-module.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAGpD,qBAIa,aAAa;IACxB;;;OAGG;WACW,OAAO,CAAC,OAAO,GAAE,oBAAyB,GAAG,OAAO,aAAa;CAyChF"}
@@ -0,0 +1,7 @@
1
+ import type { Middleware } from '../middleware';
2
+ import { MetricsCollector } from './collector';
3
+ /**
4
+ * 创建 HTTP 请求指标收集中间件
5
+ */
6
+ export declare function createHttpMetricsMiddleware(collector: MetricsCollector): Middleware;
7
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/metrics/middleware.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,gBAAgB,GAAG,UAAU,CAsCnF"}
@@ -0,0 +1,23 @@
1
+ import type { MetricDataPoint } from './types';
2
+ /**
3
+ * 将指标数据点转换为 Prometheus 格式
4
+ */
5
+ export declare class PrometheusFormatter {
6
+ /**
7
+ * 格式化指标为 Prometheus 文本格式
8
+ */
9
+ format(dataPoints: MetricDataPoint[]): string;
10
+ /**
11
+ * 按指标名称分组
12
+ */
13
+ private groupByMetricName;
14
+ /**
15
+ * 格式化标签
16
+ */
17
+ private formatLabels;
18
+ /**
19
+ * 转义标签值
20
+ */
21
+ private escapeLabelValue;
22
+ }
23
+ //# sourceMappingURL=prometheus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prometheus.d.ts","sourceRoot":"","sources":["../../src/metrics/prometheus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C;;GAEG;AACH,qBAAa,mBAAmB;IAC9B;;OAEG;IACI,MAAM,CAAC,UAAU,EAAE,eAAe,EAAE,GAAG,MAAM;IAgCpD;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAazB;;OAEG;IACH,OAAO,CAAC,YAAY;IAYpB;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAGzB"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * 指标类型
3
+ */
4
+ export type MetricType = 'counter' | 'gauge' | 'histogram' | 'summary';
5
+ /**
6
+ * 指标标签
7
+ */
8
+ export type MetricLabels = Record<string, string>;
9
+ /**
10
+ * 指标值
11
+ */
12
+ export type MetricValue = number;
13
+ /**
14
+ * 指标数据点
15
+ */
16
+ export interface MetricDataPoint {
17
+ /**
18
+ * 指标名称
19
+ */
20
+ name: string;
21
+ /**
22
+ * 指标类型
23
+ */
24
+ type: MetricType;
25
+ /**
26
+ * 指标值
27
+ */
28
+ value: MetricValue;
29
+ /**
30
+ * 标签
31
+ */
32
+ labels?: MetricLabels;
33
+ /**
34
+ * 帮助文本
35
+ */
36
+ help?: string;
37
+ }
38
+ /**
39
+ * 自定义指标
40
+ */
41
+ export interface CustomMetric {
42
+ /**
43
+ * 指标名称
44
+ */
45
+ name: string;
46
+ /**
47
+ * 指标类型
48
+ */
49
+ type: MetricType;
50
+ /**
51
+ * 帮助文本
52
+ */
53
+ help?: string;
54
+ /**
55
+ * 获取当前值
56
+ * @param labels - 标签
57
+ * @returns 指标值
58
+ */
59
+ getValue(labels?: MetricLabels): MetricValue | Promise<MetricValue>;
60
+ }
61
+ /**
62
+ * MetricsModule 配置选项
63
+ */
64
+ export interface MetricsModuleOptions {
65
+ /**
66
+ * 是否启用 HTTP 请求指标收集
67
+ * @default true
68
+ */
69
+ enableHttpMetrics?: boolean;
70
+ /**
71
+ * 自定义指标列表
72
+ */
73
+ customMetrics?: CustomMetric[];
74
+ /**
75
+ * Metrics 端点路径
76
+ * @default '/metrics'
77
+ */
78
+ path?: string;
79
+ }
80
+ /**
81
+ * Metrics 服务 Token
82
+ */
83
+ export declare const METRICS_SERVICE_TOKEN: unique symbol;
84
+ /**
85
+ * Metrics 选项 Token
86
+ */
87
+ export declare const METRICS_OPTIONS_TOKEN: unique symbol;
88
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/metrics/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,WAAW,GAAG,SAAS,CAAC;AAEvE;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAElD;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC;AAEjC;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,IAAI,EAAE,UAAU,CAAC;IAEjB;;OAEG;IACH,KAAK,EAAE,WAAW,CAAC;IAEnB;;OAEG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;IAEtB;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,IAAI,EAAE,UAAU,CAAC;IAEjB;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CACrE;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;OAEG;IACH,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAE/B;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,eAAO,MAAM,qBAAqB,eAA+C,CAAC;AAElF;;GAEG;AACH,eAAO,MAAM,qBAAqB,eAA+C,CAAC"}
@@ -3,4 +3,5 @@ export { createErrorHandlingMiddleware } from './error-handler';
3
3
  export { createCorsMiddleware } from './cors';
4
4
  export { createFileUploadMiddleware } from './file-upload';
5
5
  export { createStaticFileMiddleware } from './static-file';
6
+ export { createRateLimitMiddleware, createTokenKeyGenerator, createUserKeyGenerator, type RateLimitOptions, type RateLimitStore, } from './rate-limit';
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/middleware/builtin/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,8BAA8B,EAAE,MAAM,UAAU,CAAC;AAClF,OAAO,EAAE,6BAA6B,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/middleware/builtin/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,8BAA8B,EAAE,MAAM,UAAU,CAAC;AAClF,OAAO,EAAE,6BAA6B,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EACL,yBAAyB,EACzB,uBAAuB,EACvB,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,KAAK,cAAc,GACpB,MAAM,cAAc,CAAC"}
@@ -0,0 +1,104 @@
1
+ import type { Context } from '../../core/context';
2
+ import type { Middleware } from '../middleware';
3
+ /**
4
+ * 速率限制存储接口
5
+ */
6
+ export interface RateLimitStore {
7
+ /**
8
+ * 获取当前计数
9
+ * @param key - 存储键
10
+ * @returns 当前计数
11
+ */
12
+ get(key: string): Promise<number>;
13
+ /**
14
+ * 增加计数
15
+ * @param key - 存储键
16
+ * @param windowMs - 时间窗口(毫秒)
17
+ * @returns 增加后的计数
18
+ */
19
+ increment(key: string, windowMs: number): Promise<number>;
20
+ /**
21
+ * 重置计数
22
+ * @param key - 存储键
23
+ */
24
+ reset(key: string): Promise<void>;
25
+ }
26
+ /**
27
+ * 内存存储实现(使用 Map)
28
+ */
29
+ export declare class MemoryRateLimitStore implements RateLimitStore {
30
+ private store;
31
+ get(key: string): Promise<number>;
32
+ increment(key: string, windowMs: number): Promise<number>;
33
+ reset(key: string): Promise<void>;
34
+ /**
35
+ * 清理过期条目(可选,用于内存管理)
36
+ */
37
+ cleanup(): void;
38
+ }
39
+ /**
40
+ * 速率限制选项
41
+ */
42
+ export interface RateLimitOptions {
43
+ /**
44
+ * 时间窗口内的最大请求数
45
+ */
46
+ max: number;
47
+ /**
48
+ * 时间窗口(毫秒)
49
+ * @default 60000 (1 分钟)
50
+ */
51
+ windowMs?: number;
52
+ /**
53
+ * 存储实现(默认使用内存存储)
54
+ */
55
+ store?: RateLimitStore;
56
+ /**
57
+ * 获取限流键的函数
58
+ * @param context - 请求上下文
59
+ * @returns 限流键
60
+ */
61
+ keyGenerator?: (context: Context) => string | Promise<string>;
62
+ /**
63
+ * 是否跳过成功响应(只对错误响应计数)
64
+ * @default false
65
+ */
66
+ skipSuccessfulRequests?: boolean;
67
+ /**
68
+ * 是否跳过失败响应(只对成功响应计数)
69
+ * @default false
70
+ */
71
+ skipFailedRequests?: boolean;
72
+ /**
73
+ * 自定义错误消息
74
+ */
75
+ message?: string;
76
+ /**
77
+ * 自定义错误状态码
78
+ * @default 429
79
+ */
80
+ statusCode?: number;
81
+ /**
82
+ * 是否在响应头中包含限流信息
83
+ * @default true
84
+ */
85
+ standardHeaders?: boolean;
86
+ /**
87
+ * 是否启用 X-RateLimit-* 响应头
88
+ * @default true
89
+ */
90
+ legacyHeaders?: boolean;
91
+ }
92
+ /**
93
+ * 创建速率限制中间件
94
+ */
95
+ export declare function createRateLimitMiddleware(options: RateLimitOptions): Middleware;
96
+ /**
97
+ * 基于 Token/User 的键生成器
98
+ */
99
+ export declare function createTokenKeyGenerator(tokenHeader?: string): (context: Context) => string;
100
+ /**
101
+ * 基于用户 ID 的键生成器(需要从认证上下文获取)
102
+ */
103
+ export declare function createUserKeyGenerator(getUserId: (context: Context) => string | null | undefined): (context: Context) => string;
104
+ //# sourceMappingURL=rate-limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../../src/middleware/builtin/rate-limit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAElC;;;;;OAKG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE1D;;;OAGG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnC;AAED;;GAEG;AACH,qBAAa,oBAAqB,YAAW,cAAc;IACzD,OAAO,CAAC,KAAK,CAAgE;IAEhE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAejC,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAgBzD,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9C;;OAEG;IACI,OAAO,IAAI,IAAI;CAQvB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IAEZ;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,KAAK,CAAC,EAAE,cAAc,CAAC;IAEvB;;;;OAIG;IACH,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE9D;;;OAGG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AASD;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,gBAAgB,GAAG,UAAU,CAiE/E;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,GAAE,MAAwB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAW3G;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAS/H"}
@@ -1,11 +1,18 @@
1
1
  import 'reflect-metadata';
2
2
  import type { Middleware } from './middleware';
3
+ import { type RateLimitOptions } from './builtin/rate-limit';
3
4
  /**
4
5
  * UseMiddleware 装饰器
5
6
  * 可用于控制器类或方法
6
7
  * @param middlewares - 中间件列表
7
8
  */
8
9
  export declare function UseMiddleware(...middlewares: Middleware[]): ClassDecorator & MethodDecorator;
10
+ /**
11
+ * RateLimit 装饰器
12
+ * 用于在控制器方法上应用速率限制
13
+ * @param options - 速率限制选项
14
+ */
15
+ export declare function RateLimit(options: RateLimitOptions): MethodDecorator;
9
16
  /**
10
17
  * 获取类级中间件
11
18
  * @param constructor - 控制器构造函数
@@ -1 +1 @@
1
- {"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../../src/middleware/decorators.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAoC/C;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,WAAW,EAAE,UAAU,EAAE,GAAG,cAAc,GAAG,eAAe,CAQ5F;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,GAAG,UAAU,EAAE,CAIlG;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAAG,MAAM,GAC3B,UAAU,EAAE,CAKd"}
1
+ {"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../../src/middleware/decorators.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAA6B,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAoCxF;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,WAAW,EAAE,UAAU,EAAE,GAAG,cAAc,GAAG,eAAe,CAQ5F;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAKpE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,GAAG,UAAU,EAAE,CAIlG;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAAG,MAAM,GAC3B,UAAU,EAAE,CAKd"}
@@ -1,5 +1,5 @@
1
1
  export type { Middleware, NextFunction } from './middleware';
2
2
  export { MiddlewarePipeline, runMiddlewares } from './pipeline';
3
- export { UseMiddleware, getClassMiddlewares, getMethodMiddlewares } from './decorators';
3
+ export { UseMiddleware, RateLimit, getClassMiddlewares, getMethodMiddlewares } from './decorators';
4
4
  export { createLoggerMiddleware, createRequestLoggingMiddleware, createErrorHandlingMiddleware, createCorsMiddleware, } from './builtin';
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACxF,OAAO,EACL,sBAAsB,EACtB,8BAA8B,EAC9B,6BAA6B,EAC7B,oBAAoB,GACrB,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACnG,OAAO,EACL,sBAAsB,EACtB,8BAA8B,EAC9B,6BAA6B,EAC7B,oBAAoB,GACrB,MAAM,WAAW,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dangao/bun-server",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -13,7 +13,7 @@
13
13
  },
14
14
  "repository": {
15
15
  "type": "git",
16
- "url": "https://github.com/dangaogit/@dangao/bun-server.git"
16
+ "url": "https://github.com/dangaogit/bun-server.git"
17
17
  },
18
18
  "keywords": [
19
19
  "bun",
@@ -46,7 +46,7 @@
46
46
  "dts": "tsc -p tsconfig.build.json",
47
47
  "build": "bun run clean && bun run bundle && bun run dts",
48
48
  "prepare": "bun run build",
49
- "publish": "cp ../../readme.md ../../LICENSE . && bun publish --access public && rm -f ./readme.md ./LICENSE"
49
+ "publish:package": "cp ../../readme.md ../../LICENSE . && bun publish --access public && rm -f ./readme.md ./LICENSE"
50
50
  },
51
51
  "devDependencies": {
52
52
  "typescript": "5.9.3",
package/readme.md CHANGED
@@ -166,7 +166,7 @@ bun benchmark/di.bench.ts
166
166
 
167
167
  ## 路线图
168
168
 
169
- 详细路线图、阶段目标与完成情况请查阅 [`.roadmap.md`](./.roadmap.md)。
169
+ 详细路线图、阶段目标与完成情况请查阅 [`.roadmap/v0.3.0.md`](./.roadmap/v0.3.0.md)。
170
170
 
171
171
  ## 工程规范
172
172