seahaven-door-unlock-api/lambda/blf-sync/blf-xml.ts
Adam Moussa bbc113497a
Some checks failed
Deploy / deploy (push) Has been cancelled
feat(3cx): sync office department blfs via xapi (PLAT-116) (#80)
* feat(3cx): sync office department BLFs via XAPI

Keep unlock and lockdown keys in the templates and write colleague plus shared-parking BLFs per extension so phones skip their own line.

* fix(3cx): preserve parking BLF IDs and fail the job on PATCH errors
2026-08-27 14:58:55 -04:00

63 lines
1.7 KiB
TypeScript

export interface BlfEntry {
id: string;
blfNo: number;
blfType: string;
blfTypeId: string;
value: string;
}
const BLF_TAG =
/<BLF\b([^>/]*)(?:\s*\/>|>([\s\S]*?)<\/BLF>)/gi;
function attr(attrs: string, name: string): string {
const match = attrs.match(new RegExp(`\\b${name}="([^"]*)"`, "i"));
return match?.[1] ?? "";
}
export function parseBlfs(xml: string | undefined | null): BlfEntry[] {
if (!xml) {
return [];
}
const entries: BlfEntry[] = [];
for (const match of xml.matchAll(BLF_TAG)) {
const attrs = match[1] ?? "";
const blfNo = Number.parseInt(attr(attrs, "BLFNo"), 10);
if (!Number.isFinite(blfNo)) {
continue;
}
entries.push({
id: attr(attrs, "ID") || "-1",
blfNo,
blfType: attr(attrs, "BLFType") || "BLF",
blfTypeId: attr(attrs, "BLFTypeID") || "0",
value: (match[2] ?? "").trim(),
});
}
return entries;
}
function escapeXml(value: string): string {
return value
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;");
}
export function serializeBlfs(entries: BlfEntry[]): string {
const sorted = [...entries].sort((a, b) => a.blfNo - b.blfNo);
const inner = sorted
.map((entry) => {
const attrs = `ID="${escapeXml(entry.id)}" BLFNo="${entry.blfNo}" BLFType="${escapeXml(entry.blfType)}" BLFTypeID="${escapeXml(entry.blfTypeId)}"`;
if (entry.value === "") {
return `<BLF ${attrs} />`;
}
return `<BLF ${attrs}>${escapeXml(entry.value)}</BLF>`;
})
.join("");
return `<PhoneDevice><BLFS>${inner}</BLFS></PhoneDevice>`;
}
export function blfsEqual(a: string | undefined | null, b: string): boolean {
return serializeBlfs(parseBlfs(a)) === serializeBlfs(parseBlfs(b));
}