farion1231/cc-switch · critical · Error
crypto API not available - please update your operating…
Error message
crypto API not available - please update your operating system
What it means
generateUUID prefers crypto.randomUUID() and falls back to a manual v4 built on crypto.getRandomValues; the throw fires only when the Web Crypto API is missing entirely (neither method exists on globalThis.crypto). Browsers expose crypto only in secure contexts, and Node only globals it from v19 — so this is an environment problem, not a logic problem, and it breaks every call site that creates IDs.
Solutions
- Run tests on Node >= 19, or polyfill in test setup: globalThis.crypto = require('node:crypto').webcrypto
- Serve the app from https:// or localhost so the browser/WebView marks the context secure
- Provide any getRandomValues polyfill on the host before app code runs
Example fix
// before (Node < 19 test run)
const id = generateUUID(); // throws 'crypto API not available...'
// after (vitest.setup.ts)
import { webcrypto } from 'node:crypto';
if (!globalThis.crypto?.getRandomValues) {
Object.defineProperty(globalThis, 'crypto', { value: webcrypto });
}
const id = generateUUID(); Defensive patterns
Strategy: fallback
Validate before calling
const hasWebCrypto =
typeof globalThis.crypto?.randomUUID === 'function' ||
typeof globalThis.crypto?.getRandomValues === 'function';
if (!hasWebCrypto) {
// provision a polyfill before any generateUUID call site runs
} Try / catch
try {
const id = generateUUID();
} catch (error) {
if (error instanceof Error && error.message.includes('crypto API not available')) {
// environment misconfiguration: fix the host (secure context / polyfill), do not swallow
throw error;
}
throw error;
} Prevention
- Run tests on Node >= 19 or set up a crypto polyfill in test setup files
- Serve the web app from localhost or https so the context is secure
- Add a startup feature check for globalThis.crypto with a clear environmental message
When it happens
Trigger: Running the app or its unit tests in an insecure context (plain http:// over LAN, not localhost), an old WebView, or Node < 19 / a jsdom environment without a crypto polyfill, then invoking any code path that calls generateUUID (provider/model creation).
Common situations: Vitest/jsdom suites failing inside generateUUID; accessing the dev server via LAN IP over http; embedding the web build in an outdated shell.
AI-assisted analysis of farion1231/cc-switch@0b5da51016 (2026-08-20).
Data as JSON: /api/errors/a6a5ce85fefc791c.
Report an issue: GitHub.
Appendix: source
Thrown at src/utils/uuid.ts:20
* 生成 UUID v4
*
* 优先使用 crypto.randomUUID(),不可用时使用 crypto.getRandomValues() 实现
*
* 兼容性:
* - crypto.randomUUID(): Chrome 92+, Safari 15.4+, Firefox 95+
* - crypto.getRandomValues(): Chrome 11+, Safari 5+, Firefox 21+
*/
export function generateUUID(): string {
const cryptoApi = globalThis.crypto;
// 优先使用原生 API
if (typeof cryptoApi?.randomUUID === "function") {
return cryptoApi.randomUUID();
}
// Fallback: 使用 crypto.getRandomValues 实现 UUID v4
if (!cryptoApi?.getRandomValues) {
throw new Error(
"crypto API not available - please update your operating system",
);
}
const bytes = new Uint8Array(16);
cryptoApi.getRandomValues(bytes);
// 设置版本 (4) 和变体 (RFC 4122)
bytes[6] = (bytes[6] & 0x0f) | 0x40;
bytes[8] = (bytes[8] & 0x3f) | 0x80;
const hex = Array.from(bytes)
.map((b) => b.toString(16).padStart(2, "0"))
.join("");
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
}
View on GitHub (pinned to 0b5da51016)