UNPKG

@tanstack/offline-transactions

Version:

Offline-first transaction capabilities for TanStack DB

1 lines 7.06 kB
{"version":3,"file":"BroadcastChannelLeader.cjs","sources":["../../../src/coordination/BroadcastChannelLeader.ts"],"sourcesContent":["import { BaseLeaderElection } from './LeaderElection'\n\ninterface LeaderMessage {\n type: `heartbeat` | `election` | `leadership-claim`\n tabId: string\n timestamp: number\n}\n\nexport class BroadcastChannelLeader extends BaseLeaderElection {\n private channelName: string\n private tabId: string\n private channel: BroadcastChannel | null = null\n private heartbeatInterval: number | null = null\n private electionTimeout: number | null = null\n private lastLeaderHeartbeat = 0\n private readonly heartbeatIntervalMs = 5000\n private readonly electionTimeoutMs = 10000\n\n constructor(channelName = `offline-executor-leader`) {\n super()\n this.channelName = channelName\n this.tabId = crypto.randomUUID()\n this.setupChannel()\n }\n\n private setupChannel(): void {\n if (!this.isBroadcastChannelSupported()) {\n return\n }\n\n this.channel = new BroadcastChannel(this.channelName)\n this.channel.addEventListener(`message`, this.handleMessage)\n }\n\n private handleMessage = (event: MessageEvent<LeaderMessage>): void => {\n const { type, tabId, timestamp } = event.data\n\n if (tabId === this.tabId) {\n return\n }\n\n switch (type) {\n case `heartbeat`:\n if (this.isLeaderState && tabId < this.tabId) {\n this.releaseLeadership()\n } else if (!this.isLeaderState) {\n this.lastLeaderHeartbeat = timestamp\n this.cancelElection()\n }\n break\n\n case `election`:\n if (this.isLeaderState) {\n this.sendHeartbeat()\n } else if (tabId > this.tabId) {\n this.startElection()\n }\n break\n\n case `leadership-claim`:\n if (this.isLeaderState && tabId < this.tabId) {\n this.releaseLeadership()\n }\n break\n }\n }\n\n async requestLeadership(): Promise<boolean> {\n if (!this.isBroadcastChannelSupported()) {\n return false\n }\n\n if (this.isLeaderState) {\n return true\n }\n\n this.startElection()\n\n return new Promise((resolve) => {\n setTimeout(() => {\n resolve(this.isLeaderState)\n }, 1000)\n })\n }\n\n private startElection(): void {\n if (this.electionTimeout) {\n return\n }\n\n this.sendMessage({\n type: `election`,\n tabId: this.tabId,\n timestamp: Date.now(),\n })\n\n this.electionTimeout = window.setTimeout(() => {\n const timeSinceLastHeartbeat = Date.now() - this.lastLeaderHeartbeat\n\n if (timeSinceLastHeartbeat > this.electionTimeoutMs) {\n this.claimLeadership()\n }\n\n this.electionTimeout = null\n }, this.electionTimeoutMs)\n }\n\n private cancelElection(): void {\n if (this.electionTimeout) {\n clearTimeout(this.electionTimeout)\n this.electionTimeout = null\n }\n }\n\n private claimLeadership(): void {\n this.notifyLeadershipChange(true)\n this.sendMessage({\n type: `leadership-claim`,\n tabId: this.tabId,\n timestamp: Date.now(),\n })\n this.startHeartbeat()\n }\n\n private startHeartbeat(): void {\n if (this.heartbeatInterval) {\n return\n }\n\n this.sendHeartbeat()\n\n this.heartbeatInterval = window.setInterval(() => {\n this.sendHeartbeat()\n }, this.heartbeatIntervalMs)\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval)\n this.heartbeatInterval = null\n }\n }\n\n private sendHeartbeat(): void {\n this.sendMessage({\n type: `heartbeat`,\n tabId: this.tabId,\n timestamp: Date.now(),\n })\n }\n\n private sendMessage(message: LeaderMessage): void {\n if (this.channel) {\n this.channel.postMessage(message)\n }\n }\n\n releaseLeadership(): void {\n this.stopHeartbeat()\n this.cancelElection()\n this.notifyLeadershipChange(false)\n }\n\n private isBroadcastChannelSupported(): boolean {\n return typeof BroadcastChannel !== `undefined`\n }\n\n static isSupported(): boolean {\n return typeof BroadcastChannel !== `undefined`\n }\n\n dispose(): void {\n this.releaseLeadership()\n\n if (this.channel) {\n this.channel.removeEventListener(`message`, this.handleMessage)\n this.channel.close()\n this.channel = null\n }\n }\n}\n"],"names":["BaseLeaderElection"],"mappings":";;;AAQO,MAAM,+BAA+BA,eAAAA,mBAAmB;AAAA,EAU7D,YAAY,cAAc,2BAA2B;AACnD,UAAA;AARF,SAAQ,UAAmC;AAC3C,SAAQ,oBAAmC;AAC3C,SAAQ,kBAAiC;AACzC,SAAQ,sBAAsB;AAC9B,SAAiB,sBAAsB;AACvC,SAAiB,oBAAoB;AAkBrC,SAAQ,gBAAgB,CAAC,UAA6C;AACpE,YAAM,EAAE,MAAM,OAAO,UAAA,IAAc,MAAM;AAEzC,UAAI,UAAU,KAAK,OAAO;AACxB;AAAA,MACF;AAEA,cAAQ,MAAA;AAAA,QACN,KAAK;AACH,cAAI,KAAK,iBAAiB,QAAQ,KAAK,OAAO;AAC5C,iBAAK,kBAAA;AAAA,UACP,WAAW,CAAC,KAAK,eAAe;AAC9B,iBAAK,sBAAsB;AAC3B,iBAAK,eAAA;AAAA,UACP;AACA;AAAA,QAEF,KAAK;AACH,cAAI,KAAK,eAAe;AACtB,iBAAK,cAAA;AAAA,UACP,WAAW,QAAQ,KAAK,OAAO;AAC7B,iBAAK,cAAA;AAAA,UACP;AACA;AAAA,QAEF,KAAK;AACH,cAAI,KAAK,iBAAiB,QAAQ,KAAK,OAAO;AAC5C,iBAAK,kBAAA;AAAA,UACP;AACA;AAAA,MAAA;AAAA,IAEN;AA7CE,SAAK,cAAc;AACnB,SAAK,QAAQ,OAAO,WAAA;AACpB,SAAK,aAAA;AAAA,EACP;AAAA,EAEQ,eAAqB;AAC3B,QAAI,CAAC,KAAK,+BAA+B;AACvC;AAAA,IACF;AAEA,SAAK,UAAU,IAAI,iBAAiB,KAAK,WAAW;AACpD,SAAK,QAAQ,iBAAiB,WAAW,KAAK,aAAa;AAAA,EAC7D;AAAA,EAmCA,MAAM,oBAAsC;AAC1C,QAAI,CAAC,KAAK,+BAA+B;AACvC,aAAO;AAAA,IACT;AAEA,QAAI,KAAK,eAAe;AACtB,aAAO;AAAA,IACT;AAEA,SAAK,cAAA;AAEL,WAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,iBAAW,MAAM;AACf,gBAAQ,KAAK,aAAa;AAAA,MAC5B,GAAG,GAAI;AAAA,IACT,CAAC;AAAA,EACH;AAAA,EAEQ,gBAAsB;AAC5B,QAAI,KAAK,iBAAiB;AACxB;AAAA,IACF;AAEA,SAAK,YAAY;AAAA,MACf,MAAM;AAAA,MACN,OAAO,KAAK;AAAA,MACZ,WAAW,KAAK,IAAA;AAAA,IAAI,CACrB;AAED,SAAK,kBAAkB,OAAO,WAAW,MAAM;AAC7C,YAAM,yBAAyB,KAAK,IAAA,IAAQ,KAAK;AAEjD,UAAI,yBAAyB,KAAK,mBAAmB;AACnD,aAAK,gBAAA;AAAA,MACP;AAEA,WAAK,kBAAkB;AAAA,IACzB,GAAG,KAAK,iBAAiB;AAAA,EAC3B;AAAA,EAEQ,iBAAuB;AAC7B,QAAI,KAAK,iBAAiB;AACxB,mBAAa,KAAK,eAAe;AACjC,WAAK,kBAAkB;AAAA,IACzB;AAAA,EACF;AAAA,EAEQ,kBAAwB;AAC9B,SAAK,uBAAuB,IAAI;AAChC,SAAK,YAAY;AAAA,MACf,MAAM;AAAA,MACN,OAAO,KAAK;AAAA,MACZ,WAAW,KAAK,IAAA;AAAA,IAAI,CACrB;AACD,SAAK,eAAA;AAAA,EACP;AAAA,EAEQ,iBAAuB;AAC7B,QAAI,KAAK,mBAAmB;AAC1B;AAAA,IACF;AAEA,SAAK,cAAA;AAEL,SAAK,oBAAoB,OAAO,YAAY,MAAM;AAChD,WAAK,cAAA;AAAA,IACP,GAAG,KAAK,mBAAmB;AAAA,EAC7B;AAAA,EAEQ,gBAAsB;AAC5B,QAAI,KAAK,mBAAmB;AAC1B,oBAAc,KAAK,iBAAiB;AACpC,WAAK,oBAAoB;AAAA,IAC3B;AAAA,EACF;AAAA,EAEQ,gBAAsB;AAC5B,SAAK,YAAY;AAAA,MACf,MAAM;AAAA,MACN,OAAO,KAAK;AAAA,MACZ,WAAW,KAAK,IAAA;AAAA,IAAI,CACrB;AAAA,EACH;AAAA,EAEQ,YAAY,SAA8B;AAChD,QAAI,KAAK,SAAS;AAChB,WAAK,QAAQ,YAAY,OAAO;AAAA,IAClC;AAAA,EACF;AAAA,EAEA,oBAA0B;AACxB,SAAK,cAAA;AACL,SAAK,eAAA;AACL,SAAK,uBAAuB,KAAK;AAAA,EACnC;AAAA,EAEQ,8BAAuC;AAC7C,WAAO,OAAO,qBAAqB;AAAA,EACrC;AAAA,EAEA,OAAO,cAAuB;AAC5B,WAAO,OAAO,qBAAqB;AAAA,EACrC;AAAA,EAEA,UAAgB;AACd,SAAK,kBAAA;AAEL,QAAI,KAAK,SAAS;AAChB,WAAK,QAAQ,oBAAoB,WAAW,KAAK,aAAa;AAC9D,WAAK,QAAQ,MAAA;AACb,WAAK,UAAU;AAAA,IACjB;AAAA,EACF;AACF;;"}