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

  1. Run tests on Node >= 19, or polyfill in test setup: globalThis.crypto = require('node:crypto').webcrypto
  2. Serve the app from https:// or localhost so the browser/WebView marks the context secure
  3. 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

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)