import re def normalize_handle(handle: str) -> str: handle = handle.strip() if handle.startswith("bluebubbles:"): handle = handle[len("bluebubbles:") :] return handle def extract_handle_from_chat_guid(chat_guid: str) -> str: parts = chat_guid.split(";") if len(parts) >= 3: return parts[2] return chat_guid def is_dm_chat_guid(chat_guid: str) -> bool: return ";-;" in chat_guid def is_group_chat_guid(chat_guid: str) -> bool: return ";+;" in chat_guid def parse_target(raw: str) -> dict: if not raw: return {"type": "unknown", "value": "", "is_group": False} if raw.startswith("chat_guid:"): guid = raw[len("chat_guid:") :] is_group = is_group_chat_guid(guid) return {"type": "chat_guid", "value": guid, "is_group": is_group} if raw.startswith("chat_id:"): return {"type": "chat_id", "value": raw[len("chat_id:") :], "is_group": True} if raw.startswith("chat_identifier:"): return {"type": "chat_identifier", "value": raw[len("chat_identifier:") :], "is_group": True} if raw.startswith("group:"): return {"type": "group", "value": raw[len("group:") :], "is_group": True} return {"type": "handle", "value": normalize_handle(raw), "is_group": False} def resolve_chat_guid_from_data(data: dict) -> str | None: for key in ("chatGuid", "chat_guid", "chat_id", "chatIdentifier"): if data.get(key): return data[key] return None def normalize_phone_lookup_key(value: str) -> str | None: digits = re.sub(r"\D", "", value) if len(digits) == 11 and digits.startswith("1"): digits = digits[1:] return digits if len(digits) >= 7 else None