@dangao/bun-server 1.1.4 → 1.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.
package/dist/index.js CHANGED
@@ -774,6 +774,164 @@ class BunServer {
774
774
  }
775
775
  }
776
776
 
777
+ // src/core/context-service.ts
778
+ import { AsyncLocalStorage } from "async_hooks";
779
+
780
+ // src/di/decorators.ts
781
+ import"reflect-metadata";
782
+ import { LoggerManager as LoggerManager2 } from "@dangao/logsmith";
783
+ var DEPENDENCY_METADATA_KEY = Symbol("dependency:metadata");
784
+ var INJECTABLE_METADATA_KEY = Symbol("injectable");
785
+ var typeReferenceMap = new WeakMap;
786
+ function Injectable(config) {
787
+ return function(target) {
788
+ Reflect.defineMetadata(INJECTABLE_METADATA_KEY, true, target);
789
+ if (config?.lifecycle) {
790
+ Reflect.defineMetadata("lifecycle", config.lifecycle, target);
791
+ }
792
+ };
793
+ }
794
+ function Inject(token) {
795
+ return function(target, _propertyKey, parameterIndex) {
796
+ const logger = LoggerManager2.getLogger();
797
+ const constructor = typeof target === "function" ? target : target?.constructor;
798
+ if (!constructor) {
799
+ return;
800
+ }
801
+ const paramTypes = Reflect.getMetadata("design:paramtypes", constructor);
802
+ const paramType = paramTypes?.[parameterIndex];
803
+ let metadata = Reflect.getMetadata(DEPENDENCY_METADATA_KEY, constructor) || [];
804
+ const paramCount = paramTypes?.length || 0;
805
+ while (metadata.length < paramCount) {
806
+ metadata.push(undefined);
807
+ }
808
+ let dependencyType;
809
+ let dependencyToken;
810
+ if (token) {
811
+ if (typeof token === "string" || typeof token === "symbol") {
812
+ dependencyToken = token;
813
+ dependencyType = paramType || Object;
814
+ } else {
815
+ dependencyType = token;
816
+ }
817
+ } else {
818
+ if (!paramType) {
819
+ throw new Error(`Cannot determine dependency type for parameter ${parameterIndex} of ${constructor.name}. ` + "Please provide explicit type using @Inject(Type) or ensure emitDecoratorMetadata is enabled.");
820
+ }
821
+ dependencyType = paramType;
822
+ }
823
+ if (!typeReferenceMap.has(constructor)) {
824
+ typeReferenceMap.set(constructor, new Map);
825
+ }
826
+ const typeRefs = typeReferenceMap.get(constructor);
827
+ typeRefs.set(String(parameterIndex), dependencyType);
828
+ metadata[parameterIndex] = {
829
+ index: parameterIndex,
830
+ type: dependencyType,
831
+ token: dependencyToken
832
+ };
833
+ if (constructor.name === "Service" || constructor.name === "Level2") {
834
+ logger.debug(`[DI Debug] @Inject(${token ? typeof token === "function" ? token.name : String(token) : "auto"}) on ${constructor.name}[${parameterIndex}]: saving metadata.length=${metadata.length}`);
835
+ }
836
+ Reflect.defineMetadata(DEPENDENCY_METADATA_KEY, metadata, constructor);
837
+ if (constructor.name === "Service" || constructor.name === "Level2") {
838
+ const savedMetadata = Reflect.getMetadata(DEPENDENCY_METADATA_KEY, constructor);
839
+ logger.debug(`[DI Debug] @Inject on ${constructor.name}: saved metadata.exists=${savedMetadata ? "yes" : "no"}, length=${savedMetadata?.length || 0}`);
840
+ }
841
+ };
842
+ }
843
+ function getDependencyMetadata(target) {
844
+ const constructor = typeof target === "function" ? target : target?.constructor;
845
+ if (!constructor) {
846
+ return [];
847
+ }
848
+ const rawMetadata = Reflect.getMetadata(DEPENDENCY_METADATA_KEY, constructor);
849
+ const metadata = rawMetadata || [];
850
+ if (constructor.name === "Service" || constructor.name === "Level2") {
851
+ LoggerManager2.getLogger().debug(`[DI Debug] getDependencyMetadata(${constructor.name}): rawMetadata=${rawMetadata ? "exists" : "undefined"}, length=${metadata.length}`);
852
+ }
853
+ const typeRefs = typeReferenceMap.get(constructor);
854
+ if (typeRefs) {
855
+ for (let i = 0;i < metadata.length; i++) {
856
+ const meta = metadata[i];
857
+ if (meta !== undefined && meta !== null) {
858
+ const typeRef = typeRefs.get(String(meta.index));
859
+ if (typeRef && typeof typeRef === "function") {
860
+ meta.type = typeRef;
861
+ }
862
+ }
863
+ }
864
+ }
865
+ return metadata;
866
+ }
867
+ function getLifecycle(target) {
868
+ return Reflect.getMetadata("lifecycle", target);
869
+ }
870
+ function getTypeReference(constructor, parameterIndex) {
871
+ const typeRefs = typeReferenceMap.get(constructor);
872
+ if (typeRefs) {
873
+ return typeRefs.get(String(parameterIndex));
874
+ }
875
+ return;
876
+ }
877
+
878
+ // src/core/context-service.ts
879
+ var contextStore = new AsyncLocalStorage;
880
+ var CONTEXT_SERVICE_TOKEN = Symbol("ContextService");
881
+
882
+ class ContextService {
883
+ getContext() {
884
+ return contextStore.getStore();
885
+ }
886
+ getHeader(key) {
887
+ const context = this.getContext();
888
+ return context?.getHeader(key) ?? null;
889
+ }
890
+ getQuery(key) {
891
+ const context = this.getContext();
892
+ return context?.getQuery(key) ?? null;
893
+ }
894
+ getQueryAll() {
895
+ const context = this.getContext();
896
+ return context?.getQueryAll() ?? {};
897
+ }
898
+ getParam(key) {
899
+ const context = this.getContext();
900
+ return context?.getParam(key);
901
+ }
902
+ getBody() {
903
+ const context = this.getContext();
904
+ return context?.body ?? null;
905
+ }
906
+ getMethod() {
907
+ const context = this.getContext();
908
+ return context?.method ?? "";
909
+ }
910
+ getPath() {
911
+ const context = this.getContext();
912
+ return context?.path ?? "";
913
+ }
914
+ getUrl() {
915
+ const context = this.getContext();
916
+ return context?.url;
917
+ }
918
+ getClientIp() {
919
+ const context = this.getContext();
920
+ return context?.getClientIp() ?? "unknown";
921
+ }
922
+ setHeader(key, value) {
923
+ const context = this.getContext();
924
+ context?.setHeader(key, value);
925
+ }
926
+ setStatus(code) {
927
+ const context = this.getContext();
928
+ context?.setStatus(code);
929
+ }
930
+ }
931
+ ContextService = __legacyDecorateClassTS([
932
+ Injectable()
933
+ ], ContextService);
934
+
777
935
  // src/middleware/pipeline.ts
778
936
  class MiddlewarePipeline {
779
937
  middlewares = [];
@@ -1043,107 +1201,8 @@ var Lifecycle;
1043
1201
  Lifecycle2["Scoped"] = "scoped";
1044
1202
  })(Lifecycle ||= {});
1045
1203
 
1046
- // src/di/decorators.ts
1047
- import"reflect-metadata";
1048
- import { LoggerManager as LoggerManager2 } from "@dangao/logsmith";
1049
- var DEPENDENCY_METADATA_KEY = Symbol("dependency:metadata");
1050
- var INJECTABLE_METADATA_KEY = Symbol("injectable");
1051
- var typeReferenceMap = new WeakMap;
1052
- function Injectable(config) {
1053
- return function(target) {
1054
- Reflect.defineMetadata(INJECTABLE_METADATA_KEY, true, target);
1055
- if (config?.lifecycle) {
1056
- Reflect.defineMetadata("lifecycle", config.lifecycle, target);
1057
- }
1058
- };
1059
- }
1060
- function Inject(token) {
1061
- return function(target, _propertyKey, parameterIndex) {
1062
- const logger = LoggerManager2.getLogger();
1063
- const constructor = typeof target === "function" ? target : target?.constructor;
1064
- if (!constructor) {
1065
- return;
1066
- }
1067
- const paramTypes = Reflect.getMetadata("design:paramtypes", constructor);
1068
- const paramType = paramTypes?.[parameterIndex];
1069
- let metadata = Reflect.getMetadata(DEPENDENCY_METADATA_KEY, constructor) || [];
1070
- const paramCount = paramTypes?.length || 0;
1071
- while (metadata.length < paramCount) {
1072
- metadata.push(undefined);
1073
- }
1074
- let dependencyType;
1075
- let dependencyToken;
1076
- if (token) {
1077
- if (typeof token === "string" || typeof token === "symbol") {
1078
- dependencyToken = token;
1079
- dependencyType = paramType || Object;
1080
- } else {
1081
- dependencyType = token;
1082
- }
1083
- } else {
1084
- if (!paramType) {
1085
- throw new Error(`Cannot determine dependency type for parameter ${parameterIndex} of ${constructor.name}. ` + "Please provide explicit type using @Inject(Type) or ensure emitDecoratorMetadata is enabled.");
1086
- }
1087
- dependencyType = paramType;
1088
- }
1089
- if (!typeReferenceMap.has(constructor)) {
1090
- typeReferenceMap.set(constructor, new Map);
1091
- }
1092
- const typeRefs = typeReferenceMap.get(constructor);
1093
- typeRefs.set(String(parameterIndex), dependencyType);
1094
- metadata[parameterIndex] = {
1095
- index: parameterIndex,
1096
- type: dependencyType,
1097
- token: dependencyToken
1098
- };
1099
- if (constructor.name === "Service" || constructor.name === "Level2") {
1100
- logger.debug(`[DI Debug] @Inject(${token ? typeof token === "function" ? token.name : String(token) : "auto"}) on ${constructor.name}[${parameterIndex}]: saving metadata.length=${metadata.length}`);
1101
- }
1102
- Reflect.defineMetadata(DEPENDENCY_METADATA_KEY, metadata, constructor);
1103
- if (constructor.name === "Service" || constructor.name === "Level2") {
1104
- const savedMetadata = Reflect.getMetadata(DEPENDENCY_METADATA_KEY, constructor);
1105
- logger.debug(`[DI Debug] @Inject on ${constructor.name}: saved metadata.exists=${savedMetadata ? "yes" : "no"}, length=${savedMetadata?.length || 0}`);
1106
- }
1107
- };
1108
- }
1109
- function getDependencyMetadata(target) {
1110
- const constructor = typeof target === "function" ? target : target?.constructor;
1111
- if (!constructor) {
1112
- return [];
1113
- }
1114
- const rawMetadata = Reflect.getMetadata(DEPENDENCY_METADATA_KEY, constructor);
1115
- const metadata = rawMetadata || [];
1116
- if (constructor.name === "Service" || constructor.name === "Level2") {
1117
- LoggerManager2.getLogger().debug(`[DI Debug] getDependencyMetadata(${constructor.name}): rawMetadata=${rawMetadata ? "exists" : "undefined"}, length=${metadata.length}`);
1118
- }
1119
- const typeRefs = typeReferenceMap.get(constructor);
1120
- if (typeRefs) {
1121
- for (let i = 0;i < metadata.length; i++) {
1122
- const meta = metadata[i];
1123
- if (meta !== undefined && meta !== null) {
1124
- const typeRef = typeRefs.get(String(meta.index));
1125
- if (typeRef && typeof typeRef === "function") {
1126
- meta.type = typeRef;
1127
- }
1128
- }
1129
- }
1130
- }
1131
- return metadata;
1132
- }
1133
- function getLifecycle(target) {
1134
- return Reflect.getMetadata("lifecycle", target);
1135
- }
1136
- function getTypeReference(constructor, parameterIndex) {
1137
- const typeRefs = typeReferenceMap.get(constructor);
1138
- if (typeRefs) {
1139
- return typeRefs.get(String(parameterIndex));
1140
- }
1141
- return;
1142
- }
1143
-
1144
1204
  // src/di/container.ts
1145
1205
  import { LoggerManager as LoggerManager3 } from "@dangao/logsmith";
1146
-
1147
1206
  class Container {
1148
1207
  parent;
1149
1208
  constructor(options = {}) {
@@ -1151,6 +1210,7 @@ class Container {
1151
1210
  }
1152
1211
  providers = new Map;
1153
1212
  singletons = new Map;
1213
+ scopedInstances = new WeakMap;
1154
1214
  typeToToken = new Map;
1155
1215
  dependencyPlans = new Map;
1156
1216
  register(token, config) {
@@ -1200,6 +1260,20 @@ class Container {
1200
1260
  return singleton;
1201
1261
  }
1202
1262
  }
1263
+ if (provider.lifecycle === "scoped" /* Scoped */) {
1264
+ const context = contextStore.getStore();
1265
+ if (context) {
1266
+ let scopedMap = this.scopedInstances.get(context);
1267
+ if (!scopedMap) {
1268
+ scopedMap = new Map;
1269
+ this.scopedInstances.set(context, scopedMap);
1270
+ }
1271
+ const scopedInstance = scopedMap.get(tokenKey);
1272
+ if (scopedInstance) {
1273
+ return scopedInstance;
1274
+ }
1275
+ }
1276
+ }
1203
1277
  let instance;
1204
1278
  if (provider.factory) {
1205
1279
  instance = provider.factory();
@@ -1213,6 +1287,17 @@ class Container {
1213
1287
  if (provider.lifecycle === "singleton" /* Singleton */) {
1214
1288
  this.singletons.set(tokenKey, instance);
1215
1289
  }
1290
+ if (provider.lifecycle === "scoped" /* Scoped */) {
1291
+ const context = contextStore.getStore();
1292
+ if (context) {
1293
+ let scopedMap = this.scopedInstances.get(context);
1294
+ if (!scopedMap) {
1295
+ scopedMap = new Map;
1296
+ this.scopedInstances.set(context, scopedMap);
1297
+ }
1298
+ scopedMap.set(tokenKey, instance);
1299
+ }
1300
+ }
1216
1301
  return instance;
1217
1302
  }
1218
1303
  resolveInternal(token) {
@@ -1236,21 +1321,43 @@ class Container {
1236
1321
  return singleton;
1237
1322
  }
1238
1323
  }
1239
- if (provider.factory) {
1240
- const instance = provider.factory();
1241
- if (provider.lifecycle === "singleton" /* Singleton */) {
1242
- this.singletons.set(token, instance);
1324
+ if (provider.lifecycle === "scoped" /* Scoped */) {
1325
+ const context = contextStore.getStore();
1326
+ if (context) {
1327
+ let scopedMap = this.scopedInstances.get(context);
1328
+ if (!scopedMap) {
1329
+ scopedMap = new Map;
1330
+ this.scopedInstances.set(context, scopedMap);
1331
+ }
1332
+ const scopedInstance = scopedMap.get(token);
1333
+ if (scopedInstance) {
1334
+ return scopedInstance;
1335
+ }
1243
1336
  }
1244
- return instance;
1245
1337
  }
1246
- if (provider.implementation && typeof provider.implementation === "function") {
1247
- const instance = this.instantiate(provider.implementation);
1248
- if (provider.lifecycle === "singleton" /* Singleton */) {
1249
- this.singletons.set(token, instance);
1338
+ let instance;
1339
+ if (provider.factory) {
1340
+ instance = provider.factory();
1341
+ } else if (provider.implementation && typeof provider.implementation === "function") {
1342
+ instance = this.instantiate(provider.implementation);
1343
+ } else {
1344
+ throw new Error(`Cannot instantiate token: ${String(token)}. Factory function required.`);
1345
+ }
1346
+ if (provider.lifecycle === "singleton" /* Singleton */) {
1347
+ this.singletons.set(token, instance);
1348
+ }
1349
+ if (provider.lifecycle === "scoped" /* Scoped */) {
1350
+ const context = contextStore.getStore();
1351
+ if (context) {
1352
+ let scopedMap = this.scopedInstances.get(context);
1353
+ if (!scopedMap) {
1354
+ scopedMap = new Map;
1355
+ this.scopedInstances.set(context, scopedMap);
1356
+ }
1357
+ scopedMap.set(token, instance);
1250
1358
  }
1251
- return instance;
1252
1359
  }
1253
- throw new Error(`Cannot instantiate token: ${String(token)}. Factory function required.`);
1360
+ return instance;
1254
1361
  }
1255
1362
  if (typeof token === "function") {
1256
1363
  return this.resolve(token);
@@ -1371,6 +1478,25 @@ function Param(key) {
1371
1478
  function Header(key) {
1372
1479
  return createParamDecorator("header" /* HEADER */, key);
1373
1480
  }
1481
+ function QueryMap(options) {
1482
+ return function(target, propertyKey, parameterIndex) {
1483
+ const existingParams = Reflect.getMetadata(PARAM_METADATA_KEY, target, propertyKey) || [];
1484
+ const normalizedOptions = typeof options === "function" ? { transform: options } : options ?? {};
1485
+ existingParams.push({ type: "query_map" /* QUERY_MAP */, index: parameterIndex, options: normalizedOptions });
1486
+ Reflect.defineMetadata(PARAM_METADATA_KEY, existingParams, target, propertyKey);
1487
+ };
1488
+ }
1489
+ function HeaderMap(options) {
1490
+ return function(target, propertyKey, parameterIndex) {
1491
+ const existingParams = Reflect.getMetadata(PARAM_METADATA_KEY, target, propertyKey) || [];
1492
+ const normalizedOptions = typeof options === "function" ? { transform: options } : options ?? {};
1493
+ existingParams.push({ type: "header_map" /* HEADER_MAP */, index: parameterIndex, options: normalizedOptions });
1494
+ Reflect.defineMetadata(PARAM_METADATA_KEY, existingParams, target, propertyKey);
1495
+ };
1496
+ }
1497
+ function Context2() {
1498
+ return createParamDecorator("context" /* CONTEXT */);
1499
+ }
1374
1500
  function getParamMetadata(target, propertyKey) {
1375
1501
  return Reflect.getMetadata(PARAM_METADATA_KEY, target, propertyKey) || [];
1376
1502
  }
@@ -1578,6 +1704,12 @@ class ParamBinder {
1578
1704
  }
1579
1705
  } catch {}
1580
1706
  return;
1707
+ case "context" /* CONTEXT */:
1708
+ return contextStore.getStore() ?? context;
1709
+ case "query_map" /* QUERY_MAP */:
1710
+ return await this.getQueryMapValue(meta.options, context);
1711
+ case "header_map" /* HEADER_MAP */:
1712
+ return await this.getHeaderMapValue(meta.options, context);
1581
1713
  default:
1582
1714
  return;
1583
1715
  }
@@ -1601,6 +1733,52 @@ class ParamBinder {
1601
1733
  static getHeaderValue(key, context) {
1602
1734
  return context.getHeader(key);
1603
1735
  }
1736
+ static async getQueryMapValue(options, context) {
1737
+ const result = {};
1738
+ const searchParams = context.query;
1739
+ for (const key of searchParams.keys()) {
1740
+ const values = searchParams.getAll(key);
1741
+ if (values.length === 1) {
1742
+ result[key] = values[0];
1743
+ } else {
1744
+ result[key] = values;
1745
+ }
1746
+ }
1747
+ let output = result;
1748
+ if (options?.transform) {
1749
+ output = await options.transform(result);
1750
+ }
1751
+ if (options?.validate) {
1752
+ await options.validate(output);
1753
+ }
1754
+ return output;
1755
+ }
1756
+ static async getHeaderMapValue(options, context) {
1757
+ const normalize = options?.normalize ?? true;
1758
+ const pick = options?.pick?.map((key) => key.toLowerCase());
1759
+ const headers = context.headers;
1760
+ const result = {};
1761
+ headers.forEach((value, rawKey) => {
1762
+ const key = normalize ? rawKey.toLowerCase() : rawKey;
1763
+ if (pick && !pick.includes(key)) {
1764
+ return;
1765
+ }
1766
+ const parts = value.split(",").map((item) => item.trim()).filter((item) => item.length > 0);
1767
+ if (parts.length <= 1) {
1768
+ result[key] = parts[0] ?? "";
1769
+ } else {
1770
+ result[key] = parts;
1771
+ }
1772
+ });
1773
+ let output = result;
1774
+ if (options?.transform) {
1775
+ output = await options.transform(result);
1776
+ }
1777
+ if (options?.validate) {
1778
+ await options.validate(output);
1779
+ }
1780
+ return output;
1781
+ }
1604
1782
  }
1605
1783
 
1606
1784
  // src/controller/metadata.ts
@@ -2903,6 +3081,7 @@ class Application {
2903
3081
  const container = ControllerRegistry.getInstance().getContainer();
2904
3082
  const interceptorRegistry = new InterceptorRegistry;
2905
3083
  container.registerInstance(INTERCEPTOR_REGISTRY_TOKEN, interceptorRegistry);
3084
+ container.registerInstance(CONTEXT_SERVICE_TOKEN, new ContextService);
2906
3085
  this.registerExtension(new LoggerExtension);
2907
3086
  }
2908
3087
  use(middleware) {
@@ -2944,19 +3123,21 @@ class Application {
2944
3123
  }
2945
3124
  }
2946
3125
  async handleRequest(context) {
2947
- if (["POST", "PUT", "PATCH"].includes(context.method)) {
2948
- await context.getBody();
2949
- }
2950
- const registry = RouteRegistry.getInstance();
2951
- const router = registry.getRouter();
2952
- await router.preHandle(context);
2953
- return await this.middlewarePipeline.run(context, async () => {
2954
- const response = await router.handle(context);
2955
- if (response) {
2956
- return response;
2957
- }
2958
- context.setStatus(404);
2959
- return context.createResponse({ error: "Not Found" });
3126
+ return await contextStore.run(context, async () => {
3127
+ if (["POST", "PUT", "PATCH"].includes(context.method)) {
3128
+ await context.getBody();
3129
+ }
3130
+ const registry = RouteRegistry.getInstance();
3131
+ const router = registry.getRouter();
3132
+ await router.preHandle(context);
3133
+ return await this.middlewarePipeline.run(context, async () => {
3134
+ const response = await router.handle(context);
3135
+ if (response) {
3136
+ return response;
3137
+ }
3138
+ context.setStatus(404);
3139
+ return context.createResponse({ error: "Not Found" });
3140
+ });
2960
3141
  });
2961
3142
  }
2962
3143
  registerController(controllerClass) {
@@ -3445,7 +3626,7 @@ SwaggerModule = __legacyDecorateClassTS([
3445
3626
  })
3446
3627
  ], SwaggerModule);
3447
3628
  // src/security/context.ts
3448
- import { AsyncLocalStorage } from "async_hooks";
3629
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
3449
3630
 
3450
3631
  class SecurityContextImpl {
3451
3632
  _authentication = null;
@@ -3470,7 +3651,7 @@ class SecurityContextImpl {
3470
3651
  }
3471
3652
 
3472
3653
  class SecurityContextHolder {
3473
- static storage = new AsyncLocalStorage;
3654
+ static storage = new AsyncLocalStorage2;
3474
3655
  static getContext() {
3475
3656
  let context = this.storage.getStore();
3476
3657
  if (!context) {
@@ -6630,6 +6811,7 @@ export {
6630
6811
  createFileUploadMiddleware,
6631
6812
  createErrorHandlingMiddleware,
6632
6813
  createCorsMiddleware,
6814
+ contextStore,
6633
6815
  checkRoles,
6634
6816
  WebSocketGatewayRegistry,
6635
6817
  WebSocketGateway,
@@ -6666,6 +6848,7 @@ export {
6666
6848
  QueueService,
6667
6849
  QueueModule,
6668
6850
  Queue,
6851
+ QueryMap,
6669
6852
  Query,
6670
6853
  QUEUE_SERVICE_TOKEN,
6671
6854
  QUEUE_OPTIONS_TOKEN,
@@ -6726,6 +6909,7 @@ export {
6726
6909
  INTERCEPTOR_REGISTRY_TOKEN,
6727
6910
  HttpException,
6728
6911
  HealthModule,
6912
+ HeaderMap,
6729
6913
  Header,
6730
6914
  HEALTH_OPTIONS_TOKEN,
6731
6915
  HEALTH_INDICATORS_TOKEN,
@@ -6745,6 +6929,8 @@ export {
6745
6929
  Cron,
6746
6930
  ControllerRegistry,
6747
6931
  Controller,
6932
+ ContextService,
6933
+ Context2 as ContextParam,
6748
6934
  Context,
6749
6935
  Container,
6750
6936
  ConnectionPool,
@@ -6758,6 +6944,7 @@ export {
6758
6944
  CacheInterceptor,
6759
6945
  CacheEvict,
6760
6946
  Cache,
6947
+ CONTEXT_SERVICE_TOKEN,
6761
6948
  CONFIG_SERVICE_TOKEN,
6762
6949
  CACHE_SERVICE_TOKEN,
6763
6950
  CACHE_OPTIONS_TOKEN,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dangao/bun-server",
3
- "version": "1.1.4",
3
+ "version": "1.3.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -14,6 +14,9 @@ export enum ParamType {
14
14
  PARAM = 'param',
15
15
  HEADER = 'header',
16
16
  SESSION = 'session',
17
+ CONTEXT = 'context',
18
+ QUERY_MAP = 'query_map',
19
+ HEADER_MAP = 'header_map',
17
20
  }
18
21
 
19
22
  /**
@@ -23,6 +26,7 @@ export interface ParamMetadata {
23
26
  type: ParamType;
24
27
  key?: string;
25
28
  index: number;
29
+ options?: unknown;
26
30
  }
27
31
 
28
32
  /**
@@ -72,6 +76,76 @@ export function Header(key: string) {
72
76
  return createParamDecorator(ParamType.HEADER, key);
73
77
  }
74
78
 
79
+ /**
80
+ * QueryMap 注解选项
81
+ */
82
+ export interface QueryMapOptions<T = unknown> {
83
+ transform?: (input: Record<string, string | string[]>) => T | Promise<T>;
84
+ validate?: (dto: T) => void | Promise<void>;
85
+ }
86
+
87
+ /**
88
+ * HeaderMap 注解选项
89
+ */
90
+ export interface HeaderMapOptions<T = unknown> {
91
+ normalize?: boolean;
92
+ pick?: string[];
93
+ transform?: (input: Record<string, string | string[]>) => T | Promise<T>;
94
+ validate?: (dto: T) => void | Promise<void>;
95
+ }
96
+
97
+ /**
98
+ * QueryMap 参数装饰器
99
+ * 一次性注入完整查询对象
100
+ */
101
+ export function QueryMap<T = Record<string, string | string[]>>(
102
+ options?: QueryMapOptions<T> | ((input: Record<string, string | string[]>) => T | Promise<T>),
103
+ ) {
104
+ return function (target: any, propertyKey: string | symbol | undefined, parameterIndex: number) {
105
+ const existingParams: ParamMetadata[] =
106
+ Reflect.getMetadata(PARAM_METADATA_KEY, target, propertyKey as string) || [];
107
+ const normalizedOptions: QueryMapOptions<T> =
108
+ typeof options === 'function' ? { transform: options } : options ?? {};
109
+ existingParams.push({ type: ParamType.QUERY_MAP, index: parameterIndex, options: normalizedOptions });
110
+ Reflect.defineMetadata(PARAM_METADATA_KEY, existingParams, target, propertyKey as string);
111
+ };
112
+ }
113
+
114
+ /**
115
+ * HeaderMap 参数装饰器
116
+ * 一次性注入完整 headers 对象
117
+ */
118
+ export function HeaderMap<T = Record<string, string | string[]>>(
119
+ options?: HeaderMapOptions<T> | ((input: Record<string, string | string[]>) => T | Promise<T>),
120
+ ) {
121
+ return function (target: any, propertyKey: string | symbol | undefined, parameterIndex: number) {
122
+ const existingParams: ParamMetadata[] =
123
+ Reflect.getMetadata(PARAM_METADATA_KEY, target, propertyKey as string) || [];
124
+ const normalizedOptions: HeaderMapOptions<T> =
125
+ typeof options === 'function' ? { transform: options } : options ?? {};
126
+ existingParams.push({ type: ParamType.HEADER_MAP, index: parameterIndex, options: normalizedOptions });
127
+ Reflect.defineMetadata(PARAM_METADATA_KEY, existingParams, target, propertyKey as string);
128
+ };
129
+ }
130
+
131
+ /**
132
+ * Context 参数装饰器
133
+ * 用于在控制器方法中注入当前请求的 Context 对象
134
+ *
135
+ * @example
136
+ * ```typescript
137
+ * @GET('/users/:id')
138
+ * public async getUser(@Param('id') id: string, @Context() context: Context) {
139
+ * // 可以直接访问 context
140
+ * const header = context.getHeader('Authorization');
141
+ * return { id, header };
142
+ * }
143
+ * ```
144
+ */
145
+ export function Context() {
146
+ return createParamDecorator(ParamType.CONTEXT);
147
+ }
148
+
75
149
  /**
76
150
  * 获取参数元数据
77
151
  * @param target - 目标对象
@@ -1,5 +1,19 @@
1
- export { Body, Query, Param, Header, getParamMetadata, ParamType } from './decorators';
2
- export type { ParamMetadata } from './decorators';
1
+ export {
2
+ Body,
3
+ Query,
4
+ QueryMap,
5
+ Param,
6
+ Header,
7
+ HeaderMap,
8
+ Context,
9
+ getParamMetadata,
10
+ ParamType,
11
+ } from './decorators';
12
+ export type {
13
+ ParamMetadata,
14
+ QueryMapOptions,
15
+ HeaderMapOptions,
16
+ } from './decorators';
3
17
  export { ParamBinder } from './param-binder';
4
18
  export { Controller, ControllerRegistry } from './controller';
5
19
  export type { ControllerMetadata } from './controller';