fix(fe): crypto.randomUUID not in non-secure contexts (LAN http) -> newId() fallback

The LAN dev URL (http://192.168.1.202) is not a secure context, so
crypto.randomUUID is undefined and adding a photo threw
'TypeError: crypto.randomUUID is not a function'. Add newId() (randomUUID
when available, else crypto.getRandomValues UUIDv4) and use it in draft()
and PhotoImport. Verified in Chromium.
This commit is contained in:
2026-09-25 07:54:15 -07:00
parent 7913e630d6
commit 3321a7cfdf
2 changed files with 24 additions and 2 deletions
+2 -1
View File
@@ -1,6 +1,7 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte';
import type { Photo } from '../lib/types';
import { newId } from '../lib/types';
import { keepForSheet } from '../mask/sheetKeep';
import { decodeOrientedBitmap } from './decodeOrientedBitmap';
@@ -75,7 +76,7 @@
if (!f.type.startsWith('image/')) { error = 'Only images'; return; }
const url = URL.createObjectURL(f);
previews.push({
id: crypto.randomUUID(),
id: newId(),
seq: i,
isCalibration: i === 0,
url,
+22 -1
View File
@@ -1,5 +1,26 @@
export type SlabStatus = 'draft' | 'calibrated' | 'ready' | 'publishing' | 'published' | 'failed';
/**
* Random UUID. crypto.randomUUID is only defined in secure contexts (https/
* localhost); the LAN dev URL (http://192.168.1.202) is not, so fall back to
* crypto.getRandomValues when it is absent.
*/
export function newId(): string {
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
return crypto.randomUUID();
}
const bytes = new Uint8Array(16);
if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {
crypto.getRandomValues(bytes);
} else {
for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256);
}
bytes[6] = (bytes[6] & 0x0f) | 0x40; // version 4
bytes[8] = (bytes[8] & 0x3f) | 0x80; // variant
const hex = Array.from(bytes, (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)}`;
}
export interface Photo {
id: string;
seq: number;
@@ -86,7 +107,7 @@ export interface Taxonomy {
/** Public factory: a fresh SlabDraft with demo defaults; spread to override. */
export function draft(overrides: Partial<SlabDraft> = {}): SlabDraft {
return {
id: crypto.randomUUID(),
id: newId(),
status: 'draft',
photos: [],
calibrationPhotoId: '',