@mcp-i/core 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 (226) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +390 -0
  3. package/dist/auth/handshake.d.ts +104 -0
  4. package/dist/auth/handshake.d.ts.map +1 -0
  5. package/dist/auth/handshake.js +230 -0
  6. package/dist/auth/handshake.js.map +1 -0
  7. package/dist/auth/index.d.ts +3 -0
  8. package/dist/auth/index.d.ts.map +1 -0
  9. package/dist/auth/index.js +2 -0
  10. package/dist/auth/index.js.map +1 -0
  11. package/dist/auth/types.d.ts +31 -0
  12. package/dist/auth/types.d.ts.map +1 -0
  13. package/dist/auth/types.js +7 -0
  14. package/dist/auth/types.js.map +1 -0
  15. package/dist/delegation/audience-validator.d.ts +9 -0
  16. package/dist/delegation/audience-validator.d.ts.map +1 -0
  17. package/dist/delegation/audience-validator.js +17 -0
  18. package/dist/delegation/audience-validator.js.map +1 -0
  19. package/dist/delegation/bitstring.d.ts +37 -0
  20. package/dist/delegation/bitstring.d.ts.map +1 -0
  21. package/dist/delegation/bitstring.js +117 -0
  22. package/dist/delegation/bitstring.js.map +1 -0
  23. package/dist/delegation/cascading-revocation.d.ts +45 -0
  24. package/dist/delegation/cascading-revocation.d.ts.map +1 -0
  25. package/dist/delegation/cascading-revocation.js +148 -0
  26. package/dist/delegation/cascading-revocation.js.map +1 -0
  27. package/dist/delegation/delegation-graph.d.ts +49 -0
  28. package/dist/delegation/delegation-graph.d.ts.map +1 -0
  29. package/dist/delegation/delegation-graph.js +99 -0
  30. package/dist/delegation/delegation-graph.js.map +1 -0
  31. package/dist/delegation/did-key-resolver.d.ts +64 -0
  32. package/dist/delegation/did-key-resolver.d.ts.map +1 -0
  33. package/dist/delegation/did-key-resolver.js +154 -0
  34. package/dist/delegation/did-key-resolver.js.map +1 -0
  35. package/dist/delegation/did-web-resolver.d.ts +83 -0
  36. package/dist/delegation/did-web-resolver.d.ts.map +1 -0
  37. package/dist/delegation/did-web-resolver.js +218 -0
  38. package/dist/delegation/did-web-resolver.js.map +1 -0
  39. package/dist/delegation/index.d.ts +21 -0
  40. package/dist/delegation/index.d.ts.map +1 -0
  41. package/dist/delegation/index.js +21 -0
  42. package/dist/delegation/index.js.map +1 -0
  43. package/dist/delegation/outbound-headers.d.ts +81 -0
  44. package/dist/delegation/outbound-headers.d.ts.map +1 -0
  45. package/dist/delegation/outbound-headers.js +139 -0
  46. package/dist/delegation/outbound-headers.js.map +1 -0
  47. package/dist/delegation/outbound-proof.d.ts +43 -0
  48. package/dist/delegation/outbound-proof.d.ts.map +1 -0
  49. package/dist/delegation/outbound-proof.js +52 -0
  50. package/dist/delegation/outbound-proof.js.map +1 -0
  51. package/dist/delegation/statuslist-manager.d.ts +44 -0
  52. package/dist/delegation/statuslist-manager.d.ts.map +1 -0
  53. package/dist/delegation/statuslist-manager.js +126 -0
  54. package/dist/delegation/statuslist-manager.js.map +1 -0
  55. package/dist/delegation/storage/memory-graph-storage.d.ts +70 -0
  56. package/dist/delegation/storage/memory-graph-storage.d.ts.map +1 -0
  57. package/dist/delegation/storage/memory-graph-storage.js +145 -0
  58. package/dist/delegation/storage/memory-graph-storage.js.map +1 -0
  59. package/dist/delegation/storage/memory-statuslist-storage.d.ts +19 -0
  60. package/dist/delegation/storage/memory-statuslist-storage.d.ts.map +1 -0
  61. package/dist/delegation/storage/memory-statuslist-storage.js +33 -0
  62. package/dist/delegation/storage/memory-statuslist-storage.js.map +1 -0
  63. package/dist/delegation/utils.d.ts +49 -0
  64. package/dist/delegation/utils.d.ts.map +1 -0
  65. package/dist/delegation/utils.js +131 -0
  66. package/dist/delegation/utils.js.map +1 -0
  67. package/dist/delegation/vc-issuer.d.ts +56 -0
  68. package/dist/delegation/vc-issuer.d.ts.map +1 -0
  69. package/dist/delegation/vc-issuer.js +80 -0
  70. package/dist/delegation/vc-issuer.js.map +1 -0
  71. package/dist/delegation/vc-verifier.d.ts +112 -0
  72. package/dist/delegation/vc-verifier.d.ts.map +1 -0
  73. package/dist/delegation/vc-verifier.js +280 -0
  74. package/dist/delegation/vc-verifier.js.map +1 -0
  75. package/dist/index.d.ts +45 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +53 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/logging/index.d.ts +2 -0
  80. package/dist/logging/index.d.ts.map +1 -0
  81. package/dist/logging/index.js +2 -0
  82. package/dist/logging/index.js.map +1 -0
  83. package/dist/logging/logger.d.ts +23 -0
  84. package/dist/logging/logger.d.ts.map +1 -0
  85. package/dist/logging/logger.js +82 -0
  86. package/dist/logging/logger.js.map +1 -0
  87. package/dist/middleware/index.d.ts +7 -0
  88. package/dist/middleware/index.d.ts.map +1 -0
  89. package/dist/middleware/index.js +7 -0
  90. package/dist/middleware/index.js.map +1 -0
  91. package/dist/middleware/with-mcpi.d.ts +152 -0
  92. package/dist/middleware/with-mcpi.d.ts.map +1 -0
  93. package/dist/middleware/with-mcpi.js +472 -0
  94. package/dist/middleware/with-mcpi.js.map +1 -0
  95. package/dist/proof/errors.d.ts +49 -0
  96. package/dist/proof/errors.d.ts.map +1 -0
  97. package/dist/proof/errors.js +61 -0
  98. package/dist/proof/errors.js.map +1 -0
  99. package/dist/proof/generator.d.ts +65 -0
  100. package/dist/proof/generator.d.ts.map +1 -0
  101. package/dist/proof/generator.js +163 -0
  102. package/dist/proof/generator.js.map +1 -0
  103. package/dist/proof/index.d.ts +4 -0
  104. package/dist/proof/index.d.ts.map +1 -0
  105. package/dist/proof/index.js +4 -0
  106. package/dist/proof/index.js.map +1 -0
  107. package/dist/proof/verifier.d.ts +108 -0
  108. package/dist/proof/verifier.d.ts.map +1 -0
  109. package/dist/proof/verifier.js +299 -0
  110. package/dist/proof/verifier.js.map +1 -0
  111. package/dist/providers/base.d.ts +64 -0
  112. package/dist/providers/base.d.ts.map +1 -0
  113. package/dist/providers/base.js +19 -0
  114. package/dist/providers/base.js.map +1 -0
  115. package/dist/providers/index.d.ts +3 -0
  116. package/dist/providers/index.d.ts.map +1 -0
  117. package/dist/providers/index.js +3 -0
  118. package/dist/providers/index.js.map +1 -0
  119. package/dist/providers/memory.d.ts +33 -0
  120. package/dist/providers/memory.d.ts.map +1 -0
  121. package/dist/providers/memory.js +102 -0
  122. package/dist/providers/memory.js.map +1 -0
  123. package/dist/session/index.d.ts +2 -0
  124. package/dist/session/index.d.ts.map +1 -0
  125. package/dist/session/index.js +2 -0
  126. package/dist/session/index.js.map +1 -0
  127. package/dist/session/manager.d.ts +77 -0
  128. package/dist/session/manager.d.ts.map +1 -0
  129. package/dist/session/manager.js +251 -0
  130. package/dist/session/manager.js.map +1 -0
  131. package/dist/types/protocol.d.ts +320 -0
  132. package/dist/types/protocol.d.ts.map +1 -0
  133. package/dist/types/protocol.js +229 -0
  134. package/dist/types/protocol.js.map +1 -0
  135. package/dist/utils/base58.d.ts +31 -0
  136. package/dist/utils/base58.d.ts.map +1 -0
  137. package/dist/utils/base58.js +104 -0
  138. package/dist/utils/base58.js.map +1 -0
  139. package/dist/utils/base64.d.ts +13 -0
  140. package/dist/utils/base64.d.ts.map +1 -0
  141. package/dist/utils/base64.js +99 -0
  142. package/dist/utils/base64.js.map +1 -0
  143. package/dist/utils/crypto-service.d.ts +37 -0
  144. package/dist/utils/crypto-service.d.ts.map +1 -0
  145. package/dist/utils/crypto-service.js +153 -0
  146. package/dist/utils/crypto-service.js.map +1 -0
  147. package/dist/utils/did-helpers.d.ts +156 -0
  148. package/dist/utils/did-helpers.d.ts.map +1 -0
  149. package/dist/utils/did-helpers.js +193 -0
  150. package/dist/utils/did-helpers.js.map +1 -0
  151. package/dist/utils/ed25519-constants.d.ts +18 -0
  152. package/dist/utils/ed25519-constants.d.ts.map +1 -0
  153. package/dist/utils/ed25519-constants.js +21 -0
  154. package/dist/utils/ed25519-constants.js.map +1 -0
  155. package/dist/utils/index.d.ts +5 -0
  156. package/dist/utils/index.d.ts.map +1 -0
  157. package/dist/utils/index.js +5 -0
  158. package/dist/utils/index.js.map +1 -0
  159. package/package.json +105 -0
  160. package/src/__tests__/integration/full-flow.test.ts +362 -0
  161. package/src/__tests__/providers/base.test.ts +173 -0
  162. package/src/__tests__/providers/memory.test.ts +332 -0
  163. package/src/__tests__/utils/mock-providers.ts +319 -0
  164. package/src/__tests__/utils/node-crypto-provider.ts +93 -0
  165. package/src/auth/handshake.ts +411 -0
  166. package/src/auth/index.ts +11 -0
  167. package/src/auth/types.ts +40 -0
  168. package/src/delegation/__tests__/audience-validator.test.ts +110 -0
  169. package/src/delegation/__tests__/bitstring.test.ts +346 -0
  170. package/src/delegation/__tests__/cascading-revocation.test.ts +624 -0
  171. package/src/delegation/__tests__/delegation-graph.test.ts +623 -0
  172. package/src/delegation/__tests__/did-key-resolver.test.ts +265 -0
  173. package/src/delegation/__tests__/did-web-resolver.test.ts +467 -0
  174. package/src/delegation/__tests__/outbound-headers.test.ts +230 -0
  175. package/src/delegation/__tests__/outbound-proof.test.ts +179 -0
  176. package/src/delegation/__tests__/statuslist-manager.test.ts +515 -0
  177. package/src/delegation/__tests__/utils.test.ts +185 -0
  178. package/src/delegation/__tests__/vc-issuer.test.ts +487 -0
  179. package/src/delegation/__tests__/vc-verifier.test.ts +1029 -0
  180. package/src/delegation/audience-validator.ts +24 -0
  181. package/src/delegation/bitstring.ts +160 -0
  182. package/src/delegation/cascading-revocation.ts +224 -0
  183. package/src/delegation/delegation-graph.ts +143 -0
  184. package/src/delegation/did-key-resolver.ts +181 -0
  185. package/src/delegation/did-web-resolver.ts +270 -0
  186. package/src/delegation/index.ts +33 -0
  187. package/src/delegation/outbound-headers.ts +193 -0
  188. package/src/delegation/outbound-proof.ts +90 -0
  189. package/src/delegation/statuslist-manager.ts +219 -0
  190. package/src/delegation/storage/__tests__/memory-graph-storage.test.ts +366 -0
  191. package/src/delegation/storage/__tests__/memory-statuslist-storage.test.ts +228 -0
  192. package/src/delegation/storage/memory-graph-storage.ts +178 -0
  193. package/src/delegation/storage/memory-statuslist-storage.ts +42 -0
  194. package/src/delegation/utils.ts +189 -0
  195. package/src/delegation/vc-issuer.ts +137 -0
  196. package/src/delegation/vc-verifier.ts +440 -0
  197. package/src/index.ts +264 -0
  198. package/src/logging/__tests__/logger.test.ts +366 -0
  199. package/src/logging/index.ts +6 -0
  200. package/src/logging/logger.ts +91 -0
  201. package/src/middleware/__tests__/with-mcpi.test.ts +504 -0
  202. package/src/middleware/index.ts +16 -0
  203. package/src/middleware/with-mcpi.ts +766 -0
  204. package/src/proof/__tests__/proof-generator.test.ts +483 -0
  205. package/src/proof/__tests__/verifier.test.ts +488 -0
  206. package/src/proof/errors.ts +75 -0
  207. package/src/proof/generator.ts +255 -0
  208. package/src/proof/index.ts +22 -0
  209. package/src/proof/verifier.ts +449 -0
  210. package/src/providers/base.ts +68 -0
  211. package/src/providers/index.ts +15 -0
  212. package/src/providers/memory.ts +130 -0
  213. package/src/session/__tests__/session-manager.test.ts +342 -0
  214. package/src/session/index.ts +7 -0
  215. package/src/session/manager.ts +332 -0
  216. package/src/types/protocol.ts +596 -0
  217. package/src/utils/__tests__/base58.test.ts +281 -0
  218. package/src/utils/__tests__/base64.test.ts +239 -0
  219. package/src/utils/__tests__/crypto-service.test.ts +530 -0
  220. package/src/utils/__tests__/did-helpers.test.ts +156 -0
  221. package/src/utils/base58.ts +115 -0
  222. package/src/utils/base64.ts +116 -0
  223. package/src/utils/crypto-service.ts +209 -0
  224. package/src/utils/did-helpers.ts +210 -0
  225. package/src/utils/ed25519-constants.ts +23 -0
  226. package/src/utils/index.ts +9 -0
package/src/index.ts ADDED
@@ -0,0 +1,264 @@
1
+ /**
2
+ * @mcp-i/core — MCP-I Protocol Reference Implementation
3
+ *
4
+ * Delegation, proof, and session for Model Context Protocol Identity.
5
+ * This package is a DIF TAAWG protocol reference implementation.
6
+ *
7
+ * Related Spec: https://modelcontextprotocol-identity.io
8
+ *
9
+ * ## Error handling strategy
10
+ *
11
+ * - **Validation functions** (`verify*`, `validate*`) return result objects `{ valid, reason }` — never throw
12
+ * - **Construction/setup functions** throw `Error` on invalid configuration
13
+ * - **Resolution functions** (`resolve*`, `fetch*`) return `null` on failure — never throw
14
+ *
15
+ * This ensures callers can always handle failures without try/catch on validation paths.
16
+ */
17
+
18
+ // Protocol types
19
+ export type {
20
+ DelegationConstraints,
21
+ DelegationRecord,
22
+ DelegationCredential,
23
+ DelegationStatus,
24
+ CredentialStatus,
25
+ StatusList2021Credential,
26
+ Proof,
27
+ HandshakeRequest,
28
+ SessionContext,
29
+ NonceCache,
30
+ MCPClientInfo,
31
+ MCPClientSessionInfo,
32
+ SessionIdentityState,
33
+ DetachedProof,
34
+ ProofMeta,
35
+ CanonicalHashes,
36
+ AuditRecord,
37
+ AuditContext,
38
+ AuditEventContext,
39
+ NeedsAuthorizationError,
40
+ AuthorizationDisplay,
41
+ CrispBudget,
42
+ CrispScope,
43
+ } from './types/protocol.js';
44
+
45
+ export {
46
+ wrapDelegationAsVC,
47
+ extractDelegationFromVC,
48
+ isDelegationCredentialExpired,
49
+ isDelegationCredentialNotYetValid,
50
+ validateDelegationCredential,
51
+ validateDetachedProof,
52
+ createNeedsAuthorizationError,
53
+ isNeedsAuthorizationError,
54
+ DELEGATION_CREDENTIAL_CONTEXT,
55
+ DEFAULT_SESSION_TTL_MINUTES,
56
+ DEFAULT_TIMESTAMP_SKEW_SECONDS,
57
+ NONCE_LENGTH_BYTES,
58
+ } from './types/protocol.js';
59
+
60
+ // Delegation module
61
+ export {
62
+ DelegationCredentialIssuer,
63
+ createDelegationIssuer,
64
+ type IssueDelegationOptions,
65
+ type VCSigningFunction,
66
+ type IdentityProvider as DelegationIdentityProvider,
67
+ } from './delegation/vc-issuer.js';
68
+
69
+ export {
70
+ DelegationCredentialVerifier,
71
+ createDelegationVerifier,
72
+ type DelegationVCVerificationResult,
73
+ type VerifyDelegationVCOptions,
74
+ type DIDResolver,
75
+ type DIDDocument,
76
+ type VerificationMethod,
77
+ type StatusListResolver,
78
+ type SignatureVerificationFunction,
79
+ } from './delegation/vc-verifier.js';
80
+
81
+ export {
82
+ DelegationGraphManager,
83
+ createDelegationGraph,
84
+ type DelegationNode,
85
+ type DelegationGraphStorageProvider,
86
+ } from './delegation/delegation-graph.js';
87
+
88
+ export {
89
+ StatusList2021Manager,
90
+ createStatusListManager,
91
+ type StatusListStorageProvider,
92
+ type StatusListIdentityProvider,
93
+ } from './delegation/statuslist-manager.js';
94
+
95
+ export {
96
+ CascadingRevocationManager,
97
+ createCascadingRevocationManager,
98
+ type RevocationEvent,
99
+ type RevocationHook,
100
+ type CascadingRevocationOptions,
101
+ } from './delegation/cascading-revocation.js';
102
+
103
+ export {
104
+ BitstringManager,
105
+ isIndexSet,
106
+ type CompressionFunction,
107
+ type DecompressionFunction,
108
+ } from './delegation/bitstring.js';
109
+
110
+ export {
111
+ verifyDelegationAudience,
112
+ } from './delegation/audience-validator.js';
113
+
114
+ export {
115
+ buildDelegationProofJWT,
116
+ buildChainString,
117
+ type DelegationProofOptions,
118
+ type Ed25519PrivateJWK,
119
+ } from './delegation/outbound-proof.js';
120
+
121
+ export {
122
+ buildOutboundDelegationHeaders,
123
+ OUTBOUND_HEADER_NAMES,
124
+ type OutboundDelegationContext,
125
+ type OutboundDelegationHeaders,
126
+ } from './delegation/outbound-headers.js';
127
+
128
+ export {
129
+ canonicalizeJSON,
130
+ createUnsignedVCJWT,
131
+ completeVCJWT,
132
+ parseVCJWT,
133
+ type VCJWTHeader,
134
+ type VCJWTPayload,
135
+ } from './delegation/utils.js';
136
+
137
+ export { MemoryStatusListStorage } from './delegation/storage/memory-statuslist-storage.js';
138
+
139
+ export { MemoryDelegationGraphStorage } from './delegation/storage/memory-graph-storage.js';
140
+
141
+ export {
142
+ createDidKeyResolver,
143
+ resolveDidKeySync,
144
+ isEd25519DidKey,
145
+ extractPublicKeyFromDidKey,
146
+ publicKeyToJwk,
147
+ } from './delegation/did-key-resolver.js';
148
+
149
+ export {
150
+ DidWebResolver,
151
+ createDidWebResolver,
152
+ isDidWeb,
153
+ parseDidWeb,
154
+ didWebToUrl,
155
+ } from './delegation/did-web-resolver.js';
156
+
157
+ // Utils
158
+ export {
159
+ base58Encode,
160
+ base58Decode,
161
+ isValidBase58,
162
+ } from './utils/base58.js';
163
+
164
+ export {
165
+ isValidDid,
166
+ getDidMethod,
167
+ normalizeDid,
168
+ compareDids,
169
+ getServerDid,
170
+ extractAgentId,
171
+ extractAgentSlug,
172
+ generateDidKeyFromBytes,
173
+ generateDidKeyFromBase64,
174
+ } from './utils/did-helpers.js';
175
+
176
+ // Auth module
177
+ export {
178
+ verifyOrHints,
179
+ hasSensitiveScopes,
180
+ MemoryResumeTokenStore,
181
+ type AuthHandshakeConfig,
182
+ type VerifyOrHintsResult,
183
+ type AgentReputation,
184
+ type ResumeTokenStore,
185
+ type DelegationVerifier,
186
+ type VerifyDelegationResult,
187
+ } from './auth/index.js';
188
+
189
+ // Proof module
190
+ export {
191
+ ProofGenerator,
192
+ createProofResponse,
193
+ extractCanonicalData,
194
+ type ProofAgentIdentity,
195
+ type ToolRequest,
196
+ type ToolResponse,
197
+ type ProofOptions,
198
+ } from './proof/index.js';
199
+
200
+ export {
201
+ ProofVerifier,
202
+ type ProofVerifierConfig,
203
+ type ProofVerificationResult,
204
+ } from './proof/verifier.js';
205
+
206
+ export {
207
+ ProofVerificationError,
208
+ PROOF_VERIFICATION_ERROR_CODES,
209
+ createProofVerificationError,
210
+ type ProofVerificationErrorCode,
211
+ } from './proof/errors.js';
212
+
213
+ // Session module
214
+ export {
215
+ SessionManager,
216
+ createHandshakeRequest,
217
+ validateHandshakeFormat,
218
+ type SessionConfig,
219
+ type HandshakeResult,
220
+ } from './session/index.js';
221
+
222
+ // Providers
223
+ export {
224
+ CryptoProvider,
225
+ ClockProvider,
226
+ FetchProvider,
227
+ StorageProvider,
228
+ NonceCacheProvider,
229
+ IdentityProvider,
230
+ type AgentIdentity,
231
+ } from './providers/base.js';
232
+
233
+ export {
234
+ MemoryStorageProvider,
235
+ MemoryNonceCacheProvider,
236
+ MemoryIdentityProvider,
237
+ } from './providers/memory.js';
238
+
239
+ // Middleware
240
+ export {
241
+ createMCPIMiddleware,
242
+ type MCPIConfig,
243
+ type MCPIDelegationConfig,
244
+ type MCPIIdentityConfig,
245
+ type MCPIMiddleware,
246
+ type MCPIToolDefinition,
247
+ type MCPIToolHandler,
248
+ type MCPIServer,
249
+ } from './middleware/index.js';
250
+
251
+ // Logging
252
+ export {
253
+ logger,
254
+ createDefaultConsoleLogger,
255
+ type Logger,
256
+ type Level,
257
+ } from './logging/index.js';
258
+
259
+ // Ed25519 Constants
260
+ export {
261
+ ED25519_PKCS8_DER_HEADER,
262
+ ED25519_SPKI_DER_HEADER_LENGTH,
263
+ ED25519_KEY_SIZE,
264
+ } from './utils/index.js';
@@ -0,0 +1,366 @@
1
+ /**
2
+ * Logger Unit Tests
3
+ *
4
+ * Tests transport-aware logging behavior:
5
+ * - Level filtering
6
+ * - Transport mode (stdio vs SSE/HTTP)
7
+ * - Console method mapping
8
+ */
9
+
10
+ import { describe, it, expect, beforeEach, vi, afterEach } from "vitest";
11
+ import {
12
+ createDefaultConsoleLogger,
13
+ logger,
14
+ type Logger,
15
+ type Level,
16
+ } from "../logger.js";
17
+
18
+ describe("Logger - Level Filtering", () => {
19
+ let testLogger: Logger;
20
+ let consoleDebug: ReturnType<typeof vi.spyOn>;
21
+ let consoleInfo: ReturnType<typeof vi.spyOn>;
22
+ let consoleWarn: ReturnType<typeof vi.spyOn>;
23
+ let consoleError: ReturnType<typeof vi.spyOn>;
24
+
25
+ beforeEach(() => {
26
+ testLogger = createDefaultConsoleLogger();
27
+ consoleDebug = vi.spyOn(console, "debug").mockImplementation(() => {});
28
+ consoleInfo = vi.spyOn(console, "info").mockImplementation(() => {});
29
+ consoleWarn = vi.spyOn(console, "warn").mockImplementation(() => {});
30
+ consoleError = vi.spyOn(console, "error").mockImplementation(() => {});
31
+ });
32
+
33
+ afterEach(() => {
34
+ vi.restoreAllMocks();
35
+ });
36
+
37
+ it("should log all levels when level is 'debug'", () => {
38
+ testLogger.configure({ level: "debug" });
39
+ testLogger.debug("debug message");
40
+ testLogger.info("info message");
41
+ testLogger.warn("warn message");
42
+ testLogger.error("error message");
43
+
44
+ expect(consoleDebug).toHaveBeenCalledWith("debug message");
45
+ expect(consoleInfo).toHaveBeenCalledWith("info message");
46
+ expect(consoleWarn).toHaveBeenCalledWith("warn message");
47
+ expect(consoleError).toHaveBeenCalledWith("error message");
48
+ });
49
+
50
+ it("should filter out debug when level is 'info'", () => {
51
+ testLogger.configure({ level: "info" });
52
+ testLogger.debug("debug message");
53
+ testLogger.info("info message");
54
+ testLogger.warn("warn message");
55
+ testLogger.error("error message");
56
+
57
+ expect(consoleDebug).not.toHaveBeenCalled();
58
+ expect(consoleInfo).toHaveBeenCalledWith("info message");
59
+ expect(consoleWarn).toHaveBeenCalledWith("warn message");
60
+ expect(consoleError).toHaveBeenCalledWith("error message");
61
+ });
62
+
63
+ it("should filter out debug and info when level is 'warn'", () => {
64
+ testLogger.configure({ level: "warn" });
65
+ testLogger.debug("debug message");
66
+ testLogger.info("info message");
67
+ testLogger.warn("warn message");
68
+ testLogger.error("error message");
69
+
70
+ expect(consoleDebug).not.toHaveBeenCalled();
71
+ expect(consoleInfo).not.toHaveBeenCalled();
72
+ expect(consoleWarn).toHaveBeenCalledWith("warn message");
73
+ expect(consoleError).toHaveBeenCalledWith("error message");
74
+ });
75
+
76
+ it("should only log error when level is 'error'", () => {
77
+ testLogger.configure({ level: "error" });
78
+ testLogger.debug("debug message");
79
+ testLogger.info("info message");
80
+ testLogger.warn("warn message");
81
+ testLogger.error("error message");
82
+
83
+ expect(consoleDebug).not.toHaveBeenCalled();
84
+ expect(consoleInfo).not.toHaveBeenCalled();
85
+ expect(consoleWarn).not.toHaveBeenCalled();
86
+ expect(consoleError).toHaveBeenCalledWith("error message");
87
+ });
88
+ });
89
+
90
+ describe("Logger - Transport Mode (SSE/HTTP)", () => {
91
+ let testLogger: Logger;
92
+ let consoleDebug: ReturnType<typeof vi.spyOn>;
93
+ let consoleInfo: ReturnType<typeof vi.spyOn>;
94
+ let consoleWarn: ReturnType<typeof vi.spyOn>;
95
+ let consoleError: ReturnType<typeof vi.spyOn>;
96
+
97
+ beforeEach(() => {
98
+ testLogger = createDefaultConsoleLogger();
99
+ consoleDebug = vi.spyOn(console, "debug").mockImplementation(() => {});
100
+ consoleInfo = vi.spyOn(console, "info").mockImplementation(() => {});
101
+ consoleWarn = vi.spyOn(console, "warn").mockImplementation(() => {});
102
+ consoleError = vi.spyOn(console, "error").mockImplementation(() => {});
103
+ });
104
+
105
+ afterEach(() => {
106
+ vi.restoreAllMocks();
107
+ });
108
+
109
+ it("should map levels to correct console methods for SSE transport", () => {
110
+ testLogger.configure({ level: "debug", transport: "sse" });
111
+ testLogger.debug("debug message");
112
+ testLogger.info("info message");
113
+ testLogger.warn("warn message");
114
+ testLogger.error("error message");
115
+
116
+ expect(consoleDebug).toHaveBeenCalledWith("debug message");
117
+ expect(consoleInfo).toHaveBeenCalledWith("info message");
118
+ expect(consoleWarn).toHaveBeenCalledWith("warn message");
119
+ expect(consoleError).toHaveBeenCalledWith("error message");
120
+ });
121
+
122
+ it("should map levels to correct console methods for HTTP transport", () => {
123
+ testLogger.configure({ level: "debug", transport: "http" });
124
+ testLogger.debug("debug message");
125
+ testLogger.info("info message");
126
+ testLogger.warn("warn message");
127
+ testLogger.error("error message");
128
+
129
+ expect(consoleDebug).toHaveBeenCalledWith("debug message");
130
+ expect(consoleInfo).toHaveBeenCalledWith("info message");
131
+ expect(consoleWarn).toHaveBeenCalledWith("warn message");
132
+ expect(consoleError).toHaveBeenCalledWith("error message");
133
+ });
134
+ });
135
+
136
+ describe("Logger - Transport Mode (stdio)", () => {
137
+ let testLogger: Logger;
138
+ let consoleError: ReturnType<typeof vi.spyOn>;
139
+ let consoleInfo: ReturnType<typeof vi.spyOn>;
140
+ let consoleWarn: ReturnType<typeof vi.spyOn>;
141
+ let consoleDebug: ReturnType<typeof vi.spyOn>;
142
+
143
+ beforeEach(() => {
144
+ testLogger = createDefaultConsoleLogger();
145
+ consoleError = vi.spyOn(console, "error").mockImplementation(() => {});
146
+ consoleInfo = vi.spyOn(console, "info").mockImplementation(() => {});
147
+ consoleWarn = vi.spyOn(console, "warn").mockImplementation(() => {});
148
+ consoleDebug = vi.spyOn(console, "debug").mockImplementation(() => {});
149
+ });
150
+
151
+ afterEach(() => {
152
+ vi.restoreAllMocks();
153
+ });
154
+
155
+ it("should route all levels to console.error for stdio transport", () => {
156
+ testLogger.configure({ level: "debug", transport: "stdio" });
157
+ testLogger.debug("debug message");
158
+ testLogger.info("info message");
159
+ testLogger.warn("warn message");
160
+ testLogger.error("error message");
161
+
162
+ // All should go to console.error (stderr)
163
+ expect(consoleError).toHaveBeenCalledTimes(4);
164
+ expect(consoleError).toHaveBeenCalledWith("debug message");
165
+ expect(consoleError).toHaveBeenCalledWith("info message");
166
+ expect(consoleError).toHaveBeenCalledWith("warn message");
167
+ expect(consoleError).toHaveBeenCalledWith("error message");
168
+
169
+ // Other console methods should not be called
170
+ expect(consoleDebug).not.toHaveBeenCalled();
171
+ expect(consoleInfo).not.toHaveBeenCalled();
172
+ expect(consoleWarn).not.toHaveBeenCalled();
173
+ });
174
+
175
+ it("should route all levels to console.error when forceStderr is true", () => {
176
+ testLogger.configure({ level: "debug", forceStderr: true });
177
+ testLogger.debug("debug message");
178
+ testLogger.info("info message");
179
+ testLogger.warn("warn message");
180
+ testLogger.error("error message");
181
+
182
+ // All should go to console.error (stderr)
183
+ expect(consoleError).toHaveBeenCalledTimes(4);
184
+ expect(consoleError).toHaveBeenCalledWith("debug message");
185
+ expect(consoleError).toHaveBeenCalledWith("info message");
186
+ expect(consoleError).toHaveBeenCalledWith("warn message");
187
+ expect(consoleError).toHaveBeenCalledWith("error message");
188
+
189
+ // Other console methods should not be called
190
+ expect(consoleDebug).not.toHaveBeenCalled();
191
+ expect(consoleInfo).not.toHaveBeenCalled();
192
+ expect(consoleWarn).not.toHaveBeenCalled();
193
+ });
194
+
195
+ it("should disable forceStderr when forceStderr is explicitly false", () => {
196
+ testLogger.configure({ level: "debug", transport: "stdio" });
197
+ testLogger.configure({ forceStderr: false });
198
+ testLogger.debug("debug message");
199
+ testLogger.info("info message");
200
+ testLogger.warn("warn message");
201
+ testLogger.error("error message");
202
+
203
+ // Should use normal console method mapping
204
+ expect(consoleDebug).toHaveBeenCalledWith("debug message");
205
+ expect(consoleInfo).toHaveBeenCalledWith("info message");
206
+ expect(consoleWarn).toHaveBeenCalledWith("warn message");
207
+ expect(consoleError).toHaveBeenCalledWith("error message");
208
+ });
209
+
210
+ it("should reset forceStderr when switching from stdio to sse transport", () => {
211
+ // First configure with stdio (should set forceStderr = true)
212
+ testLogger.configure({ level: "debug", transport: "stdio" });
213
+ testLogger.info("via stdio");
214
+ expect(consoleError).toHaveBeenCalledWith("via stdio");
215
+
216
+ // Clear mocks
217
+ consoleError.mockClear();
218
+ consoleInfo.mockClear();
219
+
220
+ // Now switch to sse transport (should reset forceStderr = false)
221
+ testLogger.configure({ transport: "sse" });
222
+ testLogger.info("via sse");
223
+
224
+ // Should use console.info, not console.error
225
+ expect(consoleInfo).toHaveBeenCalledWith("via sse");
226
+ expect(consoleError).not.toHaveBeenCalled();
227
+ });
228
+
229
+ it("should reset forceStderr when switching from stdio to http transport", () => {
230
+ // First configure with stdio (should set forceStderr = true)
231
+ testLogger.configure({ level: "debug", transport: "stdio" });
232
+ testLogger.warn("via stdio");
233
+ expect(consoleError).toHaveBeenCalledWith("via stdio");
234
+
235
+ // Clear mocks
236
+ consoleError.mockClear();
237
+ consoleWarn.mockClear();
238
+
239
+ // Now switch to http transport (should reset forceStderr = false)
240
+ testLogger.configure({ transport: "http" });
241
+ testLogger.warn("via http");
242
+
243
+ // Should use console.warn, not console.error
244
+ expect(consoleWarn).toHaveBeenCalledWith("via http");
245
+ expect(consoleError).not.toHaveBeenCalled();
246
+ });
247
+
248
+ it("should respect explicit forceStderr:true even when transport is sse", () => {
249
+ // Configure with sse but force stderr
250
+ testLogger.configure({ level: "debug", transport: "sse", forceStderr: true });
251
+ testLogger.info("forced to stderr");
252
+
253
+ // Should use console.error because forceStderr is explicit
254
+ expect(consoleError).toHaveBeenCalledWith("forced to stderr");
255
+ expect(consoleInfo).not.toHaveBeenCalled();
256
+ });
257
+ });
258
+
259
+ describe("Logger - Console Method Fallbacks", () => {
260
+ let testLogger: Logger;
261
+ let consoleLog: ReturnType<typeof vi.spyOn>;
262
+ let consoleError: ReturnType<typeof vi.spyOn>;
263
+
264
+ beforeEach(() => {
265
+ testLogger = createDefaultConsoleLogger();
266
+ consoleLog = vi.spyOn(console, "log").mockImplementation(() => {});
267
+ consoleError = vi.spyOn(console, "error").mockImplementation(() => {});
268
+ });
269
+
270
+ afterEach(() => {
271
+ vi.restoreAllMocks();
272
+ });
273
+
274
+ it("should fallback to console.log when console.debug is unavailable", () => {
275
+ // Mock console.debug as undefined
276
+ const originalDebug = console.debug;
277
+ (console as any).debug = undefined;
278
+
279
+ testLogger.configure({ level: "debug" });
280
+ testLogger.debug("debug message");
281
+
282
+ expect(consoleLog).toHaveBeenCalledWith("debug message");
283
+
284
+ // Restore
285
+ console.debug = originalDebug;
286
+ });
287
+
288
+ it("should fallback to console.log when console.info is unavailable", () => {
289
+ // Mock console.info as undefined
290
+ const originalInfo = console.info;
291
+ (console as any).info = undefined;
292
+
293
+ testLogger.configure({ level: "info" });
294
+ testLogger.info("info message");
295
+
296
+ expect(consoleLog).toHaveBeenCalledWith("info message");
297
+
298
+ // Restore
299
+ console.info = originalInfo;
300
+ });
301
+
302
+ it("should fallback to console.error when console.warn is unavailable", () => {
303
+ // Mock console.warn as undefined
304
+ const originalWarn = console.warn;
305
+ (console as any).warn = undefined;
306
+
307
+ testLogger.configure({ level: "warn" });
308
+ testLogger.warn("warn message");
309
+
310
+ expect(consoleError).toHaveBeenCalledWith("warn message");
311
+
312
+ // Restore
313
+ console.warn = originalWarn;
314
+ });
315
+ });
316
+
317
+ describe("Logger - Singleton Instance", () => {
318
+ it("should export a singleton logger instance", () => {
319
+ expect(logger).toBeDefined();
320
+ expect(typeof logger.debug).toBe("function");
321
+ expect(typeof logger.info).toBe("function");
322
+ expect(typeof logger.warn).toBe("function");
323
+ expect(typeof logger.error).toBe("function");
324
+ expect(typeof logger.configure).toBe("function");
325
+ });
326
+
327
+ it("should allow configuring the singleton logger", () => {
328
+ const consoleError = vi.spyOn(console, "error").mockImplementation(() => {});
329
+ const consoleInfo = vi.spyOn(console, "info").mockImplementation(() => {});
330
+
331
+ logger.configure({ level: "info" });
332
+ logger.debug("should not log");
333
+ logger.info("should log");
334
+
335
+ expect(consoleError).not.toHaveBeenCalled();
336
+ expect(consoleInfo).toHaveBeenCalledWith("should log");
337
+
338
+ vi.restoreAllMocks();
339
+ });
340
+ });
341
+
342
+ describe("Logger - Multiple Arguments", () => {
343
+ let testLogger: Logger;
344
+ let consoleInfo: ReturnType<typeof vi.spyOn>;
345
+
346
+ beforeEach(() => {
347
+ testLogger = createDefaultConsoleLogger();
348
+ consoleInfo = vi.spyOn(console, "info").mockImplementation(() => {});
349
+ });
350
+
351
+ afterEach(() => {
352
+ vi.restoreAllMocks();
353
+ });
354
+
355
+ it("should pass all arguments to console method", () => {
356
+ testLogger.configure({ level: "debug" });
357
+ testLogger.info("message", { key: "value" }, 123, true);
358
+
359
+ expect(consoleInfo).toHaveBeenCalledWith(
360
+ "message",
361
+ { key: "value" },
362
+ 123,
363
+ true
364
+ );
365
+ });
366
+ });
@@ -0,0 +1,6 @@
1
+ export {
2
+ logger,
3
+ createDefaultConsoleLogger,
4
+ type Logger,
5
+ type Level,
6
+ } from './logger.js';