import values from "./web-settings.json" with { type: "json" }; function freeze(value) { if (value && typeof value === "object") { Object.values(value).forEach(freeze); Object.freeze(value); } return value; } function finitePositive(value, name) { if (!Number.isFinite(value) || value <= 0) throw new Error(`web_settings_invalid:${name}`); } for (const [name, value] of Object.entries(values.runtime.planner)) if (name !== "blend") finitePositive(value, `planner.${name}`); for (const [name, value] of Object.entries(values.runtime.io)) { if (name === "spindle_tolerance") { if (!Number.isFinite(value) || value < 0) throw new Error("web_settings_invalid:io.spindle_tolerance"); } else finitePositive(value, `io.${name}`); } for (const [name, value] of Object.entries(values.viewer.camera)) finitePositive(value, `camera.${name}`); finitePositive(values.viewer.mm_scale, "mm_scale"); finitePositive(values.viewer.pixel_ratio_limit, "pixel_ratio_limit"); for (const key of ["poll_ms", "jog_cycles", "run_cycles", "preview_progress_ms", "zoom", "zoom_min", "zoom_max", "zoom_step"]) finitePositive(values.ui[key], key); finitePositive(values.ui.override_debounce_ms, "override_debounce_ms"); if (!(values.ui.motion_scale_min > 0 && values.ui.motion_scale_min <= 1)) throw new Error("web_settings_invalid:motion_scale_min"); if (!values.ui.jog_increments.every((value) => Number.isFinite(Number(value)) && Number(value) > 0)) throw new Error("web_settings_invalid:jog_increments"); if (values.ui.zoom_min > values.ui.zoom_max || values.ui.zoom < values.ui.zoom_min || values.ui.zoom > values.ui.zoom_max) throw new Error("web_settings_invalid:zoom_range"); if (!["x", "y", "y2", "z", "z2", "p"].includes(values.ui.initial_view)) throw new Error("web_settings_invalid:initial_view"); for (const key of ["jog_cycles", "run_cycles"]) if (!Number.isSafeInteger(values.ui[key])) throw new Error(`web_settings_invalid:${key}`); if (values.viewer.camera.near >= values.viewer.camera.far || values.viewer.camera.min_distance >= values.viewer.camera.max_distance) throw new Error("web_settings_invalid:camera_range"); for (const model of Object.values(values.viewer.models)) finitePositive(model.datum_z_mm, "model_datum"); if (values.runtime.planner.max_feed_override < 1) throw new Error("web_settings_invalid:feed_limit"); for (const key of ["spindle_count", "tool_capacity", "encoder_count"]) if (!Number.isSafeInteger(values.runtime.io[key])) throw new Error(`web_settings_invalid:io.${key}`); export const WEB_SETTINGS = freeze(values); export function axisImagePath(name, base = ".") { return `${base.replace(/\/$/, "")}/${WEB_SETTINGS.assets.axis_images}/${name}`; }