import { isPiWebPluginId } from "./pluginIds.js"; const MACHINE_PLUGIN_ID_PREFIX = "machine."; export interface MachineScopedPluginIdParts { machineId: string; pluginId: string; } export function machineScopedPluginId(machineId: string, pluginId: string): string { if (machineId === "") throw new Error("Machine id is required"); if (!isPiWebPluginId(pluginId)) throw new Error(`Invalid PI WEB plugin id: ${pluginId}`); return `${MACHINE_PLUGIN_ID_PREFIX}${stringToHex(machineId)}.${pluginId}`; } export function parseMachineScopedPluginId(pluginId: string): MachineScopedPluginIdParts | undefined { if (!pluginId.startsWith(MACHINE_PLUGIN_ID_PREFIX)) return undefined; const rest = pluginId.slice(MACHINE_PLUGIN_ID_PREFIX.length); const separator = rest.indexOf("."); if (separator < 1) return undefined; const encodedMachineId = rest.slice(0, separator); const sourcePluginId = rest.slice(separator + 1); if (!isHexString(encodedMachineId) || !isPiWebPluginId(sourcePluginId)) return undefined; const machineId = hexToString(encodedMachineId); if (machineId === "") return undefined; return { machineId, pluginId: sourcePluginId }; } function stringToHex(value: string): string { return [...new TextEncoder().encode(value)] .map((byte) => byte.toString(16).padStart(2, "0")) .join(""); } function hexToString(value: string): string { const bytes = new Uint8Array(value.length / 2); for (let index = 0; index < value.length; index += 2) { bytes[index / 2] = Number.parseInt(value.slice(index, index + 2), 16); } return new TextDecoder().decode(bytes); } function isHexString(value: string): boolean { return value.length > 0 && value.length % 2 === 0 && /^[0-9a-f]+$/u.test(value); }