diff --git a/A00_Common/main.ts b/A00_Common/main.ts index 192dc84f..3ffa2037 100644 --- a/A00_Common/main.ts +++ b/A00_Common/main.ts @@ -8,6 +8,7 @@ * - hashchange 1회 구독: 셸 chrome 갱신 + 현재 라우트 렌더 * ========================================================================== */ +import "./random_uuid_polyfill"; import "@ui/ui_template_theme.css"; import { injectBaseStyles } from "@ui/ui_template_elements"; import { ROUTES, type RoutePath } from "@config/config_frontend"; diff --git a/A00_Common/random_uuid_polyfill.ts b/A00_Common/random_uuid_polyfill.ts new file mode 100644 index 00000000..edc40154 --- /dev/null +++ b/A00_Common/random_uuid_polyfill.ts @@ -0,0 +1,16 @@ +/** + * http + IP 주소(예: Tailscale)는 보안 문맥이 아니라 `crypto.randomUUID` 가 없음. + * getRandomValues(보안 문맥 아니어도 됨)로 v4 UUID 를 채움 · 이미 있으면 그대로. + * `main.ts` 가 맨 먼저 부름. CAD 짝 = `B07_DesignDetail/openwebcad/src/random-uuid-polyfill.ts`. + */ +if (typeof crypto !== "undefined" && typeof crypto.randomUUID !== "function") { + crypto.randomUUID = () => { + const bytes = crypto.getRandomValues(new Uint8Array(16)); + bytes[6] = (bytes[6] & 0x0f) | 0x40; + bytes[8] = (bytes[8] & 0x3f) | 0x80; + const hex = Array.from(bytes, (byte) => byte.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)}` as `${string}-${string}-${string}-${string}-${string}`; + }; +} + +export {}; diff --git a/B07_DesignDetail/openwebcad/src/main.tsx b/B07_DesignDetail/openwebcad/src/main.tsx index bc8f2dab..795a65e8 100644 --- a/B07_DesignDetail/openwebcad/src/main.tsx +++ b/B07_DesignDetail/openwebcad/src/main.tsx @@ -1,3 +1,4 @@ +import './random-uuid-polyfill'; import { Point } from '@flatten-js/core'; import React from 'react'; import ReactDOM from 'react-dom/client'; diff --git a/B07_DesignDetail/openwebcad/src/random-uuid-polyfill.ts b/B07_DesignDetail/openwebcad/src/random-uuid-polyfill.ts new file mode 100644 index 00000000..ea537f5c --- /dev/null +++ b/B07_DesignDetail/openwebcad/src/random-uuid-polyfill.ts @@ -0,0 +1,16 @@ +/** + * http + IP 주소(예: Tailscale)는 보안 문맥이 아니라 `crypto.randomUUID` 가 없음 — 개체 만들기에서 죽음. + * getRandomValues(보안 문맥 아니어도 됨)로 v4 UUID 를 채움 · 이미 있으면 그대로. + * `main.tsx` 가 맨 먼저 부름. 앱 본체 짝 = `A00_Common/random_uuid_polyfill.ts`. + */ +if (typeof crypto !== 'undefined' && typeof crypto.randomUUID !== 'function') { + crypto.randomUUID = () => { + const bytes = crypto.getRandomValues(new Uint8Array(16)); + bytes[6] = (bytes[6] & 0x0f) | 0x40; + bytes[8] = (bytes[8] & 0x3f) | 0x80; + const hex = Array.from(bytes, (byte) => byte.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)}` as `${string}-${string}-${string}-${string}-${string}`; + }; +} + +export {}; diff --git a/resources/tester/cad/random-uuid-polyfill.test.ts b/resources/tester/cad/random-uuid-polyfill.test.ts new file mode 100644 index 00000000..9c35a3da --- /dev/null +++ b/resources/tester/cad/random-uuid-polyfill.test.ts @@ -0,0 +1,26 @@ +/** + * http + IP(보안 문맥 아님)에서 비는 crypto.randomUUID 대체 검증 — CAD · 앱 본체 두 벌. + * 실행: node --experimental-strip-types resources/tester/cad/random-uuid-polyfill.test.ts + */ +import assert from 'node:assert/strict'; + +const V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/; +const native = crypto.randomUUID; + +for (const path of [ + '../../../B07_DesignDetail/openwebcad/src/random-uuid-polyfill.ts', + '../../../A00_Common/random_uuid_polyfill.ts', +]) { + // biome-ignore lint: 시험 — 보안 문맥 아닌 브라우저처럼 비움 + (crypto as any).randomUUID = undefined; + await import(`${path}?${Math.random()}`); + const ids = Array.from({ length: 200 }, () => crypto.randomUUID()); + assert.ok(ids.every((id) => V4.test(id)), `${path}: v4 모양`); + assert.equal(new Set(ids).size, ids.length, `${path}: 안 겹침`); +} + +// 이미 있으면 그대로 +crypto.randomUUID = native; +await import(`../../../A00_Common/random_uuid_polyfill.ts?${Math.random()}`); +assert.equal(crypto.randomUUID, native, '원래 것 유지'); +console.log('random-uuid 대체 시험 통과');