@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
@@ -0,0 +1,281 @@
1
+ /**
2
+ * Tests for Base58 Utilities
3
+ */
4
+
5
+ import { describe, it, expect } from "vitest";
6
+ import { base58Encode, base58Decode, isValidBase58 } from "../base58.js";
7
+
8
+ describe("Base58 Utilities", () => {
9
+ describe("base58Encode", () => {
10
+ it("should encode bytes to Base58", () => {
11
+ const bytes = new Uint8Array([72, 101, 108, 108, 111]); // "Hello"
12
+ const encoded = base58Encode(bytes);
13
+
14
+ expect(encoded).toBeDefined();
15
+ expect(typeof encoded).toBe("string");
16
+ expect(encoded.length).toBeGreaterThan(0);
17
+ });
18
+
19
+ it("should encode empty bytes to empty string", () => {
20
+ const bytes = new Uint8Array(0);
21
+ const encoded = base58Encode(bytes);
22
+
23
+ expect(encoded).toBe("");
24
+ });
25
+
26
+ it("should encode single byte", () => {
27
+ const bytes = new Uint8Array([42]);
28
+ const encoded = base58Encode(bytes);
29
+
30
+ expect(encoded).toBeDefined();
31
+ expect(encoded.length).toBeGreaterThan(0);
32
+ });
33
+
34
+ it("should encode bytes with leading zeros", () => {
35
+ const bytes = new Uint8Array([0, 0, 1, 2, 3]);
36
+ const encoded = base58Encode(bytes);
37
+
38
+ // Leading zeros should be encoded as '1'
39
+ expect(encoded.startsWith("1")).toBe(true);
40
+ });
41
+
42
+ it("should encode all zero bytes", () => {
43
+ const bytes = new Uint8Array([0, 0, 0]);
44
+ const encoded = base58Encode(bytes);
45
+
46
+ expect(encoded).toBeDefined();
47
+ // All zeros should result in multiple '1' characters
48
+ expect(encoded.length).toBeGreaterThan(0);
49
+ });
50
+
51
+ it("should produce deterministic output", () => {
52
+ const bytes = new Uint8Array([1, 2, 3, 4, 5]);
53
+ const encoded1 = base58Encode(bytes);
54
+ const encoded2 = base58Encode(bytes);
55
+
56
+ expect(encoded1).toBe(encoded2);
57
+ });
58
+ });
59
+
60
+ describe("base58Decode", () => {
61
+ it("should decode Base58 to bytes", () => {
62
+ const original = new Uint8Array([72, 101, 108, 108, 111]);
63
+ const encoded = base58Encode(original);
64
+ const decoded = base58Decode(encoded);
65
+
66
+ expect(decoded).toEqual(original);
67
+ });
68
+
69
+ it("should decode empty string to empty bytes", () => {
70
+ const decoded = base58Decode("");
71
+
72
+ expect(decoded).toEqual(new Uint8Array(0));
73
+ });
74
+
75
+ it("should decode string with leading '1' characters", () => {
76
+ // Leading '1' characters represent leading zeros
77
+ const encoded = "11ABC";
78
+ const decoded = base58Decode(encoded);
79
+
80
+ expect(decoded).toBeDefined();
81
+ expect(decoded[0]).toBe(0);
82
+ expect(decoded[1]).toBe(0);
83
+ });
84
+
85
+ it("should round-trip encode and decode", () => {
86
+ const testCases = [
87
+ new Uint8Array([1, 2, 3]),
88
+ new Uint8Array([255, 255, 255]),
89
+ new Uint8Array([0, 1, 2]),
90
+ new Uint8Array([128, 64, 32]),
91
+ ];
92
+
93
+ for (const bytes of testCases) {
94
+ const encoded = base58Encode(bytes);
95
+ const decoded = base58Decode(encoded);
96
+
97
+ expect(decoded).toEqual(bytes);
98
+ }
99
+ });
100
+
101
+ it("should throw error for invalid Base58 character", () => {
102
+ expect(() => {
103
+ base58Decode("invalid@base58");
104
+ }).toThrow("Invalid base58 character");
105
+ });
106
+
107
+ it("should throw error for character '0'", () => {
108
+ expect(() => {
109
+ base58Decode("ABC0DEF");
110
+ }).toThrow("Invalid base58 character");
111
+ });
112
+
113
+ it("should throw error for character 'O'", () => {
114
+ expect(() => {
115
+ base58Decode("ABCODEF");
116
+ }).toThrow("Invalid base58 character");
117
+ });
118
+
119
+ it("should throw error for character 'I'", () => {
120
+ expect(() => {
121
+ base58Decode("ABCDIEF");
122
+ }).toThrow("Invalid base58 character");
123
+ });
124
+
125
+ it("should throw error for character 'l'", () => {
126
+ expect(() => {
127
+ base58Decode("ABCDlEF");
128
+ }).toThrow("Invalid base58 character");
129
+ });
130
+ });
131
+
132
+ describe("isValidBase58", () => {
133
+ it("should return true for valid Base58 string", () => {
134
+ const valid = base58Encode(new Uint8Array([1, 2, 3]));
135
+ expect(isValidBase58(valid)).toBe(true);
136
+ });
137
+
138
+ it("should return true for empty string", () => {
139
+ expect(isValidBase58("")).toBe(true);
140
+ });
141
+
142
+ it("should return false for string with invalid character '0'", () => {
143
+ expect(isValidBase58("ABC0DEF")).toBe(false);
144
+ });
145
+
146
+ it("should return false for string with invalid character 'O'", () => {
147
+ expect(isValidBase58("ABCODEF")).toBe(false);
148
+ });
149
+
150
+ it("should return false for string with invalid character 'I'", () => {
151
+ expect(isValidBase58("ABCDIEF")).toBe(false);
152
+ });
153
+
154
+ it("should return false for string with invalid character 'l'", () => {
155
+ expect(isValidBase58("ABCDlEF")).toBe(false);
156
+ });
157
+
158
+ it("should return false for string with special characters", () => {
159
+ expect(isValidBase58("ABC@DEF")).toBe(false);
160
+ expect(isValidBase58("ABC-DEF")).toBe(false);
161
+ expect(isValidBase58("ABC DEF")).toBe(false);
162
+ });
163
+
164
+ it("should return true for all valid Base58 characters", () => {
165
+ const validChars =
166
+ "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
167
+ expect(isValidBase58(validChars)).toBe(true);
168
+ });
169
+
170
+ it("should return true for string with only '1' characters", () => {
171
+ expect(isValidBase58("1111")).toBe(true);
172
+ });
173
+ });
174
+
175
+ describe("Edge Cases", () => {
176
+ it("should handle large byte arrays", () => {
177
+ const largeArray = new Uint8Array(100);
178
+ for (let i = 0; i < 100; i++) {
179
+ largeArray[i] = i % 256;
180
+ }
181
+
182
+ const encoded = base58Encode(largeArray);
183
+ const decoded = base58Decode(encoded);
184
+
185
+ expect(decoded).toEqual(largeArray);
186
+ });
187
+
188
+ it("should handle bytes with maximum values", () => {
189
+ const maxBytes = new Uint8Array([255, 255, 255, 255]);
190
+ const encoded = base58Encode(maxBytes);
191
+ const decoded = base58Decode(encoded);
192
+
193
+ expect(decoded).toEqual(maxBytes);
194
+ });
195
+
196
+ it("should handle single byte encoding/decoding", () => {
197
+ for (let i = 0; i < 256; i++) {
198
+ const bytes = new Uint8Array([i]);
199
+ const encoded = base58Encode(bytes);
200
+ const decoded = base58Decode(encoded);
201
+
202
+ expect(decoded).toEqual(bytes);
203
+ }
204
+ });
205
+
206
+ it("should handle mixed leading zeros and non-zero bytes", () => {
207
+ const testCases = [
208
+ new Uint8Array([0, 1]),
209
+ new Uint8Array([0, 0, 1]),
210
+ new Uint8Array([0, 255]),
211
+ new Uint8Array([0, 0, 0, 1, 2, 3]),
212
+ ];
213
+
214
+ for (const bytes of testCases) {
215
+ const encoded = base58Encode(bytes);
216
+ const decoded = base58Decode(encoded);
217
+
218
+ expect(decoded).toEqual(bytes);
219
+ }
220
+ });
221
+
222
+ it("should produce shorter output for small values", () => {
223
+ const small = new Uint8Array([1]);
224
+ const large = new Uint8Array([255, 255, 255]);
225
+
226
+ const smallEncoded = base58Encode(small);
227
+ const largeEncoded = base58Encode(large);
228
+
229
+ // Small values should produce shorter Base58 strings
230
+ expect(smallEncoded.length).toBeLessThan(largeEncoded.length);
231
+ });
232
+ });
233
+
234
+ describe("Real-world DID:key Examples", () => {
235
+ it("should encode/decode Ed25519 public key bytes", () => {
236
+ // Example Ed25519 public key (32 bytes)
237
+ const ed25519Key = new Uint8Array([
238
+ 0xed,
239
+ 0x01, // Ed25519 multicodec prefix
240
+ 0x12,
241
+ 0x34,
242
+ 0x56,
243
+ 0x78,
244
+ 0x9a,
245
+ 0xbc,
246
+ 0xde,
247
+ 0xf0,
248
+ 0x12,
249
+ 0x34,
250
+ 0x56,
251
+ 0x78,
252
+ 0x9a,
253
+ 0xbc,
254
+ 0xde,
255
+ 0xf0,
256
+ 0x12,
257
+ 0x34,
258
+ 0x56,
259
+ 0x78,
260
+ 0x9a,
261
+ 0xbc,
262
+ 0xde,
263
+ 0xf0,
264
+ 0x12,
265
+ 0x34,
266
+ 0x56,
267
+ 0x78,
268
+ 0x9a,
269
+ 0xbc,
270
+ 0xde,
271
+ 0xf0,
272
+ ]);
273
+
274
+ const encoded = base58Encode(ed25519Key);
275
+ expect(isValidBase58(encoded)).toBe(true);
276
+
277
+ const decoded = base58Decode(encoded);
278
+ expect(decoded).toEqual(ed25519Key);
279
+ });
280
+ });
281
+ });
@@ -0,0 +1,239 @@
1
+ /**
2
+ * Tests for Base64URL Utilities
3
+ */
4
+
5
+ import { describe, it, expect } from "vitest";
6
+ import {
7
+ base64urlDecodeToString,
8
+ base64urlDecodeToBytes,
9
+ base64urlEncodeFromString,
10
+ base64urlEncodeFromBytes,
11
+ bytesToBase64,
12
+ base64ToBytes,
13
+ } from "../base64.js";
14
+
15
+ describe("Base64URL Utilities", () => {
16
+ describe("base64urlEncodeFromString", () => {
17
+ it("should encode string to base64url", () => {
18
+ const input = "Hello, World!";
19
+ const encoded = base64urlEncodeFromString(input);
20
+
21
+ expect(encoded).toBeDefined();
22
+ expect(encoded).not.toContain("+");
23
+ expect(encoded).not.toContain("/");
24
+ expect(encoded).not.toContain("=");
25
+ });
26
+
27
+ it("should encode empty string", () => {
28
+ const encoded = base64urlEncodeFromString("");
29
+ expect(encoded).toBe("");
30
+ });
31
+
32
+ it("should encode special characters", () => {
33
+ const input = "test@example.com";
34
+ const encoded = base64urlEncodeFromString(input);
35
+ const decoded = base64urlDecodeToString(encoded);
36
+
37
+ expect(decoded).toBe(input);
38
+ });
39
+
40
+ it("should encode Unicode characters", () => {
41
+ // In Node.js, Buffer.from handles Unicode correctly
42
+ // btoa doesn't handle Unicode, but our function falls back to Buffer
43
+ // Test with characters that work in both paths
44
+ const input = "Hello 世界 World";
45
+
46
+ // This should work in Node.js (Buffer path)
47
+ const encoded = base64urlEncodeFromString(input);
48
+ const decoded = base64urlDecodeToString(encoded);
49
+
50
+ expect(decoded).toBe(input);
51
+ });
52
+ });
53
+
54
+ describe("base64urlDecodeToString", () => {
55
+ it("should decode base64url string", () => {
56
+ const original = "Hello, World!";
57
+ const encoded = base64urlEncodeFromString(original);
58
+ const decoded = base64urlDecodeToString(encoded);
59
+
60
+ expect(decoded).toBe(original);
61
+ });
62
+
63
+ it("should decode string without padding", () => {
64
+ // Base64URL strings don't have padding
65
+ const encoded = "SGVsbG8gV29ybGQ"; // "Hello World" in base64url
66
+ const decoded = base64urlDecodeToString(encoded);
67
+
68
+ expect(decoded).toBe("Hello World");
69
+ });
70
+
71
+ it("should decode string with padding", () => {
72
+ // Even if padding is present, it should work
73
+ const encoded = "SGVsbG8="; // "Hello" with padding
74
+ const decoded = base64urlDecodeToString(encoded);
75
+
76
+ expect(decoded).toBe("Hello");
77
+ });
78
+
79
+ it("should throw error for invalid base64url string", () => {
80
+ expect(() => {
81
+ base64urlDecodeToString("invalid-base64!!!");
82
+ }).toThrow("Invalid base64url string");
83
+ });
84
+
85
+ it("should throw error for string with invalid characters", () => {
86
+ expect(() => {
87
+ base64urlDecodeToString("SGVsbG8@World");
88
+ }).toThrow("Invalid base64url string");
89
+ });
90
+
91
+ it("should handle empty string", () => {
92
+ const decoded = base64urlDecodeToString("");
93
+ expect(decoded).toBe("");
94
+ });
95
+ });
96
+
97
+ describe("base64urlEncodeFromBytes", () => {
98
+ it("should encode Uint8Array to base64url", () => {
99
+ const bytes = new Uint8Array([72, 101, 108, 108, 111]); // "Hello"
100
+ const encoded = base64urlEncodeFromBytes(bytes);
101
+
102
+ expect(encoded).toBeDefined();
103
+ expect(encoded).not.toContain("+");
104
+ expect(encoded).not.toContain("/");
105
+ expect(encoded).not.toContain("=");
106
+ });
107
+
108
+ it("should encode empty Uint8Array", () => {
109
+ const bytes = new Uint8Array(0);
110
+ const encoded = base64urlEncodeFromBytes(bytes);
111
+ expect(encoded).toBe("");
112
+ });
113
+
114
+ it("should round-trip encode and decode", () => {
115
+ const original = new Uint8Array([1, 2, 3, 4, 5, 255]);
116
+ const encoded = base64urlEncodeFromBytes(original);
117
+ const decoded = base64urlDecodeToBytes(encoded);
118
+
119
+ expect(decoded).toEqual(original);
120
+ });
121
+ });
122
+
123
+ describe("base64urlDecodeToBytes", () => {
124
+ it("should decode base64url to Uint8Array", () => {
125
+ const original = new Uint8Array([72, 101, 108, 108, 111]);
126
+ const encoded = base64urlEncodeFromBytes(original);
127
+ const decoded = base64urlDecodeToBytes(encoded);
128
+
129
+ expect(decoded).toEqual(original);
130
+ });
131
+
132
+ it("should decode without padding", () => {
133
+ const encoded = "SGVsbG8"; // "Hello" without padding
134
+ const decoded = base64urlDecodeToBytes(encoded);
135
+
136
+ expect(decoded).toEqual(new Uint8Array([72, 101, 108, 108, 111]));
137
+ });
138
+
139
+ it("should throw error for invalid base64url", () => {
140
+ expect(() => {
141
+ base64urlDecodeToBytes("invalid!!!");
142
+ }).toThrow(); // atob throws "Invalid character"
143
+ });
144
+
145
+ it("should handle empty string", () => {
146
+ const decoded = base64urlDecodeToBytes("");
147
+ expect(decoded).toEqual(new Uint8Array(0));
148
+ });
149
+ });
150
+
151
+ describe("bytesToBase64", () => {
152
+ it("should convert bytes to standard base64", () => {
153
+ const bytes = new Uint8Array([72, 101, 108, 108, 111]);
154
+ const base64 = bytesToBase64(bytes);
155
+
156
+ expect(base64).toBeDefined();
157
+ expect(base64).toBe("SGVsbG8="); // Standard base64 includes padding
158
+ });
159
+
160
+ it("should handle empty bytes", () => {
161
+ const bytes = new Uint8Array(0);
162
+ const base64 = bytesToBase64(bytes);
163
+ expect(base64).toBe("");
164
+ });
165
+
166
+ it("should include padding when needed", () => {
167
+ const bytes = new Uint8Array([72]); // Single byte
168
+ const base64 = bytesToBase64(bytes);
169
+ expect(base64).toContain("="); // Should have padding
170
+ });
171
+ });
172
+
173
+ describe("base64ToBytes", () => {
174
+ it("should convert standard base64 to bytes", () => {
175
+ const base64 = "SGVsbG8="; // "Hello" in standard base64
176
+ const bytes = base64ToBytes(base64);
177
+
178
+ expect(bytes).toEqual(new Uint8Array([72, 101, 108, 108, 111]));
179
+ });
180
+
181
+ it("should handle base64 without padding", () => {
182
+ const base64 = "SGVsbG8"; // Without padding
183
+ const bytes = base64ToBytes(base64);
184
+
185
+ expect(bytes).toBeDefined();
186
+ });
187
+
188
+ it("should handle empty string", () => {
189
+ const bytes = base64ToBytes("");
190
+ expect(bytes).toEqual(new Uint8Array(0));
191
+ });
192
+
193
+ it("should round-trip with bytesToBase64", () => {
194
+ const original = new Uint8Array([1, 2, 3, 255, 0]);
195
+ const base64 = bytesToBase64(original);
196
+ const decoded = base64ToBytes(base64);
197
+
198
+ expect(decoded).toEqual(original);
199
+ });
200
+ });
201
+
202
+ describe("Edge Cases", () => {
203
+ it("should handle large byte arrays", () => {
204
+ const largeArray = new Uint8Array(1000);
205
+ for (let i = 0; i < 1000; i++) {
206
+ largeArray[i] = i % 256;
207
+ }
208
+
209
+ const encoded = base64urlEncodeFromBytes(largeArray);
210
+ const decoded = base64urlDecodeToBytes(encoded);
211
+
212
+ expect(decoded).toEqual(largeArray);
213
+ });
214
+
215
+ it("should handle bytes with all zeros", () => {
216
+ const zeros = new Uint8Array([0, 0, 0, 0]);
217
+ const encoded = base64urlEncodeFromBytes(zeros);
218
+ const decoded = base64urlDecodeToBytes(encoded);
219
+
220
+ expect(decoded).toEqual(zeros);
221
+ });
222
+
223
+ it("should handle bytes with all 255s", () => {
224
+ const maxBytes = new Uint8Array([255, 255, 255, 255]);
225
+ const encoded = base64urlEncodeFromBytes(maxBytes);
226
+ const decoded = base64urlDecodeToBytes(encoded);
227
+
228
+ expect(decoded).toEqual(maxBytes);
229
+ });
230
+
231
+ it("should handle single byte", () => {
232
+ const single = new Uint8Array([42]);
233
+ const encoded = base64urlEncodeFromBytes(single);
234
+ const decoded = base64urlDecodeToBytes(encoded);
235
+
236
+ expect(decoded).toEqual(single);
237
+ });
238
+ });
239
+ });