export type Domain = `${string}.${string}` export type BlipDomain = 'msging.net' | 'blip.ai' | '0mn.io' export type Identity = `${string}@${Domain}` export type NodeShape = Identity | `${Identity}/${string}` export type NodeLike = Node | NodeShape export type PossiblyNode = NodeLike | string export class Node extends String { constructor( public readonly name: string, public readonly domain: Domain, public readonly instance?: string, ) { super(`${encodeURIComponent(name)}@${domain}${instance ? `/${instance}` : ''}`) } public toIdentity(): Identity { return `${encodeURIComponent(this.name)}@${this.domain}` } public withInstance(instance: string) { return new Node(this.name, this.domain, instance) } public getSource() { switch (this.domain) { case '0mn.io': return 'Blip Chat' case 'messenger.gw.msging.net': return 'Messenger' case 'instagram.gw.msging.net': return 'Instagram' case 'wa.gw.msging.net': return 'WhatsApp' case 'businessmessages.gw.msging.net': return 'Google Business Messages' case 'telegram.gw.msging.net': return 'Telegram' case 'workplace.gw.msging.net': return 'Workplace' case 'mailgun.gw.msging.net': return 'Email' case 'msging.net': return 'Bot' case 'blip.ai': return 'Blip' case 'tunnel.msging.net': return 'Tunnel' case 'custom.gw.msging.net': { if (this.name.endsWith('.mail')) { return 'Email' } else if (this.name.endsWith('.slack')) { return 'Slack' } else { return 'Custom' } } default: return 'Unknown' } } public static from(node: PossiblyNode): Node public static from(nameOrPossibleNode: PossiblyNode, domain: Domain): Node public static from(nameOrPossibleNode: PossiblyNode, domain?: Domain): Node { if (nameOrPossibleNode instanceof Node) { return nameOrPossibleNode } if (Node.isValid(nameOrPossibleNode)) { const [name, otherPart] = nameOrPossibleNode.split('@') const [domain, instance] = otherPart.split('/') return new Node(decodeURIComponent(name), domain as Domain, instance) } if (domain) { return new Node(decodeURIComponent(nameOrPossibleNode), domain) } throw new Error(`Invalid node shape: ${nameOrPossibleNode}`) } public static isValid(node: string | null | undefined): node is NodeShape { return node ? /^.+@.+\..+/.test(node) : false } }