Archived
feat: load machine-scoped remote plugins
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { machineScopedPluginId, parseMachineScopedPluginId } from "./machinePluginIds";
|
||||
|
||||
describe("machine-scoped plugin ids", () => {
|
||||
it("encodes machine ids into valid plugin ids and decodes them", () => {
|
||||
const scoped = machineScopedPluginId("550e8400-e29b-41d4-a716-446655440000", "project-tools");
|
||||
|
||||
expect(scoped).toMatch(/^machine\.[0-9a-f]+\.project-tools$/u);
|
||||
expect(parseMachineScopedPluginId(scoped)).toEqual({ machineId: "550e8400-e29b-41d4-a716-446655440000", pluginId: "project-tools" });
|
||||
});
|
||||
|
||||
it("leaves normal plugin ids unparsed", () => {
|
||||
expect(parseMachineScopedPluginId("project-tools")).toBeUndefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user