stated-protocol-parser 1.0.6 → 5.0.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 (109) hide show
  1. package/README.md +231 -22
  2. package/dist/constants.d.ts +193 -15
  3. package/dist/constants.d.ts.map +1 -1
  4. package/dist/constants.js +197 -20
  5. package/dist/constants.js.map +1 -1
  6. package/dist/esm/constants.d.ts +193 -15
  7. package/dist/esm/constants.d.ts.map +1 -1
  8. package/dist/esm/{hash.browser.d.ts → hash.d.ts} +11 -5
  9. package/dist/esm/hash.d.ts.map +1 -0
  10. package/dist/esm/index.d.ts +4 -42
  11. package/dist/esm/index.d.ts.map +1 -1
  12. package/dist/esm/index.js +2102 -641
  13. package/dist/esm/index.js.map +7 -1
  14. package/dist/esm/protocol.d.ts +30 -0
  15. package/dist/esm/protocol.d.ts.map +1 -0
  16. package/dist/esm/signature.d.ts +49 -0
  17. package/dist/esm/signature.d.ts.map +1 -0
  18. package/dist/esm/types.d.ts +26 -60
  19. package/dist/esm/types.d.ts.map +1 -1
  20. package/dist/esm/utils.d.ts +10 -0
  21. package/dist/esm/utils.d.ts.map +1 -1
  22. package/dist/{hash.browser.d.ts → hash.d.ts} +11 -5
  23. package/dist/hash.d.ts.map +1 -0
  24. package/dist/{hash.browser.js → hash.js} +44 -10
  25. package/dist/hash.js.map +1 -0
  26. package/dist/index.d.ts +4 -42
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +4 -674
  29. package/dist/index.js.map +1 -1
  30. package/dist/protocol.d.ts +30 -0
  31. package/dist/protocol.d.ts.map +1 -0
  32. package/dist/protocol.js +677 -0
  33. package/dist/protocol.js.map +1 -0
  34. package/dist/signature.d.ts +49 -0
  35. package/dist/signature.d.ts.map +1 -0
  36. package/dist/signature.js +169 -0
  37. package/dist/signature.js.map +1 -0
  38. package/dist/types.d.ts +26 -60
  39. package/dist/types.d.ts.map +1 -1
  40. package/dist/types.js +27 -0
  41. package/dist/types.js.map +1 -1
  42. package/dist/utils.d.ts +10 -0
  43. package/dist/utils.d.ts.map +1 -1
  44. package/dist/utils.js +79 -11
  45. package/dist/utils.js.map +1 -1
  46. package/package.json +25 -16
  47. package/src/constants.ts +228 -44
  48. package/src/fixtures.test.ts +236 -0
  49. package/src/hash.test.ts +217 -215
  50. package/src/hash.ts +99 -0
  51. package/src/index.ts +5 -678
  52. package/src/organisation-verification.test.ts +50 -0
  53. package/src/person-verification.test.ts +55 -0
  54. package/src/poll.test.ts +28 -0
  55. package/src/protocol.ts +871 -0
  56. package/src/rating.test.ts +25 -0
  57. package/src/signature.test.ts +200 -0
  58. package/src/signature.ts +159 -0
  59. package/src/statement.test.ts +101 -0
  60. package/src/types.ts +155 -156
  61. package/src/utils.test.ts +140 -0
  62. package/src/utils.ts +102 -16
  63. package/dist/esm/constants.js +0 -47
  64. package/dist/esm/constants.js.map +0 -1
  65. package/dist/esm/hash.browser.d.ts.map +0 -1
  66. package/dist/esm/hash.browser.js +0 -58
  67. package/dist/esm/hash.browser.js.map +0 -1
  68. package/dist/esm/hash.node.d.ts +0 -31
  69. package/dist/esm/hash.node.d.ts.map +0 -1
  70. package/dist/esm/hash.node.js +0 -43
  71. package/dist/esm/hash.node.js.map +0 -1
  72. package/dist/esm/hash.test.d.ts +0 -2
  73. package/dist/esm/hash.test.d.ts.map +0 -1
  74. package/dist/esm/hash.test.js +0 -181
  75. package/dist/esm/hash.test.js.map +0 -1
  76. package/dist/esm/index.test.d.ts +0 -2
  77. package/dist/esm/index.test.d.ts.map +0 -1
  78. package/dist/esm/index.test.js +0 -293
  79. package/dist/esm/index.test.js.map +0 -1
  80. package/dist/esm/types.js +0 -2
  81. package/dist/esm/types.js.map +0 -1
  82. package/dist/esm/utils.js +0 -23
  83. package/dist/esm/utils.js.map +0 -1
  84. package/dist/esm/v3.d.ts +0 -5
  85. package/dist/esm/v3.d.ts.map +0 -1
  86. package/dist/esm/v3.js +0 -60
  87. package/dist/esm/v3.js.map +0 -1
  88. package/dist/hash.browser.d.ts.map +0 -1
  89. package/dist/hash.browser.js.map +0 -1
  90. package/dist/hash.node.d.ts +0 -31
  91. package/dist/hash.node.d.ts.map +0 -1
  92. package/dist/hash.node.js +0 -53
  93. package/dist/hash.node.js.map +0 -1
  94. package/dist/hash.test.d.ts +0 -2
  95. package/dist/hash.test.d.ts.map +0 -1
  96. package/dist/hash.test.js +0 -183
  97. package/dist/hash.test.js.map +0 -1
  98. package/dist/index.test.d.ts +0 -2
  99. package/dist/index.test.d.ts.map +0 -1
  100. package/dist/index.test.js +0 -295
  101. package/dist/index.test.js.map +0 -1
  102. package/dist/v3.d.ts +0 -5
  103. package/dist/v3.d.ts.map +0 -1
  104. package/dist/v3.js +0 -64
  105. package/dist/v3.js.map +0 -1
  106. package/src/hash.browser.ts +0 -65
  107. package/src/hash.node.ts +0 -47
  108. package/src/index.test.ts +0 -378
  109. package/src/v3.ts +0 -62
package/src/hash.test.ts CHANGED
@@ -1,217 +1,219 @@
1
- import { sha256, verify, fromUrlSafeBase64, toUrlSafeBase64 } from './hash.node';
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert';
3
+ import { sha256, verify, fromUrlSafeBase64, toUrlSafeBase64 } from './hash';
2
4
 
3
5
  describe('Hash utilities', () => {
4
- describe('sha256', () => {
5
- it('should hash a simple string', () => {
6
- const input = 'hello world';
7
- const hash = sha256(input);
8
-
9
- // Verify it's URL-safe (no +, /, or =)
10
- expect(hash).not.toContain('+');
11
- expect(hash).not.toContain('/');
12
- expect(hash).not.toContain('=');
13
-
14
- // Verify consistent output
15
- const hash2 = sha256(input);
16
- expect(hash).toBe(hash2);
17
- });
18
-
19
- it('should produce correct hash for known input', () => {
20
- const input = 'hello world';
21
- const expectedHash = 'uU0nuZNNPgilLlLX2n2r-sSE7-N6U4DukIj3rOLvzek';
22
- const hash = sha256(input);
23
- expect(hash).toBe(expectedHash);
24
- });
25
-
26
- it('should handle empty string', () => {
27
- const hash = sha256('');
28
- expect(hash).toBeTruthy();
29
- expect(typeof hash).toBe('string');
30
- });
31
-
32
- it('should handle unicode characters', () => {
33
- const input = '你好世界 🌍';
34
- const hash = sha256(input);
35
- expect(hash).toBeTruthy();
36
- expect(typeof hash).toBe('string');
37
-
38
- // Verify consistency
39
- const hash2 = sha256(input);
40
- expect(hash).toBe(hash2);
41
- });
42
-
43
- it('should handle Buffer input', () => {
44
- const data = Buffer.from('hello world');
45
- const hash = sha256(data);
46
-
47
- // Should produce same hash as string input
48
- const stringHash = sha256('hello world');
49
- expect(hash).toBe(stringHash);
50
- });
51
-
52
- it('should produce different hashes for different inputs', () => {
53
- const hash1 = sha256('hello');
54
- const hash2 = sha256('world');
55
- expect(hash1).not.toBe(hash2);
56
- });
57
-
58
- it('should produce 43-character URL-safe base64 string', () => {
59
- const hash = sha256('test');
60
- // SHA-256 produces 256 bits = 32 bytes
61
- // Base64 encoding: 32 bytes * 4/3 = 42.67, rounded up = 43 chars (without padding)
62
- expect(hash.length).toBe(43);
63
- });
64
- });
65
-
66
- describe('verify', () => {
67
- it('should verify correct hash', () => {
68
- const content = 'hello world';
69
- const hash = sha256(content);
70
- const isValid = verify(content, hash);
71
- expect(isValid).toBe(true);
72
- });
73
-
74
- it('should reject incorrect hash', () => {
75
- const content = 'hello world';
76
- const wrongHash = 'incorrect_hash_value_here_1234567890';
77
- const isValid = verify(content, wrongHash);
78
- expect(isValid).toBe(false);
79
- });
80
-
81
- it('should reject hash for different content', () => {
82
- const content1 = 'hello world';
83
- const content2 = 'goodbye world';
84
- const hash1 = sha256(content1);
85
- const isValid = verify(content2, hash1);
86
- expect(isValid).toBe(false);
87
- });
88
-
89
- it('should work with Buffer', () => {
90
- const data = Buffer.from('test data');
91
- const hash = sha256(data);
92
- const isValid = verify(data, hash);
93
- expect(isValid).toBe(true);
94
- });
95
- });
96
-
97
- describe('fromUrlSafeBase64', () => {
98
- it('should convert URL-safe base64 to standard base64', () => {
99
- // Use a URL-safe string that contains both - and _ characters
100
- const urlSafe = 'abc-def_ghi';
101
- const standard = fromUrlSafeBase64(urlSafe);
102
-
103
- // Should replace - with + and _ with /
104
- expect(standard).toContain('+');
105
- expect(standard).toContain('/');
106
- // Should add padding
107
- expect(standard.endsWith('=')).toBe(true);
108
- });
109
-
110
- it('should add correct padding', () => {
111
- // Test different padding scenarios
112
- const testCases = [
113
- { input: 'abc', expectedPadding: 1 },
114
- { input: 'abcd', expectedPadding: 0 },
115
- { input: 'abcde', expectedPadding: 3 },
116
- { input: 'abcdef', expectedPadding: 2 },
117
- ];
118
-
119
- testCases.forEach(({ input, expectedPadding }) => {
120
- const result = fromUrlSafeBase64(input);
121
- const paddingCount = (result.match(/=/g) || []).length;
122
- expect(paddingCount).toBe(expectedPadding);
123
- });
124
- });
125
-
126
- it('should handle strings without special characters', () => {
127
- const input = 'abcdefghijklmnop';
128
- const result = fromUrlSafeBase64(input);
129
- expect(result).toBeTruthy();
130
- });
131
- });
132
-
133
- describe('toUrlSafeBase64', () => {
134
- it('should convert standard base64 to URL-safe', () => {
135
- const standard = 'uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek=';
136
- const urlSafe = toUrlSafeBase64(standard);
137
-
138
- // Should not contain standard base64 special characters
139
- expect(urlSafe).not.toContain('+');
140
- expect(urlSafe).not.toContain('/');
141
- expect(urlSafe).not.toContain('=');
142
-
143
- // Should contain URL-safe replacements
144
- expect(urlSafe).toContain('-');
145
- });
146
-
147
- it('should remove padding', () => {
148
- const withPadding = 'abc=';
149
- const result = toUrlSafeBase64(withPadding);
150
- expect(result).not.toContain('=');
151
- expect(result).toBe('abc');
152
- });
153
-
154
- it('should be reversible with fromUrlSafeBase64', () => {
155
- // Start with a standard base64 string with special chars
156
- const original = 'test+data/with==';
157
- const urlSafe = toUrlSafeBase64(original);
158
- const restored = fromUrlSafeBase64(urlSafe);
159
-
160
- // Should restore to equivalent base64 (padding might differ slightly)
161
- expect(restored.replace(/=+$/, '')).toBe(original.replace(/=+$/, ''));
162
- });
163
- });
164
-
165
- describe('Round-trip conversions', () => {
166
- it('should maintain hash integrity through URL-safe conversion', () => {
167
- const content = 'test content for hashing';
168
- const hash = sha256(content);
169
-
170
- // Convert to standard base64 and back
171
- const standard = fromUrlSafeBase64(hash);
172
- const backToUrlSafe = toUrlSafeBase64(standard);
173
-
174
- expect(backToUrlSafe).toBe(hash);
175
- });
176
-
177
- it('should verify hash after conversion', () => {
178
- const content = 'verification test';
179
- const hash = sha256(content);
180
-
181
- // Convert and back
182
- const standard = fromUrlSafeBase64(hash);
183
- const urlSafe = toUrlSafeBase64(standard);
184
-
185
- // Should still verify
186
- const isValid = verify(content, urlSafe);
187
- expect(isValid).toBe(true);
188
- });
189
- });
190
-
191
- describe('Edge cases', () => {
192
- it('should handle very long strings', () => {
193
- const longString = 'a'.repeat(10000);
194
- const hash = sha256(longString);
195
- expect(hash).toBeTruthy();
196
- expect(hash.length).toBe(43);
197
- });
198
-
199
- it('should handle special characters', () => {
200
- const special = '!@#$%^&*()_+-=[]{}|;:,.<>?';
201
- const hash = sha256(special);
202
- expect(hash).toBeTruthy();
203
-
204
- const isValid = verify(special, hash);
205
- expect(isValid).toBe(true);
206
- });
207
-
208
- it('should handle newlines and whitespace', () => {
209
- const withNewlines = 'line1\nline2\r\nline3\ttab';
210
- const hash = sha256(withNewlines);
211
- expect(hash).toBeTruthy();
212
-
213
- const isValid = verify(withNewlines, hash);
214
- expect(isValid).toBe(true);
215
- });
216
- });
217
- });
6
+ describe('sha256', () => {
7
+ it('should hash a simple string', () => {
8
+ const input = 'hello world';
9
+ const hash = sha256(input);
10
+
11
+ // Verify it's URL-safe (no +, /, or =)
12
+ assert.ok(!hash.includes('+'));
13
+ assert.ok(!hash.includes('/'));
14
+ assert.ok(!hash.includes('='));
15
+
16
+ // Verify consistent output
17
+ const hash2 = sha256(input);
18
+ assert.strictEqual(hash, hash2);
19
+ });
20
+
21
+ it('should produce correct hash for known input', () => {
22
+ const input = 'hello world';
23
+ const expectedHash = 'uU0nuZNNPgilLlLX2n2r-sSE7-N6U4DukIj3rOLvzek';
24
+ const hash = sha256(input);
25
+ assert.strictEqual(hash, expectedHash);
26
+ });
27
+
28
+ it('should handle empty string', () => {
29
+ const hash = sha256('');
30
+ assert.ok(hash);
31
+ assert.strictEqual(typeof hash, 'string');
32
+ });
33
+
34
+ it('should handle unicode characters', () => {
35
+ const input = '你好世界 🌍';
36
+ const hash = sha256(input);
37
+ assert.ok(hash);
38
+ assert.strictEqual(typeof hash, 'string');
39
+
40
+ // Verify consistency
41
+ const hash2 = sha256(input);
42
+ assert.strictEqual(hash, hash2);
43
+ });
44
+
45
+ it('should handle Buffer input', () => {
46
+ const data = Buffer.from('hello world');
47
+ const hash = sha256(data);
48
+
49
+ // Should produce same hash as string input
50
+ const stringHash = sha256('hello world');
51
+ assert.strictEqual(hash, stringHash);
52
+ });
53
+
54
+ it('should produce different hashes for different inputs', () => {
55
+ const hash1 = sha256('hello');
56
+ const hash2 = sha256('world');
57
+ assert.notStrictEqual(hash1, hash2);
58
+ });
59
+
60
+ it('should produce 43-character URL-safe base64 string', () => {
61
+ const hash = sha256('test');
62
+ // SHA-256 produces 256 bits = 32 bytes
63
+ // Base64 encoding: 32 bytes * 4/3 = 42.67, rounded up = 43 chars (without padding)
64
+ assert.strictEqual(hash.length, 43);
65
+ });
66
+ });
67
+
68
+ describe('verify', () => {
69
+ it('should verify correct hash', () => {
70
+ const content = 'hello world';
71
+ const hash = sha256(content);
72
+ const isValid = verify(content, hash);
73
+ assert.strictEqual(isValid, true);
74
+ });
75
+
76
+ it('should reject incorrect hash', () => {
77
+ const content = 'hello world';
78
+ const wrongHash = 'incorrect_hash_value_here_1234567890';
79
+ const isValid = verify(content, wrongHash);
80
+ assert.strictEqual(isValid, false);
81
+ });
82
+
83
+ it('should reject hash for different content', () => {
84
+ const content1 = 'hello world';
85
+ const content2 = 'goodbye world';
86
+ const hash1 = sha256(content1);
87
+ const isValid = verify(content2, hash1);
88
+ assert.strictEqual(isValid, false);
89
+ });
90
+
91
+ it('should work with Buffer', () => {
92
+ const data = Buffer.from('test data');
93
+ const hash = sha256(data);
94
+ const isValid = verify(data, hash);
95
+ assert.strictEqual(isValid, true);
96
+ });
97
+ });
98
+
99
+ describe('fromUrlSafeBase64', () => {
100
+ it('should convert URL-safe base64 to standard base64', () => {
101
+ // Use a URL-safe string that contains both - and _ characters
102
+ const urlSafe = 'abc-def_ghi';
103
+ const standard = fromUrlSafeBase64(urlSafe);
104
+
105
+ // Should replace - with + and _ with /
106
+ assert.ok(standard.includes('+'));
107
+ assert.ok(standard.includes('/'));
108
+ // Should add padding
109
+ assert.strictEqual(standard.endsWith('='), true);
110
+ });
111
+
112
+ it('should add correct padding', () => {
113
+ // Test different padding scenarios
114
+ const testCases = [
115
+ { input: 'abc', expectedPadding: 1 },
116
+ { input: 'abcd', expectedPadding: 0 },
117
+ { input: 'abcde', expectedPadding: 3 },
118
+ { input: 'abcdef', expectedPadding: 2 },
119
+ ];
120
+
121
+ testCases.forEach(({ input, expectedPadding }) => {
122
+ const result = fromUrlSafeBase64(input);
123
+ const paddingCount = (result.match(/=/g) || []).length;
124
+ assert.strictEqual(paddingCount, expectedPadding);
125
+ });
126
+ });
127
+
128
+ it('should handle strings without special characters', () => {
129
+ const input = 'abcdefghijklmnop';
130
+ const result = fromUrlSafeBase64(input);
131
+ assert.ok(result);
132
+ });
133
+ });
134
+
135
+ describe('toUrlSafeBase64', () => {
136
+ it('should convert standard base64 to URL-safe', () => {
137
+ const standard = 'uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek=';
138
+ const urlSafe = toUrlSafeBase64(standard);
139
+
140
+ // Should not contain standard base64 special characters
141
+ assert.ok(!urlSafe.includes('+'));
142
+ assert.ok(!urlSafe.includes('/'));
143
+ assert.ok(!urlSafe.includes('='));
144
+
145
+ // Should contain URL-safe replacements
146
+ assert.ok(urlSafe.includes('-'));
147
+ });
148
+
149
+ it('should remove padding', () => {
150
+ const withPadding = 'abc=';
151
+ const result = toUrlSafeBase64(withPadding);
152
+ assert.ok(!result.includes('='));
153
+ assert.strictEqual(result, 'abc');
154
+ });
155
+
156
+ it('should be reversible with fromUrlSafeBase64', () => {
157
+ // Start with a standard base64 string with special chars
158
+ const original = 'test+data/with==';
159
+ const urlSafe = toUrlSafeBase64(original);
160
+ const restored = fromUrlSafeBase64(urlSafe);
161
+
162
+ // Should restore to equivalent base64 (padding might differ slightly)
163
+ assert.strictEqual(restored.replace(/=+$/, ''), original.replace(/=+$/, ''));
164
+ });
165
+ });
166
+
167
+ describe('Round-trip conversions', () => {
168
+ it('should maintain hash integrity through URL-safe conversion', () => {
169
+ const content = 'test content for hashing';
170
+ const hash = sha256(content);
171
+
172
+ // Convert to standard base64 and back
173
+ const standard = fromUrlSafeBase64(hash);
174
+ const backToUrlSafe = toUrlSafeBase64(standard);
175
+
176
+ assert.strictEqual(backToUrlSafe, hash);
177
+ });
178
+
179
+ it('should verify hash after conversion', () => {
180
+ const content = 'verification test';
181
+ const hash = sha256(content);
182
+
183
+ // Convert and back
184
+ const standard = fromUrlSafeBase64(hash);
185
+ const urlSafe = toUrlSafeBase64(standard);
186
+
187
+ // Should still verify
188
+ const isValid = verify(content, urlSafe);
189
+ assert.strictEqual(isValid, true);
190
+ });
191
+ });
192
+
193
+ describe('Edge cases', () => {
194
+ it('should handle very long strings', () => {
195
+ const longString = 'a'.repeat(10000);
196
+ const hash = sha256(longString);
197
+ assert.ok(hash);
198
+ assert.strictEqual(hash.length, 43);
199
+ });
200
+
201
+ it('should handle special characters', () => {
202
+ const special = '!@#$%^&*()_+-=[]{}|;:,.<>?';
203
+ const hash = sha256(special);
204
+ assert.ok(hash);
205
+
206
+ const isValid = verify(special, hash);
207
+ assert.strictEqual(isValid, true);
208
+ });
209
+
210
+ it('should handle newlines and whitespace', () => {
211
+ const withNewlines = 'line1\nline2\r\nline3\ttab';
212
+ const hash = sha256(withNewlines);
213
+ assert.ok(hash);
214
+
215
+ const isValid = verify(withNewlines, hash);
216
+ assert.strictEqual(isValid, true);
217
+ });
218
+ });
219
+ });
package/src/hash.ts ADDED
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Universal hash utilities using @noble/hashes
3
+ * Works in both browser and Node.js environments
4
+ */
5
+
6
+ import { sha256 as nobleSha256 } from '@noble/hashes/sha2.js';
7
+
8
+ /**
9
+ * Compute SHA-256 hash of a string and return it as URL-safe base64
10
+ * Works in both browser and Node.js environments
11
+ * @param input - The string or buffer to hash
12
+ * @returns URL-safe base64 encoded hash
13
+ */
14
+ export const sha256 = (input: string | Uint8Array): string => {
15
+ let data: Uint8Array;
16
+
17
+ if (typeof input === 'string') {
18
+ const encoder = new TextEncoder();
19
+ data = encoder.encode(input);
20
+ } else {
21
+ data = input;
22
+ }
23
+
24
+ // Use @noble/hashes for consistent cross-platform hashing
25
+ const hashArray = nobleSha256(data);
26
+
27
+ // Convert to base64
28
+ const base64 = bytesToBase64(hashArray);
29
+
30
+ // Make URL-safe: remove padding and replace + with - and / with _
31
+ const urlSafe = base64.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
32
+
33
+ return urlSafe;
34
+ };
35
+
36
+ /**
37
+ * Verify that content matches a given hash
38
+ * @param content - The content to verify
39
+ * @param hash - The expected hash
40
+ * @returns True if the hash matches
41
+ */
42
+ export const verify = (content: string | Uint8Array, hash: string): boolean => {
43
+ const computed = sha256(content);
44
+ return computed === hash;
45
+ };
46
+
47
+ /**
48
+ * Convert URL-safe base64 back to standard base64
49
+ * @param urlSafe - URL-safe base64 string
50
+ * @returns Standard base64 string with padding
51
+ */
52
+ export const fromUrlSafeBase64 = (urlSafe: string): string => {
53
+ const base64 = urlSafe.replace(/-/g, '+').replace(/_/g, '/');
54
+ // Add padding if needed
55
+ const padding = '='.repeat((4 - (base64.length % 4)) % 4);
56
+ return base64 + padding;
57
+ };
58
+
59
+ /**
60
+ * Convert standard base64 to URL-safe base64
61
+ * @param base64 - Standard base64 string
62
+ * @returns URL-safe base64 string without padding
63
+ */
64
+ export const toUrlSafeBase64 = (base64: string): string => {
65
+ return base64.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
66
+ };
67
+
68
+ /**
69
+ * Convert bytes to base64 string
70
+ * @param bytes - Uint8Array to convert
71
+ * @returns Base64 string
72
+ */
73
+ function bytesToBase64(bytes: Uint8Array): string {
74
+ // Use btoa if available (browser), otherwise use Buffer (Node.js)
75
+ if (typeof btoa !== 'undefined') {
76
+ return btoa(String.fromCharCode(...Array.from(bytes)));
77
+ } else {
78
+ return Buffer.from(bytes).toString('base64');
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Convert base64 string to bytes
84
+ * @param base64 - Base64 string to convert
85
+ * @returns Uint8Array
86
+ */
87
+ export function base64ToBytes(base64: string): Uint8Array {
88
+ // Use atob if available (browser), otherwise use Buffer (Node.js)
89
+ if (typeof atob !== 'undefined') {
90
+ const binaryString = atob(base64);
91
+ const bytes = new Uint8Array(binaryString.length);
92
+ for (let i = 0; i < binaryString.length; i++) {
93
+ bytes[i] = binaryString.charCodeAt(i);
94
+ }
95
+ return bytes;
96
+ } else {
97
+ return new Uint8Array(Buffer.from(base64, 'base64'));
98
+ }
99
+ }