@zeke-02/tinfoil 0.0.11 → 0.11.7

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 (105) hide show
  1. package/dist/ai-sdk-provider.browser.d.ts +12 -0
  2. package/dist/ai-sdk-provider.browser.d.ts.map +1 -0
  3. package/dist/{esm/ai-sdk-provider.mjs → ai-sdk-provider.browser.js} +9 -5
  4. package/dist/ai-sdk-provider.browser.js.map +1 -0
  5. package/dist/ai-sdk-provider.d.ts +6 -1
  6. package/dist/ai-sdk-provider.d.ts.map +1 -0
  7. package/dist/ai-sdk-provider.js +12 -11
  8. package/dist/ai-sdk-provider.js.map +1 -0
  9. package/dist/config.d.ts +2 -1
  10. package/dist/config.d.ts.map +1 -0
  11. package/dist/config.js +3 -5
  12. package/dist/config.js.map +1 -0
  13. package/dist/encrypted-body-fetch.d.ts +8 -2
  14. package/dist/encrypted-body-fetch.d.ts.map +1 -0
  15. package/dist/encrypted-body-fetch.js +27 -26
  16. package/dist/encrypted-body-fetch.js.map +1 -0
  17. package/dist/env.d.ts +1 -0
  18. package/dist/env.d.ts.map +1 -0
  19. package/dist/env.js +2 -4
  20. package/dist/env.js.map +1 -0
  21. package/dist/index.browser.d.ts +8 -7
  22. package/dist/index.browser.d.ts.map +1 -0
  23. package/dist/index.browser.js +8 -28
  24. package/dist/index.browser.js.map +1 -0
  25. package/dist/index.d.ts +9 -8
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +10 -47
  28. package/dist/index.js.map +1 -0
  29. package/dist/pinned-tls-fetch.d.ts +1 -0
  30. package/dist/pinned-tls-fetch.d.ts.map +1 -0
  31. package/dist/pinned-tls-fetch.js +13 -17
  32. package/dist/pinned-tls-fetch.js.map +1 -0
  33. package/dist/router.d.ts +1 -0
  34. package/dist/router.d.ts.map +1 -0
  35. package/dist/router.js +6 -7
  36. package/dist/router.js.map +1 -0
  37. package/dist/{esm/secure-client.d.ts → secure-client.browser.d.ts} +2 -1
  38. package/dist/secure-client.browser.d.ts.map +1 -0
  39. package/dist/{esm/secure-client.mjs → secure-client.browser.js} +46 -56
  40. package/dist/secure-client.browser.js.map +1 -0
  41. package/dist/secure-client.d.ts +2 -1
  42. package/dist/secure-client.d.ts.map +1 -0
  43. package/dist/secure-client.js +51 -65
  44. package/dist/secure-client.js.map +1 -0
  45. package/dist/secure-fetch.browser.d.ts +1 -0
  46. package/dist/secure-fetch.browser.d.ts.map +1 -0
  47. package/dist/secure-fetch.browser.js +4 -6
  48. package/dist/secure-fetch.browser.js.map +1 -0
  49. package/dist/secure-fetch.d.ts +1 -0
  50. package/dist/secure-fetch.d.ts.map +1 -0
  51. package/dist/secure-fetch.js +16 -8
  52. package/dist/secure-fetch.js.map +1 -0
  53. package/dist/{tinfoilai.d.ts → tinfoil-ai.browser.d.ts} +5 -2
  54. package/dist/tinfoil-ai.browser.d.ts.map +1 -0
  55. package/dist/{tinfoilai.js → tinfoil-ai.browser.js} +50 -39
  56. package/dist/tinfoil-ai.browser.js.map +1 -0
  57. package/dist/{esm/tinfoilai.d.ts → tinfoil-ai.d.ts} +5 -2
  58. package/dist/tinfoil-ai.d.ts.map +1 -0
  59. package/dist/{esm/tinfoilai.mjs → tinfoil-ai.js} +29 -11
  60. package/dist/tinfoil-ai.js.map +1 -0
  61. package/dist/unverified-client.d.ts +1 -2
  62. package/dist/unverified-client.d.ts.map +1 -0
  63. package/dist/unverified-client.js +10 -13
  64. package/dist/unverified-client.js.map +1 -0
  65. package/dist/verifier.d.ts +2 -141
  66. package/dist/verifier.d.ts.map +1 -0
  67. package/dist/verifier.js +2 -570
  68. package/dist/verifier.js.map +1 -0
  69. package/package.json +48 -41
  70. package/LICENSE +0 -661
  71. package/README.md +0 -183
  72. package/dist/__tests__/test-utils.d.ts +0 -1
  73. package/dist/__tests__/test-utils.js +0 -44
  74. package/dist/esm/__tests__/test-utils.d.ts +0 -1
  75. package/dist/esm/__tests__/test-utils.mjs +0 -38
  76. package/dist/esm/ai-sdk-provider.d.ts +0 -7
  77. package/dist/esm/config.d.ts +0 -13
  78. package/dist/esm/config.mjs +0 -13
  79. package/dist/esm/encrypted-body-fetch.d.ts +0 -13
  80. package/dist/esm/encrypted-body-fetch.mjs +0 -105
  81. package/dist/esm/env.d.ts +0 -5
  82. package/dist/esm/env.mjs +0 -17
  83. package/dist/esm/fetch-adapter.d.ts +0 -21
  84. package/dist/esm/fetch-adapter.mjs +0 -23
  85. package/dist/esm/index.browser.d.ts +0 -7
  86. package/dist/esm/index.browser.mjs +0 -8
  87. package/dist/esm/index.d.ts +0 -9
  88. package/dist/esm/index.mjs +0 -13
  89. package/dist/esm/pinned-tls-fetch.d.ts +0 -1
  90. package/dist/esm/pinned-tls-fetch.mjs +0 -110
  91. package/dist/esm/router.d.ts +0 -11
  92. package/dist/esm/router.mjs +0 -33
  93. package/dist/esm/secure-fetch.browser.d.ts +0 -1
  94. package/dist/esm/secure-fetch.browser.mjs +0 -10
  95. package/dist/esm/secure-fetch.d.ts +0 -1
  96. package/dist/esm/secure-fetch.mjs +0 -12
  97. package/dist/esm/unverified-client.d.ts +0 -18
  98. package/dist/esm/unverified-client.mjs +0 -61
  99. package/dist/esm/verifier.d.ts +0 -141
  100. package/dist/esm/verifier.mjs +0 -532
  101. package/dist/esm/wasm-exec.js +0 -668
  102. package/dist/esm/wasm-exec.mjs +0 -668
  103. package/dist/fetch-adapter.d.ts +0 -21
  104. package/dist/fetch-adapter.js +0 -27
  105. package/dist/wasm-exec.js +0 -668
@@ -1,532 +0,0 @@
1
- /**
2
- * VERIFIER COMPONENT OVERVIEW
3
- * ==========================
4
- *
5
- * This implementation performs end-to-end enclave and code verification entirely on the
6
- * client using a Go WebAssembly module, and exposes a small TypeScript API around it.
7
- *
8
- * UNIFIED VERIFICATION FLOW
9
- * The primary API is `verify()`, which invokes the Go WASM `verify(enclaveHost, repo)`
10
- * function that performs all verification steps atomically:
11
- *
12
- * 1) DIGEST FETCH
13
- * - Fetches the latest release digest from GitHub
14
- * - Uses Tinfoil GitHub proxy (https://api-github-proxy.tinfoil.sh) to avoid rate limits
15
- *
16
- * 2) CODE INTEGRITY (Release Verification)
17
- * - Verifies code provenance using Sigstore/Rekor for GitHub Actions builds
18
- * - Returns the expected code measurement for the release
19
- *
20
- * 3) REMOTE ATTESTATION (Enclave Verification)
21
- * - Performs runtime attestation against the target enclave hostname
22
- * - Verifies vendor certificate chains inside WASM (AMD SEV-SNP / Intel TDX)
23
- * - Returns the enclave's runtime measurement and cryptographic keys (TLS fingerprint and HPKE)
24
- *
25
- * 4) HARDWARE VERIFICATION (for TDX platforms)
26
- * - Fetches and verifies TDX platform measurements if required
27
- * - Validates hardware attestation against expected measurements
28
- *
29
- * 5) CODE CONSISTENCY (Measurement Comparison)
30
- * - Compares the runtime measurement with the expected code measurement
31
- * - Uses platform-aware comparison rules for different TEE types
32
- *
33
- * ERROR HANDLING
34
- * When verification fails, errors are prefixed with the failing step:
35
- * - `fetchDigest:` - Failed to fetch GitHub release digest
36
- * - `verifyCode:` - Failed to verify code provenance
37
- * - `verifyEnclave:` - Failed runtime attestation
38
- * - `verifyHardware:` - Failed TDX hardware verification
39
- * - `validateTLS:` - TLS public key validation failed
40
- * - `measurements:` - Measurement comparison failed
41
- *
42
- * RUNTIME AND DELIVERY
43
- * - All verification executes locally via WebAssembly (Go → WASM)
44
- * - WASM loader: `wasm-exec.js`
45
- * - WASM module URL: https://tinfoilsh.github.io/verifier/tinfoil-verifier.wasm
46
- * - Works in Node 20+ and modern browsers with lightweight polyfills for
47
- * `performance`, `TextEncoder`/`TextDecoder`, and `crypto.getRandomValues`
48
- * - Go stdout/stderr is suppressed by default; toggle via `suppressWasmLogs()`
49
- *
50
- * PROXIES AND TRUST
51
- * - GitHub proxy is used only to avoid rate limits; the WASM logic independently
52
- * validates release provenance via Sigstore transparency logs
53
- * - AMD KDS access may be proxied within the WASM for availability; AMD roots are
54
- * embedded and the full chain is verified in Go to prevent forgery
55
- *
56
- * SUPPORTED PLATFORMS
57
- * - AMD SEV-SNP
58
- * - Intel TDX (with hardware platform verification)
59
- * - Predicate types: SNP/TDX multi-platform v1, TDX guest v1/v2, SEV-SNP guest v1
60
- *
61
- * PUBLIC API (this module)
62
- * - `new Verifier({ serverURL, configRepo? })`
63
- * - `verify()` → Promise<AttestationResponse> - full end-to-end verification returning cryptographic keys and measurement
64
- * - `getVerificationDocument()` → VerificationDocument | undefined - detailed step-by-step verification results
65
- * - `suppressWasmLogs(suppress?)` → void - control WASM log output
66
- */
67
- import { TINFOIL_CONFIG } from "./config.mjs";
68
- import { getFetch } from "./fetch-adapter.mjs";
69
- let cachedTextEncoder = null;
70
- function getTextEncoder() {
71
- if (!cachedTextEncoder) {
72
- if (typeof globalThis.TextEncoder !== "function") {
73
- throw new Error("TextEncoder is not available in this environment");
74
- }
75
- cachedTextEncoder = globalThis.TextEncoder;
76
- }
77
- return cachedTextEncoder;
78
- }
79
- let cachedTextDecoder = null;
80
- function getTextDecoder() {
81
- if (!cachedTextDecoder) {
82
- if (typeof globalThis.TextDecoder !== "function") {
83
- throw new Error("TextDecoder is not available in this environment");
84
- }
85
- cachedTextDecoder = globalThis.TextDecoder;
86
- }
87
- return cachedTextDecoder;
88
- }
89
- const nodeRequire = createNodeRequire();
90
- let wasmExecLoader = null;
91
- /**
92
- * Verifier performs attestation verification for Tinfoil enclaves
93
- *
94
- * The verifier loads a WebAssembly module (compiled from Go) that performs
95
- * end-to-end attestation verification:
96
- * 1. Fetches the latest code release digest from GitHub
97
- * 2. Verifies code provenance using Sigstore/Rekor
98
- * 3. Performs runtime attestation against the enclave
99
- * 4. Verifies hardware measurements (for TDX platforms)
100
- * 5. Compares code and runtime measurements using platform-specific logic
101
- *
102
- * Primary method: verify() - Returns AttestationResponse with cryptographic keys
103
- * Verification details: getVerificationDocument() - Returns step-by-step results
104
- */
105
- export class Verifier {
106
- constructor(options) {
107
- if (!options?.serverURL) {
108
- throw new Error("serverURL is required for Verifier");
109
- }
110
- this.serverURL = new URL(options.serverURL).hostname;
111
- this.configRepo =
112
- options?.configRepo ?? TINFOIL_CONFIG.INFERENCE_PROXY_REPO;
113
- }
114
- /**
115
- * Execute a function with a fresh WASM instance that auto-cleans up
116
- * This ensures Go runtime doesn't keep the process alive
117
- */
118
- static async executeWithWasm(fn) {
119
- await initializeWasmGlobals();
120
- const goInstance = new globalThis.Go();
121
- // Load WASM module
122
- const fetchFn = getFetch();
123
- const wasmResponse = await fetchFn(Verifier.defaultWasmUrl);
124
- if (!wasmResponse.ok) {
125
- throw new Error(`Failed to fetch WASM: ${wasmResponse.status} ${wasmResponse.statusText}`);
126
- }
127
- const wasmBuffer = await wasmResponse.arrayBuffer();
128
- const result = await WebAssembly.instantiate(wasmBuffer, goInstance.importObject);
129
- // Start the Go instance in the background
130
- // We don't await this - it runs continuously
131
- goInstance.run(result.instance);
132
- // Wait for WASM functions to be available
133
- await new Promise((resolve) => setTimeout(resolve, 100));
134
- if (typeof globalThis.verifyCode === "undefined" ||
135
- typeof globalThis.verifyEnclave === "undefined") {
136
- await new Promise((resolve) => setTimeout(resolve, 500));
137
- }
138
- // Apply log suppression if requested
139
- if (Verifier.wasmLogsSuppressed && globalThis.fs?.writeSync) {
140
- const fsObj = globalThis.fs;
141
- if (!Verifier.originalFsWriteSync) {
142
- Verifier.originalFsWriteSync = fsObj.writeSync.bind(fsObj);
143
- }
144
- fsObj.writeSync = function (_fd, buf) {
145
- return buf.length;
146
- };
147
- }
148
- try {
149
- // Execute the user's function
150
- const result = await fn();
151
- return result;
152
- }
153
- finally {
154
- // Clean up the Go instance
155
- if (goInstance._scheduledTimeouts instanceof Map) {
156
- for (const timeoutId of goInstance._scheduledTimeouts.values()) {
157
- clearTimeout(timeoutId);
158
- }
159
- goInstance._scheduledTimeouts.clear();
160
- }
161
- if (typeof goInstance.exit === "function") {
162
- try {
163
- goInstance.exit(0);
164
- }
165
- catch (e) {
166
- // Ignore exit errors
167
- }
168
- }
169
- }
170
- }
171
- /**
172
- * Perform end-to-end attestation verification
173
- *
174
- * This method performs all verification steps atomically via the Go WASM verify() function:
175
- * 1. Fetches the latest code digest from GitHub releases
176
- * 2. Verifies code provenance using Sigstore/Rekor
177
- * 3. Performs runtime attestation against the enclave
178
- * 4. Verifies hardware measurements (for TDX platforms)
179
- * 5. Compares code and runtime measurements using platform-specific logic
180
- *
181
- * The WASM runtime is automatically initialized and cleaned up within this method.
182
- * A detailed verification document is saved and can be accessed via getVerificationDocument().
183
- *
184
- * @returns AttestationResponse containing cryptographic keys (TLS/HPKE) and enclave measurement
185
- * @throws Error if measurements don't match or verification fails at any step
186
- */
187
- async verify() {
188
- return Verifier.executeWithWasm(async () => {
189
- return this.verifyInternal();
190
- });
191
- }
192
- /**
193
- * Save a failed verification document
194
- */
195
- saveFailedVerificationDocument(steps) {
196
- this.lastVerificationDocument = {
197
- configRepo: this.configRepo,
198
- enclaveHost: this.serverURL,
199
- releaseDigest: "",
200
- codeMeasurement: { type: "", registers: [] },
201
- enclaveMeasurement: { measurement: { type: "", registers: [] } },
202
- tlsPublicKey: "",
203
- hpkePublicKey: "",
204
- hardwareMeasurement: undefined,
205
- codeFingerprint: "",
206
- enclaveFingerprint: "",
207
- selectedRouterEndpoint: this.serverURL,
208
- securityVerified: false,
209
- steps,
210
- };
211
- }
212
- /**
213
- * Internal verification logic that runs within WASM context
214
- */
215
- async verifyInternal() {
216
- const steps = {
217
- fetchDigest: { status: "pending" },
218
- verifyCode: { status: "pending" },
219
- verifyEnclave: { status: "pending" },
220
- compareMeasurements: { status: "pending" },
221
- };
222
- if (typeof globalThis.verify !== "function") {
223
- steps.fetchDigest = {
224
- status: "failed",
225
- error: "WASM verify function not available",
226
- };
227
- this.saveFailedVerificationDocument(steps);
228
- throw new Error("WASM verify function not available");
229
- }
230
- let groundTruth;
231
- try {
232
- const groundTruthJSON = await globalThis.verify(this.serverURL, this.configRepo);
233
- groundTruth = JSON.parse(groundTruthJSON);
234
- // Mark all steps as successful since WASM verify() succeeded
235
- steps.fetchDigest = { status: "success" };
236
- steps.verifyCode = { status: "success" };
237
- steps.verifyEnclave = { status: "success" };
238
- steps.compareMeasurements = { status: "success" };
239
- }
240
- catch (error) {
241
- const errorMessage = error instanceof Error ? error.message : String(error);
242
- if (errorMessage.startsWith("fetchDigest:")) {
243
- steps.fetchDigest = { status: "failed", error: errorMessage };
244
- }
245
- else if (errorMessage.startsWith("verifyCode:")) {
246
- steps.fetchDigest = { status: "success" };
247
- steps.verifyCode = { status: "failed", error: errorMessage };
248
- }
249
- else if (errorMessage.startsWith("verifyEnclave:")) {
250
- steps.fetchDigest = { status: "success" };
251
- steps.verifyCode = { status: "success" };
252
- steps.verifyEnclave = { status: "failed", error: errorMessage };
253
- }
254
- else if (errorMessage.startsWith("measurements:")) {
255
- steps.fetchDigest = { status: "success" };
256
- steps.verifyCode = { status: "success" };
257
- steps.verifyEnclave = { status: "success" };
258
- steps.compareMeasurements = { status: "failed", error: errorMessage };
259
- }
260
- else if (errorMessage.startsWith("verifyHardware:") ||
261
- errorMessage.startsWith("validateTLS:")) {
262
- steps.fetchDigest = { status: "success" };
263
- steps.verifyCode = { status: "success" };
264
- steps.verifyEnclave = { status: "success" };
265
- steps.otherError = { status: "failed", error: errorMessage };
266
- }
267
- else {
268
- steps.otherError = { status: "failed", error: errorMessage };
269
- }
270
- this.saveFailedVerificationDocument(steps);
271
- throw error;
272
- }
273
- const attestation = {
274
- tlsPublicKeyFingerprint: groundTruth.tls_public_key,
275
- hpkePublicKey: groundTruth.hpke_public_key,
276
- measurement: groundTruth.enclave_measurement,
277
- };
278
- this.lastVerificationDocument = {
279
- configRepo: this.configRepo,
280
- enclaveHost: this.serverURL,
281
- releaseDigest: groundTruth.digest,
282
- codeMeasurement: groundTruth.code_measurement,
283
- enclaveMeasurement: attestation,
284
- tlsPublicKey: groundTruth.tls_public_key,
285
- hpkePublicKey: groundTruth.hpke_public_key,
286
- hardwareMeasurement: groundTruth.hardware_measurement,
287
- codeFingerprint: groundTruth.code_fingerprint,
288
- enclaveFingerprint: groundTruth.enclave_fingerprint,
289
- selectedRouterEndpoint: this.serverURL,
290
- securityVerified: true,
291
- steps,
292
- };
293
- return attestation;
294
- }
295
- /**
296
- * Returns the verification document from the last verify() call
297
- *
298
- * The document contains detailed step-by-step verification results including:
299
- * - Step status (pending/success/failed) for each verification phase
300
- * - Measurements, fingerprints, and cryptographic keys
301
- * - Error messages for any failed steps
302
- *
303
- * Available even if verification failed, allowing inspection of which step failed.
304
- *
305
- * @returns VerificationDocument with complete verification details, or undefined if verify() hasn't been called
306
- */
307
- getVerificationDocument() {
308
- return this.lastVerificationDocument;
309
- }
310
- }
311
- Verifier.goInstance = null;
312
- Verifier.initializationPromise = null;
313
- Verifier.defaultWasmUrl = "https://tinfoilsh.github.io/verifier/tinfoil-verifier.wasm";
314
- Verifier.originalFsWriteSync = null;
315
- Verifier.wasmLogsSuppressed = true;
316
- Verifier.globalsInitialized = false;
317
- // Start initialization as soon as the module loads
318
- function shouldAutoInitializeWasm() {
319
- const globalAny = globalThis;
320
- const env = globalAny.process?.env;
321
- const autoInitFlag = env?.TINFOIL_SKIP_WASM_AUTO_INIT ?? env?.TINFOIL_DISABLE_WASM_AUTO_INIT;
322
- if (typeof autoInitFlag === "string") {
323
- const normalized = autoInitFlag.toLowerCase();
324
- if (normalized === "1" || normalized === "true") {
325
- return false;
326
- }
327
- }
328
- if (env?.NODE_ENV === "test") {
329
- return false;
330
- }
331
- const isNode = typeof globalAny.process?.versions?.node === "string";
332
- if (isNode) {
333
- return false;
334
- }
335
- const hasBrowserGlobals = typeof globalAny.window === "object" &&
336
- typeof globalAny.document === "object";
337
- return hasBrowserGlobals;
338
- }
339
- /**
340
- * Control WASM log output
341
- *
342
- * The Go WASM runtime outputs logs (stdout/stderr) through a polyfilled fs.writeSync.
343
- * This function allows suppressing those logs without affecting other console output.
344
- * By default, WASM logs are suppressed to reduce noise.
345
- *
346
- * @param suppress - Whether to suppress WASM logs (default: true)
347
- * @returns void
348
- */
349
- export function suppressWasmLogs(suppress = true) {
350
- globalThis.__tinfoilSuppressWasmLogs = suppress;
351
- Verifier.wasmLogsSuppressed = suppress;
352
- const fsObj = globalThis.fs;
353
- if (!fsObj || typeof fsObj.writeSync !== "function")
354
- return;
355
- if (suppress) {
356
- if (!Verifier.originalFsWriteSync) {
357
- Verifier.originalFsWriteSync = fsObj.writeSync.bind(fsObj);
358
- }
359
- fsObj.writeSync = function (_fd, buf) {
360
- return buf.length;
361
- };
362
- }
363
- else if (Verifier.originalFsWriteSync) {
364
- fsObj.writeSync = Verifier.originalFsWriteSync;
365
- }
366
- }
367
- /**
368
- * Initialize globals needed for Go WASM runtime
369
- * This function sets up browser-like globals that the Go WASM runtime expects
370
- */
371
- async function initializeWasmGlobals() {
372
- // Only initialize once
373
- if (Verifier.globalsInitialized) {
374
- return;
375
- }
376
- const root = globalThis;
377
- // Performance API (Go runtime expects a few methods to exist)
378
- if (!root.performance) {
379
- root.performance = {
380
- now: () => Date.now(),
381
- markResourceTiming: () => { },
382
- mark: () => { },
383
- measure: () => { },
384
- clearMarks: () => { },
385
- clearMeasures: () => { },
386
- getEntriesByName: () => [],
387
- getEntriesByType: () => [],
388
- getEntries: () => [],
389
- };
390
- }
391
- else {
392
- root.performance.now = root.performance.now ?? (() => Date.now());
393
- root.performance.markResourceTiming =
394
- root.performance.markResourceTiming ?? (() => { });
395
- root.performance.mark = root.performance.mark ?? (() => { });
396
- root.performance.measure = root.performance.measure ?? (() => { });
397
- root.performance.clearMarks = root.performance.clearMarks ?? (() => { });
398
- root.performance.clearMeasures =
399
- root.performance.clearMeasures ?? (() => { });
400
- root.performance.getEntriesByName =
401
- root.performance.getEntriesByName ?? (() => []);
402
- root.performance.getEntriesByType =
403
- root.performance.getEntriesByType ?? (() => []);
404
- root.performance.getEntries = root.performance.getEntries ?? (() => []);
405
- }
406
- // Text encoding
407
- if (!root.TextEncoder) {
408
- root.TextEncoder = getTextEncoder();
409
- }
410
- if (!root.TextDecoder) {
411
- root.TextDecoder = getTextDecoder();
412
- }
413
- // Crypto API (needed by Go WASM)
414
- ensureCrypto(root);
415
- // Default: suppress WASM (Go) stdout/stderr logs unless explicitly enabled by caller
416
- if (typeof root.__tinfoilSuppressWasmLogs === "undefined") {
417
- root.__tinfoilSuppressWasmLogs = true;
418
- }
419
- // Force process to stay running (prevent Go from exiting Node process)
420
- // This is a common issue with Go WASM in Node - it calls process.exit()
421
- if (root.process &&
422
- typeof root.process.exit === "function" &&
423
- !root.__tinfoilProcessExitPatched) {
424
- root.__tinfoilProcessExitPatched = true;
425
- const originalExit = root.process.exit.bind(root.process);
426
- root.__tinfoilOriginalProcessExit = originalExit;
427
- // Replace process.exit to prevent the Go WASM runtime from terminating the Node.js process.
428
- // When wasm log suppression is enabled, suppress the informational log about the ignored exit
429
- // so callers can silence only the WASM-related noise while keeping application logs intact.
430
- root.process.exit = ((code) => {
431
- if (!root.__tinfoilSuppressWasmLogs) {
432
- console.log(`Process exit called with code ${code} - ignoring to keep runtime alive`);
433
- }
434
- return undefined;
435
- });
436
- }
437
- await loadWasmExec();
438
- Verifier.globalsInitialized = true;
439
- }
440
- function ensureCrypto(root) {
441
- const hasWorkingGetRandomValues = root.crypto && typeof root.crypto.getRandomValues === "function"
442
- ? root.crypto
443
- : resolveWindowCrypto(root);
444
- if (hasWorkingGetRandomValues) {
445
- if (!root.crypto) {
446
- root.crypto = hasWorkingGetRandomValues;
447
- }
448
- return;
449
- }
450
- const nodeRandomBytes = resolveNodeRandomBytes();
451
- if (!nodeRandomBytes) {
452
- throw new Error("crypto.getRandomValues is not available in this environment");
453
- }
454
- const fallbackCrypto = {
455
- getRandomValues: (buffer) => {
456
- const bytes = nodeRandomBytes(buffer.length);
457
- buffer.set(bytes);
458
- return buffer;
459
- },
460
- };
461
- try {
462
- root.crypto = fallbackCrypto;
463
- }
464
- catch {
465
- Object.defineProperty(root, "crypto", {
466
- configurable: true,
467
- enumerable: false,
468
- value: fallbackCrypto,
469
- writable: false,
470
- });
471
- }
472
- }
473
- function resolveWindowCrypto(root) {
474
- const maybeWindow = root.window ?? (typeof window !== "undefined" ? window : undefined);
475
- if (maybeWindow?.crypto &&
476
- typeof maybeWindow.crypto.getRandomValues === "function") {
477
- return maybeWindow.crypto;
478
- }
479
- return undefined;
480
- }
481
- function resolveNodeRandomBytes() {
482
- if (!nodeRequire) {
483
- return undefined;
484
- }
485
- try {
486
- const cryptoModule = nodeRequire("crypto");
487
- const randomBytes = typeof cryptoModule?.randomBytes === "function"
488
- ? cryptoModule.randomBytes
489
- : undefined;
490
- if (randomBytes) {
491
- return (size) => {
492
- const result = randomBytes(size);
493
- return result instanceof Uint8Array ? result : new Uint8Array(result);
494
- };
495
- }
496
- }
497
- catch {
498
- return undefined;
499
- }
500
- return undefined;
501
- }
502
- function loadWasmExec() {
503
- if (!wasmExecLoader) {
504
- wasmExecLoader = (async () => {
505
- // Prefer a dynamic import so bundlers (Next/Webpack/Vite) include the file.
506
- // If that fails (e.g., pure Node without bundler), fall back to require.
507
- try {
508
- // @ts-expect-error: Local JS helper has no TS types; ambient module declared in wasm-exec.d.ts
509
- await import("./wasm-exec.mjs");
510
- }
511
- catch {
512
- if (nodeRequire) {
513
- nodeRequire("./wasm-exec.js");
514
- return;
515
- }
516
- throw new Error("Failed to load wasm-exec.js via dynamic import, and require() is unavailable");
517
- }
518
- })();
519
- wasmExecLoader.catch(() => {
520
- wasmExecLoader = null;
521
- });
522
- }
523
- return wasmExecLoader;
524
- }
525
- function createNodeRequire() {
526
- try {
527
- return typeof require === "function" ? require : undefined;
528
- }
529
- catch {
530
- return undefined;
531
- }
532
- }