@xurenxiang1219/pingcode-mcp 0.3.1

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 (268) hide show
  1. package/.env.example +115 -0
  2. package/.env.stdio.local.example +13 -0
  3. package/README.md +222 -0
  4. package/dist/approve-write.d.ts +3 -0
  5. package/dist/approve-write.d.ts.map +1 -0
  6. package/dist/approve-write.js +81 -0
  7. package/dist/approve-write.js.map +1 -0
  8. package/dist/auth/cimd-client-resolver.d.ts +35 -0
  9. package/dist/auth/cimd-client-resolver.d.ts.map +1 -0
  10. package/dist/auth/cimd-client-resolver.js +293 -0
  11. package/dist/auth/cimd-client-resolver.js.map +1 -0
  12. package/dist/auth/memory-store.d.ts +15 -0
  13. package/dist/auth/memory-store.d.ts.map +1 -0
  14. package/dist/auth/memory-store.js +46 -0
  15. package/dist/auth/memory-store.js.map +1 -0
  16. package/dist/auth/pingcode-oauth-client.d.ts +23 -0
  17. package/dist/auth/pingcode-oauth-client.d.ts.map +1 -0
  18. package/dist/auth/pingcode-oauth-client.js +103 -0
  19. package/dist/auth/pingcode-oauth-client.js.map +1 -0
  20. package/dist/auth/pingcode-oauth-provider.d.ts +70 -0
  21. package/dist/auth/pingcode-oauth-provider.d.ts.map +1 -0
  22. package/dist/auth/pingcode-oauth-provider.js +414 -0
  23. package/dist/auth/pingcode-oauth-provider.js.map +1 -0
  24. package/dist/auth/redis-store.d.ts +16 -0
  25. package/dist/auth/redis-store.d.ts.map +1 -0
  26. package/dist/auth/redis-store.js +54 -0
  27. package/dist/auth/redis-store.js.map +1 -0
  28. package/dist/auth/runtime.d.ts +10 -0
  29. package/dist/auth/runtime.d.ts.map +1 -0
  30. package/dist/auth/runtime.js +57 -0
  31. package/dist/auth/runtime.js.map +1 -0
  32. package/dist/auth/store.d.ts +35 -0
  33. package/dist/auth/store.d.ts.map +1 -0
  34. package/dist/auth/store.js +55 -0
  35. package/dist/auth/store.js.map +1 -0
  36. package/dist/auth/token-cipher.d.ts +7 -0
  37. package/dist/auth/token-cipher.d.ts.map +1 -0
  38. package/dist/auth/token-cipher.js +36 -0
  39. package/dist/auth/token-cipher.js.map +1 -0
  40. package/dist/config.d.ts +54 -0
  41. package/dist/config.d.ts.map +1 -0
  42. package/dist/config.js +270 -0
  43. package/dist/config.js.map +1 -0
  44. package/dist/domain/content-hash.d.ts +5 -0
  45. package/dist/domain/content-hash.d.ts.map +1 -0
  46. package/dist/domain/content-hash.js +17 -0
  47. package/dist/domain/content-hash.js.map +1 -0
  48. package/dist/domain/requirement-context.d.ts +29 -0
  49. package/dist/domain/requirement-context.d.ts.map +1 -0
  50. package/dist/domain/requirement-context.js +2 -0
  51. package/dist/domain/requirement-context.js.map +1 -0
  52. package/dist/domain/test-case-context.d.ts +56 -0
  53. package/dist/domain/test-case-context.d.ts.map +1 -0
  54. package/dist/domain/test-case-context.js +2 -0
  55. package/dist/domain/test-case-context.js.map +1 -0
  56. package/dist/domain/work-item-context.d.ts +47 -0
  57. package/dist/domain/work-item-context.d.ts.map +1 -0
  58. package/dist/domain/work-item-context.js +2 -0
  59. package/dist/domain/work-item-context.js.map +1 -0
  60. package/dist/environment.d.ts +2 -0
  61. package/dist/environment.d.ts.map +1 -0
  62. package/dist/environment.js +21 -0
  63. package/dist/environment.js.map +1 -0
  64. package/dist/index.d.ts +3 -0
  65. package/dist/index.d.ts.map +1 -0
  66. package/dist/index.js +52 -0
  67. package/dist/index.js.map +1 -0
  68. package/dist/inspect-wiki.d.ts +3 -0
  69. package/dist/inspect-wiki.d.ts.map +1 -0
  70. package/dist/inspect-wiki.js +49 -0
  71. package/dist/inspect-wiki.js.map +1 -0
  72. package/dist/logger.d.ts +9 -0
  73. package/dist/logger.d.ts.map +1 -0
  74. package/dist/logger.js +40 -0
  75. package/dist/logger.js.map +1 -0
  76. package/dist/mcp/create-server.d.ts +10 -0
  77. package/dist/mcp/create-server.d.ts.map +1 -0
  78. package/dist/mcp/create-server.js +40 -0
  79. package/dist/mcp/create-server.js.map +1 -0
  80. package/dist/mcp/pagination-guidance.d.ts +19 -0
  81. package/dist/mcp/pagination-guidance.d.ts.map +1 -0
  82. package/dist/mcp/pagination-guidance.js +36 -0
  83. package/dist/mcp/pagination-guidance.js.map +1 -0
  84. package/dist/mcp/reference-resolution.d.ts +19 -0
  85. package/dist/mcp/reference-resolution.d.ts.map +1 -0
  86. package/dist/mcp/reference-resolution.js +160 -0
  87. package/dist/mcp/reference-resolution.js.map +1 -0
  88. package/dist/mcp/tool-registry.d.ts +2 -0
  89. package/dist/mcp/tool-registry.d.ts.map +1 -0
  90. package/dist/mcp/tool-registry.js +55 -0
  91. package/dist/mcp/tool-registry.js.map +1 -0
  92. package/dist/mcp/tool-runtime.d.ts +22 -0
  93. package/dist/mcp/tool-runtime.d.ts.map +1 -0
  94. package/dist/mcp/tool-runtime.js +214 -0
  95. package/dist/mcp/tool-runtime.js.map +1 -0
  96. package/dist/mcp/tools/member-role.d.ts +8 -0
  97. package/dist/mcp/tools/member-role.d.ts.map +1 -0
  98. package/dist/mcp/tools/member-role.js +451 -0
  99. package/dist/mcp/tools/member-role.js.map +1 -0
  100. package/dist/mcp/tools/metadata.d.ts +5 -0
  101. package/dist/mcp/tools/metadata.d.ts.map +1 -0
  102. package/dist/mcp/tools/metadata.js +606 -0
  103. package/dist/mcp/tools/metadata.js.map +1 -0
  104. package/dist/mcp/tools/project-context.d.ts +4 -0
  105. package/dist/mcp/tools/project-context.d.ts.map +1 -0
  106. package/dist/mcp/tools/project-context.js +111 -0
  107. package/dist/mcp/tools/project-context.js.map +1 -0
  108. package/dist/mcp/tools/project.d.ts +7 -0
  109. package/dist/mcp/tools/project.d.ts.map +1 -0
  110. package/dist/mcp/tools/project.js +370 -0
  111. package/dist/mcp/tools/project.js.map +1 -0
  112. package/dist/mcp/tools/relation.d.ts +7 -0
  113. package/dist/mcp/tools/relation.d.ts.map +1 -0
  114. package/dist/mcp/tools/relation.js +592 -0
  115. package/dist/mcp/tools/relation.js.map +1 -0
  116. package/dist/mcp/tools/runtime-info.d.ts +4 -0
  117. package/dist/mcp/tools/runtime-info.d.ts.map +1 -0
  118. package/dist/mcp/tools/runtime-info.js +49 -0
  119. package/dist/mcp/tools/runtime-info.js.map +1 -0
  120. package/dist/mcp/tools/ship-suite.d.ts +7 -0
  121. package/dist/mcp/tools/ship-suite.d.ts.map +1 -0
  122. package/dist/mcp/tools/ship-suite.js +636 -0
  123. package/dist/mcp/tools/ship-suite.js.map +1 -0
  124. package/dist/mcp/tools/ship.d.ts +7 -0
  125. package/dist/mcp/tools/ship.d.ts.map +1 -0
  126. package/dist/mcp/tools/ship.js +617 -0
  127. package/dist/mcp/tools/ship.js.map +1 -0
  128. package/dist/mcp/tools/sync.d.ts +10 -0
  129. package/dist/mcp/tools/sync.d.ts.map +1 -0
  130. package/dist/mcp/tools/sync.js +1110 -0
  131. package/dist/mcp/tools/sync.js.map +1 -0
  132. package/dist/mcp/tools/task.d.ts +5 -0
  133. package/dist/mcp/tools/task.d.ts.map +1 -0
  134. package/dist/mcp/tools/task.js +236 -0
  135. package/dist/mcp/tools/task.js.map +1 -0
  136. package/dist/mcp/tools/test-case-bulk.d.ts +7 -0
  137. package/dist/mcp/tools/test-case-bulk.d.ts.map +1 -0
  138. package/dist/mcp/tools/test-case-bulk.js +297 -0
  139. package/dist/mcp/tools/test-case-bulk.js.map +1 -0
  140. package/dist/mcp/tools/test-case-delete.d.ts +7 -0
  141. package/dist/mcp/tools/test-case-delete.d.ts.map +1 -0
  142. package/dist/mcp/tools/test-case-delete.js +247 -0
  143. package/dist/mcp/tools/test-case-delete.js.map +1 -0
  144. package/dist/mcp/tools/test-case.d.ts +5 -0
  145. package/dist/mcp/tools/test-case.d.ts.map +1 -0
  146. package/dist/mcp/tools/test-case.js +155 -0
  147. package/dist/mcp/tools/test-case.js.map +1 -0
  148. package/dist/mcp/tools/test-library.d.ts +7 -0
  149. package/dist/mcp/tools/test-library.d.ts.map +1 -0
  150. package/dist/mcp/tools/test-library.js +302 -0
  151. package/dist/mcp/tools/test-library.js.map +1 -0
  152. package/dist/mcp/tools/wiki.d.ts +5 -0
  153. package/dist/mcp/tools/wiki.d.ts.map +1 -0
  154. package/dist/mcp/tools/wiki.js +266 -0
  155. package/dist/mcp/tools/wiki.js.map +1 -0
  156. package/dist/mcp/write-approval.d.ts +48 -0
  157. package/dist/mcp/write-approval.d.ts.map +1 -0
  158. package/dist/mcp/write-approval.js +321 -0
  159. package/dist/mcp/write-approval.js.map +1 -0
  160. package/dist/observability/metrics.d.ts +46 -0
  161. package/dist/observability/metrics.d.ts.map +1 -0
  162. package/dist/observability/metrics.js +79 -0
  163. package/dist/observability/metrics.js.map +1 -0
  164. package/dist/pingcode/access-token-provider.d.ts +5 -0
  165. package/dist/pingcode/access-token-provider.d.ts.map +1 -0
  166. package/dist/pingcode/access-token-provider.js +2 -0
  167. package/dist/pingcode/access-token-provider.js.map +1 -0
  168. package/dist/pingcode/client.d.ts +43 -0
  169. package/dist/pingcode/client.d.ts.map +1 -0
  170. package/dist/pingcode/client.js +300 -0
  171. package/dist/pingcode/client.js.map +1 -0
  172. package/dist/pingcode/errors.d.ts +20 -0
  173. package/dist/pingcode/errors.d.ts.map +1 -0
  174. package/dist/pingcode/errors.js +14 -0
  175. package/dist/pingcode/errors.js.map +1 -0
  176. package/dist/pingcode/schemas.d.ts +465 -0
  177. package/dist/pingcode/schemas.d.ts.map +1 -0
  178. package/dist/pingcode/schemas.js +450 -0
  179. package/dist/pingcode/schemas.js.map +1 -0
  180. package/dist/pingcode/token-provider.d.ts +20 -0
  181. package/dist/pingcode/token-provider.d.ts.map +1 -0
  182. package/dist/pingcode/token-provider.js +97 -0
  183. package/dist/pingcode/token-provider.js.map +1 -0
  184. package/dist/pingcode/write-response.d.ts +9 -0
  185. package/dist/pingcode/write-response.d.ts.map +1 -0
  186. package/dist/pingcode/write-response.js +39 -0
  187. package/dist/pingcode/write-response.js.map +1 -0
  188. package/dist/services.d.ts +22 -0
  189. package/dist/services.d.ts.map +1 -0
  190. package/dist/services.js +84 -0
  191. package/dist/services.js.map +1 -0
  192. package/dist/sources/metadata-source.d.ts +445 -0
  193. package/dist/sources/metadata-source.d.ts.map +1 -0
  194. package/dist/sources/metadata-source.js +167 -0
  195. package/dist/sources/metadata-source.js.map +1 -0
  196. package/dist/sources/project-context-source.d.ts +61 -0
  197. package/dist/sources/project-context-source.d.ts.map +1 -0
  198. package/dist/sources/project-context-source.js +224 -0
  199. package/dist/sources/project-context-source.js.map +1 -0
  200. package/dist/sources/relation-source.d.ts +83 -0
  201. package/dist/sources/relation-source.d.ts.map +1 -0
  202. package/dist/sources/relation-source.js +129 -0
  203. package/dist/sources/relation-source.js.map +1 -0
  204. package/dist/sources/requirement-source.d.ts +5 -0
  205. package/dist/sources/requirement-source.d.ts.map +1 -0
  206. package/dist/sources/requirement-source.js +2 -0
  207. package/dist/sources/requirement-source.js.map +1 -0
  208. package/dist/sources/ship-source.d.ts +67 -0
  209. package/dist/sources/ship-source.d.ts.map +1 -0
  210. package/dist/sources/ship-source.js +135 -0
  211. package/dist/sources/ship-source.js.map +1 -0
  212. package/dist/sources/test-case-source.d.ts +30 -0
  213. package/dist/sources/test-case-source.d.ts.map +1 -0
  214. package/dist/sources/test-case-source.js +206 -0
  215. package/dist/sources/test-case-source.js.map +1 -0
  216. package/dist/sources/wiki-source.d.ts +34 -0
  217. package/dist/sources/wiki-source.d.ts.map +1 -0
  218. package/dist/sources/wiki-source.js +136 -0
  219. package/dist/sources/wiki-source.js.map +1 -0
  220. package/dist/sources/work-item-source.d.ts +33 -0
  221. package/dist/sources/work-item-source.d.ts.map +1 -0
  222. package/dist/sources/work-item-source.js +159 -0
  223. package/dist/sources/work-item-source.js.map +1 -0
  224. package/dist/sources/write-source.d.ts +461 -0
  225. package/dist/sources/write-source.d.ts.map +1 -0
  226. package/dist/sources/write-source.js +174 -0
  227. package/dist/sources/write-source.js.map +1 -0
  228. package/dist/transports/bearer-auth.d.ts +20 -0
  229. package/dist/transports/bearer-auth.d.ts.map +1 -0
  230. package/dist/transports/bearer-auth.js +79 -0
  231. package/dist/transports/bearer-auth.js.map +1 -0
  232. package/dist/transports/http.d.ts +11 -0
  233. package/dist/transports/http.d.ts.map +1 -0
  234. package/dist/transports/http.js +203 -0
  235. package/dist/transports/http.js.map +1 -0
  236. package/dist/transports/metrics-auth.d.ts +3 -0
  237. package/dist/transports/metrics-auth.d.ts.map +1 -0
  238. package/dist/transports/metrics-auth.js +22 -0
  239. package/dist/transports/metrics-auth.js.map +1 -0
  240. package/dist/transports/stdio.d.ts +5 -0
  241. package/dist/transports/stdio.d.ts.map +1 -0
  242. package/dist/transports/stdio.js +11 -0
  243. package/dist/transports/stdio.js.map +1 -0
  244. package/dist/uat/run-label.d.ts +2 -0
  245. package/dist/uat/run-label.d.ts.map +1 -0
  246. package/dist/uat/run-label.js +12 -0
  247. package/dist/uat/run-label.js.map +1 -0
  248. package/dist/verify.d.ts +3 -0
  249. package/dist/verify.d.ts.map +1 -0
  250. package/dist/verify.js +59 -0
  251. package/dist/verify.js.map +1 -0
  252. package/dist/write/approval.d.ts +35 -0
  253. package/dist/write/approval.d.ts.map +1 -0
  254. package/dist/write/approval.js +66 -0
  255. package/dist/write/approval.js.map +1 -0
  256. package/dist/write/plan.d.ts +2 -0
  257. package/dist/write/plan.d.ts.map +1 -0
  258. package/dist/write/plan.js +17 -0
  259. package/dist/write/plan.js.map +1 -0
  260. package/dist/write/runtime.d.ts +90 -0
  261. package/dist/write/runtime.d.ts.map +1 -0
  262. package/dist/write/runtime.js +244 -0
  263. package/dist/write/runtime.js.map +1 -0
  264. package/dist/write/store.d.ts +101 -0
  265. package/dist/write/store.d.ts.map +1 -0
  266. package/dist/write/store.js +201 -0
  267. package/dist/write/store.js.map +1 -0
  268. package/package.json +58 -0
@@ -0,0 +1,293 @@
1
+ import { createHash } from "node:crypto";
2
+ import { lookup as dnsLookup } from "node:dns/promises";
3
+ import { request as httpsRequest } from "node:https";
4
+ import { BlockList, isIP } from "node:net";
5
+ import { InvalidClientMetadataError } from "@modelcontextprotocol/sdk/server/auth/errors.js";
6
+ import { OAuthClientInformationFullSchema, OAuthClientMetadataSchema, } from "@modelcontextprotocol/sdk/shared/auth.js";
7
+ import { z } from "zod";
8
+ const DEFAULT_CACHE_TTL_SECONDS = 5 * 60;
9
+ const MAX_CACHE_TTL_SECONDS = 10 * 60;
10
+ const DEFAULT_TIMEOUT_MS = 5000;
11
+ const DEFAULT_MAX_RESPONSE_BYTES = 64 * 1024;
12
+ const cimdDocumentSchema = OAuthClientMetadataSchema.extend({
13
+ client_id: z.string().min(1),
14
+ });
15
+ const specialUseAddresses = createSpecialUseBlockLists();
16
+ export class CimdClientResolver {
17
+ options;
18
+ cache = new Map();
19
+ allowedHosts;
20
+ timeoutMs;
21
+ maxResponseBytes;
22
+ lookup;
23
+ requestDocument;
24
+ now;
25
+ constructor(options) {
26
+ this.options = options;
27
+ this.allowedHosts = new Set((options.allowedHosts ?? []).map((host) => host.trim().toLowerCase()).filter(Boolean));
28
+ this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
29
+ this.maxResponseBytes = options.maxResponseBytes ?? DEFAULT_MAX_RESPONSE_BYTES;
30
+ this.lookup = options.lookup ?? lookupPublicAddresses;
31
+ this.requestDocument = options.requestDocument ?? requestCimdDocument;
32
+ this.now = options.now ?? Date.now;
33
+ }
34
+ async resolve(clientId) {
35
+ const url = parseCimdClientId(clientId);
36
+ if (!url) {
37
+ return undefined;
38
+ }
39
+ const cached = this.cache.get(clientId);
40
+ if (cached && cached.expiresAtMs > this.now()) {
41
+ return cached.client;
42
+ }
43
+ this.cache.delete(clientId);
44
+ if (this.allowedHosts.size > 0 && !this.allowedHosts.has(url.hostname.toLowerCase())) {
45
+ throw invalidMetadata("CIMD Client host 不在允許清單中");
46
+ }
47
+ let addresses;
48
+ try {
49
+ addresses = await this.lookup(stripIpv6Brackets(url.hostname));
50
+ }
51
+ catch (error) {
52
+ throw invalidMetadata("無法解析 CIMD Client host", error);
53
+ }
54
+ if (addresses.length === 0 || addresses.some((entry) => isSpecialUseAddress(entry.address))) {
55
+ throw invalidMetadata("CIMD Client host 不得解析到特殊用途網路位址");
56
+ }
57
+ let response;
58
+ try {
59
+ response = await this.requestDocument(url, addresses, this.timeoutMs, this.maxResponseBytes);
60
+ }
61
+ catch (error) {
62
+ throw invalidMetadata("無法取得 CIMD Client metadata", error);
63
+ }
64
+ if (response.status !== 200) {
65
+ throw invalidMetadata("CIMD Client metadata 必須返回 HTTP 200");
66
+ }
67
+ if (!isJsonContentType(response.contentType)) {
68
+ throw invalidMetadata("CIMD Client metadata 必須返回 JSON");
69
+ }
70
+ let rawDocument;
71
+ try {
72
+ rawDocument = JSON.parse(response.body);
73
+ }
74
+ catch (error) {
75
+ throw invalidMetadata("CIMD Client metadata 不是有效的 JSON", error);
76
+ }
77
+ if (hasForbiddenClientSecret(rawDocument)) {
78
+ throw invalidMetadata("CIMD 公開 Client 不得包含 Client Secret");
79
+ }
80
+ const parsed = cimdDocumentSchema.safeParse(rawDocument);
81
+ if (!parsed.success) {
82
+ throw invalidMetadata("CIMD Client metadata 不符合預期資料結構", parsed.error);
83
+ }
84
+ if (parsed.data.client_id !== clientId) {
85
+ throw invalidMetadata("CIMD metadata 的 client_id 與文件 URL 不一致");
86
+ }
87
+ if (parsed.data.redirect_uris.length === 0 || parsed.data.redirect_uris.length > 20) {
88
+ throw invalidMetadata("CIMD metadata 必須包含 1 至 20 個 Redirect URI");
89
+ }
90
+ if (parsed.data.token_endpoint_auth_method !== undefined &&
91
+ parsed.data.token_endpoint_auth_method !== "none") {
92
+ throw invalidMetadata("CIMD 目前只支援公開 Client 的 none 認證方式");
93
+ }
94
+ if (parsed.data.grant_types !== undefined &&
95
+ !parsed.data.grant_types.includes("authorization_code")) {
96
+ throw invalidMetadata("CIMD Client 必須支援 authorization_code");
97
+ }
98
+ if (parsed.data.response_types !== undefined &&
99
+ !parsed.data.response_types.includes("code")) {
100
+ throw invalidMetadata("CIMD Client 必須支援 code response type");
101
+ }
102
+ const client = OAuthClientInformationFullSchema.parse({
103
+ ...parsed.data,
104
+ token_endpoint_auth_method: "none",
105
+ client_id: clientId,
106
+ client_id_issued_at: Math.floor(this.now() / 1000),
107
+ });
108
+ const cacheTtlSeconds = parseCacheTtlSeconds(response.cacheControl);
109
+ if (cacheTtlSeconds > 0) {
110
+ this.cache.set(clientId, {
111
+ client,
112
+ expiresAtMs: this.now() + cacheTtlSeconds * 1000,
113
+ });
114
+ }
115
+ this.options.logger.debug("已解析 MCP CIMD Client metadata", {
116
+ clientReference: createHash("sha256").update(clientId).digest("hex").slice(0, 12),
117
+ clientHost: url.hostname,
118
+ redirectUriCount: client.redirect_uris.length,
119
+ cacheTtlSeconds,
120
+ });
121
+ return client;
122
+ }
123
+ }
124
+ function parseCimdClientId(clientId) {
125
+ let url;
126
+ try {
127
+ url = new URL(clientId);
128
+ }
129
+ catch {
130
+ return undefined;
131
+ }
132
+ if (url.protocol !== "https:") {
133
+ return undefined;
134
+ }
135
+ if (url.pathname === "/" ||
136
+ url.username ||
137
+ url.password ||
138
+ url.hash ||
139
+ url.search ||
140
+ hasDotPathSegment(clientId)) {
141
+ throw invalidMetadata("CIMD client_id URL 不符合安全限制");
142
+ }
143
+ return url;
144
+ }
145
+ async function lookupPublicAddresses(hostname) {
146
+ if (isIP(hostname)) {
147
+ return [{ address: hostname, family: isIP(hostname) }];
148
+ }
149
+ return dnsLookup(hostname, { all: true, verbatim: true });
150
+ }
151
+ function requestCimdDocument(url, addresses, timeoutMs, maxResponseBytes) {
152
+ const selected = addresses[0];
153
+ if (!selected) {
154
+ return Promise.reject(new Error("CIMD host 沒有可用位址"));
155
+ }
156
+ return new Promise((resolve, reject) => {
157
+ const request = httpsRequest(url, {
158
+ method: "GET",
159
+ headers: {
160
+ Accept: "application/json, application/*+json",
161
+ "User-Agent": "pingcode-mcp/0.1.0",
162
+ },
163
+ family: selected.family,
164
+ lookup: (_hostname, _options, callback) => {
165
+ callback(null, selected.address, selected.family);
166
+ },
167
+ signal: AbortSignal.timeout(timeoutMs),
168
+ }, (response) => {
169
+ const declaredLength = Number(response.headers["content-length"]);
170
+ if (Number.isFinite(declaredLength) && declaredLength > maxResponseBytes) {
171
+ response.destroy(new Error("CIMD metadata 超過大小限制"));
172
+ return;
173
+ }
174
+ const chunks = [];
175
+ let receivedBytes = 0;
176
+ response.on("data", (chunk) => {
177
+ receivedBytes += chunk.length;
178
+ if (receivedBytes > maxResponseBytes) {
179
+ response.destroy(new Error("CIMD metadata 超過大小限制"));
180
+ return;
181
+ }
182
+ chunks.push(chunk);
183
+ });
184
+ response.once("end", () => {
185
+ resolve({
186
+ status: response.statusCode ?? 0,
187
+ contentType: singleHeader(response.headers["content-type"]),
188
+ cacheControl: singleHeader(response.headers["cache-control"]),
189
+ body: Buffer.concat(chunks).toString("utf8"),
190
+ });
191
+ });
192
+ response.once("error", reject);
193
+ });
194
+ request.once("error", reject);
195
+ request.end();
196
+ });
197
+ }
198
+ function isJsonContentType(value) {
199
+ if (!value) {
200
+ return false;
201
+ }
202
+ const mediaType = value.split(";", 1)[0]?.trim().toLowerCase();
203
+ return mediaType === "application/json" || Boolean(mediaType?.match(/^application\/.+\+json$/));
204
+ }
205
+ function hasForbiddenClientSecret(value) {
206
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
207
+ return false;
208
+ }
209
+ return "client_secret" in value || "client_secret_expires_at" in value;
210
+ }
211
+ function parseCacheTtlSeconds(value) {
212
+ if (!value || /(?:^|,)\s*no-store\s*(?:,|$)/i.test(value)) {
213
+ return value ? 0 : DEFAULT_CACHE_TTL_SECONDS;
214
+ }
215
+ const match = value.match(/(?:^|,)\s*max-age=(\d+)\s*(?:,|$)/i);
216
+ if (!match) {
217
+ return DEFAULT_CACHE_TTL_SECONDS;
218
+ }
219
+ return Math.min(Number(match[1]), MAX_CACHE_TTL_SECONDS);
220
+ }
221
+ function isSpecialUseAddress(address) {
222
+ const family = isIP(address);
223
+ if (family === 4) {
224
+ return specialUseAddresses.ipv4.check(address, "ipv4");
225
+ }
226
+ if (family === 6) {
227
+ return specialUseAddresses.ipv6.check(address, "ipv6");
228
+ }
229
+ return true;
230
+ }
231
+ function createSpecialUseBlockLists() {
232
+ const ipv4 = new BlockList();
233
+ const ipv6 = new BlockList();
234
+ const ipv4Subnets = [
235
+ ["0.0.0.0", 8],
236
+ ["10.0.0.0", 8],
237
+ ["100.64.0.0", 10],
238
+ ["127.0.0.0", 8],
239
+ ["169.254.0.0", 16],
240
+ ["172.16.0.0", 12],
241
+ ["192.0.0.0", 24],
242
+ ["192.0.2.0", 24],
243
+ ["192.168.0.0", 16],
244
+ ["198.18.0.0", 15],
245
+ ["198.51.100.0", 24],
246
+ ["203.0.113.0", 24],
247
+ ["224.0.0.0", 4],
248
+ ["240.0.0.0", 4],
249
+ ];
250
+ const ipv6Subnets = [
251
+ ["::", 128],
252
+ ["::1", 128],
253
+ ["::ffff:0:0", 96],
254
+ ["64:ff9b::", 96],
255
+ ["100::", 64],
256
+ ["2001::", 23],
257
+ ["2001:db8::", 32],
258
+ ["fc00::", 7],
259
+ ["fe80::", 10],
260
+ ["ff00::", 8],
261
+ ];
262
+ for (const [network, prefix] of ipv4Subnets) {
263
+ ipv4.addSubnet(network, prefix, "ipv4");
264
+ }
265
+ for (const [network, prefix] of ipv6Subnets) {
266
+ ipv6.addSubnet(network, prefix, "ipv6");
267
+ }
268
+ return { ipv4, ipv6 };
269
+ }
270
+ function hasDotPathSegment(value) {
271
+ const authorityEnd = value.indexOf("/", "https://".length);
272
+ if (authorityEnd < 0) {
273
+ return false;
274
+ }
275
+ const rawPath = value.slice(authorityEnd).split(/[?#]/, 1)[0] ?? "";
276
+ return rawPath
277
+ .split("/")
278
+ .some((segment) => /^(?:\.|%2e|\.%2e|%2e\.|%2e%2e)$/i.test(segment));
279
+ }
280
+ function stripIpv6Brackets(value) {
281
+ return value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
282
+ }
283
+ function singleHeader(value) {
284
+ return Array.isArray(value) ? (value[0] ?? null) : (value ?? null);
285
+ }
286
+ function invalidMetadata(message, cause) {
287
+ const error = new InvalidClientMetadataError(message);
288
+ if (cause !== undefined) {
289
+ Object.defineProperty(error, "cause", { value: cause, enumerable: false });
290
+ }
291
+ return error;
292
+ }
293
+ //# sourceMappingURL=cimd-client-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cimd-client-resolver.js","sourceRoot":"","sources":["../../src/auth/cimd-client-resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { RawOAuthStore } from "./store.js";
2
+ export declare class MemoryOAuthStore implements RawOAuthStore {
3
+ private readonly now;
4
+ private readonly entries;
5
+ constructor(now?: () => number);
6
+ get(key: string): Promise<string | undefined>;
7
+ set(key: string, value: string, ttlSeconds: number): Promise<void>;
8
+ consume(key: string): Promise<string | undefined>;
9
+ delete(key: string): Promise<void>;
10
+ setIfAbsent(key: string, value: string, ttlSeconds: number): Promise<boolean>;
11
+ compareAndDelete(key: string, expectedValue: string): Promise<void>;
12
+ ping(): Promise<void>;
13
+ close(): Promise<void>;
14
+ }
15
+ //# sourceMappingURL=memory-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-store.d.ts","sourceRoot":"","sources":["../../src/auth/memory-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAOhD,qBAAa,gBAAiB,YAAW,aAAa;IAGxC,OAAO,CAAC,QAAQ,CAAC,GAAG;IAFhC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;gBAEvB,GAAG,GAAE,MAAM,MAAiB;IAEnD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAY7C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlE,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAMjD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlC,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQ7E,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMnE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAErB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
@@ -0,0 +1,46 @@
1
+ export class MemoryOAuthStore {
2
+ now;
3
+ entries = new Map();
4
+ constructor(now = Date.now) {
5
+ this.now = now;
6
+ }
7
+ async get(key) {
8
+ const entry = this.entries.get(key);
9
+ if (!entry) {
10
+ return undefined;
11
+ }
12
+ if (entry.expiresAtMs <= this.now()) {
13
+ this.entries.delete(key);
14
+ return undefined;
15
+ }
16
+ return entry.value;
17
+ }
18
+ async set(key, value, ttlSeconds) {
19
+ this.entries.set(key, { value, expiresAtMs: this.now() + ttlSeconds * 1000 });
20
+ }
21
+ async consume(key) {
22
+ const value = await this.get(key);
23
+ this.entries.delete(key);
24
+ return value;
25
+ }
26
+ async delete(key) {
27
+ this.entries.delete(key);
28
+ }
29
+ async setIfAbsent(key, value, ttlSeconds) {
30
+ if ((await this.get(key)) !== undefined) {
31
+ return false;
32
+ }
33
+ await this.set(key, value, ttlSeconds);
34
+ return true;
35
+ }
36
+ async compareAndDelete(key, expectedValue) {
37
+ if ((await this.get(key)) === expectedValue) {
38
+ this.entries.delete(key);
39
+ }
40
+ }
41
+ async ping() { }
42
+ async close() {
43
+ this.entries.clear();
44
+ }
45
+ }
46
+ //# sourceMappingURL=memory-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-store.js","sourceRoot":"","sources":["../../src/auth/memory-store.ts"],"names":[],"mappings":"AAOA,MAAM,OAAO,gBAAgB;IAGE;IAFZ,OAAO,GAAG,IAAI,GAAG,EAAiB,CAAC;IAEpD,YAA6B,MAAoB,IAAI,CAAC,GAAG;QAA5B,QAAG,GAAH,GAAG,CAAyB;IAAG,CAAC;IAE7D,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,IAAI,KAAK,CAAC,WAAW,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YACpC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,KAAK,CAAC,KAAK,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,KAAa,EAAE,UAAkB;QACtD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,GAAG,IAAI,EAAE,CAAC,CAAC;IAChF,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,GAAW;QACvB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAW;QACtB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,GAAW,EAAE,KAAa,EAAE,UAAkB;QAC9D,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;YACxC,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;QACvC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,GAAW,EAAE,aAAqB;QACvD,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,aAAa,EAAE,CAAC;YAC5C,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI,KAAmB,CAAC;IAE9B,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;CACF"}
@@ -0,0 +1,23 @@
1
+ import type { PingCodeCredentials } from "../config.js";
2
+ import type { Logger } from "../logger.js";
3
+ import { type FetchLike } from "../pingcode/token-provider.js";
4
+ export interface PingCodeUserTokens {
5
+ accessToken: string;
6
+ refreshToken: string;
7
+ expiresAtMs: number;
8
+ }
9
+ export declare class PingCodeOAuthClient {
10
+ private readonly authorizationBaseUrl;
11
+ private readonly apiBaseUrl;
12
+ private readonly credentials;
13
+ private readonly timeoutMs;
14
+ private readonly logger;
15
+ private readonly fetchImpl;
16
+ private readonly now;
17
+ constructor(authorizationBaseUrl: string, apiBaseUrl: string, credentials: PingCodeCredentials, timeoutMs: number, logger: Logger, fetchImpl?: FetchLike, now?: () => number);
18
+ createAuthorizationUrl(state: string): URL;
19
+ exchangeAuthorizationCode(code: string): Promise<PingCodeUserTokens>;
20
+ refresh(refreshToken: string): Promise<PingCodeUserTokens>;
21
+ private requestToken;
22
+ }
23
+ //# sourceMappingURL=pingcode-oauth-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pingcode-oauth-client.d.ts","sourceRoot":"","sources":["../../src/auth/pingcode-oauth-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAG3C,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAEhF,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,mBAAmB;IAE5B,OAAO,CAAC,QAAQ,CAAC,oBAAoB;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,GAAG;gBANH,oBAAoB,EAAE,MAAM,EAC5B,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,mBAAmB,EAChC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,GAAE,SAAiB,EAC5B,GAAG,GAAE,MAAM,MAAiB;IAG/C,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG;IAQpC,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAiBpE,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;YAYlD,YAAY;CAqD3B"}
@@ -0,0 +1,103 @@
1
+ import { PingCodeError } from "../pingcode/errors.js";
2
+ import { userOAuthTokenSchema } from "../pingcode/schemas.js";
3
+ import { normalizeExpiry } from "../pingcode/token-provider.js";
4
+ export class PingCodeOAuthClient {
5
+ authorizationBaseUrl;
6
+ apiBaseUrl;
7
+ credentials;
8
+ timeoutMs;
9
+ logger;
10
+ fetchImpl;
11
+ now;
12
+ constructor(authorizationBaseUrl, apiBaseUrl, credentials, timeoutMs, logger, fetchImpl = fetch, now = Date.now) {
13
+ this.authorizationBaseUrl = authorizationBaseUrl;
14
+ this.apiBaseUrl = apiBaseUrl;
15
+ this.credentials = credentials;
16
+ this.timeoutMs = timeoutMs;
17
+ this.logger = logger;
18
+ this.fetchImpl = fetchImpl;
19
+ this.now = now;
20
+ }
21
+ createAuthorizationUrl(state) {
22
+ const url = new URL("authorize", `${this.authorizationBaseUrl}/`);
23
+ url.searchParams.set("response_type", "code");
24
+ url.searchParams.set("client_id", this.credentials.clientId);
25
+ url.searchParams.set("state", state);
26
+ return url;
27
+ }
28
+ async exchangeAuthorizationCode(code) {
29
+ const payload = await this.requestToken({
30
+ grant_type: "authorization_code",
31
+ client_id: this.credentials.clientId,
32
+ client_secret: this.credentials.clientSecret,
33
+ code,
34
+ });
35
+ if (!payload.refreshToken) {
36
+ throw new PingCodeError("PingCode 使用者 Token 響應缺少 Refresh Token", "INVALID_RESPONSE");
37
+ }
38
+ return {
39
+ accessToken: payload.accessToken,
40
+ refreshToken: payload.refreshToken,
41
+ expiresAtMs: payload.expiresAtMs,
42
+ };
43
+ }
44
+ async refresh(refreshToken) {
45
+ const payload = await this.requestToken({
46
+ grant_type: "refresh_token",
47
+ refresh_token: refreshToken,
48
+ });
49
+ return {
50
+ accessToken: payload.accessToken,
51
+ refreshToken: payload.refreshToken ?? refreshToken,
52
+ expiresAtMs: payload.expiresAtMs,
53
+ };
54
+ }
55
+ async requestToken(query) {
56
+ const url = new URL("v1/auth/token", `${this.apiBaseUrl}/`);
57
+ for (const [key, value] of Object.entries(query)) {
58
+ url.searchParams.set(key, value);
59
+ }
60
+ let response;
61
+ try {
62
+ response = await this.fetchImpl(url, {
63
+ method: "GET",
64
+ headers: { Accept: "application/json" },
65
+ signal: AbortSignal.timeout(this.timeoutMs),
66
+ });
67
+ }
68
+ catch (error) {
69
+ const timeout = isTimeoutError(error);
70
+ throw new PingCodeError(timeout ? "取得 PingCode 使用者 Token 逾時" : "無法連線到 PingCode 認證服務", timeout ? "TIMEOUT" : "UPSTREAM_UNAVAILABLE", { retryable: true, cause: error });
71
+ }
72
+ if (!response.ok) {
73
+ this.logger.warn("請求 PingCode 使用者 Token 失敗", { status: response.status });
74
+ throw new PingCodeError("PingCode 拒絕了使用者 OAuth 請求", "AUTHENTICATION_FAILED", {
75
+ status: response.status,
76
+ });
77
+ }
78
+ let body;
79
+ try {
80
+ body = await response.json();
81
+ }
82
+ catch (error) {
83
+ throw new PingCodeError("PingCode 返回了無效的使用者 Token 響應", "INVALID_RESPONSE", {
84
+ cause: error,
85
+ });
86
+ }
87
+ const parsed = userOAuthTokenSchema.safeParse(body);
88
+ if (!parsed.success) {
89
+ throw new PingCodeError("PingCode 使用者 Token 響應不符合預期資料結構", "INVALID_RESPONSE", {
90
+ cause: parsed.error,
91
+ });
92
+ }
93
+ return {
94
+ accessToken: parsed.data.access_token,
95
+ ...(parsed.data.refresh_token ? { refreshToken: parsed.data.refresh_token } : {}),
96
+ expiresAtMs: normalizeExpiry(parsed.data.expires_in, this.now()),
97
+ };
98
+ }
99
+ }
100
+ function isTimeoutError(error) {
101
+ return error instanceof Error && (error.name === "TimeoutError" || error.name === "AbortError");
102
+ }
103
+ //# sourceMappingURL=pingcode-oauth-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pingcode-oauth-client.js","sourceRoot":"","sources":["../../src/auth/pingcode-oauth-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ import type { Request, Response } from "express";
2
+ import type { OAuthRegisteredClientsStore } from "@modelcontextprotocol/sdk/server/auth/clients.js";
3
+ import type { AuthorizationParams, OAuthServerProvider } from "@modelcontextprotocol/sdk/server/auth/provider.js";
4
+ import type { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types.js";
5
+ import type { OAuthClientInformationFull, OAuthTokenRevocationRequest, OAuthTokens } from "@modelcontextprotocol/sdk/shared/auth.js";
6
+ import type { AccessTokenProvider } from "../pingcode/access-token-provider.js";
7
+ import type { Logger } from "../logger.js";
8
+ import { PingCodeOAuthClient } from "./pingcode-oauth-client.js";
9
+ import type { CimdClientResolverLike } from "./cimd-client-resolver.js";
10
+ import type { OAuthStore } from "./store.js";
11
+ interface PingCodeOAuthProviderOptions {
12
+ store: OAuthStore;
13
+ pingCodeClient: PingCodeOAuthClient;
14
+ publicBaseUrl: string;
15
+ accessTokenTtlSeconds: number;
16
+ refreshTokenTtlSeconds: number;
17
+ dcrClientTtlSeconds?: number;
18
+ cimdClientResolver?: CimdClientResolverLike;
19
+ logger: Logger;
20
+ now?: () => number;
21
+ }
22
+ export declare class PingCodeOAuthProvider implements OAuthServerProvider {
23
+ readonly clientsStore: OAuthRegisteredClientsStore;
24
+ readonly scope = "pingcode:read";
25
+ readonly scopes: string[];
26
+ readonly resourceUrl: URL;
27
+ readonly callbackUrl: URL;
28
+ readonly supportsCimd: boolean;
29
+ private readonly store;
30
+ private readonly pingCodeClient;
31
+ private readonly accessTokenTtlSeconds;
32
+ private readonly refreshTokenTtlSeconds;
33
+ private readonly dcrClientTtlSeconds;
34
+ private readonly logger;
35
+ private readonly cimdClientResolver;
36
+ private readonly now;
37
+ private readonly secureCookies;
38
+ constructor(options: PingCodeOAuthProviderOptions);
39
+ authorize(client: OAuthClientInformationFull, params: AuthorizationParams, response: Response): Promise<void>;
40
+ handlePingCodeCallback(request: Request, response: Response): Promise<void>;
41
+ challengeForAuthorizationCode(client: OAuthClientInformationFull, authorizationCode: string): Promise<string>;
42
+ exchangeAuthorizationCode(client: OAuthClientInformationFull, authorizationCode: string, _codeVerifier?: string, redirectUri?: string, resource?: URL): Promise<OAuthTokens>;
43
+ exchangeRefreshToken(client: OAuthClientInformationFull, refreshToken: string, scopes?: string[], resource?: URL): Promise<OAuthTokens>;
44
+ verifyAccessToken(token: string): Promise<AuthInfo>;
45
+ revokeToken(client: OAuthClientInformationFull, request: OAuthTokenRevocationRequest): Promise<void>;
46
+ getPingCodeAccessToken(mcpAccessToken: string, forceRefresh?: boolean): Promise<string>;
47
+ private getClient;
48
+ private logClientRegistrationMethod;
49
+ private registerClient;
50
+ private issueTokens;
51
+ private validateScopes;
52
+ private validateResource;
53
+ private redirectToClient;
54
+ private clientKey;
55
+ private transactionKey;
56
+ private authorizationCodeKey;
57
+ private accessTokenKey;
58
+ private refreshTokenKey;
59
+ private sessionKey;
60
+ }
61
+ export declare class UserOAuthTokenProvider implements AccessTokenProvider {
62
+ private readonly provider;
63
+ private readonly mcpAccessToken;
64
+ private forceRefresh;
65
+ constructor(provider: PingCodeOAuthProvider, mcpAccessToken: string);
66
+ getAccessToken(): Promise<string>;
67
+ invalidate(): void;
68
+ }
69
+ export {};
70
+ //# sourceMappingURL=pingcode-oauth-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pingcode-oauth-provider.d.ts","sourceRoot":"","sources":["../../src/auth/pingcode-oauth-provider.ts"],"names":[],"mappings":"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"}