{"record":{"id":"a6a5ce85fefc791c","repo":"farion1231/cc-switch","slug":"crypto-api-not-available-please-update-your-oper","errorCode":null,"errorMessage":"crypto API not available - please update your operating system","messagePattern":"crypto API not available - please update your operating system","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"src/utils/uuid.ts","lineNumber":20,"sourceCode":" * 生成 UUID v4\n *\n * 优先使用 crypto.randomUUID()，不可用时使用 crypto.getRandomValues() 实现\n *\n * 兼容性：\n * - crypto.randomUUID(): Chrome 92+, Safari 15.4+, Firefox 95+\n * - crypto.getRandomValues(): Chrome 11+, Safari 5+, Firefox 21+\n */\nexport function generateUUID(): string {\n  const cryptoApi = globalThis.crypto;\n\n  // 优先使用原生 API\n  if (typeof cryptoApi?.randomUUID === \"function\") {\n    return cryptoApi.randomUUID();\n  }\n\n  // Fallback: 使用 crypto.getRandomValues 实现 UUID v4\n  if (!cryptoApi?.getRandomValues) {\n    throw new Error(\n      \"crypto API not available - please update your operating system\",\n    );\n  }\n\n  const bytes = new Uint8Array(16);\n  cryptoApi.getRandomValues(bytes);\n\n  // 设置版本 (4) 和变体 (RFC 4122)\n  bytes[6] = (bytes[6] & 0x0f) | 0x40;\n  bytes[8] = (bytes[8] & 0x3f) | 0x80;\n\n  const hex = Array.from(bytes)\n    .map((b) => b.toString(16).padStart(2, \"0\"))\n    .join(\"\");\n\n  return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/farion1231/cc-switch/blob/a2e22f330273a5b6ffa87cb8b82b624601bac562/src/utils/uuid.ts#L2-L38","documentation":"generateUUID first tries crypto.randomUUID, then builds a UUID v4 from crypto.getRandomValues. If globalThis.crypto exposes neither function, it throws - the runtime has no Web Crypto API at all. In a browser/webview this means an ancient engine (update the OS); in Node it means a pre-19 runtime without --experimental-global-webcrypto; in jsdom-based tests it usually means no crypto polyfill was installed.","triggerScenarios":"generateUUID() under Node.js < 19 without the webcrypto flag, a jsdom test setup lacking globalThis.crypto, or a legacy embedded WebView without crypto support.","commonSituations":"Jest/Vitest jsdom environments; CI images pinned to old Node; older Linux WebKitGTK/Android WebView builds.","solutions":["Polyfill before app/test boot: import { webcrypto } from 'node:crypto' and assign globalThis.crypto","Upgrade to Node >= 19 (or pass --experimental-global-webcrypto on 15-18)","Update the OS/WebView so the native crypto API is present"],"exampleFix":"// before (vitest/jest jsdom setup file)\n// generateUUID() throws: crypto API not available\n\n// after\nimport { webcrypto } from \"node:crypto\";\nif (!globalThis.crypto) {\n  globalThis.crypto = webcrypto as Crypto;\n}","handlingStrategy":"fallback","validationCode":"// Run once at boot / test setup\nconst hasWebCrypto =\n  typeof globalThis.crypto?.randomUUID === \"function\" ||\n  typeof globalThis.crypto?.getRandomValues === \"function\";\n\nif (!hasWebCrypto) {\n  const { webcrypto } = await import(\"node:crypto\");\n  globalThis.crypto = webcrypto as Crypto;\n}","typeGuard":"function hasCryptoApi(c: unknown): c is Crypto {\n  return (\n    !!c &&\n    (typeof (c as Crypto).randomUUID === \"function\" ||\n      typeof (c as Crypto).getRandomValues === \"function\")\n  );\n}","tryCatchPattern":"try {\n  id = generateUUID();\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"crypto API not available\")) {\n    throw new Error(\"This app needs a runtime with Web Crypto. Update the OS/browser or polyfill globalThis.crypto.\");\n  }\n  throw e;\n}","preventionTips":["Install the webcrypto polyfill in jsdom test setups before importing app code","Run CI on Node >= 19 so globalThis.crypto exists natively","Probe crypto support at startup and fail fast with an upgrade hint"],"tags":["crypto","uuid","environment","compatibility","tests"],"backgroundTag":null,"analyzedSha":"a2e22f330273a5b6ffa87cb8b82b624601bac562","analyzedAt":"2026-08-16T03:46:07.889Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}