nstarter-http-request 0.1.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.
Files changed (263) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +160 -0
  3. package/dist/cjs/adapter/axios.adapter.js +224 -0
  4. package/dist/cjs/adapter/axios.adapter.js.map +1 -0
  5. package/dist/cjs/adapter/base.js +134 -0
  6. package/dist/cjs/adapter/base.js.map +1 -0
  7. package/dist/cjs/adapter/index.js +20 -0
  8. package/dist/cjs/adapter/index.js.map +1 -0
  9. package/dist/cjs/adapter/undici.adapter.js +272 -0
  10. package/dist/cjs/adapter/undici.adapter.js.map +1 -0
  11. package/dist/cjs/client.js +409 -0
  12. package/dist/cjs/client.js.map +1 -0
  13. package/dist/cjs/config.js +69 -0
  14. package/dist/cjs/config.js.map +1 -0
  15. package/dist/cjs/const/config.const.js +53 -0
  16. package/dist/cjs/const/config.const.js.map +1 -0
  17. package/dist/cjs/const/dns.const.js +16 -0
  18. package/dist/cjs/const/dns.const.js.map +1 -0
  19. package/dist/cjs/const/enum.const.js +22 -0
  20. package/dist/cjs/const/enum.const.js.map +1 -0
  21. package/dist/cjs/const/index.js +21 -0
  22. package/dist/cjs/const/index.js.map +1 -0
  23. package/dist/cjs/const/ip.const.js +110 -0
  24. package/dist/cjs/const/ip.const.js.map +1 -0
  25. package/dist/cjs/index.js +25 -0
  26. package/dist/cjs/index.js.map +1 -0
  27. package/dist/cjs/logger/base.js +60 -0
  28. package/dist/cjs/logger/base.js.map +1 -0
  29. package/dist/cjs/logger/http_client.logger.js +209 -0
  30. package/dist/cjs/logger/http_client.logger.js.map +1 -0
  31. package/dist/cjs/logger/index.js +20 -0
  32. package/dist/cjs/logger/index.js.map +1 -0
  33. package/dist/cjs/logger/log.filter.js +126 -0
  34. package/dist/cjs/logger/log.filter.js.map +1 -0
  35. package/dist/cjs/security/dns.validator.js +137 -0
  36. package/dist/cjs/security/dns.validator.js.map +1 -0
  37. package/dist/cjs/security/index.js +21 -0
  38. package/dist/cjs/security/index.js.map +1 -0
  39. package/dist/cjs/security/ip.validator.js +107 -0
  40. package/dist/cjs/security/ip.validator.js.map +1 -0
  41. package/dist/cjs/security/ssrf.guard.js +180 -0
  42. package/dist/cjs/security/ssrf.guard.js.map +1 -0
  43. package/dist/cjs/security/url.validator.js +170 -0
  44. package/dist/cjs/security/url.validator.js.map +1 -0
  45. package/dist/cjs/tsconfig.tsbuildinfo +1 -0
  46. package/dist/cjs/types/adapter.js +6 -0
  47. package/dist/cjs/types/adapter.js.map +1 -0
  48. package/dist/cjs/types/client.js +6 -0
  49. package/dist/cjs/types/client.js.map +1 -0
  50. package/dist/cjs/types/config.js +6 -0
  51. package/dist/cjs/types/config.js.map +1 -0
  52. package/dist/cjs/types/errors.js +35 -0
  53. package/dist/cjs/types/errors.js.map +1 -0
  54. package/dist/cjs/types/index.js +35 -0
  55. package/dist/cjs/types/index.js.map +1 -0
  56. package/dist/cjs/types/ip.js +6 -0
  57. package/dist/cjs/types/ip.js.map +1 -0
  58. package/dist/cjs/types/logger.js +6 -0
  59. package/dist/cjs/types/logger.js.map +1 -0
  60. package/dist/cjs/types/request_response.js +6 -0
  61. package/dist/cjs/types/request_response.js.map +1 -0
  62. package/dist/cjs/types/security.js +6 -0
  63. package/dist/cjs/types/security.js.map +1 -0
  64. package/dist/cjs/types/trace.js +14 -0
  65. package/dist/cjs/types/trace.js.map +1 -0
  66. package/dist/cjs/utils/common.js +31 -0
  67. package/dist/cjs/utils/common.js.map +1 -0
  68. package/dist/cjs/utils/domain.js +79 -0
  69. package/dist/cjs/utils/domain.js.map +1 -0
  70. package/dist/cjs/utils/index.js +44 -0
  71. package/dist/cjs/utils/index.js.map +1 -0
  72. package/dist/cjs/utils/ip.range.js +200 -0
  73. package/dist/cjs/utils/ip.range.js.map +1 -0
  74. package/dist/cjs/utils/trace.context.js +213 -0
  75. package/dist/cjs/utils/trace.context.js.map +1 -0
  76. package/dist/esm/adapter/axios.adapter.js +184 -0
  77. package/dist/esm/adapter/axios.adapter.js.map +1 -0
  78. package/dist/esm/adapter/base.js +130 -0
  79. package/dist/esm/adapter/base.js.map +1 -0
  80. package/dist/esm/adapter/index.js +4 -0
  81. package/dist/esm/adapter/index.js.map +1 -0
  82. package/dist/esm/adapter/undici.adapter.js +235 -0
  83. package/dist/esm/adapter/undici.adapter.js.map +1 -0
  84. package/dist/esm/client.js +405 -0
  85. package/dist/esm/client.js.map +1 -0
  86. package/dist/esm/config.js +65 -0
  87. package/dist/esm/config.js.map +1 -0
  88. package/dist/esm/const/config.const.js +50 -0
  89. package/dist/esm/const/config.const.js.map +1 -0
  90. package/dist/esm/const/dns.const.js +13 -0
  91. package/dist/esm/const/dns.const.js.map +1 -0
  92. package/dist/esm/const/enum.const.js +19 -0
  93. package/dist/esm/const/enum.const.js.map +1 -0
  94. package/dist/esm/const/index.js +5 -0
  95. package/dist/esm/const/index.js.map +1 -0
  96. package/dist/esm/const/ip.const.js +107 -0
  97. package/dist/esm/const/ip.const.js.map +1 -0
  98. package/dist/esm/index.js +9 -0
  99. package/dist/esm/index.js.map +1 -0
  100. package/dist/esm/logger/base.js +55 -0
  101. package/dist/esm/logger/base.js.map +1 -0
  102. package/dist/esm/logger/http_client.logger.js +205 -0
  103. package/dist/esm/logger/http_client.logger.js.map +1 -0
  104. package/dist/esm/logger/index.js +4 -0
  105. package/dist/esm/logger/index.js.map +1 -0
  106. package/dist/esm/logger/log.filter.js +122 -0
  107. package/dist/esm/logger/log.filter.js.map +1 -0
  108. package/dist/esm/security/dns.validator.js +133 -0
  109. package/dist/esm/security/dns.validator.js.map +1 -0
  110. package/dist/esm/security/index.js +5 -0
  111. package/dist/esm/security/index.js.map +1 -0
  112. package/dist/esm/security/ip.validator.js +103 -0
  113. package/dist/esm/security/ip.validator.js.map +1 -0
  114. package/dist/esm/security/ssrf.guard.js +176 -0
  115. package/dist/esm/security/ssrf.guard.js.map +1 -0
  116. package/dist/esm/security/url.validator.js +166 -0
  117. package/dist/esm/security/url.validator.js.map +1 -0
  118. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -0
  119. package/dist/esm/types/adapter.js +5 -0
  120. package/dist/esm/types/adapter.js.map +1 -0
  121. package/dist/esm/types/client.js +5 -0
  122. package/dist/esm/types/client.js.map +1 -0
  123. package/dist/esm/types/config.js +5 -0
  124. package/dist/esm/types/config.js.map +1 -0
  125. package/dist/esm/types/errors.js +30 -0
  126. package/dist/esm/types/errors.js.map +1 -0
  127. package/dist/esm/types/index.js +19 -0
  128. package/dist/esm/types/index.js.map +1 -0
  129. package/dist/esm/types/ip.js +5 -0
  130. package/dist/esm/types/ip.js.map +1 -0
  131. package/dist/esm/types/logger.js +5 -0
  132. package/dist/esm/types/logger.js.map +1 -0
  133. package/dist/esm/types/request_response.js +5 -0
  134. package/dist/esm/types/request_response.js.map +1 -0
  135. package/dist/esm/types/security.js +5 -0
  136. package/dist/esm/types/security.js.map +1 -0
  137. package/dist/esm/types/trace.js +11 -0
  138. package/dist/esm/types/trace.js.map +1 -0
  139. package/dist/esm/utils/common.js +27 -0
  140. package/dist/esm/utils/common.js.map +1 -0
  141. package/dist/esm/utils/domain.js +71 -0
  142. package/dist/esm/utils/domain.js.map +1 -0
  143. package/dist/esm/utils/index.js +7 -0
  144. package/dist/esm/utils/index.js.map +1 -0
  145. package/dist/esm/utils/ip.range.js +187 -0
  146. package/dist/esm/utils/ip.range.js.map +1 -0
  147. package/dist/esm/utils/trace.context.js +199 -0
  148. package/dist/esm/utils/trace.context.js.map +1 -0
  149. package/dist/types/adapter/axios.adapter.d.ts +51 -0
  150. package/dist/types/adapter/axios.adapter.d.ts.map +1 -0
  151. package/dist/types/adapter/base.d.ts +56 -0
  152. package/dist/types/adapter/base.d.ts.map +1 -0
  153. package/dist/types/adapter/index.d.ts +4 -0
  154. package/dist/types/adapter/index.d.ts.map +1 -0
  155. package/dist/types/adapter/undici.adapter.d.ts +68 -0
  156. package/dist/types/adapter/undici.adapter.d.ts.map +1 -0
  157. package/dist/types/client.d.ts +105 -0
  158. package/dist/types/client.d.ts.map +1 -0
  159. package/dist/types/config.d.ts +14 -0
  160. package/dist/types/config.d.ts.map +1 -0
  161. package/dist/types/const/config.const.d.ts +23 -0
  162. package/dist/types/const/config.const.d.ts.map +1 -0
  163. package/dist/types/const/dns.const.d.ts +13 -0
  164. package/dist/types/const/dns.const.d.ts.map +1 -0
  165. package/dist/types/const/enum.const.d.ts +17 -0
  166. package/dist/types/const/enum.const.d.ts.map +1 -0
  167. package/dist/types/const/index.d.ts +5 -0
  168. package/dist/types/const/index.d.ts.map +1 -0
  169. package/dist/types/const/ip.const.d.ts +42 -0
  170. package/dist/types/const/ip.const.d.ts.map +1 -0
  171. package/dist/types/index.d.ts +9 -0
  172. package/dist/types/index.d.ts.map +1 -0
  173. package/dist/types/logger/base.d.ts +42 -0
  174. package/dist/types/logger/base.d.ts.map +1 -0
  175. package/dist/types/logger/http_client.logger.d.ts +49 -0
  176. package/dist/types/logger/http_client.logger.d.ts.map +1 -0
  177. package/dist/types/logger/index.d.ts +4 -0
  178. package/dist/types/logger/index.d.ts.map +1 -0
  179. package/dist/types/logger/log.filter.d.ts +56 -0
  180. package/dist/types/logger/log.filter.d.ts.map +1 -0
  181. package/dist/types/security/dns.validator.d.ts +61 -0
  182. package/dist/types/security/dns.validator.d.ts.map +1 -0
  183. package/dist/types/security/index.d.ts +5 -0
  184. package/dist/types/security/index.d.ts.map +1 -0
  185. package/dist/types/security/ip.validator.d.ts +31 -0
  186. package/dist/types/security/ip.validator.d.ts.map +1 -0
  187. package/dist/types/security/ssrf.guard.d.ts +54 -0
  188. package/dist/types/security/ssrf.guard.d.ts.map +1 -0
  189. package/dist/types/security/url.validator.d.ts +76 -0
  190. package/dist/types/security/url.validator.d.ts.map +1 -0
  191. package/dist/types/types/adapter.d.ts +30 -0
  192. package/dist/types/types/adapter.d.ts.map +1 -0
  193. package/dist/types/types/client.d.ts +85 -0
  194. package/dist/types/types/client.d.ts.map +1 -0
  195. package/dist/types/types/config.d.ts +99 -0
  196. package/dist/types/types/config.d.ts.map +1 -0
  197. package/dist/types/types/errors.d.ts +23 -0
  198. package/dist/types/types/errors.d.ts.map +1 -0
  199. package/dist/types/types/index.d.ts +10 -0
  200. package/dist/types/types/index.d.ts.map +1 -0
  201. package/dist/types/types/ip.d.ts +32 -0
  202. package/dist/types/types/ip.d.ts.map +1 -0
  203. package/dist/types/types/logger.d.ts +136 -0
  204. package/dist/types/types/logger.d.ts.map +1 -0
  205. package/dist/types/types/request_response.d.ts +54 -0
  206. package/dist/types/types/request_response.d.ts.map +1 -0
  207. package/dist/types/types/security.d.ts +115 -0
  208. package/dist/types/types/security.d.ts.map +1 -0
  209. package/dist/types/types/trace.d.ts +34 -0
  210. package/dist/types/types/trace.d.ts.map +1 -0
  211. package/dist/types/utils/common.d.ts +14 -0
  212. package/dist/types/utils/common.d.ts.map +1 -0
  213. package/dist/types/utils/domain.d.ts +39 -0
  214. package/dist/types/utils/domain.d.ts.map +1 -0
  215. package/dist/types/utils/index.d.ts +6 -0
  216. package/dist/types/utils/index.d.ts.map +1 -0
  217. package/dist/types/utils/ip.range.d.ts +61 -0
  218. package/dist/types/utils/ip.range.d.ts.map +1 -0
  219. package/dist/types/utils/trace.context.d.ts +106 -0
  220. package/dist/types/utils/trace.context.d.ts.map +1 -0
  221. package/docs/adapters.md +53 -0
  222. package/docs/configuration.md +149 -0
  223. package/docs/logging.md +70 -0
  224. package/docs/proxy.md +44 -0
  225. package/docs/security.md +56 -0
  226. package/docs/trace-context.md +436 -0
  227. package/package.json +50 -0
  228. package/src/adapter/axios.adapter.ts +228 -0
  229. package/src/adapter/base.ts +180 -0
  230. package/src/adapter/index.ts +3 -0
  231. package/src/adapter/undici.adapter.ts +282 -0
  232. package/src/client.ts +552 -0
  233. package/src/config.ts +86 -0
  234. package/src/const/config.const.ts +60 -0
  235. package/src/const/dns.const.ts +15 -0
  236. package/src/const/enum.const.ts +17 -0
  237. package/src/const/index.ts +4 -0
  238. package/src/const/ip.const.ts +139 -0
  239. package/src/index.ts +8 -0
  240. package/src/logger/base.ts +75 -0
  241. package/src/logger/http_client.logger.ts +272 -0
  242. package/src/logger/index.ts +3 -0
  243. package/src/logger/log.filter.ts +149 -0
  244. package/src/security/dns.validator.ts +170 -0
  245. package/src/security/index.ts +4 -0
  246. package/src/security/ip.validator.ts +124 -0
  247. package/src/security/ssrf.guard.ts +224 -0
  248. package/src/security/url.validator.ts +192 -0
  249. package/src/types/adapter.ts +38 -0
  250. package/src/types/client.ts +119 -0
  251. package/src/types/config.ts +110 -0
  252. package/src/types/errors.ts +38 -0
  253. package/src/types/index.ts +27 -0
  254. package/src/types/ip.ts +34 -0
  255. package/src/types/logger.ts +150 -0
  256. package/src/types/request_response.ts +65 -0
  257. package/src/types/security.ts +126 -0
  258. package/src/types/trace.ts +35 -0
  259. package/src/utils/common.ts +28 -0
  260. package/src/utils/domain.ts +78 -0
  261. package/src/utils/index.ts +7 -0
  262. package/src/utils/ip.range.ts +218 -0
  263. package/src/utils/trace.context.ts +240 -0
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Trace 标志位
3
+ */
4
+ export enum TraceFlags {
5
+ /** 未采样 */
6
+ NONE = 0x00,
7
+ /** 已采样 */
8
+ SAMPLED = 0x01
9
+ }
10
+
11
+ /**
12
+ * Traceparent 接口
13
+ */
14
+ export interface TraceParent {
15
+ /** 版本号(当前固定为 00) */
16
+ version: string;
17
+ /** Trace ID(32位十六进制字符串) */
18
+ traceId: string;
19
+ /** Parent ID/Span ID(16位十六进制字符串) */
20
+ parentId: string;
21
+ /** Trace 标志位(2位十六进制字符串) */
22
+ traceFlags: string;
23
+ }
24
+
25
+ /**
26
+ * Traceparent 生成选项
27
+ */
28
+ export interface TraceParentOptions {
29
+ /** 自定义 Trace ID(不提供则自动生成) */
30
+ traceId?: string;
31
+ /** 自定义 Parent ID(不提供则自动生成) */
32
+ parentId?: string;
33
+ /** 是否采样(默认 true) */
34
+ sampled?: boolean;
35
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * 延迟函数
3
+ * @param ms 延迟毫秒数
4
+ */
5
+ export function delay(ms: number): Promise<void> {
6
+ return new Promise(resolve => {
7
+ setTimeout(resolve, ms);
8
+ });
9
+ }
10
+
11
+ /**
12
+ * 超时函数
13
+ * @param promise 原始 Promise
14
+ * @param ms 超时毫秒数
15
+ * @param message 超时错误消息
16
+ * @returns 超时后的 Promise
17
+ */
18
+ export function withTimeout<T>(promise: Promise<T>, ms: number, message = 'Operation timed out'): Promise<T> {
19
+ return new Promise<T>((resolve, reject) => {
20
+ const timer = setTimeout(() => {
21
+ reject(new Error(message));
22
+ }, ms);
23
+
24
+ promise
25
+ .then(resolve, reject)
26
+ .finally(() => clearTimeout(timer));
27
+ });
28
+ }
@@ -0,0 +1,78 @@
1
+ import escapeRegexp from 'escape-string-regexp';
2
+
3
+ /**
4
+ * 根据域名模式列表生成正则表达式数组(通配符模式)
5
+ * 支持规则:
6
+ * 1. 通配符匹配 eg `*.example.com`(只匹配一级子域名,不包括根域名和多级子域名)
7
+ * 2. 精确匹配 eg `example.com`(仅匹配指定域名)
8
+ *
9
+ * @param patterns 域名模式列表
10
+ * @returns 正则表达式数组
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const regexps = createDomainMatchers(['example.com', '*.example.com']);
15
+ * regexps[0].test('example.com'); // true - 精确匹配
16
+ * regexps[1].test('api.example.com'); // true - 通配符匹配一级子域名
17
+ * regexps[1].test('test.api.example.com'); // false - 不匹配多级子域名
18
+ * regexps[1].test('example.com'); // false - 不匹配根域名
19
+ * ```
20
+ */
21
+ export const createDomainMatchers = (patterns: string[]): RegExp[] => {
22
+ return patterns.map((pattern) => {
23
+ const trimmedPattern = pattern.trim();
24
+
25
+ // 通配符模式:*.example.com
26
+ // 只匹配一级子域名(如 api.example.com, www.example.com)
27
+ // 不匹配根域名(example.com)和多级子域名(test.api.example.com)
28
+ if (trimmedPattern.startsWith('*.')) {
29
+ const domain = trimmedPattern.slice(2); // 移除 *. 前缀
30
+ const escapedDomain = escapeRegexp(domain);
31
+ // 匹配:一个或多个非点字符(一级子域名)+ 点 + 域名
32
+ return new RegExp(`^[^.]+\\.${ escapedDomain }$`, 'i');
33
+ }
34
+
35
+ // 精确匹配:example.com
36
+ // 仅匹配指定的域名
37
+ const escapedPattern = escapeRegexp(trimmedPattern);
38
+ return new RegExp(`^${ escapedPattern }$`, 'i');
39
+ });
40
+ };
41
+
42
+ /**
43
+ * 根据域名模式列表生成正则表达式数组(传统模式,用于正向代理等场景)
44
+ * @TODO 需要存量用户跑完正向代理兼容后切换到通配符模式.
45
+ * 支持规则:
46
+ * 1. 完全匹配 eg `www.example.com`
47
+ * 2. 后缀匹配 eg `.example.com`(匹配所有子域名)
48
+ * 3. 前缀匹配 eg `172.168.0.`(主要用于 IP 地址匹配)
49
+ *
50
+ * @param patterns 域名模式列表
51
+ * @returns 正则表达式数组
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * const regexps = createLegacyDomainMatchers(['example.com', '.example.com']);
56
+ * regexps[0].test('example.com'); // true - 完全匹配
57
+ * regexps[1].test('api.example.com'); // true - 后缀匹配
58
+ * ```
59
+ */
60
+ export const createLegacyDomainMatchers = (patterns: string[]): RegExp[] => {
61
+ return patterns.map((pattern) => {
62
+ const lowerPattern = pattern.toLowerCase();
63
+
64
+ // 以 . 开头,生成后缀匹配正则(如 .example.com 匹配所有子域名)
65
+ if (lowerPattern.startsWith('.')) {
66
+ return new RegExp(`${ escapeRegexp(pattern) }$`, 'i');
67
+ }
68
+
69
+ // 以 . 结尾,生成前缀匹配正则(如 172.168.0. 匹配 172.168.0.x)
70
+ if (lowerPattern.endsWith('.')) {
71
+ return new RegExp(`^${ escapeRegexp(pattern) }`, 'i');
72
+ }
73
+
74
+ // 字符串完全匹配
75
+ return new RegExp(`^${ escapeRegexp(pattern) }$`, 'i');
76
+ });
77
+ };
78
+
@@ -0,0 +1,7 @@
1
+ export * as IpRangeUtils from './ip.range';
2
+ export * as CommonUtils from './common';
3
+ export * as DomainUtils from './domain';
4
+ export * as TraceContextUtils from './trace.context';
5
+
6
+ // 导出 TraceContext 类供外部直接使用
7
+ export { TraceContext } from './trace.context';
@@ -0,0 +1,218 @@
1
+ /**
2
+ * IP 地址范围工具
3
+ */
4
+
5
+ import type {
6
+ CompiledIpv4Range,
7
+ CompiledIpv6Range
8
+ } from '../types';
9
+
10
+ /**
11
+ * 将 IPv4 地址转换为数字
12
+ */
13
+ export function ipv4ToNumber(ip: string): number {
14
+ const parts = ip.split('.');
15
+ return (
16
+ (parseInt(parts[0], 10) << 24) +
17
+ (parseInt(parts[1], 10) << 16) +
18
+ (parseInt(parts[2], 10) << 8) +
19
+ parseInt(parts[3], 10)
20
+ ) >>> 0; // 无符号右移确保为正数
21
+ }
22
+
23
+ /**
24
+ * 预编译 IPv4 CIDR 范围
25
+ * @param cidr CIDR 表示法,如 "192.168.0.0/16"
26
+ */
27
+ export function compileIpv4Range(cidr: string): CompiledIpv4Range {
28
+ const [network, prefixStr] = cidr.split('/');
29
+ const prefix = parseInt(prefixStr, 10);
30
+
31
+ if (prefix < 0 || prefix > 32) {
32
+ throw new Error(`Invalid CIDR prefix: ${ prefix }`);
33
+ }
34
+
35
+ const networkNum = ipv4ToNumber(network);
36
+ const mask = (0xffffffff << (32 - prefix)) >>> 0;
37
+
38
+ return {
39
+ network: networkNum & mask,
40
+ mask,
41
+ cidr
42
+ };
43
+ }
44
+
45
+ /**
46
+ * 检查 IPv4 地址是否在预编译的范围内(高性能版本)
47
+ * @param ip IP 地址
48
+ * @param compiledRange 预编译的范围
49
+ */
50
+ export function isIpv4InCompiledRange(ip: string, compiledRange: CompiledIpv4Range): boolean {
51
+ const ipNum = ipv4ToNumber(ip);
52
+ return (ipNum & compiledRange.mask) === compiledRange.network;
53
+ }
54
+
55
+ /**
56
+ * 将 IPv6 地址转换为 BigInt 数组(高 64 位和低 64 位)
57
+ */
58
+ export function ipv6ToBigInt(ip: string): [bigint, bigint] {
59
+ // 标准化 IPv6 地址
60
+ const normalized = normalizeIpv6(ip);
61
+ const parts = normalized.split(':');
62
+
63
+ let high = BigInt(0);
64
+ let low = BigInt(0);
65
+
66
+ for (let i = 0; i < 4; i++) {
67
+ high = (high << BigInt(16)) | BigInt(parseInt(parts[i], 16));
68
+ }
69
+
70
+ for (let i = 4; i < 8; i++) {
71
+ low = (low << BigInt(16)) | BigInt(parseInt(parts[i], 16));
72
+ }
73
+
74
+ return [high, low];
75
+ }
76
+
77
+ /**
78
+ * 标准化 IPv6 地址(展开缩写)
79
+ */
80
+ export function normalizeIpv6(ip: string): string {
81
+ // 移除区域 ID(如 fe80::1%eth0 中的 %eth0)
82
+ const cleaned = ip.split('%')[0];
83
+
84
+ // 处理 :: 缩写
85
+ const parts = cleaned.split(':');
86
+ const filled: string[] = [];
87
+
88
+ let doubleColonIndex = -1;
89
+ for (let i = 0; i < parts.length; i++) {
90
+ if (parts[i] === '') {
91
+ if (doubleColonIndex === -1) {
92
+ doubleColonIndex = i;
93
+ }
94
+ } else {
95
+ filled.push(parts[i].padStart(4, '0'));
96
+ }
97
+ }
98
+
99
+ // 填充 :: 省略的部分
100
+ if (doubleColonIndex !== -1) {
101
+ const missing = 8 - filled.length;
102
+ const before = filled.slice(0, doubleColonIndex === 0 ? 0 : doubleColonIndex);
103
+ const after = filled.slice(doubleColonIndex === 0 ? 0 : doubleColonIndex);
104
+ const zeros = Array(missing).fill('0000');
105
+ return [...before, ...zeros, ...after].join(':');
106
+ }
107
+
108
+ return filled.join(':');
109
+ }
110
+
111
+ /**
112
+ * 预编译 IPv6 CIDR 范围
113
+ * @param cidr CIDR 表示法,如 "fe80::/10"
114
+ */
115
+ export function compileIpv6Range(cidr: string): CompiledIpv6Range {
116
+ const [network, prefixStr] = cidr.split('/');
117
+ const prefix = parseInt(prefixStr, 10);
118
+
119
+ if (prefix < 0 || prefix > 128) {
120
+ throw new Error(`Invalid IPv6 CIDR prefix: ${ prefix }`);
121
+ }
122
+
123
+ const [netHigh, netLow] = ipv6ToBigInt(network);
124
+
125
+ let maskHigh: bigint;
126
+ let maskLow: bigint;
127
+
128
+ if (prefix <= 64) {
129
+ // 只需要掩码高 64 位
130
+ maskHigh = (BigInt(0xffffffffffffffffn) << BigInt(64 - prefix)) & BigInt(0xffffffffffffffffn);
131
+ maskLow = BigInt(0);
132
+ } else {
133
+ // 高 64 位全部掩码,低 64 位部分掩码
134
+ maskHigh = BigInt(0xffffffffffffffffn);
135
+ maskLow = (BigInt(0xffffffffffffffffn) << BigInt(128 - prefix)) & BigInt(0xffffffffffffffffn);
136
+ }
137
+
138
+ return {
139
+ networkHigh: netHigh & maskHigh,
140
+ networkLow: netLow & maskLow,
141
+ maskHigh,
142
+ maskLow,
143
+ prefix,
144
+ cidr
145
+ };
146
+ }
147
+
148
+ /**
149
+ * 检查 IPv6 地址是否在预编译的范围内(高性能版本)
150
+ * @param ip IPv6 地址
151
+ * @param compiledRange 预编译的范围
152
+ */
153
+ export function isIpv6InCompiledRange(ip: string, compiledRange: CompiledIpv6Range): boolean {
154
+ const [ipHigh, ipLow] = ipv6ToBigInt(ip);
155
+
156
+ if (compiledRange.prefix <= 64) {
157
+ // 只需要比较高 64 位
158
+ return (ipHigh & compiledRange.maskHigh) === compiledRange.networkHigh;
159
+ } else {
160
+ // 高 64 位必须完全匹配,低 64 位部分匹配
161
+ return (ipHigh & compiledRange.maskHigh) === compiledRange.networkHigh &&
162
+ (ipLow & compiledRange.maskLow) === compiledRange.networkLow;
163
+ }
164
+ }
165
+
166
+ /**
167
+ * 批量预编译 IPv4 CIDR 范围列表
168
+ * @param cidrs CIDR 范围列表
169
+ */
170
+ export function compileIpv4Ranges(cidrs: string[]): CompiledIpv4Range[] {
171
+ return cidrs.map(cidr => compileIpv4Range(cidr));
172
+ }
173
+
174
+ /**
175
+ * 批量预编译 IPv6 CIDR 范围列表
176
+ * @param cidrs CIDR 范围列表
177
+ */
178
+ export function compileIpv6Ranges(cidrs: string[]): CompiledIpv6Range[] {
179
+ return cidrs.map(cidr => compileIpv6Range(cidr));
180
+ }
181
+
182
+ /**
183
+ * 检查 IPv4 地址是否匹配任一预编译范围(高性能版本)
184
+ * @param ip IPv4 地址
185
+ * @param compiledRanges 预编译的范围列表
186
+ */
187
+ export function isIpv4InAnyCompiledRange(ip: string, compiledRanges: CompiledIpv4Range[]): boolean {
188
+ const ipNum = ipv4ToNumber(ip);
189
+ for (const range of compiledRanges) {
190
+ if ((ipNum & range.mask) === range.network) {
191
+ return true;
192
+ }
193
+ }
194
+ return false;
195
+ }
196
+
197
+ /**
198
+ * 检查 IPv6 地址是否匹配任一预编译范围(高性能版本)
199
+ * @param ip IPv6 地址
200
+ * @param compiledRanges 预编译的范围列表
201
+ */
202
+ export function isIpv6InAnyCompiledRange(ip: string, compiledRanges: CompiledIpv6Range[]): boolean {
203
+ const [ipHigh, ipLow] = ipv6ToBigInt(ip);
204
+ for (const range of compiledRanges) {
205
+ if (range.prefix <= 64) {
206
+ if ((ipHigh & range.maskHigh) === range.networkHigh) {
207
+ return true;
208
+ }
209
+ } else {
210
+ if ((ipHigh & range.maskHigh) === range.networkHigh &&
211
+ (ipLow & range.maskLow) === range.networkLow) {
212
+ return true;
213
+ }
214
+ }
215
+ }
216
+ return false;
217
+ }
218
+
@@ -0,0 +1,240 @@
1
+ /**
2
+ * W3C Trace Context 工具
3
+ * 实现 W3C Trace Context 规范:https://www.w3.org/TR/trace-context/
4
+ */
5
+
6
+ import type {
7
+ TraceParent,
8
+ TraceParentOptions
9
+ } from '../types';
10
+ import {
11
+ TraceFlags
12
+ } from '../types';
13
+
14
+ /**
15
+ * 生成随机十六进制字符串
16
+ * @param length 字符串长度
17
+ * @returns 十六进制字符串
18
+ */
19
+ function generateRandomHex(length: number): string {
20
+ const bytes = Math.ceil(length / 2);
21
+ const buffer = new Uint8Array(bytes);
22
+
23
+ if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
24
+ crypto.getRandomValues(buffer);
25
+ } else {
26
+ // Fallback for Node.js environment
27
+ for (let i = 0; i < bytes; i++) {
28
+ buffer[i] = Math.floor(Math.random() * 256);
29
+ }
30
+ }
31
+
32
+ return Array.from(buffer)
33
+ .map(b => b.toString(16).padStart(2, '0'))
34
+ .join('')
35
+ .slice(0, length);
36
+ }
37
+
38
+ /**
39
+ * 生成符合 W3C 规范的 Trace ID(32位十六进制)
40
+ * @returns Trace ID
41
+ */
42
+ export function generateTraceId(): string {
43
+ return generateRandomHex(32);
44
+ }
45
+
46
+ /**
47
+ * 生成符合 W3C 规范的 Span ID(16位十六进制)
48
+ * @returns Span ID
49
+ */
50
+ export function generateSpanId(): string {
51
+ return generateRandomHex(16);
52
+ }
53
+
54
+ /**
55
+ * 验证 Trace ID 格式
56
+ * @param traceId Trace ID
57
+ * @returns 是否有效
58
+ */
59
+ export function isValidTraceId(traceId: string): boolean {
60
+ // Trace ID 必须是32位十六进制字符串,且不能全为0
61
+ return /^[0-9a-f]{32}$/i.test(traceId) && traceId !== '00000000000000000000000000000000';
62
+ }
63
+
64
+ /**
65
+ * 验证 Span ID 格式
66
+ * @param spanId Span ID
67
+ * @returns 是否有效
68
+ */
69
+ export function isValidSpanId(spanId: string): boolean {
70
+ // Span ID 必须是16位十六进制字符串,且不能全为0
71
+ return /^[0-9a-f]{16}$/i.test(spanId) && spanId !== '0000000000000000';
72
+ }
73
+
74
+ /**
75
+ * 验证 Trace Flags 格式
76
+ * @param flags Trace Flags
77
+ * @returns 是否有效
78
+ */
79
+ export function isValidTraceFlags(flags: string): boolean {
80
+ // Trace Flags 必须是2位十六进制字符串
81
+ return /^[0-9a-f]{2}$/i.test(flags);
82
+ }
83
+
84
+ /**
85
+ * 生成 traceparent 头值
86
+ * @param options 生成选项
87
+ * @returns traceparent 字符串
88
+ */
89
+ export function generateTraceParent(options: TraceParentOptions = {}): string {
90
+ const traceId = options.traceId || generateTraceId();
91
+ const parentId = options.parentId || generateSpanId();
92
+ const sampled = options.sampled !== false;
93
+ const traceFlags = sampled ? '01' : '00';
94
+
95
+ // 验证参数
96
+ if (!isValidTraceId(traceId)) {
97
+ throw new Error(`Invalid trace ID: ${ traceId }. Must be 32 hex characters and not all zeros.`);
98
+ }
99
+ if (!isValidSpanId(parentId)) {
100
+ throw new Error(`Invalid span ID: ${ parentId }. Must be 16 hex characters and not all zeros.`);
101
+ }
102
+
103
+ return `00-${ traceId }-${ parentId }-${ traceFlags }`;
104
+ }
105
+
106
+ /**
107
+ * 解析 traceparent 头值
108
+ * @param traceparent traceparent 字符串
109
+ * @returns 解析后的对象,解析失败返回 null
110
+ */
111
+ export function parseTraceParent(traceparent: string): TraceParent | null {
112
+ if (!traceparent || typeof traceparent !== 'string') {
113
+ return null;
114
+ }
115
+
116
+ // 规范格式:version-trace-id-parent-id-trace-flags
117
+ const parts = traceparent.trim().split('-');
118
+
119
+ if (parts.length !== 4) {
120
+ return null;
121
+ }
122
+
123
+ const [version, traceId, parentId, traceFlags] = parts;
124
+
125
+ // 验证版本号(当前只支持 00)
126
+ if (version !== '00') {
127
+ return null;
128
+ }
129
+
130
+ // 验证各部分格式
131
+ if (!isValidTraceId(traceId) || !isValidSpanId(parentId) || !isValidTraceFlags(traceFlags)) {
132
+ return null;
133
+ }
134
+
135
+ return {
136
+ version,
137
+ traceId: traceId.toLowerCase(),
138
+ parentId: parentId.toLowerCase(),
139
+ traceFlags: traceFlags.toLowerCase()
140
+ };
141
+ }
142
+
143
+ /**
144
+ * 验证 traceparent 头值是否符合规范
145
+ * @param traceparent traceparent 字符串
146
+ * @returns 是否有效
147
+ */
148
+ export function isValidTraceParent(traceparent: string): boolean {
149
+ return parseTraceParent(traceparent) !== null;
150
+ }
151
+
152
+ /**
153
+ * 从现有 traceparent 创建子 span
154
+ * @param parentTraceParent 父级 traceparent 字符串
155
+ * @param sampled 是否采样(不提供则继承父级)
156
+ * @returns 新的 traceparent 字符串
157
+ */
158
+ export function createChildSpan(parentTraceParent: string, sampled?: boolean): string {
159
+ const parsed = parseTraceParent(parentTraceParent);
160
+
161
+ if (!parsed) {
162
+ throw new Error(`Invalid parent traceparent: ${ parentTraceParent }`);
163
+ }
164
+
165
+ // 继承 trace ID,生成新的 span ID
166
+ const newSpanId = generateSpanId();
167
+
168
+ // 继承或指定采样标志
169
+ const parentSampled = parseInt(parsed.traceFlags, 16) & TraceFlags.SAMPLED;
170
+ const newSampled = sampled !== undefined ? sampled : !!parentSampled;
171
+ const newFlags = newSampled ? '01' : '00';
172
+
173
+ return `00-${ parsed.traceId }-${ newSpanId }-${ newFlags }`;
174
+ }
175
+
176
+ /**
177
+ * 检查 traceparent 是否已采样
178
+ * @param traceparent traceparent 字符串
179
+ * @returns 是否采样
180
+ */
181
+ export function isSampled(traceparent: string): boolean {
182
+ const parsed = parseTraceParent(traceparent);
183
+ if (!parsed) {
184
+ return false;
185
+ }
186
+
187
+ const flags = parseInt(parsed.traceFlags, 16);
188
+ return !!(flags & TraceFlags.SAMPLED);
189
+ }
190
+
191
+ /**
192
+ * Trace Context 工具类
193
+ */
194
+ export class TraceContext {
195
+ /**
196
+ * 生成 traceparent
197
+ */
198
+ public static generate = generateTraceParent;
199
+
200
+ /**
201
+ * 解析 traceparent
202
+ */
203
+ public static parse = parseTraceParent;
204
+
205
+ /**
206
+ * 验证 traceparent
207
+ */
208
+ public static isValid = isValidTraceParent;
209
+
210
+ /**
211
+ * 创建子 span
212
+ */
213
+ public static createChild = createChildSpan;
214
+
215
+ /**
216
+ * 检查是否采样
217
+ */
218
+ public static isSampled = isSampled;
219
+
220
+ /**
221
+ * 生成 Trace ID
222
+ */
223
+ public static generateTraceId = generateTraceId;
224
+
225
+ /**
226
+ * 生成 Span ID
227
+ */
228
+ public static generateSpanId = generateSpanId;
229
+
230
+ /**
231
+ * 验证 Trace ID
232
+ */
233
+ public static isValidTraceId = isValidTraceId;
234
+
235
+ /**
236
+ * 验证 Span ID
237
+ */
238
+ public static isValidSpanId = isValidSpanId;
239
+ }
240
+