almostnode 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 (216) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +731 -0
  3. package/dist/__sw__.js +394 -0
  4. package/dist/ai-chatbot-demo-entry.d.ts +6 -0
  5. package/dist/ai-chatbot-demo-entry.d.ts.map +1 -0
  6. package/dist/ai-chatbot-demo.d.ts +42 -0
  7. package/dist/ai-chatbot-demo.d.ts.map +1 -0
  8. package/dist/assets/runtime-worker-D9x_Ddwz.js +60543 -0
  9. package/dist/assets/runtime-worker-D9x_Ddwz.js.map +1 -0
  10. package/dist/convex-app-demo-entry.d.ts +6 -0
  11. package/dist/convex-app-demo-entry.d.ts.map +1 -0
  12. package/dist/convex-app-demo.d.ts +68 -0
  13. package/dist/convex-app-demo.d.ts.map +1 -0
  14. package/dist/cors-proxy.d.ts +46 -0
  15. package/dist/cors-proxy.d.ts.map +1 -0
  16. package/dist/create-runtime.d.ts +42 -0
  17. package/dist/create-runtime.d.ts.map +1 -0
  18. package/dist/demo.d.ts +6 -0
  19. package/dist/demo.d.ts.map +1 -0
  20. package/dist/dev-server.d.ts +97 -0
  21. package/dist/dev-server.d.ts.map +1 -0
  22. package/dist/frameworks/next-dev-server.d.ts +202 -0
  23. package/dist/frameworks/next-dev-server.d.ts.map +1 -0
  24. package/dist/frameworks/vite-dev-server.d.ts +85 -0
  25. package/dist/frameworks/vite-dev-server.d.ts.map +1 -0
  26. package/dist/index.cjs +14965 -0
  27. package/dist/index.cjs.map +1 -0
  28. package/dist/index.d.ts +71 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.mjs +14867 -0
  31. package/dist/index.mjs.map +1 -0
  32. package/dist/next-demo.d.ts +49 -0
  33. package/dist/next-demo.d.ts.map +1 -0
  34. package/dist/npm/index.d.ts +71 -0
  35. package/dist/npm/index.d.ts.map +1 -0
  36. package/dist/npm/registry.d.ts +66 -0
  37. package/dist/npm/registry.d.ts.map +1 -0
  38. package/dist/npm/resolver.d.ts +52 -0
  39. package/dist/npm/resolver.d.ts.map +1 -0
  40. package/dist/npm/tarball.d.ts +29 -0
  41. package/dist/npm/tarball.d.ts.map +1 -0
  42. package/dist/runtime-interface.d.ts +90 -0
  43. package/dist/runtime-interface.d.ts.map +1 -0
  44. package/dist/runtime.d.ts +103 -0
  45. package/dist/runtime.d.ts.map +1 -0
  46. package/dist/sandbox-helpers.d.ts +43 -0
  47. package/dist/sandbox-helpers.d.ts.map +1 -0
  48. package/dist/sandbox-runtime.d.ts +65 -0
  49. package/dist/sandbox-runtime.d.ts.map +1 -0
  50. package/dist/server-bridge.d.ts +89 -0
  51. package/dist/server-bridge.d.ts.map +1 -0
  52. package/dist/shims/assert.d.ts +51 -0
  53. package/dist/shims/assert.d.ts.map +1 -0
  54. package/dist/shims/async_hooks.d.ts +37 -0
  55. package/dist/shims/async_hooks.d.ts.map +1 -0
  56. package/dist/shims/buffer.d.ts +20 -0
  57. package/dist/shims/buffer.d.ts.map +1 -0
  58. package/dist/shims/child_process-browser.d.ts +92 -0
  59. package/dist/shims/child_process-browser.d.ts.map +1 -0
  60. package/dist/shims/child_process.d.ts +93 -0
  61. package/dist/shims/child_process.d.ts.map +1 -0
  62. package/dist/shims/chokidar.d.ts +55 -0
  63. package/dist/shims/chokidar.d.ts.map +1 -0
  64. package/dist/shims/cluster.d.ts +52 -0
  65. package/dist/shims/cluster.d.ts.map +1 -0
  66. package/dist/shims/crypto.d.ts +122 -0
  67. package/dist/shims/crypto.d.ts.map +1 -0
  68. package/dist/shims/dgram.d.ts +34 -0
  69. package/dist/shims/dgram.d.ts.map +1 -0
  70. package/dist/shims/diagnostics_channel.d.ts +80 -0
  71. package/dist/shims/diagnostics_channel.d.ts.map +1 -0
  72. package/dist/shims/dns.d.ts +87 -0
  73. package/dist/shims/dns.d.ts.map +1 -0
  74. package/dist/shims/domain.d.ts +25 -0
  75. package/dist/shims/domain.d.ts.map +1 -0
  76. package/dist/shims/esbuild.d.ts +105 -0
  77. package/dist/shims/esbuild.d.ts.map +1 -0
  78. package/dist/shims/events.d.ts +37 -0
  79. package/dist/shims/events.d.ts.map +1 -0
  80. package/dist/shims/fs.d.ts +115 -0
  81. package/dist/shims/fs.d.ts.map +1 -0
  82. package/dist/shims/fsevents.d.ts +67 -0
  83. package/dist/shims/fsevents.d.ts.map +1 -0
  84. package/dist/shims/http.d.ts +217 -0
  85. package/dist/shims/http.d.ts.map +1 -0
  86. package/dist/shims/http2.d.ts +81 -0
  87. package/dist/shims/http2.d.ts.map +1 -0
  88. package/dist/shims/https.d.ts +36 -0
  89. package/dist/shims/https.d.ts.map +1 -0
  90. package/dist/shims/inspector.d.ts +25 -0
  91. package/dist/shims/inspector.d.ts.map +1 -0
  92. package/dist/shims/module.d.ts +22 -0
  93. package/dist/shims/module.d.ts.map +1 -0
  94. package/dist/shims/net.d.ts +100 -0
  95. package/dist/shims/net.d.ts.map +1 -0
  96. package/dist/shims/os.d.ts +159 -0
  97. package/dist/shims/os.d.ts.map +1 -0
  98. package/dist/shims/path.d.ts +72 -0
  99. package/dist/shims/path.d.ts.map +1 -0
  100. package/dist/shims/perf_hooks.d.ts +50 -0
  101. package/dist/shims/perf_hooks.d.ts.map +1 -0
  102. package/dist/shims/process.d.ts +93 -0
  103. package/dist/shims/process.d.ts.map +1 -0
  104. package/dist/shims/querystring.d.ts +23 -0
  105. package/dist/shims/querystring.d.ts.map +1 -0
  106. package/dist/shims/readdirp.d.ts +52 -0
  107. package/dist/shims/readdirp.d.ts.map +1 -0
  108. package/dist/shims/readline.d.ts +62 -0
  109. package/dist/shims/readline.d.ts.map +1 -0
  110. package/dist/shims/rollup.d.ts +34 -0
  111. package/dist/shims/rollup.d.ts.map +1 -0
  112. package/dist/shims/sentry.d.ts +163 -0
  113. package/dist/shims/sentry.d.ts.map +1 -0
  114. package/dist/shims/stream.d.ts +181 -0
  115. package/dist/shims/stream.d.ts.map +1 -0
  116. package/dist/shims/tls.d.ts +53 -0
  117. package/dist/shims/tls.d.ts.map +1 -0
  118. package/dist/shims/tty.d.ts +30 -0
  119. package/dist/shims/tty.d.ts.map +1 -0
  120. package/dist/shims/url.d.ts +64 -0
  121. package/dist/shims/url.d.ts.map +1 -0
  122. package/dist/shims/util.d.ts +106 -0
  123. package/dist/shims/util.d.ts.map +1 -0
  124. package/dist/shims/v8.d.ts +73 -0
  125. package/dist/shims/v8.d.ts.map +1 -0
  126. package/dist/shims/vfs-adapter.d.ts +126 -0
  127. package/dist/shims/vfs-adapter.d.ts.map +1 -0
  128. package/dist/shims/vm.d.ts +45 -0
  129. package/dist/shims/vm.d.ts.map +1 -0
  130. package/dist/shims/worker_threads.d.ts +66 -0
  131. package/dist/shims/worker_threads.d.ts.map +1 -0
  132. package/dist/shims/ws.d.ts +66 -0
  133. package/dist/shims/ws.d.ts.map +1 -0
  134. package/dist/shims/zlib.d.ts +161 -0
  135. package/dist/shims/zlib.d.ts.map +1 -0
  136. package/dist/transform.d.ts +24 -0
  137. package/dist/transform.d.ts.map +1 -0
  138. package/dist/virtual-fs.d.ts +226 -0
  139. package/dist/virtual-fs.d.ts.map +1 -0
  140. package/dist/vite-demo.d.ts +35 -0
  141. package/dist/vite-demo.d.ts.map +1 -0
  142. package/dist/vite-sw.js +132 -0
  143. package/dist/worker/runtime-worker.d.ts +8 -0
  144. package/dist/worker/runtime-worker.d.ts.map +1 -0
  145. package/dist/worker-runtime.d.ts +50 -0
  146. package/dist/worker-runtime.d.ts.map +1 -0
  147. package/package.json +85 -0
  148. package/src/ai-chatbot-demo-entry.ts +244 -0
  149. package/src/ai-chatbot-demo.ts +509 -0
  150. package/src/convex-app-demo-entry.ts +1107 -0
  151. package/src/convex-app-demo.ts +1316 -0
  152. package/src/cors-proxy.ts +81 -0
  153. package/src/create-runtime.ts +147 -0
  154. package/src/demo.ts +304 -0
  155. package/src/dev-server.ts +274 -0
  156. package/src/frameworks/next-dev-server.ts +2224 -0
  157. package/src/frameworks/vite-dev-server.ts +702 -0
  158. package/src/index.ts +101 -0
  159. package/src/next-demo.ts +1784 -0
  160. package/src/npm/index.ts +347 -0
  161. package/src/npm/registry.ts +152 -0
  162. package/src/npm/resolver.ts +385 -0
  163. package/src/npm/tarball.ts +209 -0
  164. package/src/runtime-interface.ts +103 -0
  165. package/src/runtime.ts +1046 -0
  166. package/src/sandbox-helpers.ts +173 -0
  167. package/src/sandbox-runtime.ts +252 -0
  168. package/src/server-bridge.ts +426 -0
  169. package/src/shims/assert.ts +664 -0
  170. package/src/shims/async_hooks.ts +86 -0
  171. package/src/shims/buffer.ts +75 -0
  172. package/src/shims/child_process-browser.ts +217 -0
  173. package/src/shims/child_process.ts +463 -0
  174. package/src/shims/chokidar.ts +313 -0
  175. package/src/shims/cluster.ts +67 -0
  176. package/src/shims/crypto.ts +830 -0
  177. package/src/shims/dgram.ts +47 -0
  178. package/src/shims/diagnostics_channel.ts +196 -0
  179. package/src/shims/dns.ts +172 -0
  180. package/src/shims/domain.ts +58 -0
  181. package/src/shims/esbuild.ts +805 -0
  182. package/src/shims/events.ts +195 -0
  183. package/src/shims/fs.ts +803 -0
  184. package/src/shims/fsevents.ts +63 -0
  185. package/src/shims/http.ts +904 -0
  186. package/src/shims/http2.ts +96 -0
  187. package/src/shims/https.ts +86 -0
  188. package/src/shims/inspector.ts +30 -0
  189. package/src/shims/module.ts +82 -0
  190. package/src/shims/net.ts +359 -0
  191. package/src/shims/os.ts +195 -0
  192. package/src/shims/path.ts +199 -0
  193. package/src/shims/perf_hooks.ts +92 -0
  194. package/src/shims/process.ts +346 -0
  195. package/src/shims/querystring.ts +97 -0
  196. package/src/shims/readdirp.ts +228 -0
  197. package/src/shims/readline.ts +110 -0
  198. package/src/shims/rollup.ts +80 -0
  199. package/src/shims/sentry.ts +133 -0
  200. package/src/shims/stream.ts +1126 -0
  201. package/src/shims/tls.ts +95 -0
  202. package/src/shims/tty.ts +64 -0
  203. package/src/shims/url.ts +171 -0
  204. package/src/shims/util.ts +312 -0
  205. package/src/shims/v8.ts +113 -0
  206. package/src/shims/vfs-adapter.ts +402 -0
  207. package/src/shims/vm.ts +83 -0
  208. package/src/shims/worker_threads.ts +111 -0
  209. package/src/shims/ws.ts +382 -0
  210. package/src/shims/zlib.ts +289 -0
  211. package/src/transform.ts +313 -0
  212. package/src/types/external.d.ts +67 -0
  213. package/src/virtual-fs.ts +903 -0
  214. package/src/vite-demo.ts +577 -0
  215. package/src/worker/runtime-worker.ts +128 -0
  216. package/src/worker-runtime.ts +145 -0
@@ -0,0 +1,830 @@
1
+ /**
2
+ * Node.js crypto module shim
3
+ * Provides cryptographic utilities using Web Crypto API
4
+ */
5
+
6
+ import { Buffer } from './stream';
7
+ import { EventEmitter } from './events';
8
+
9
+ // ============================================================================
10
+ // Random functions
11
+ // ============================================================================
12
+
13
+ export function randomBytes(size: number): Buffer {
14
+ const array = new Uint8Array(size);
15
+ crypto.getRandomValues(array);
16
+ return Buffer.from(array);
17
+ }
18
+
19
+ export function randomUUID(): string {
20
+ return crypto.randomUUID();
21
+ }
22
+
23
+ export function randomInt(min: number, max?: number): number {
24
+ if (max === undefined) {
25
+ max = min;
26
+ min = 0;
27
+ }
28
+ const range = max - min;
29
+ const array = new Uint32Array(1);
30
+ crypto.getRandomValues(array);
31
+ return min + (array[0] % range);
32
+ }
33
+
34
+ export function getRandomValues<T extends ArrayBufferView>(array: T): T {
35
+ return crypto.getRandomValues(array);
36
+ }
37
+
38
+ // ============================================================================
39
+ // Hash functions
40
+ // ============================================================================
41
+
42
+ export function createHash(algorithm: string): Hash {
43
+ return new Hash(algorithm);
44
+ }
45
+
46
+ class Hash {
47
+ private algorithm: string;
48
+ private data: Uint8Array[] = [];
49
+
50
+ constructor(algorithm: string) {
51
+ this.algorithm = normalizeHashAlgorithm(algorithm);
52
+ }
53
+
54
+ update(data: string | Buffer, encoding?: string): this {
55
+ let buffer: Buffer;
56
+ if (typeof data === 'string') {
57
+ if (encoding === 'base64') {
58
+ buffer = Buffer.from(atob(data));
59
+ } else {
60
+ buffer = Buffer.from(data);
61
+ }
62
+ } else {
63
+ buffer = data;
64
+ }
65
+ this.data.push(buffer);
66
+ return this;
67
+ }
68
+
69
+ async digestAsync(encoding?: string): Promise<string | Buffer> {
70
+ const combined = concatBuffers(this.data);
71
+ const dataBuffer = new Uint8Array(combined).buffer as ArrayBuffer;
72
+ const hashBuffer = await crypto.subtle.digest(this.algorithm, dataBuffer);
73
+ return encodeResult(new Uint8Array(hashBuffer), encoding);
74
+ }
75
+
76
+ digest(encoding?: string): string | Buffer {
77
+ // WebCrypto is async-only, so we store a pending promise and return a placeholder
78
+ // This is a limitation - for sync usage, packages should use the async version
79
+ // For now, we compute synchronously using a fallback
80
+ const combined = concatBuffers(this.data);
81
+
82
+ // Use synchronous hash implementation
83
+ const hash = syncHash(combined, this.algorithm);
84
+ return encodeResult(hash, encoding);
85
+ }
86
+ }
87
+
88
+ // ============================================================================
89
+ // HMAC functions
90
+ // ============================================================================
91
+
92
+ export function createHmac(algorithm: string, key: string | Buffer): Hmac {
93
+ return new Hmac(algorithm, key);
94
+ }
95
+
96
+ class Hmac {
97
+ private algorithm: string;
98
+ private key: Buffer;
99
+ private data: Uint8Array[] = [];
100
+
101
+ constructor(algorithm: string, key: string | Buffer) {
102
+ this.algorithm = normalizeHashAlgorithm(algorithm);
103
+ this.key = typeof key === 'string' ? Buffer.from(key) : key;
104
+ }
105
+
106
+ update(data: string | Buffer, encoding?: string): this {
107
+ const buffer = typeof data === 'string' ? Buffer.from(data) : data;
108
+ this.data.push(buffer);
109
+ return this;
110
+ }
111
+
112
+ async digestAsync(encoding?: string): Promise<string | Buffer> {
113
+ const combined = concatBuffers(this.data);
114
+ const keyBuffer = new Uint8Array(this.key).buffer as ArrayBuffer;
115
+ const dataBuffer = new Uint8Array(combined).buffer as ArrayBuffer;
116
+
117
+ const cryptoKey = await crypto.subtle.importKey(
118
+ 'raw',
119
+ keyBuffer,
120
+ { name: 'HMAC', hash: this.algorithm },
121
+ false,
122
+ ['sign']
123
+ );
124
+
125
+ const signature = await crypto.subtle.sign('HMAC', cryptoKey, dataBuffer);
126
+ return encodeResult(new Uint8Array(signature), encoding);
127
+ }
128
+
129
+ digest(encoding?: string): string | Buffer {
130
+ // Synchronous fallback - uses simple HMAC approximation
131
+ const combined = concatBuffers(this.data);
132
+ const hash = syncHmac(combined, this.key, this.algorithm);
133
+ return encodeResult(hash, encoding);
134
+ }
135
+ }
136
+
137
+ // ============================================================================
138
+ // PBKDF2 (Password-Based Key Derivation Function 2)
139
+ // ============================================================================
140
+
141
+ type BinaryLike = string | Buffer | Uint8Array;
142
+
143
+ /**
144
+ * Async PBKDF2 implementation using WebCrypto
145
+ */
146
+ async function pbkdf2Async(
147
+ password: BinaryLike,
148
+ salt: BinaryLike,
149
+ iterations: number,
150
+ keylen: number,
151
+ digest: string
152
+ ): Promise<Buffer> {
153
+ const passwordBuffer = typeof password === 'string' ? Buffer.from(password) : (password instanceof Uint8Array ? password : Buffer.from(password));
154
+ const saltBuffer = typeof salt === 'string' ? Buffer.from(salt) : (salt instanceof Uint8Array ? salt : Buffer.from(salt));
155
+
156
+ // Convert to ArrayBuffer for WebCrypto compatibility
157
+ const passwordArrayBuffer = new Uint8Array(passwordBuffer).buffer as ArrayBuffer;
158
+ const saltArrayBuffer = new Uint8Array(saltBuffer).buffer as ArrayBuffer;
159
+
160
+ const key = await crypto.subtle.importKey(
161
+ 'raw',
162
+ passwordArrayBuffer,
163
+ 'PBKDF2',
164
+ false,
165
+ ['deriveBits']
166
+ );
167
+
168
+ const derivedBits = await crypto.subtle.deriveBits(
169
+ {
170
+ name: 'PBKDF2',
171
+ salt: saltArrayBuffer,
172
+ iterations,
173
+ hash: normalizeHashAlgorithm(digest),
174
+ },
175
+ key,
176
+ keylen * 8 // Convert bytes to bits
177
+ );
178
+
179
+ return Buffer.from(derivedBits);
180
+ }
181
+
182
+ /**
183
+ * PBKDF2 with callback (Node.js compatible API)
184
+ */
185
+ export function pbkdf2(
186
+ password: BinaryLike,
187
+ salt: BinaryLike,
188
+ iterations: number,
189
+ keylen: number,
190
+ digest: string,
191
+ callback: (err: Error | null, derivedKey: Buffer) => void
192
+ ): void {
193
+ pbkdf2Async(password, salt, iterations, keylen, digest)
194
+ .then(key => callback(null, key))
195
+ .catch(err => callback(err, Buffer.alloc(0)));
196
+ }
197
+
198
+ /**
199
+ * Synchronous PBKDF2 - Note: Uses a pure JS implementation since WebCrypto is async-only
200
+ * For better performance, use the async pbkdf2() function instead
201
+ */
202
+ export function pbkdf2Sync(
203
+ password: BinaryLike,
204
+ salt: BinaryLike,
205
+ iterations: number,
206
+ keylen: number,
207
+ digest: string
208
+ ): Buffer {
209
+ const passwordBuffer = typeof password === 'string' ? Buffer.from(password) : password;
210
+ const saltBuffer = typeof salt === 'string' ? Buffer.from(salt) : salt;
211
+ const hashAlg = normalizeHashAlgorithm(digest);
212
+
213
+ // Determine hash output size
214
+ let hashLen: number;
215
+ if (hashAlg.includes('512')) {
216
+ hashLen = 64;
217
+ } else if (hashAlg.includes('384')) {
218
+ hashLen = 48;
219
+ } else if (hashAlg.includes('1') || hashAlg === 'SHA-1') {
220
+ hashLen = 20;
221
+ } else {
222
+ hashLen = 32; // SHA-256 default
223
+ }
224
+
225
+ // Pure JS PBKDF2 implementation
226
+ const numBlocks = Math.ceil(keylen / hashLen);
227
+ const derivedKey = new Uint8Array(numBlocks * hashLen);
228
+
229
+ for (let blockNum = 1; blockNum <= numBlocks; blockNum++) {
230
+ // U1 = PRF(Password, Salt || INT(blockNum))
231
+ const blockNumBuf = new Uint8Array(4);
232
+ blockNumBuf[0] = (blockNum >>> 24) & 0xff;
233
+ blockNumBuf[1] = (blockNum >>> 16) & 0xff;
234
+ blockNumBuf[2] = (blockNum >>> 8) & 0xff;
235
+ blockNumBuf[3] = blockNum & 0xff;
236
+
237
+ const saltWithBlock = new Uint8Array(saltBuffer.length + 4);
238
+ saltWithBlock.set(saltBuffer);
239
+ saltWithBlock.set(blockNumBuf, saltBuffer.length);
240
+
241
+ let u = syncHmac(saltWithBlock, passwordBuffer, hashAlg);
242
+ const block = new Uint8Array(u);
243
+
244
+ // U2, U3, ... Ui
245
+ for (let i = 1; i < iterations; i++) {
246
+ u = syncHmac(u, passwordBuffer, hashAlg);
247
+ // XOR with accumulated block
248
+ for (let j = 0; j < block.length; j++) {
249
+ block[j] ^= u[j];
250
+ }
251
+ }
252
+
253
+ derivedKey.set(block, (blockNum - 1) * hashLen);
254
+ }
255
+
256
+ return Buffer.from(derivedKey.slice(0, keylen));
257
+ }
258
+
259
+ // ============================================================================
260
+ // Sign and Verify (main functions jose uses)
261
+ // ============================================================================
262
+
263
+ /**
264
+ * Calculates and returns a signature for data using the given private key
265
+ * This is the one-shot API that jose uses
266
+ */
267
+ export function sign(
268
+ algorithm: string | null | undefined,
269
+ data: Buffer | Uint8Array,
270
+ key: KeyLike,
271
+ callback?: (error: Error | null, signature: Buffer) => void
272
+ ): Buffer | void {
273
+ // Get the actual key material and algorithm
274
+ const keyInfo = extractKeyInfo(key);
275
+ const alg = algorithm || keyInfo.algorithm;
276
+
277
+ if (!alg) {
278
+ const error = new Error('Algorithm must be specified');
279
+ if (callback) {
280
+ callback(error, null as unknown as Buffer);
281
+ return;
282
+ }
283
+ throw error;
284
+ }
285
+
286
+ // For async operation with callback
287
+ if (callback) {
288
+ signAsync(alg, data, keyInfo)
289
+ .then(sig => callback(null, sig))
290
+ .catch(err => callback(err, null as unknown as Buffer));
291
+ return;
292
+ }
293
+
294
+ // Synchronous operation - we need to use a workaround
295
+ // Store the promise result for later retrieval
296
+ const result = signSync(alg, data, keyInfo);
297
+ return result;
298
+ }
299
+
300
+ /**
301
+ * Verifies the given signature for data using the given key
302
+ */
303
+ export function verify(
304
+ algorithm: string | null | undefined,
305
+ data: Buffer | Uint8Array,
306
+ key: KeyLike,
307
+ signature: Buffer | Uint8Array,
308
+ callback?: (error: Error | null, result: boolean) => void
309
+ ): boolean | void {
310
+ const keyInfo = extractKeyInfo(key);
311
+ const alg = algorithm || keyInfo.algorithm;
312
+
313
+ if (!alg) {
314
+ const error = new Error('Algorithm must be specified');
315
+ if (callback) {
316
+ callback(error, false);
317
+ return;
318
+ }
319
+ throw error;
320
+ }
321
+
322
+ if (callback) {
323
+ verifyAsync(alg, data, keyInfo, signature)
324
+ .then(result => callback(null, result))
325
+ .catch(err => callback(err, false));
326
+ return;
327
+ }
328
+
329
+ return verifySync(alg, data, keyInfo, signature);
330
+ }
331
+
332
+ // ============================================================================
333
+ // createSign / createVerify (streaming API)
334
+ // ============================================================================
335
+
336
+ export function createSign(algorithm: string): Sign {
337
+ return new Sign(algorithm);
338
+ }
339
+
340
+ export function createVerify(algorithm: string): Verify {
341
+ return new Verify(algorithm);
342
+ }
343
+
344
+ class Sign extends EventEmitter {
345
+ private algorithm: string;
346
+ private data: Uint8Array[] = [];
347
+
348
+ constructor(algorithm: string) {
349
+ super();
350
+ this.algorithm = algorithm;
351
+ }
352
+
353
+ update(data: string | Buffer, encoding?: string): this {
354
+ const buffer = typeof data === 'string' ? Buffer.from(data) : data;
355
+ this.data.push(buffer);
356
+ return this;
357
+ }
358
+
359
+ sign(privateKey: KeyLike, outputEncoding?: string): Buffer | string {
360
+ const combined = concatBuffers(this.data);
361
+ const keyInfo = extractKeyInfo(privateKey);
362
+ const signature = signSync(this.algorithm, combined, keyInfo);
363
+
364
+ if (outputEncoding === 'base64') {
365
+ return btoa(String.fromCharCode(...signature));
366
+ }
367
+ if (outputEncoding === 'hex') {
368
+ return Array.from(signature).map(b => b.toString(16).padStart(2, '0')).join('');
369
+ }
370
+ return signature;
371
+ }
372
+ }
373
+
374
+ class Verify extends EventEmitter {
375
+ private algorithm: string;
376
+ private data: Uint8Array[] = [];
377
+
378
+ constructor(algorithm: string) {
379
+ super();
380
+ this.algorithm = algorithm;
381
+ }
382
+
383
+ update(data: string | Buffer, encoding?: string): this {
384
+ const buffer = typeof data === 'string' ? Buffer.from(data) : data;
385
+ this.data.push(buffer);
386
+ return this;
387
+ }
388
+
389
+ verify(publicKey: KeyLike, signature: Buffer | string, signatureEncoding?: string): boolean {
390
+ const combined = concatBuffers(this.data);
391
+ const keyInfo = extractKeyInfo(publicKey);
392
+
393
+ let sig: Buffer;
394
+ if (typeof signature === 'string') {
395
+ if (signatureEncoding === 'base64') {
396
+ sig = Buffer.from(atob(signature));
397
+ } else if (signatureEncoding === 'hex') {
398
+ sig = Buffer.from(signature.match(/.{2}/g)!.map(byte => parseInt(byte, 16)));
399
+ } else {
400
+ sig = Buffer.from(signature);
401
+ }
402
+ } else {
403
+ sig = signature;
404
+ }
405
+
406
+ return verifySync(this.algorithm, combined, keyInfo, sig);
407
+ }
408
+ }
409
+
410
+ // ============================================================================
411
+ // KeyObject class (for key management)
412
+ // ============================================================================
413
+
414
+ export class KeyObject {
415
+ private _keyData: CryptoKey | Uint8Array;
416
+ private _type: 'public' | 'private' | 'secret';
417
+ private _algorithm?: string;
418
+
419
+ constructor(type: 'public' | 'private' | 'secret', keyData: CryptoKey | Uint8Array, algorithm?: string) {
420
+ this._type = type;
421
+ this._keyData = keyData;
422
+ this._algorithm = algorithm;
423
+ }
424
+
425
+ get type(): string {
426
+ return this._type;
427
+ }
428
+
429
+ get asymmetricKeyType(): string | undefined {
430
+ if (this._type === 'secret') return undefined;
431
+ // Infer from algorithm
432
+ if (this._algorithm?.includes('RSA')) return 'rsa';
433
+ if (this._algorithm?.includes('EC') || this._algorithm?.includes('ES')) return 'ec';
434
+ if (this._algorithm?.includes('Ed')) return 'ed25519';
435
+ return undefined;
436
+ }
437
+
438
+ get symmetricKeySize(): number | undefined {
439
+ if (this._type !== 'secret') return undefined;
440
+ if (this._keyData instanceof Uint8Array) {
441
+ return this._keyData.length * 8;
442
+ }
443
+ return undefined;
444
+ }
445
+
446
+ export(options?: { type?: string; format?: string }): Buffer | string {
447
+ // Simplified export - returns the key data
448
+ if (this._keyData instanceof Uint8Array) {
449
+ return Buffer.from(this._keyData);
450
+ }
451
+ throw new Error('Cannot export CryptoKey synchronously');
452
+ }
453
+ }
454
+
455
+ export function createSecretKey(key: Buffer | string, encoding?: string): KeyObject {
456
+ const keyBuffer = typeof key === 'string'
457
+ ? Buffer.from(key, encoding as BufferEncoding)
458
+ : key;
459
+ return new KeyObject('secret', keyBuffer);
460
+ }
461
+
462
+ export function createPublicKey(key: KeyLike): KeyObject {
463
+ const keyInfo = extractKeyInfo(key);
464
+ return new KeyObject('public', keyInfo.keyData as Uint8Array, keyInfo.algorithm);
465
+ }
466
+
467
+ export function createPrivateKey(key: KeyLike): KeyObject {
468
+ const keyInfo = extractKeyInfo(key);
469
+ return new KeyObject('private', keyInfo.keyData as Uint8Array, keyInfo.algorithm);
470
+ }
471
+
472
+ // ============================================================================
473
+ // Utility functions
474
+ // ============================================================================
475
+
476
+ export function timingSafeEqual(a: Buffer, b: Buffer): boolean {
477
+ if (a.length !== b.length) {
478
+ return false;
479
+ }
480
+ let result = 0;
481
+ for (let i = 0; i < a.length; i++) {
482
+ result |= a[i] ^ b[i];
483
+ }
484
+ return result === 0;
485
+ }
486
+
487
+ export function getCiphers(): string[] {
488
+ return ['aes-128-cbc', 'aes-256-cbc', 'aes-128-gcm', 'aes-256-gcm'];
489
+ }
490
+
491
+ export function getHashes(): string[] {
492
+ return ['sha1', 'sha256', 'sha384', 'sha512'];
493
+ }
494
+
495
+ export const constants = {
496
+ SSL_OP_ALL: 0,
497
+ RSA_PKCS1_PADDING: 1,
498
+ RSA_PKCS1_OAEP_PADDING: 4,
499
+ RSA_PKCS1_PSS_PADDING: 6,
500
+ };
501
+
502
+ // ============================================================================
503
+ // Internal helpers
504
+ // ============================================================================
505
+
506
+ type KeyLike = string | Buffer | KeyObject | { key: string | Buffer; passphrase?: string };
507
+
508
+ interface KeyInfo {
509
+ keyData: Uint8Array | CryptoKey;
510
+ algorithm?: string;
511
+ type: 'public' | 'private' | 'secret';
512
+ format: 'pem' | 'der' | 'jwk' | 'raw';
513
+ }
514
+
515
+ function normalizeHashAlgorithm(alg: string): string {
516
+ const normalized = alg.toUpperCase().replace(/[^A-Z0-9]/g, '');
517
+ switch (normalized) {
518
+ case 'SHA1': return 'SHA-1';
519
+ case 'SHA256': return 'SHA-256';
520
+ case 'SHA384': return 'SHA-384';
521
+ case 'SHA512': return 'SHA-512';
522
+ case 'MD5': return 'MD5'; // Not supported by WebCrypto
523
+ default: return alg;
524
+ }
525
+ }
526
+
527
+ function getWebCryptoAlgorithm(nodeAlgorithm: string): { name: string; hash?: string } {
528
+ const alg = nodeAlgorithm.toUpperCase().replace(/[^A-Z0-9]/g, '');
529
+
530
+ // RSA algorithms
531
+ if (alg.includes('RSA')) {
532
+ if (alg.includes('PSS')) {
533
+ const hash = alg.match(/SHA(\d+)/)?.[0] || 'SHA-256';
534
+ return { name: 'RSA-PSS', hash: `SHA-${hash.replace('SHA', '')}` };
535
+ }
536
+ const hash = alg.match(/SHA(\d+)/)?.[0] || 'SHA-256';
537
+ return { name: 'RSASSA-PKCS1-v1_5', hash: `SHA-${hash.replace('SHA', '')}` };
538
+ }
539
+
540
+ // ECDSA algorithms (ES256, ES384, ES512)
541
+ if (alg.startsWith('ES') || alg.includes('ECDSA')) {
542
+ const bits = alg.match(/\d+/)?.[0] || '256';
543
+ const hash = bits === '512' ? 'SHA-512' : bits === '384' ? 'SHA-384' : 'SHA-256';
544
+ return { name: 'ECDSA', hash };
545
+ }
546
+
547
+ // EdDSA (Ed25519)
548
+ if (alg.includes('ED25519') || alg === 'EDDSA') {
549
+ return { name: 'Ed25519' };
550
+ }
551
+
552
+ // HMAC
553
+ if (alg.includes('HS') || alg.includes('HMAC')) {
554
+ const bits = alg.match(/\d+/)?.[0] || '256';
555
+ return { name: 'HMAC', hash: `SHA-${bits}` };
556
+ }
557
+
558
+ // Default to RSA with SHA-256
559
+ return { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' };
560
+ }
561
+
562
+ function extractKeyInfo(key: KeyLike): KeyInfo {
563
+ if (key instanceof KeyObject) {
564
+ return {
565
+ keyData: (key as any)._keyData,
566
+ algorithm: (key as any)._algorithm,
567
+ type: (key as any)._type,
568
+ format: 'raw',
569
+ };
570
+ }
571
+
572
+ if (typeof key === 'object' && 'key' in key) {
573
+ return extractKeyInfo(key.key);
574
+ }
575
+
576
+ const keyStr = typeof key === 'string' ? key : key.toString();
577
+
578
+ // Detect PEM format
579
+ if (keyStr.includes('-----BEGIN')) {
580
+ const isPrivate = keyStr.includes('PRIVATE');
581
+ const isPublic = keyStr.includes('PUBLIC');
582
+
583
+ // Extract the base64 content
584
+ const base64 = keyStr
585
+ .replace(/-----BEGIN [^-]+-----/, '')
586
+ .replace(/-----END [^-]+-----/, '')
587
+ .replace(/\s/g, '');
588
+
589
+ const keyData = Buffer.from(atob(base64));
590
+
591
+ // Try to detect algorithm from key header
592
+ let algorithm: string | undefined;
593
+ if (keyStr.includes('RSA')) algorithm = 'RSA-SHA256';
594
+ else if (keyStr.includes('EC')) algorithm = 'ES256';
595
+ else if (keyStr.includes('ED25519')) algorithm = 'Ed25519';
596
+
597
+ return {
598
+ keyData,
599
+ algorithm,
600
+ type: isPrivate ? 'private' : isPublic ? 'public' : 'secret',
601
+ format: 'pem',
602
+ };
603
+ }
604
+
605
+ // Raw key data
606
+ const keyData = typeof key === 'string' ? Buffer.from(key) : key;
607
+ return {
608
+ keyData,
609
+ type: 'secret',
610
+ format: 'raw',
611
+ };
612
+ }
613
+
614
+ function concatBuffers(buffers: Uint8Array[]): Uint8Array {
615
+ const totalLength = buffers.reduce((acc, arr) => acc + arr.length, 0);
616
+ const result = new Uint8Array(totalLength);
617
+ let offset = 0;
618
+ for (const buf of buffers) {
619
+ result.set(buf, offset);
620
+ offset += buf.length;
621
+ }
622
+ return result;
623
+ }
624
+
625
+ function encodeResult(data: Uint8Array, encoding?: string): string | Buffer {
626
+ if (encoding === 'hex') {
627
+ return Array.from(data).map(b => b.toString(16).padStart(2, '0')).join('');
628
+ }
629
+ if (encoding === 'base64') {
630
+ return btoa(String.fromCharCode(...data));
631
+ }
632
+ return Buffer.from(data);
633
+ }
634
+
635
+ // Synchronous hash fallback using a simple but consistent algorithm
636
+ function syncHash(data: Uint8Array, algorithm: string): Uint8Array {
637
+ // Use a deterministic hash that produces consistent output
638
+ // This is NOT cryptographically secure but provides consistent behavior
639
+ let size: number;
640
+ if (algorithm.includes('512')) {
641
+ size = 64; // SHA-512 = 64 bytes
642
+ } else if (algorithm.includes('384')) {
643
+ size = 48; // SHA-384 = 48 bytes
644
+ } else if (algorithm.includes('1') || algorithm === 'SHA-1') {
645
+ size = 20; // SHA-1 = 20 bytes
646
+ } else {
647
+ size = 32; // SHA-256 = 32 bytes (default)
648
+ }
649
+ const result = new Uint8Array(size);
650
+
651
+ // Simple but deterministic mixing function
652
+ let h1 = 0xdeadbeef;
653
+ let h2 = 0x41c6ce57;
654
+
655
+ for (let i = 0; i < data.length; i++) {
656
+ h1 = Math.imul(h1 ^ data[i], 2654435761);
657
+ h2 = Math.imul(h2 ^ data[i], 1597334677);
658
+ }
659
+
660
+ h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
661
+ h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
662
+
663
+ // Fill result buffer
664
+ for (let i = 0; i < size; i++) {
665
+ const mix = i < size / 2 ? h1 : h2;
666
+ result[i] = (mix >>> ((i % 4) * 8)) & 0xff;
667
+ h1 = Math.imul(h1, 1103515245) + 12345;
668
+ h2 = Math.imul(h2, 1103515245) + 12345;
669
+ }
670
+
671
+ return result;
672
+ }
673
+
674
+ function syncHmac(data: Uint8Array, key: Uint8Array, algorithm: string): Uint8Array {
675
+ // Combine key and data for HMAC-like behavior
676
+ const combined = new Uint8Array(key.length + data.length);
677
+ combined.set(key, 0);
678
+ combined.set(data, key.length);
679
+ return syncHash(combined, algorithm);
680
+ }
681
+
682
+ // Async implementations using WebCrypto
683
+ async function signAsync(algorithm: string, data: Uint8Array, keyInfo: KeyInfo): Promise<Buffer> {
684
+ const webCryptoAlg = getWebCryptoAlgorithm(algorithm);
685
+
686
+ try {
687
+ // Import the key
688
+ const cryptoKey = await importKey(keyInfo, webCryptoAlg, ['sign']);
689
+
690
+ // Sign the data - convert to ArrayBuffer for WebCrypto compatibility
691
+ const signatureAlg = webCryptoAlg.hash
692
+ ? { name: webCryptoAlg.name, hash: webCryptoAlg.hash }
693
+ : { name: webCryptoAlg.name };
694
+
695
+ const dataBuffer = new Uint8Array(data).buffer as ArrayBuffer;
696
+ const signature = await crypto.subtle.sign(signatureAlg, cryptoKey, dataBuffer);
697
+ return Buffer.from(signature);
698
+ } catch (error) {
699
+ // Fallback to sync implementation
700
+ console.warn('WebCrypto sign failed, using fallback:', error);
701
+ return signSync(algorithm, data, keyInfo);
702
+ }
703
+ }
704
+
705
+ async function verifyAsync(
706
+ algorithm: string,
707
+ data: Uint8Array,
708
+ keyInfo: KeyInfo,
709
+ signature: Uint8Array
710
+ ): Promise<boolean> {
711
+ const webCryptoAlg = getWebCryptoAlgorithm(algorithm);
712
+
713
+ try {
714
+ const cryptoKey = await importKey(keyInfo, webCryptoAlg, ['verify']);
715
+
716
+ const verifyAlg = webCryptoAlg.hash
717
+ ? { name: webCryptoAlg.name, hash: webCryptoAlg.hash }
718
+ : { name: webCryptoAlg.name };
719
+
720
+ // Convert to ArrayBuffer for WebCrypto compatibility
721
+ const sigBuffer = new Uint8Array(signature).buffer as ArrayBuffer;
722
+ const dataBuffer = new Uint8Array(data).buffer as ArrayBuffer;
723
+ return await crypto.subtle.verify(verifyAlg, cryptoKey, sigBuffer, dataBuffer);
724
+ } catch (error) {
725
+ console.warn('WebCrypto verify failed, using fallback:', error);
726
+ return verifySync(algorithm, data, keyInfo, signature);
727
+ }
728
+ }
729
+
730
+ // Synchronous fallback implementations
731
+ function signSync(algorithm: string, data: Uint8Array, keyInfo: KeyInfo): Buffer {
732
+ // Create a deterministic signature based on key and data
733
+ // This is NOT cryptographically secure but allows code to run
734
+ const keyData = keyInfo.keyData instanceof Uint8Array
735
+ ? keyInfo.keyData
736
+ : new Uint8Array(0);
737
+
738
+ const combined = new Uint8Array(keyData.length + data.length);
739
+ combined.set(keyData, 0);
740
+ combined.set(data, keyData.length);
741
+
742
+ const hash = syncHash(combined, algorithm);
743
+ return Buffer.from(hash);
744
+ }
745
+
746
+ function verifySync(
747
+ algorithm: string,
748
+ data: Uint8Array,
749
+ keyInfo: KeyInfo,
750
+ signature: Uint8Array
751
+ ): boolean {
752
+ // For sync verify, we generate the expected signature and compare
753
+ const expectedSig = signSync(algorithm, data, keyInfo);
754
+ return timingSafeEqual(Buffer.from(signature), expectedSig);
755
+ }
756
+
757
+ async function importKey(
758
+ keyInfo: KeyInfo,
759
+ algorithm: { name: string; hash?: string },
760
+ usages: KeyUsage[]
761
+ ): Promise<CryptoKey> {
762
+ if (keyInfo.keyData instanceof CryptoKey) {
763
+ return keyInfo.keyData;
764
+ }
765
+
766
+ const keyData = keyInfo.keyData;
767
+ // Convert Uint8Array to ArrayBuffer for WebCrypto compatibility
768
+ const keyBuffer = new Uint8Array(keyData).buffer as ArrayBuffer;
769
+
770
+ // Determine import format
771
+ if (keyInfo.format === 'pem') {
772
+ // For PEM, we need to use SPKI (public) or PKCS8 (private)
773
+ const format = keyInfo.type === 'private' ? 'pkcs8' : 'spki';
774
+
775
+ const importAlg: RsaHashedImportParams | EcKeyImportParams | Algorithm =
776
+ algorithm.name === 'ECDSA'
777
+ ? { name: 'ECDSA', namedCurve: 'P-256' }
778
+ : algorithm.name === 'Ed25519'
779
+ ? { name: 'Ed25519' }
780
+ : { name: algorithm.name, hash: algorithm.hash || 'SHA-256' };
781
+
782
+ return await crypto.subtle.importKey(
783
+ format,
784
+ keyBuffer,
785
+ importAlg,
786
+ true,
787
+ usages
788
+ );
789
+ }
790
+
791
+ // For raw/secret keys, use raw import
792
+ if (keyInfo.type === 'secret') {
793
+ return await crypto.subtle.importKey(
794
+ 'raw',
795
+ keyBuffer,
796
+ { name: algorithm.name, hash: algorithm.hash },
797
+ true,
798
+ usages
799
+ );
800
+ }
801
+
802
+ throw new Error(`Unsupported key format: ${keyInfo.format}`);
803
+ }
804
+
805
+ // ============================================================================
806
+ // Exports
807
+ // ============================================================================
808
+
809
+ export default {
810
+ randomBytes,
811
+ randomUUID,
812
+ randomInt,
813
+ getRandomValues,
814
+ createHash,
815
+ createHmac,
816
+ createSign,
817
+ createVerify,
818
+ sign,
819
+ verify,
820
+ pbkdf2,
821
+ pbkdf2Sync,
822
+ timingSafeEqual,
823
+ getCiphers,
824
+ getHashes,
825
+ constants,
826
+ KeyObject,
827
+ createSecretKey,
828
+ createPublicKey,
829
+ createPrivateKey,
830
+ };