@supalive/core 1.7.1 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index-0XwMOQBo.d.ts +2110 -0
- package/dist/index-0XwMOQBo.d.ts.map +1 -0
- package/dist/index-BHwZ0TXc.d.ts +2126 -0
- package/dist/index-BHwZ0TXc.d.ts.map +1 -0
- package/dist/index-BSqGOgxz.d.ts +2126 -0
- package/dist/index-BSqGOgxz.d.ts.map +1 -0
- package/dist/index-BSvfTwmf.d.ts +2127 -0
- package/dist/index-BSvfTwmf.d.ts.map +1 -0
- package/dist/index-BX33pXeZ.d.ts +2126 -0
- package/dist/index-BX33pXeZ.d.ts.map +1 -0
- package/dist/index-B_eYxS62.d.ts +2127 -0
- package/dist/index-B_eYxS62.d.ts.map +1 -0
- package/dist/index-BbGO7Ejp.d.ts +2126 -0
- package/dist/index-BbGO7Ejp.d.ts.map +1 -0
- package/dist/index-C2ZMPgsI.d.ts +2114 -0
- package/dist/index-C2ZMPgsI.d.ts.map +1 -0
- package/dist/index-CTFFQWz1.d.ts +2126 -0
- package/dist/index-CTFFQWz1.d.ts.map +1 -0
- package/dist/index-CjOTzplF.d.ts +2126 -0
- package/dist/index-CjOTzplF.d.ts.map +1 -0
- package/dist/index-CmFZetc-.d.ts +2127 -0
- package/dist/index-CmFZetc-.d.ts.map +1 -0
- package/dist/index-Cmrr9Tec.d.ts +2126 -0
- package/dist/index-Cmrr9Tec.d.ts.map +1 -0
- package/dist/index-CqVR7zll.d.ts +2125 -0
- package/dist/index-CqVR7zll.d.ts.map +1 -0
- package/dist/index-CtHo5xAL.d.ts +2125 -0
- package/dist/index-CtHo5xAL.d.ts.map +1 -0
- package/dist/index-Ctw7txMT.d.ts +2166 -0
- package/dist/index-Ctw7txMT.d.ts.map +1 -0
- package/dist/index-Cwbbu-XP.d.ts +2166 -0
- package/dist/index-Cwbbu-XP.d.ts.map +1 -0
- package/dist/index-Cy8IkuGR.d.ts +2125 -0
- package/dist/index-Cy8IkuGR.d.ts.map +1 -0
- package/dist/index-D4_QHo7q.d.ts +2126 -0
- package/dist/index-D4_QHo7q.d.ts.map +1 -0
- package/dist/index-D87c8EVr.d.ts +2125 -0
- package/dist/index-D87c8EVr.d.ts.map +1 -0
- package/dist/index-D9vqKJO_.d.ts +2126 -0
- package/dist/index-D9vqKJO_.d.ts.map +1 -0
- package/dist/index-DJnKNJ6y.d.ts +2110 -0
- package/dist/index-DJnKNJ6y.d.ts.map +1 -0
- package/dist/index-DTPJn741.d.ts +2126 -0
- package/dist/index-DTPJn741.d.ts.map +1 -0
- package/dist/index-DeM-i96w.d.ts +2109 -0
- package/dist/index-DeM-i96w.d.ts.map +1 -0
- package/dist/index-DfMHVkVC.d.ts +2126 -0
- package/dist/index-DfMHVkVC.d.ts.map +1 -0
- package/dist/index-DgZeS3JK.d.ts +2166 -0
- package/dist/index-DgZeS3JK.d.ts.map +1 -0
- package/dist/index-DkfqkzsC.d.ts +2125 -0
- package/dist/index-DkfqkzsC.d.ts.map +1 -0
- package/dist/index-DzGkzEaO.d.ts +2126 -0
- package/dist/index-DzGkzEaO.d.ts.map +1 -0
- package/dist/index-Dzbvt3C2.d.ts +2127 -0
- package/dist/index-Dzbvt3C2.d.ts.map +1 -0
- package/dist/index-WvntPU0e.d.ts +2111 -0
- package/dist/index-WvntPU0e.d.ts.map +1 -0
- package/dist/index-YnlFOYMJ.d.ts +2127 -0
- package/dist/index-YnlFOYMJ.d.ts.map +1 -0
- package/dist/mysql-6XsvNwxp.d.ts +109 -0
- package/dist/mysql-6XsvNwxp.d.ts.map +1 -0
- package/dist/mysql-9euRTU3L.d.ts +109 -0
- package/dist/mysql-9euRTU3L.d.ts.map +1 -0
- package/dist/mysql-B2kTH1jJ.d.ts +109 -0
- package/dist/mysql-B2kTH1jJ.d.ts.map +1 -0
- package/dist/mysql-B49q-Cmk.d.ts +109 -0
- package/dist/mysql-B49q-Cmk.d.ts.map +1 -0
- package/dist/mysql-B5FzK4eP.js +602 -0
- package/dist/mysql-B5FzK4eP.js.map +1 -0
- package/dist/mysql-B94uJ3tN.js +602 -0
- package/dist/mysql-B94uJ3tN.js.map +1 -0
- package/dist/mysql-BB7xHRP5.d.ts +109 -0
- package/dist/mysql-BB7xHRP5.d.ts.map +1 -0
- package/dist/mysql-BF2gBly8.js +602 -0
- package/dist/mysql-BF2gBly8.js.map +1 -0
- package/dist/mysql-BK0abZ2z.d.ts +109 -0
- package/dist/mysql-BK0abZ2z.d.ts.map +1 -0
- package/dist/mysql-BK5D6KCY.d.ts +109 -0
- package/dist/mysql-BK5D6KCY.d.ts.map +1 -0
- package/dist/mysql-BNIwKbOq.js +602 -0
- package/dist/mysql-BNIwKbOq.js.map +1 -0
- package/dist/mysql-BNoXrafv.js +602 -0
- package/dist/mysql-BNoXrafv.js.map +1 -0
- package/dist/mysql-BPQInRAe.js +602 -0
- package/dist/mysql-BPQInRAe.js.map +1 -0
- package/dist/mysql-BYGEXm2C.d.ts +109 -0
- package/dist/mysql-BYGEXm2C.d.ts.map +1 -0
- package/dist/mysql-BYI8YXkW.d.ts +109 -0
- package/dist/mysql-BYI8YXkW.d.ts.map +1 -0
- package/dist/mysql-BYcoH18V.js +602 -0
- package/dist/mysql-BYcoH18V.js.map +1 -0
- package/dist/mysql-BkVE_Ujv.d.ts +109 -0
- package/dist/mysql-BkVE_Ujv.d.ts.map +1 -0
- package/dist/mysql-Bm2p56cX.d.ts +109 -0
- package/dist/mysql-Bm2p56cX.d.ts.map +1 -0
- package/dist/mysql-BpXbhT7n.d.ts +109 -0
- package/dist/mysql-BpXbhT7n.d.ts.map +1 -0
- package/dist/mysql-C5mY2vsv.d.ts +109 -0
- package/dist/mysql-C5mY2vsv.d.ts.map +1 -0
- package/dist/mysql-CA7GCR62.js +602 -0
- package/dist/mysql-CA7GCR62.js.map +1 -0
- package/dist/mysql-CB92MLis.d.ts +109 -0
- package/dist/mysql-CB92MLis.d.ts.map +1 -0
- package/dist/mysql-CJzUHhkD.d.ts +109 -0
- package/dist/mysql-CJzUHhkD.d.ts.map +1 -0
- package/dist/mysql-CMxoLJKU.js +602 -0
- package/dist/mysql-CMxoLJKU.js.map +1 -0
- package/dist/mysql-CWUc2OMX.js +602 -0
- package/dist/mysql-CWUc2OMX.js.map +1 -0
- package/dist/mysql-CXjC0ysZ.js +602 -0
- package/dist/mysql-CXjC0ysZ.js.map +1 -0
- package/dist/mysql-Cki0N6RJ.d.ts +109 -0
- package/dist/mysql-Cki0N6RJ.d.ts.map +1 -0
- package/dist/mysql-CmEj_TDt.d.ts +109 -0
- package/dist/mysql-CmEj_TDt.d.ts.map +1 -0
- package/dist/mysql-CqIRmBp7.d.ts +109 -0
- package/dist/mysql-CqIRmBp7.d.ts.map +1 -0
- package/dist/mysql-CtEorg4f.d.ts +109 -0
- package/dist/mysql-CtEorg4f.d.ts.map +1 -0
- package/dist/mysql-CuOauMxY.d.ts +109 -0
- package/dist/mysql-CuOauMxY.d.ts.map +1 -0
- package/dist/mysql-CuXo3LRu.js +602 -0
- package/dist/mysql-CuXo3LRu.js.map +1 -0
- package/dist/mysql-CzTpgBoO.js +602 -0
- package/dist/mysql-CzTpgBoO.js.map +1 -0
- package/dist/mysql-D8wL7pst.js +602 -0
- package/dist/mysql-D8wL7pst.js.map +1 -0
- package/dist/mysql-DA72G9SS.d.ts +109 -0
- package/dist/mysql-DA72G9SS.d.ts.map +1 -0
- package/dist/mysql-DGE7rJ0V.js +602 -0
- package/dist/mysql-DGE7rJ0V.js.map +1 -0
- package/dist/mysql-DVAc6aZz.d.ts +109 -0
- package/dist/mysql-DVAc6aZz.d.ts.map +1 -0
- package/dist/mysql-DVwWeE_Y.d.ts +109 -0
- package/dist/mysql-DVwWeE_Y.d.ts.map +1 -0
- package/dist/mysql-Db5cdkrK.d.ts +109 -0
- package/dist/mysql-Db5cdkrK.d.ts.map +1 -0
- package/dist/mysql-DfJaMwhW.d.ts +109 -0
- package/dist/mysql-DfJaMwhW.d.ts.map +1 -0
- package/dist/mysql-DifqBSa_.d.ts +109 -0
- package/dist/mysql-DifqBSa_.d.ts.map +1 -0
- package/dist/mysql-Dir8ENr2.d.ts +109 -0
- package/dist/mysql-Dir8ENr2.d.ts.map +1 -0
- package/dist/mysql-DpjO1Ytp.d.ts +109 -0
- package/dist/mysql-DpjO1Ytp.d.ts.map +1 -0
- package/dist/mysql-DswRsxyn.js +602 -0
- package/dist/mysql-DswRsxyn.js.map +1 -0
- package/dist/mysql-Dt8SVcVr.js +602 -0
- package/dist/mysql-Dt8SVcVr.js.map +1 -0
- package/dist/mysql-DtvfcLez.js +602 -0
- package/dist/mysql-DtvfcLez.js.map +1 -0
- package/dist/mysql-Dx64LagV.d.ts +109 -0
- package/dist/mysql-Dx64LagV.d.ts.map +1 -0
- package/dist/mysql-EDJ_yHHV.d.ts +109 -0
- package/dist/mysql-EDJ_yHHV.d.ts.map +1 -0
- package/dist/mysql-EgLnP40l.js +602 -0
- package/dist/mysql-EgLnP40l.js.map +1 -0
- package/dist/mysql-HDKtlHA7.js +602 -0
- package/dist/mysql-HDKtlHA7.js.map +1 -0
- package/dist/mysql-JpthxaEC.js +602 -0
- package/dist/mysql-JpthxaEC.js.map +1 -0
- package/dist/mysql-P_b5BFqG.js +602 -0
- package/dist/mysql-P_b5BFqG.js.map +1 -0
- package/dist/mysql-SLS-B4FA.js +602 -0
- package/dist/mysql-SLS-B4FA.js.map +1 -0
- package/dist/mysql-W2O36FZp.js +602 -0
- package/dist/mysql-W2O36FZp.js.map +1 -0
- package/dist/mysql-e29bahXC.js +602 -0
- package/dist/mysql-e29bahXC.js.map +1 -0
- package/dist/mysql-xrp4lX9M.js +602 -0
- package/dist/mysql-xrp4lX9M.js.map +1 -0
- package/dist/mysql-yzsN4kja.js +602 -0
- package/dist/mysql-yzsN4kja.js.map +1 -0
- package/dist/overlap-checker-BGIygypG.js +235 -0
- package/dist/overlap-checker-BGIygypG.js.map +1 -0
- package/dist/overlap-checker-BZShba_4.js +235 -0
- package/dist/overlap-checker-BZShba_4.js.map +1 -0
- package/dist/overlap-checker-BqR9qCfy.js +235 -0
- package/dist/overlap-checker-BqR9qCfy.js.map +1 -0
- package/dist/overlap-checker-BsSy8AzX.js +235 -0
- package/dist/overlap-checker-BsSy8AzX.js.map +1 -0
- package/dist/overlap-checker-C7ZufVA_.js +235 -0
- package/dist/overlap-checker-C7ZufVA_.js.map +1 -0
- package/dist/overlap-checker-CVOLquoJ.js +235 -0
- package/dist/overlap-checker-CVOLquoJ.js.map +1 -0
- package/dist/overlap-checker-C_TrIsl9.js +235 -0
- package/dist/overlap-checker-C_TrIsl9.js.map +1 -0
- package/dist/overlap-checker-CdY929rB.js +235 -0
- package/dist/overlap-checker-CdY929rB.js.map +1 -0
- package/dist/overlap-checker-CexhOI6d.js +235 -0
- package/dist/overlap-checker-CexhOI6d.js.map +1 -0
- package/dist/overlap-checker-CiQ0i2he.js +235 -0
- package/dist/overlap-checker-CiQ0i2he.js.map +1 -0
- package/dist/overlap-checker-Clg2Tvh1.js +235 -0
- package/dist/overlap-checker-Clg2Tvh1.js.map +1 -0
- package/dist/overlap-checker-CmH6Q_Zr.js +235 -0
- package/dist/overlap-checker-CmH6Q_Zr.js.map +1 -0
- package/dist/overlap-checker-Con95unw.js +235 -0
- package/dist/overlap-checker-Con95unw.js.map +1 -0
- package/dist/overlap-checker-D3fIwrEe.js +235 -0
- package/dist/overlap-checker-D3fIwrEe.js.map +1 -0
- package/dist/overlap-checker-D8aJEZhc.js +235 -0
- package/dist/overlap-checker-D8aJEZhc.js.map +1 -0
- package/dist/overlap-checker-DF8mpxy4.js +235 -0
- package/dist/overlap-checker-DF8mpxy4.js.map +1 -0
- package/dist/overlap-checker-DMkMOPz8.js +235 -0
- package/dist/overlap-checker-DMkMOPz8.js.map +1 -0
- package/dist/overlap-checker-DNqu1-af.js +235 -0
- package/dist/overlap-checker-DNqu1-af.js.map +1 -0
- package/dist/overlap-checker-DO4z3CWn.js +235 -0
- package/dist/overlap-checker-DO4z3CWn.js.map +1 -0
- package/dist/overlap-checker-DOuPHIda.js +235 -0
- package/dist/overlap-checker-DOuPHIda.js.map +1 -0
- package/dist/overlap-checker-DPlDexLT.js +235 -0
- package/dist/overlap-checker-DPlDexLT.js.map +1 -0
- package/dist/overlap-checker-DvVGLMNQ.js +235 -0
- package/dist/overlap-checker-DvVGLMNQ.js.map +1 -0
- package/dist/overlap-checker-FEC4bTk3.js +235 -0
- package/dist/overlap-checker-FEC4bTk3.js.map +1 -0
- package/dist/overlap-checker-JLCNx5q4.js +235 -0
- package/dist/overlap-checker-JLCNx5q4.js.map +1 -0
- package/dist/overlap-checker-fpoPpTQY.js +235 -0
- package/dist/overlap-checker-fpoPpTQY.js.map +1 -0
- package/dist/overlap-checker-j0GcZW77.js +235 -0
- package/dist/overlap-checker-j0GcZW77.js.map +1 -0
- package/dist/overlap-checker-zUQdaIYv.js +235 -0
- package/dist/overlap-checker-zUQdaIYv.js.map +1 -0
- package/dist/postgres-AyB5fPHb.js +857 -0
- package/dist/postgres-AyB5fPHb.js.map +1 -0
- package/dist/postgres-B-OZJdD9.d.ts +113 -0
- package/dist/postgres-B-OZJdD9.d.ts.map +1 -0
- package/dist/postgres-B1ybwr2I.d.ts +113 -0
- package/dist/postgres-B1ybwr2I.d.ts.map +1 -0
- package/dist/postgres-B2396cQX.js +857 -0
- package/dist/postgres-B2396cQX.js.map +1 -0
- package/dist/postgres-B7w7AW5q.d.ts +113 -0
- package/dist/postgres-B7w7AW5q.d.ts.map +1 -0
- package/dist/postgres-BE2VC-lV.d.ts +113 -0
- package/dist/postgres-BE2VC-lV.d.ts.map +1 -0
- package/dist/postgres-BIVafBnG.js +857 -0
- package/dist/postgres-BIVafBnG.js.map +1 -0
- package/dist/postgres-BJ3N1ARq.d.ts +113 -0
- package/dist/postgres-BJ3N1ARq.d.ts.map +1 -0
- package/dist/postgres-BKCshpjz.d.ts +113 -0
- package/dist/postgres-BKCshpjz.d.ts.map +1 -0
- package/dist/postgres-BLDfi_c1.js +857 -0
- package/dist/postgres-BLDfi_c1.js.map +1 -0
- package/dist/postgres-BLsYmvBT.js +857 -0
- package/dist/postgres-BLsYmvBT.js.map +1 -0
- package/dist/postgres-BOHVFFRE.d.ts +113 -0
- package/dist/postgres-BOHVFFRE.d.ts.map +1 -0
- package/dist/postgres-BSm7hkOq.js +857 -0
- package/dist/postgres-BSm7hkOq.js.map +1 -0
- package/dist/postgres-Bc0E1TrW.d.ts +113 -0
- package/dist/postgres-Bc0E1TrW.d.ts.map +1 -0
- package/dist/postgres-BoMAdlCX.d.ts +113 -0
- package/dist/postgres-BoMAdlCX.d.ts.map +1 -0
- package/dist/postgres-C4x9dHnD.js +857 -0
- package/dist/postgres-C4x9dHnD.js.map +1 -0
- package/dist/postgres-C7JBu6rW.d.ts +113 -0
- package/dist/postgres-C7JBu6rW.d.ts.map +1 -0
- package/dist/postgres-C7K6Ylb-.d.ts +113 -0
- package/dist/postgres-C7K6Ylb-.d.ts.map +1 -0
- package/dist/postgres-CECxtb8l.js +857 -0
- package/dist/postgres-CECxtb8l.js.map +1 -0
- package/dist/postgres-CGHUivER.d.ts +113 -0
- package/dist/postgres-CGHUivER.d.ts.map +1 -0
- package/dist/postgres-CH2UJrpO.js +857 -0
- package/dist/postgres-CH2UJrpO.js.map +1 -0
- package/dist/postgres-CJAn-jlg.js +857 -0
- package/dist/postgres-CJAn-jlg.js.map +1 -0
- package/dist/postgres-CPZDIBB0.d.ts +113 -0
- package/dist/postgres-CPZDIBB0.d.ts.map +1 -0
- package/dist/postgres-CaxNPOOz.js +857 -0
- package/dist/postgres-CaxNPOOz.js.map +1 -0
- package/dist/postgres-Chws2Anm.js +857 -0
- package/dist/postgres-Chws2Anm.js.map +1 -0
- package/dist/postgres-Cjmj7ESy.js +857 -0
- package/dist/postgres-Cjmj7ESy.js.map +1 -0
- package/dist/postgres-Clc1i2dP.d.ts +113 -0
- package/dist/postgres-Clc1i2dP.d.ts.map +1 -0
- package/dist/postgres-Cm-bmEN9.js +857 -0
- package/dist/postgres-Cm-bmEN9.js.map +1 -0
- package/dist/postgres-CotH5IcJ.d.ts +113 -0
- package/dist/postgres-CotH5IcJ.d.ts.map +1 -0
- package/dist/postgres-CtCEIxj_.js +857 -0
- package/dist/postgres-CtCEIxj_.js.map +1 -0
- package/dist/postgres-Cwq5EPBg.js +857 -0
- package/dist/postgres-Cwq5EPBg.js.map +1 -0
- package/dist/postgres-CzE7AZii.js +857 -0
- package/dist/postgres-CzE7AZii.js.map +1 -0
- package/dist/postgres-D-9VfxTJ.js +857 -0
- package/dist/postgres-D-9VfxTJ.js.map +1 -0
- package/dist/postgres-D3yPBJPF.d.ts +113 -0
- package/dist/postgres-D3yPBJPF.d.ts.map +1 -0
- package/dist/postgres-D5r-bNx9.d.ts +113 -0
- package/dist/postgres-D5r-bNx9.d.ts.map +1 -0
- package/dist/postgres-D9uq7-pc.d.ts +113 -0
- package/dist/postgres-D9uq7-pc.d.ts.map +1 -0
- package/dist/postgres-DC-_vGdw.js +857 -0
- package/dist/postgres-DC-_vGdw.js.map +1 -0
- package/dist/postgres-DKcSOpXu.js +857 -0
- package/dist/postgres-DKcSOpXu.js.map +1 -0
- package/dist/postgres-DKrGqh_j.d.ts +113 -0
- package/dist/postgres-DKrGqh_j.d.ts.map +1 -0
- package/dist/postgres-DPje6yca.js +857 -0
- package/dist/postgres-DPje6yca.js.map +1 -0
- package/dist/postgres-DUfgpwmk.js +857 -0
- package/dist/postgres-DUfgpwmk.js.map +1 -0
- package/dist/postgres-DkxzH2Dg.d.ts +113 -0
- package/dist/postgres-DkxzH2Dg.d.ts.map +1 -0
- package/dist/postgres-Dm2hJj_z.d.ts +113 -0
- package/dist/postgres-Dm2hJj_z.d.ts.map +1 -0
- package/dist/postgres-DmvXfcDq.d.ts +113 -0
- package/dist/postgres-DmvXfcDq.d.ts.map +1 -0
- package/dist/postgres-DpJbDdVo.d.ts +113 -0
- package/dist/postgres-DpJbDdVo.d.ts.map +1 -0
- package/dist/postgres-DqMmjAnq.js +857 -0
- package/dist/postgres-DqMmjAnq.js.map +1 -0
- package/dist/postgres-Dqo6TmkC.d.ts +113 -0
- package/dist/postgres-Dqo6TmkC.d.ts.map +1 -0
- package/dist/postgres-DuJMKfZT.js +857 -0
- package/dist/postgres-DuJMKfZT.js.map +1 -0
- package/dist/postgres-DuXHCyLM.d.ts +113 -0
- package/dist/postgres-DuXHCyLM.d.ts.map +1 -0
- package/dist/postgres-GjRa0yUX.d.ts +113 -0
- package/dist/postgres-GjRa0yUX.d.ts.map +1 -0
- package/dist/postgres-QmkUq1wW.js +857 -0
- package/dist/postgres-QmkUq1wW.js.map +1 -0
- package/dist/postgres-RYL0Miyw.js +857 -0
- package/dist/postgres-RYL0Miyw.js.map +1 -0
- package/dist/postgres-TiV0hbea.d.ts +113 -0
- package/dist/postgres-TiV0hbea.d.ts.map +1 -0
- package/dist/postgres-oXKx8meT.d.ts +113 -0
- package/dist/postgres-oXKx8meT.d.ts.map +1 -0
- package/dist/postgres-sIfan-wV.d.ts +113 -0
- package/dist/postgres-sIfan-wV.d.ts.map +1 -0
- package/dist/postgres-t-CmTR4w.js +857 -0
- package/dist/postgres-t-CmTR4w.js.map +1 -0
- package/dist/postgres-wSYI5UGF.d.ts +113 -0
- package/dist/postgres-wSYI5UGF.d.ts.map +1 -0
- package/dist/query-BLQJ9SWs.js +738 -0
- package/dist/query-BLQJ9SWs.js.map +1 -0
- package/dist/query-BMkGnyXV.js +722 -0
- package/dist/query-BMkGnyXV.js.map +1 -0
- package/dist/query-BXFo-xCO.js +705 -0
- package/dist/query-BXFo-xCO.js.map +1 -0
- package/dist/query-BXMj4jr-.js +718 -0
- package/dist/query-BXMj4jr-.js.map +1 -0
- package/dist/query-BuL8f9F8.js +724 -0
- package/dist/query-BuL8f9F8.js.map +1 -0
- package/dist/query-C10FzUWC.js +721 -0
- package/dist/query-C10FzUWC.js.map +1 -0
- package/dist/query-C4u8tD4H.js +698 -0
- package/dist/query-C4u8tD4H.js.map +1 -0
- package/dist/query-CLJCQlyA.js +722 -0
- package/dist/query-CLJCQlyA.js.map +1 -0
- package/dist/query-CMzRDKYw.js +714 -0
- package/dist/query-CMzRDKYw.js.map +1 -0
- package/dist/query-CNOc_XzM.js +709 -0
- package/dist/query-CNOc_XzM.js.map +1 -0
- package/dist/query-CVKqKDJE.js +737 -0
- package/dist/query-CVKqKDJE.js.map +1 -0
- package/dist/query-CbY0iPoj.js +724 -0
- package/dist/query-CbY0iPoj.js.map +1 -0
- package/dist/query-ClVEugE4.js +693 -0
- package/dist/query-ClVEugE4.js.map +1 -0
- package/dist/query-Cx7F-ete.js +740 -0
- package/dist/query-Cx7F-ete.js.map +1 -0
- package/dist/query-Cz7nBVio.js +738 -0
- package/dist/query-Cz7nBVio.js.map +1 -0
- package/dist/query-DC40-Yjv.js +737 -0
- package/dist/query-DC40-Yjv.js.map +1 -0
- package/dist/query-DQQ-PgGW.js +724 -0
- package/dist/query-DQQ-PgGW.js.map +1 -0
- package/dist/query-DleaAa4_.js +734 -0
- package/dist/query-DleaAa4_.js.map +1 -0
- package/dist/query-EzBrnggP.js +721 -0
- package/dist/query-EzBrnggP.js.map +1 -0
- package/dist/query-LVDVZXYz.js +729 -0
- package/dist/query-LVDVZXYz.js.map +1 -0
- package/dist/query-RyqMp8z7.js +697 -0
- package/dist/query-RyqMp8z7.js.map +1 -0
- package/dist/query-UQIzz6l1.js +722 -0
- package/dist/query-UQIzz6l1.js.map +1 -0
- package/dist/query-UzuYEXCD.js +724 -0
- package/dist/query-UzuYEXCD.js.map +1 -0
- package/dist/query-a1sRfDbW.js +739 -0
- package/dist/query-a1sRfDbW.js.map +1 -0
- package/dist/query-dsNEpb6t.js +706 -0
- package/dist/query-dsNEpb6t.js.map +1 -0
- package/dist/query-ur-jCtVr.js +740 -0
- package/dist/query-ur-jCtVr.js.map +1 -0
- package/dist/realtime_db-1gVIBhXB.js +272 -0
- package/dist/realtime_db-1gVIBhXB.js.map +1 -0
- package/dist/realtime_db-B7y4VvqK.js +272 -0
- package/dist/realtime_db-B7y4VvqK.js.map +1 -0
- package/dist/realtime_db-B9p7nVqA.js +272 -0
- package/dist/realtime_db-B9p7nVqA.js.map +1 -0
- package/dist/realtime_db-BGbxIA49.js +272 -0
- package/dist/realtime_db-BGbxIA49.js.map +1 -0
- package/dist/realtime_db-BHcg-hrk.js +272 -0
- package/dist/realtime_db-BHcg-hrk.js.map +1 -0
- package/dist/realtime_db-BNGcb0XU.js +272 -0
- package/dist/realtime_db-BNGcb0XU.js.map +1 -0
- package/dist/realtime_db-BeSfp0TC.js +272 -0
- package/dist/realtime_db-BeSfp0TC.js.map +1 -0
- package/dist/realtime_db-Bqjr53bi.js +272 -0
- package/dist/realtime_db-Bqjr53bi.js.map +1 -0
- package/dist/realtime_db-CC7YVTXO.js +272 -0
- package/dist/realtime_db-CC7YVTXO.js.map +1 -0
- package/dist/realtime_db-CKC01P0a.js +272 -0
- package/dist/realtime_db-CKC01P0a.js.map +1 -0
- package/dist/realtime_db-COWVCIVH.js +272 -0
- package/dist/realtime_db-COWVCIVH.js.map +1 -0
- package/dist/realtime_db-CRzNVBAz.js +272 -0
- package/dist/realtime_db-CRzNVBAz.js.map +1 -0
- package/dist/realtime_db-Cfkgkm9D.js +272 -0
- package/dist/realtime_db-Cfkgkm9D.js.map +1 -0
- package/dist/realtime_db-D3D8n8z1.js +272 -0
- package/dist/realtime_db-D3D8n8z1.js.map +1 -0
- package/dist/realtime_db-DI5Z16wS.js +272 -0
- package/dist/realtime_db-DI5Z16wS.js.map +1 -0
- package/dist/realtime_db-DbLFDG_j.js +272 -0
- package/dist/realtime_db-DbLFDG_j.js.map +1 -0
- package/dist/realtime_db-DiYQbfeA.js +272 -0
- package/dist/realtime_db-DiYQbfeA.js.map +1 -0
- package/dist/realtime_db-DnJ7fr2H.js +272 -0
- package/dist/realtime_db-DnJ7fr2H.js.map +1 -0
- package/dist/realtime_db-DpGFkUHy.js +272 -0
- package/dist/realtime_db-DpGFkUHy.js.map +1 -0
- package/dist/realtime_db-DpZLibPQ.js +272 -0
- package/dist/realtime_db-DpZLibPQ.js.map +1 -0
- package/dist/realtime_db-DwxYj-Si.js +272 -0
- package/dist/realtime_db-DwxYj-Si.js.map +1 -0
- package/dist/realtime_db-F0o5WP5z.js +272 -0
- package/dist/realtime_db-F0o5WP5z.js.map +1 -0
- package/dist/realtime_db-G-9ZPdwx.js +272 -0
- package/dist/realtime_db-G-9ZPdwx.js.map +1 -0
- package/dist/realtime_db-NPtQRElK.js +272 -0
- package/dist/realtime_db-NPtQRElK.js.map +1 -0
- package/dist/realtime_db-Zs7Ox8YY.js +272 -0
- package/dist/realtime_db-Zs7Ox8YY.js.map +1 -0
- package/dist/realtime_db-jQ7mhwvO.js +272 -0
- package/dist/realtime_db-jQ7mhwvO.js.map +1 -0
- package/dist/realtime_db-xIwkcoDg.js +272 -0
- package/dist/realtime_db-xIwkcoDg.js.map +1 -0
- package/dist/src/client/index.d.ts +1 -1
- package/dist/src/client/index.js +3 -3
- package/dist/src/exports/mysql.d.ts +1 -1
- package/dist/src/exports/mysql.js +1 -1
- package/dist/src/exports/postgres.d.ts +1 -1
- package/dist/src/exports/postgres.js +1 -1
- package/dist/src/exports/procedure.d.ts +2 -2
- package/dist/src/exports/procedure.js +1 -1
- package/dist/src/exports/schema-sql.d.ts +1 -1
- package/dist/src/exports/server.d.ts +4 -4
- package/dist/src/exports/server.js +3 -3
- package/dist/src/exports/subscription-manager-worker-entry.js +2 -2
- package/dist/src/exports/types.d.ts +2 -2
- package/dist/src/exports/types.js +1 -1
- package/dist/subscription-worker-5l4qavz7.js +749 -0
- package/dist/subscription-worker-5l4qavz7.js.map +1 -0
- package/dist/subscription-worker-B7sDMXsu.js +749 -0
- package/dist/subscription-worker-B7sDMXsu.js.map +1 -0
- package/dist/subscription-worker-BCXO8Lwm.js +749 -0
- package/dist/subscription-worker-BCXO8Lwm.js.map +1 -0
- package/dist/subscription-worker-BEIjeBhb.js +749 -0
- package/dist/subscription-worker-BEIjeBhb.js.map +1 -0
- package/dist/subscription-worker-BQv_WD7J.js +749 -0
- package/dist/subscription-worker-BQv_WD7J.js.map +1 -0
- package/dist/subscription-worker-Beayghw3.js +749 -0
- package/dist/subscription-worker-Beayghw3.js.map +1 -0
- package/dist/subscription-worker-C4b0RWPI.js +749 -0
- package/dist/subscription-worker-C4b0RWPI.js.map +1 -0
- package/dist/subscription-worker-CFPiS-lO.js +749 -0
- package/dist/subscription-worker-CFPiS-lO.js.map +1 -0
- package/dist/subscription-worker-CKQad7zS.js +749 -0
- package/dist/subscription-worker-CKQad7zS.js.map +1 -0
- package/dist/subscription-worker-CUGSAwmV.js +749 -0
- package/dist/subscription-worker-CUGSAwmV.js.map +1 -0
- package/dist/subscription-worker-CjYVbFq2.js +749 -0
- package/dist/subscription-worker-CjYVbFq2.js.map +1 -0
- package/dist/subscription-worker-Cm-wPcp-.js +749 -0
- package/dist/subscription-worker-Cm-wPcp-.js.map +1 -0
- package/dist/subscription-worker-Cu6-TIg3.js +749 -0
- package/dist/subscription-worker-Cu6-TIg3.js.map +1 -0
- package/dist/subscription-worker-D02vQ0YL.js +749 -0
- package/dist/subscription-worker-D02vQ0YL.js.map +1 -0
- package/dist/subscription-worker-D8TcRMuX.js +749 -0
- package/dist/subscription-worker-D8TcRMuX.js.map +1 -0
- package/dist/subscription-worker-DC9v3_Xn.js +749 -0
- package/dist/subscription-worker-DC9v3_Xn.js.map +1 -0
- package/dist/subscription-worker-DHOkFYtt.js +749 -0
- package/dist/subscription-worker-DHOkFYtt.js.map +1 -0
- package/dist/subscription-worker-DrR2G0UY.js +749 -0
- package/dist/subscription-worker-DrR2G0UY.js.map +1 -0
- package/dist/subscription-worker-Dwdp_WGy.js +749 -0
- package/dist/subscription-worker-Dwdp_WGy.js.map +1 -0
- package/dist/subscription-worker-Dy1rzhyX.js +749 -0
- package/dist/subscription-worker-Dy1rzhyX.js.map +1 -0
- package/dist/subscription-worker-DyOE3VkC.js +749 -0
- package/dist/subscription-worker-DyOE3VkC.js.map +1 -0
- package/dist/subscription-worker-O731E8Bh.js +749 -0
- package/dist/subscription-worker-O731E8Bh.js.map +1 -0
- package/dist/subscription-worker-Sj1M8tbn.js +749 -0
- package/dist/subscription-worker-Sj1M8tbn.js.map +1 -0
- package/dist/subscription-worker-Zrw5q6qO.js +749 -0
- package/dist/subscription-worker-Zrw5q6qO.js.map +1 -0
- package/dist/subscription-worker-exWsillu.js +749 -0
- package/dist/subscription-worker-exWsillu.js.map +1 -0
- package/dist/subscription-worker-pTVrvvmW.js +749 -0
- package/dist/subscription-worker-pTVrvvmW.js.map +1 -0
- package/dist/subscription-worker-zvtbinBF.js +749 -0
- package/dist/subscription-worker-zvtbinBF.js.map +1 -0
- package/dist/types_db-B039N8Em.js +173 -0
- package/dist/types_db-B039N8Em.js.map +1 -0
- package/dist/types_db-NY-7zuhP.js +173 -0
- package/dist/types_db-NY-7zuhP.js.map +1 -0
- package/dist/types_server-6U7QWGuL.d.ts +328 -0
- package/dist/types_server-6U7QWGuL.d.ts.map +1 -0
- package/dist/types_server-B2rOOZ0z.d.ts +328 -0
- package/dist/types_server-B2rOOZ0z.d.ts.map +1 -0
- package/dist/types_server-B49_-V9c.d.ts +328 -0
- package/dist/types_server-B49_-V9c.d.ts.map +1 -0
- package/dist/types_server-BDHd_YTS.d.ts +328 -0
- package/dist/types_server-BDHd_YTS.d.ts.map +1 -0
- package/dist/types_server-BEX-uJc5.d.ts +328 -0
- package/dist/types_server-BEX-uJc5.d.ts.map +1 -0
- package/dist/types_server-BH5h91D0.d.ts +328 -0
- package/dist/types_server-BH5h91D0.d.ts.map +1 -0
- package/dist/types_server-BNuTxu-E.d.ts +328 -0
- package/dist/types_server-BNuTxu-E.d.ts.map +1 -0
- package/dist/types_server-BQ33p2LM.d.ts +328 -0
- package/dist/types_server-BQ33p2LM.d.ts.map +1 -0
- package/dist/types_server-BiXcNKA3.d.ts +328 -0
- package/dist/types_server-BiXcNKA3.d.ts.map +1 -0
- package/dist/types_server-BkbGHQzW.d.ts +328 -0
- package/dist/types_server-BkbGHQzW.d.ts.map +1 -0
- package/dist/types_server-BkeSAZmH.d.ts +328 -0
- package/dist/types_server-BkeSAZmH.d.ts.map +1 -0
- package/dist/types_server-BlpFFYCI.d.ts +328 -0
- package/dist/types_server-BlpFFYCI.d.ts.map +1 -0
- package/dist/types_server-BtvZjizR.d.ts +328 -0
- package/dist/types_server-BtvZjizR.d.ts.map +1 -0
- package/dist/types_server-C38fddo_.d.ts +328 -0
- package/dist/types_server-C38fddo_.d.ts.map +1 -0
- package/dist/types_server-CN02ApQ_.d.ts +328 -0
- package/dist/types_server-CN02ApQ_.d.ts.map +1 -0
- package/dist/types_server-CPd_Fuhq.d.ts +328 -0
- package/dist/types_server-CPd_Fuhq.d.ts.map +1 -0
- package/dist/types_server-Ce4bZgQJ.d.ts +328 -0
- package/dist/types_server-Ce4bZgQJ.d.ts.map +1 -0
- package/dist/types_server-CexXO5sW.d.ts +328 -0
- package/dist/types_server-CexXO5sW.d.ts.map +1 -0
- package/dist/types_server-Cq8HGFGy.d.ts +328 -0
- package/dist/types_server-Cq8HGFGy.d.ts.map +1 -0
- package/dist/types_server-CuHsqi4p.d.ts +328 -0
- package/dist/types_server-CuHsqi4p.d.ts.map +1 -0
- package/dist/types_server-D8PzF-79.d.ts +328 -0
- package/dist/types_server-D8PzF-79.d.ts.map +1 -0
- package/dist/types_server-DB3IrC2o.d.ts +328 -0
- package/dist/types_server-DB3IrC2o.d.ts.map +1 -0
- package/dist/types_server-DUV3oRXr.d.ts +328 -0
- package/dist/types_server-DUV3oRXr.d.ts.map +1 -0
- package/dist/types_server-DYNpoqfL.d.ts +328 -0
- package/dist/types_server-DYNpoqfL.d.ts.map +1 -0
- package/dist/types_server-MkSVQQVM.d.ts +328 -0
- package/dist/types_server-MkSVQQVM.d.ts.map +1 -0
- package/dist/types_server-N_coWvBq.d.ts +328 -0
- package/dist/types_server-N_coWvBq.d.ts.map +1 -0
- package/dist/types_server-XPVdOY-I.d.ts +328 -0
- package/dist/types_server-XPVdOY-I.d.ts.map +1 -0
- package/dist/types_server-eQqn3f_C.d.ts +328 -0
- package/dist/types_server-eQqn3f_C.d.ts.map +1 -0
- package/dist/types_server-hAXcDGD4.d.ts +328 -0
- package/dist/types_server-hAXcDGD4.d.ts.map +1 -0
- package/dist/types_server-sKy9tI8G.d.ts +328 -0
- package/dist/types_server-sKy9tI8G.d.ts.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,749 @@
|
|
|
1
|
+
import { r as supaliveStringify } from "./helper-wGbzz6zo.js";
|
|
2
|
+
import { b as WriteEntrySchema, m as QueryCacheMetadataSchema, n as BigIntSchema, p as QueryCacheEntrySchema, r as CachedPgMetadataSchema, y as ReadEntrySchema } from "./types_db-B039N8Em.js";
|
|
3
|
+
import { i as mapReadSetToRaw, n as checkWriteSetAffectsReadSet, r as evaluateCacheFreshness } from "./overlap-checker-BqR9qCfy.js";
|
|
4
|
+
import { t as MySqlDatabase } from "./mysql-CA7GCR62.js";
|
|
5
|
+
import { t as PgDatabase } from "./postgres-Cwq5EPBg.js";
|
|
6
|
+
import { t as SupaliveDb } from "./realtime_db-DiYQbfeA.js";
|
|
7
|
+
import z from "zod";
|
|
8
|
+
import { v4 } from "uuid";
|
|
9
|
+
import { ExponentialBackoff, handleAll, retry } from "cockatiel";
|
|
10
|
+
import pino from "pino";
|
|
11
|
+
import "pino-pretty";
|
|
12
|
+
import { createHash } from "node:crypto";
|
|
13
|
+
import Redis$1 from "ioredis";
|
|
14
|
+
//#region src/logger.ts
|
|
15
|
+
const appInstanceId = `instance-${v4().slice(0, 8)}`;
|
|
16
|
+
const isProduction = process.env.ENV === "prod";
|
|
17
|
+
const logger$1 = pino({
|
|
18
|
+
level: process.env.LOG_LEVEL || "info",
|
|
19
|
+
timestamp: pino.stdTimeFunctions.isoTime,
|
|
20
|
+
redact: { paths: ["user.password"] },
|
|
21
|
+
transport: isProduction ? void 0 : {
|
|
22
|
+
target: "pino-pretty",
|
|
23
|
+
options: { colorize: true }
|
|
24
|
+
},
|
|
25
|
+
serializers: { "columnsTypes": (map) => {
|
|
26
|
+
if (map instanceof Map) return serializeMapValue(map);
|
|
27
|
+
return map;
|
|
28
|
+
} },
|
|
29
|
+
base: { "srv": appInstanceId }
|
|
30
|
+
});
|
|
31
|
+
function logLevelOf(name) {
|
|
32
|
+
const defaultLogLevel = process.env.DEFAULT_LOG_LEVEL || "info";
|
|
33
|
+
return process.env[name]?.toLowerCase() || defaultLogLevel;
|
|
34
|
+
}
|
|
35
|
+
function serializeMapValue(map) {
|
|
36
|
+
const obj = {};
|
|
37
|
+
for (const [k, v] of map.entries()) {
|
|
38
|
+
obj[k] = {};
|
|
39
|
+
if (v instanceof Map) for (const [innerK, innerV] of v.entries()) obj[k][innerK] = innerV;
|
|
40
|
+
else obj[k] = v;
|
|
41
|
+
}
|
|
42
|
+
return obj;
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/server/retention-watermark.ts
|
|
46
|
+
/** Redis pub/sub channel the sub-manager publishes the retention watermark on
|
|
47
|
+
* after each prune (and at startup). App-server instances subscribe and update
|
|
48
|
+
* their in-memory {@link RetentionWatermark}. Payload is the watermark `ts` as a
|
|
49
|
+
* string. */
|
|
50
|
+
const RETENTION_WATERMARK_CHANNEL = "supalive:retention_watermark";
|
|
51
|
+
/**
|
|
52
|
+
* In-memory holder for the commit-log retention watermark: the oldest commit-log
|
|
53
|
+
* ts still retained after prune (see {@link Database.getMinSnapshotTimestamp}).
|
|
54
|
+
* Read on the hot path by the query-cache freshness check — a plain variable, no
|
|
55
|
+
* per-check Redis/DB round trip. Loaded once at startup from the `metadata`
|
|
56
|
+
* table and kept fresh out-of-band: the sub-manager broadcasts the new watermark
|
|
57
|
+
* (in-process to its workers, over Redis pub/sub to app servers) each time it
|
|
58
|
+
* prunes.
|
|
59
|
+
*
|
|
60
|
+
* `set` is monotonic — the watermark only ever moves forward (pruning never
|
|
61
|
+
* un-deletes rows), so an out-of-order or stale update can never lower it, which
|
|
62
|
+
* keeps the freshness guard on the safe side (an over-estimate only costs an
|
|
63
|
+
* extra recompute; an under-estimate could serve stale data).
|
|
64
|
+
*
|
|
65
|
+
* Initial value is the -1n genesis (not 0), matching `getMinSnapshotTimestamp`
|
|
66
|
+
* and the empty-DB snapshot ts — so before anything is pruned the guard never
|
|
67
|
+
* rejects a genesis-era entry (whose snapshot is -1).
|
|
68
|
+
*/
|
|
69
|
+
var RetentionWatermark = class {
|
|
70
|
+
ts = -1n;
|
|
71
|
+
get() {
|
|
72
|
+
return this.ts;
|
|
73
|
+
}
|
|
74
|
+
set(ts) {
|
|
75
|
+
if (ts > this.ts) this.ts = ts;
|
|
76
|
+
}
|
|
77
|
+
/** Seed from the persisted watermark (metadata table). Returns the current value. */
|
|
78
|
+
async loadFrom(db) {
|
|
79
|
+
this.set(await db.getMinSnapshotTimestamp());
|
|
80
|
+
return this.ts;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region src/server/subscription-manager-types.ts
|
|
85
|
+
const RegisterSubscriptionParamsSchema = z.object({
|
|
86
|
+
/**
|
|
87
|
+
* Caller-computed FNV-1a routing key + identity for this subscription.
|
|
88
|
+
* The sub-manager trusts these values rather than re-deriving them from
|
|
89
|
+
* (queryName, args, queryIdentity); this avoids one stringify+SHA1 per
|
|
90
|
+
* register RPC. Trust is fine: the sub-manager RPC channel is fully
|
|
91
|
+
* internal.
|
|
92
|
+
*/
|
|
93
|
+
subId: z.string(),
|
|
94
|
+
cacheKey: z.string(),
|
|
95
|
+
queryName: z.string(),
|
|
96
|
+
args: z.unknown(),
|
|
97
|
+
/**
|
|
98
|
+
* Segmentation key used in the subId/cacheKey hash. Defaults to the
|
|
99
|
+
* authenticated user's id ("anonymous" when none), unless the
|
|
100
|
+
* procedure overrides it via `QueryConfig.queryIdentity`.
|
|
101
|
+
*/
|
|
102
|
+
queryIdentity: z.string(),
|
|
103
|
+
instanceName: z.string(),
|
|
104
|
+
lastSnapshotTs: BigIntSchema
|
|
105
|
+
});
|
|
106
|
+
const RegisterSubscriptionResultSchema = z.object({
|
|
107
|
+
cacheKey: z.string(),
|
|
108
|
+
recompute: z.boolean(),
|
|
109
|
+
readSet: z.array(ReadEntrySchema),
|
|
110
|
+
version: z.string().optional()
|
|
111
|
+
});
|
|
112
|
+
const RegisterSubscriptionBatchParamsSchema = z.array(RegisterSubscriptionParamsSchema);
|
|
113
|
+
const RegisterSubscriptionBatchResultSchema = z.array(RegisterSubscriptionResultSchema);
|
|
114
|
+
const UpdateSubscriptionReadSetParamsSchema = z.object({
|
|
115
|
+
cacheKey: z.string(),
|
|
116
|
+
subId: z.string(),
|
|
117
|
+
instanceName: z.string(),
|
|
118
|
+
lastSnapshotTs: BigIntSchema,
|
|
119
|
+
readSet: z.array(ReadEntrySchema)
|
|
120
|
+
});
|
|
121
|
+
/**
|
|
122
|
+
* `tracked: false` means the sub-manager has no record of this subId (e.g.
|
|
123
|
+
* a restart wiped state and the caller hasn't re-registered yet). The app
|
|
124
|
+
* server should treat this as a signal to register the sub before retrying.
|
|
125
|
+
*/
|
|
126
|
+
const UpdateSubscriptionReadSetResultSchema = z.object({ tracked: z.boolean() });
|
|
127
|
+
const UnregisterSubscriptionParamsSchema = z.object({
|
|
128
|
+
subId: z.string(),
|
|
129
|
+
instanceName: z.string()
|
|
130
|
+
});
|
|
131
|
+
const UnregisterSubscriptionsParamsSchema = z.array(UnregisterSubscriptionParamsSchema);
|
|
132
|
+
const UnregisterSubscriptionResultSchema = z.object({ ok: z.boolean() });
|
|
133
|
+
const UnregisterSubscriptionsResultSchema = z.array(z.object({ ok: z.boolean() }));
|
|
134
|
+
const InvalidateWritesetParamsSchema = z.object({ writeSet: z.array(WriteEntrySchema) });
|
|
135
|
+
const AffectedSubscriptionSchema = z.object({
|
|
136
|
+
subId: z.string(),
|
|
137
|
+
queryName: z.string(),
|
|
138
|
+
args: z.unknown(),
|
|
139
|
+
cacheKey: z.string(),
|
|
140
|
+
/**
|
|
141
|
+
* Every live instance that currently holds this subId. Routing rules:
|
|
142
|
+
* • If the writer is in this list, it recomputes locally and publishes
|
|
143
|
+
* an `update` to the rest (its own id is filtered by the publisher).
|
|
144
|
+
* • Otherwise the writer broadcasts a `recompute-race` to every entry;
|
|
145
|
+
* receivers race for a Redis lock and the winner recomputes.
|
|
146
|
+
*/
|
|
147
|
+
notifyInstances: z.array(z.string())
|
|
148
|
+
});
|
|
149
|
+
const InvalidateWritesetResultSchema = z.object({ affected: z.array(AffectedSubscriptionSchema) });
|
|
150
|
+
const RegistrationRecordSchema = z.object({
|
|
151
|
+
queryName: z.string(),
|
|
152
|
+
args: z.unknown(),
|
|
153
|
+
queryIdentity: z.string(),
|
|
154
|
+
cacheKey: z.string()
|
|
155
|
+
});
|
|
156
|
+
//#endregion
|
|
157
|
+
//#region src/db/cache.ts
|
|
158
|
+
const logger = logger$1.child({ "name": "CACHE_LAYER" }, { level: logLevelOf("SERVER_LOG_LEVEL") });
|
|
159
|
+
const redisRetryPolicy = retry(handleAll, {
|
|
160
|
+
maxAttempts: 3,
|
|
161
|
+
backoff: new ExponentialBackoff({
|
|
162
|
+
initialDelay: 5,
|
|
163
|
+
maxDelay: 2300,
|
|
164
|
+
exponent: 2
|
|
165
|
+
})
|
|
166
|
+
});
|
|
167
|
+
/** Atomic one-shot recompute write: set data + metadata iff incoming version
|
|
168
|
+
* (ARGV[3]) is not older than the stored one. KEYS: data, meta. */
|
|
169
|
+
const WRITE_DATA_AND_META = `
|
|
170
|
+
local cur = redis.call('GET', KEYS[2])
|
|
171
|
+
if cur then
|
|
172
|
+
local ok, m = pcall(cjson.decode, cur)
|
|
173
|
+
if ok and type(m) == 'table' and m.version and tonumber(ARGV[3]) < tonumber(m.version) then
|
|
174
|
+
return 0
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
redis.call('SET', KEYS[1], ARGV[1], 'EX', tonumber(ARGV[4]))
|
|
178
|
+
redis.call('SET', KEYS[2], ARGV[2], 'EX', tonumber(ARGV[4]))
|
|
179
|
+
return 1`;
|
|
180
|
+
/** Data-only write (subscribe path): set data iff incoming version (ARGV[2]) is
|
|
181
|
+
* not older than the stored metadata's version. KEYS: data, meta. */
|
|
182
|
+
const WRITE_DATA_ONLY = `
|
|
183
|
+
local cur = redis.call('GET', KEYS[2])
|
|
184
|
+
if cur then
|
|
185
|
+
local ok, m = pcall(cjson.decode, cur)
|
|
186
|
+
if ok and type(m) == 'table' and m.version and tonumber(ARGV[2]) < tonumber(m.version) then
|
|
187
|
+
return 0
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
redis.call('SET', KEYS[1], ARGV[1], 'EX', tonumber(ARGV[3]))
|
|
191
|
+
return 1`;
|
|
192
|
+
/** Metadata-only replace (subscription recompute): set meta iff incoming version
|
|
193
|
+
* (ARGV[2]) is not older than the stored one. KEYS: meta. */
|
|
194
|
+
const REPLACE_META = `
|
|
195
|
+
local cur = redis.call('GET', KEYS[1])
|
|
196
|
+
if cur then
|
|
197
|
+
local ok, m = pcall(cjson.decode, cur)
|
|
198
|
+
if ok and type(m) == 'table' and m.version and tonumber(ARGV[2]) < tonumber(m.version) then
|
|
199
|
+
return 0
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
redis.call('SET', KEYS[1], ARGV[1], 'EX', tonumber(ARGV[3]))
|
|
203
|
+
return 1`;
|
|
204
|
+
/** Metadata-only horizon advance (still-fresh subscription): bump lastSnapshotTs
|
|
205
|
+
* ONLY, without recomputing. Applies ARGV[1] iff the new horizon (ARGV[2]) is
|
|
206
|
+
* strictly ahead of the stored one AND no newer computation (stored.version >
|
|
207
|
+
* ARGV[3], the version the caller based its advance on) has landed meanwhile —
|
|
208
|
+
* so an advance never reverts a fresh recompute. KEYS: meta. */
|
|
209
|
+
const ADVANCE_META = `
|
|
210
|
+
local cur = redis.call('GET', KEYS[1])
|
|
211
|
+
if not cur then return 0 end
|
|
212
|
+
local ok, m = pcall(cjson.decode, cur)
|
|
213
|
+
if not ok or type(m) ~= 'table' then return 0 end
|
|
214
|
+
if tonumber(ARGV[2]) <= tonumber(m.lastSnapshotTs) then return 0 end
|
|
215
|
+
if m.version and tonumber(m.version) > tonumber(ARGV[3]) then return 0 end
|
|
216
|
+
redis.call('SET', KEYS[1], ARGV[1], 'EX', tonumber(ARGV[4]))
|
|
217
|
+
return 1`;
|
|
218
|
+
var CacheLayer = class {
|
|
219
|
+
redis;
|
|
220
|
+
ttlSeconds;
|
|
221
|
+
/** Cached EVALSHA digests keyed by Lua source (see evalScript). */
|
|
222
|
+
scriptShaCache = /* @__PURE__ */ new Map();
|
|
223
|
+
constructor(upstash, ttlSeconds = 3600) {
|
|
224
|
+
this.redis = upstash;
|
|
225
|
+
this.ttlSeconds = ttlSeconds;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Run a Lua script via EVALSHA using the script's SHA1 (computed locally — the
|
|
229
|
+
* same digest Redis keys scripts by, so no SCRIPT LOAD round-trip is needed on
|
|
230
|
+
* the hot path). On NOSCRIPT (the script isn't in Redis's cache yet, e.g. first
|
|
231
|
+
* use or after a Redis restart/failover) load it explicitly via SCRIPT LOAD and
|
|
232
|
+
* re-run via EVALSHA — so the script ends up cached server-side and subsequent
|
|
233
|
+
* EVALSHA calls hit. The runtime client is always ioredis (see initCacheLayer).
|
|
234
|
+
*/
|
|
235
|
+
async evalScript(src, keys, args) {
|
|
236
|
+
const redis = this.redis;
|
|
237
|
+
let sha = this.scriptShaCache.get(src);
|
|
238
|
+
if (!sha) {
|
|
239
|
+
sha = createHash("sha1").update(src).digest("hex");
|
|
240
|
+
this.scriptShaCache.set(src, sha);
|
|
241
|
+
}
|
|
242
|
+
return redisRetryPolicy.execute(async () => {
|
|
243
|
+
try {
|
|
244
|
+
return await redis.evalsha(sha, keys.length, ...keys, ...args);
|
|
245
|
+
} catch (err) {
|
|
246
|
+
if (err instanceof Error && err.message.includes("NOSCRIPT")) {
|
|
247
|
+
const loadedSha = await redis.call("SCRIPT", "LOAD", src);
|
|
248
|
+
this.scriptShaCache.set(src, loadedSha);
|
|
249
|
+
return await redis.evalsha(loadedSha, keys.length, ...keys, ...args);
|
|
250
|
+
}
|
|
251
|
+
throw err;
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
/** One-shot recompute: atomically write data + metadata (CAS on version). */
|
|
256
|
+
async setQueryCacheAndMetadataFor(cacheKey, data, metaData, ttlSeconds) {
|
|
257
|
+
const ttl = ttlSeconds ?? this.ttlSeconds;
|
|
258
|
+
const dataJson = supaliveStringify({
|
|
259
|
+
data,
|
|
260
|
+
version: metaData.version
|
|
261
|
+
});
|
|
262
|
+
const metaJson = supaliveStringify(metaData);
|
|
263
|
+
await this.evalScript(WRITE_DATA_AND_META, [this.getQueryCacheDataKey(cacheKey), this.getQeruyCacheMetaKey(cacheKey)], [
|
|
264
|
+
dataJson,
|
|
265
|
+
metaJson,
|
|
266
|
+
metaData.version,
|
|
267
|
+
String(ttl)
|
|
268
|
+
]);
|
|
269
|
+
}
|
|
270
|
+
/** Subscribe path: write the data blob only (CAS against the metadata's
|
|
271
|
+
* version). The metadata is written separately by the sub-worker; the
|
|
272
|
+
* `version` links the two so a divergent pair is detected on read. */
|
|
273
|
+
async setQueryCacheFor(cacheKey, data, version, ttlSeconds) {
|
|
274
|
+
const ttl = ttlSeconds ?? this.ttlSeconds;
|
|
275
|
+
const dataJson = supaliveStringify({
|
|
276
|
+
data,
|
|
277
|
+
version
|
|
278
|
+
});
|
|
279
|
+
await this.evalScript(WRITE_DATA_ONLY, [this.getQueryCacheDataKey(cacheKey), this.getQeruyCacheMetaKey(cacheKey)], [
|
|
280
|
+
dataJson,
|
|
281
|
+
version,
|
|
282
|
+
String(ttl)
|
|
283
|
+
]);
|
|
284
|
+
}
|
|
285
|
+
async getQueryCacheFor(cacheKey) {
|
|
286
|
+
const dataRaw = await redisRetryPolicy.execute(() => this.redis.get(this.getQueryCacheDataKey(cacheKey)));
|
|
287
|
+
if (!dataRaw) return null;
|
|
288
|
+
try {
|
|
289
|
+
const parsed = typeof dataRaw === "string" ? JSON.parse(dataRaw) : dataRaw;
|
|
290
|
+
return QueryCacheEntrySchema.parse(parsed);
|
|
291
|
+
} catch {
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/** Subscription recompute: replace the whole metadata (CAS on version). */
|
|
296
|
+
async replaceQueryCacheMetadata(cacheKey, metaData, ttlSeconds) {
|
|
297
|
+
const ttl = ttlSeconds ?? this.ttlSeconds;
|
|
298
|
+
const metaJson = supaliveStringify(metaData);
|
|
299
|
+
await this.evalScript(REPLACE_META, [this.getQeruyCacheMetaKey(cacheKey)], [
|
|
300
|
+
metaJson,
|
|
301
|
+
metaData.version,
|
|
302
|
+
String(ttl)
|
|
303
|
+
]);
|
|
304
|
+
}
|
|
305
|
+
/** Still-fresh subscription: advance `lastSnapshotTs` only, preserving the
|
|
306
|
+
* data's `version` + `readSet` (no recompute). Monotonic and non-clobbering
|
|
307
|
+
* — see ADVANCE_META. `metaData` carries the new horizon plus the version +
|
|
308
|
+
* readSet the caller read, which the script keeps unless a newer computation
|
|
309
|
+
* has since landed. */
|
|
310
|
+
async advanceQueryCacheMetadata(cacheKey, metaData, ttlSeconds) {
|
|
311
|
+
const ttl = ttlSeconds ?? this.ttlSeconds;
|
|
312
|
+
const metaJson = supaliveStringify(metaData);
|
|
313
|
+
await this.evalScript(ADVANCE_META, [this.getQeruyCacheMetaKey(cacheKey)], [
|
|
314
|
+
metaJson,
|
|
315
|
+
String(metaData.lastSnapshotTs),
|
|
316
|
+
metaData.version,
|
|
317
|
+
String(ttl)
|
|
318
|
+
]);
|
|
319
|
+
}
|
|
320
|
+
async getQueryCacheMetaData(cacheKey) {
|
|
321
|
+
const dataRaw = await redisRetryPolicy.execute(() => this.redis.get(this.getQeruyCacheMetaKey(cacheKey)));
|
|
322
|
+
if (!dataRaw) return null;
|
|
323
|
+
try {
|
|
324
|
+
const parsed = typeof dataRaw === "string" ? JSON.parse(dataRaw) : dataRaw;
|
|
325
|
+
return QueryCacheMetadataSchema.parse(parsed);
|
|
326
|
+
} catch {
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
async persistRegistrationRecord(subId, record) {
|
|
331
|
+
const data = supaliveStringify(record);
|
|
332
|
+
await redisRetryPolicy.execute(() => this.redis.set(this.getRegistrationKey(subId), data));
|
|
333
|
+
}
|
|
334
|
+
async deleteRegistrationRecord(subId) {
|
|
335
|
+
await redisRetryPolicy.execute(() => this.redis.del(this.getRegistrationKey(subId)));
|
|
336
|
+
}
|
|
337
|
+
async deleteRegistrationsRecord(subIds) {
|
|
338
|
+
if (subIds.length === 0) return;
|
|
339
|
+
await redisRetryPolicy.execute(() => this.redis.del(...subIds.map((subId) => this.getRegistrationKey(subId))));
|
|
340
|
+
}
|
|
341
|
+
async fetchRegistrationRecordsBatch(subIds) {
|
|
342
|
+
const result = /* @__PURE__ */ new Map();
|
|
343
|
+
const CHUNK_SIZE = 100;
|
|
344
|
+
for (let i = 0; i < subIds.length; i += CHUNK_SIZE) {
|
|
345
|
+
const chunk = subIds.slice(i, i + CHUNK_SIZE);
|
|
346
|
+
const keys = chunk.map((id) => `sl:reg:${id}`);
|
|
347
|
+
try {
|
|
348
|
+
if (keys.length === 0) continue;
|
|
349
|
+
const rawValues = await redisRetryPolicy.execute(() => this.redis.mget(...keys));
|
|
350
|
+
for (let j = 0; j < chunk.length; j++) {
|
|
351
|
+
const subId = chunk[j];
|
|
352
|
+
const raw = rawValues[j];
|
|
353
|
+
const rawJson = typeof raw === "string" ? JSON.parse(raw) : raw;
|
|
354
|
+
if (!raw) result.set(subId, null);
|
|
355
|
+
else try {
|
|
356
|
+
const parsed = RegistrationRecordSchema.parse(rawJson);
|
|
357
|
+
result.set(subId, parsed);
|
|
358
|
+
} catch {
|
|
359
|
+
logger.error(`Failed to parse sl:reg:${subId} during batch recovery`);
|
|
360
|
+
result.set(subId, null);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
} catch (err) {
|
|
364
|
+
logger.error(err, "Failed to fetch registration records batch");
|
|
365
|
+
for (const subId of chunk) result.set(subId, null);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return result;
|
|
369
|
+
}
|
|
370
|
+
async getCachedTableColumnTypes(key) {
|
|
371
|
+
const dataRaw = await redisRetryPolicy.execute(() => this.redis.get(key));
|
|
372
|
+
if (!dataRaw) return null;
|
|
373
|
+
try {
|
|
374
|
+
const parsed = typeof dataRaw === "string" ? JSON.parse(dataRaw) : dataRaw;
|
|
375
|
+
return CachedPgMetadataSchema.parse(parsed);
|
|
376
|
+
} catch {
|
|
377
|
+
return null;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
async setCachedTableColumnsTypes(key, value) {
|
|
381
|
+
await redisRetryPolicy.execute(() => this.redis.set(key, supaliveStringify(value)));
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Race participant: try to claim `lock:recompute:<subId>:<commitTs>`
|
|
385
|
+
* with `SET NX EX`. The single Redis round-trip both arbitrates and
|
|
386
|
+
* sets a TTL fallback in case the winner crashes mid-recompute.
|
|
387
|
+
*/
|
|
388
|
+
async tryAcquireRecomputeLock(instanceId, subId, commitTs, ttl) {
|
|
389
|
+
const key = `lock:recompute:${subId}:${commitTs}`;
|
|
390
|
+
return redisRetryPolicy.execute(async () => {
|
|
391
|
+
try {
|
|
392
|
+
return await this.redis.set(key, instanceId, "EX", ttl, "NX") === "OK";
|
|
393
|
+
} catch (err) {
|
|
394
|
+
logger.error(err, `Failed to acquire recompute lock ${key}`);
|
|
395
|
+
return false;
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
getRegistrationKey(subId) {
|
|
400
|
+
return `sl:reg:${subId}`;
|
|
401
|
+
}
|
|
402
|
+
getQueryCacheDataKey(cacheKey) {
|
|
403
|
+
return `sl:cache:${cacheKey}`;
|
|
404
|
+
}
|
|
405
|
+
getQeruyCacheMetaKey(cacheKey) {
|
|
406
|
+
return `sl:meta:${cacheKey}`;
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
//#endregion
|
|
410
|
+
//#region src/db/init_db.ts
|
|
411
|
+
/**
|
|
412
|
+
* Current core runtime-bootstrap version. Bump this whenever core needs a new
|
|
413
|
+
* runtime database operation — a data seed, a backfill, or a schema change that
|
|
414
|
+
* must be applied directly at runtime rather than through the migration
|
|
415
|
+
* pipeline. Each increment adds a case to `Database.coreMigrationStatements`.
|
|
416
|
+
*
|
|
417
|
+
* The core *schema* (the `commit_logs`/`metadata` tables and the
|
|
418
|
+
* `global_commit_ts` sequence/counter) is NOT versioned here — it comes from
|
|
419
|
+
* the generated schema (`coreTablesSql` / `generateSchemaSql`), which must be
|
|
420
|
+
* applied to the database BEFORE `initCore` runs.
|
|
421
|
+
*/
|
|
422
|
+
const CORE_VERSION = 1n;
|
|
423
|
+
/**
|
|
424
|
+
* Bring the core runtime state up to {@link CORE_VERSION}. Idempotent and safe
|
|
425
|
+
* to call from every process at startup: a lock-free version read short-circuits
|
|
426
|
+
* the common "already current" case, and the actual migration runs under a
|
|
427
|
+
* cross-process lock with a re-check so only one process applies it.
|
|
428
|
+
*
|
|
429
|
+
* Assumes the core schema already exists (apply the generated schema first);
|
|
430
|
+
* the `metadata` table is where the version and seed rows live.
|
|
431
|
+
*/
|
|
432
|
+
async function initCore(db) {
|
|
433
|
+
if (await db.getCoreVersion() >= 1n) return;
|
|
434
|
+
await db.withCoreInitLock(async (ctx) => {
|
|
435
|
+
const from = await ctx.getVersion();
|
|
436
|
+
if (from >= 1n) return;
|
|
437
|
+
for (let v = from + 1n; v <= CORE_VERSION; v++) {
|
|
438
|
+
const statements = db.coreMigrationStatements(v);
|
|
439
|
+
logger$1.info(`Migrating core schema ${v - 1n} -> ${v} (${statements.length} statements)`);
|
|
440
|
+
for (const sql of statements) await ctx.exec(sql);
|
|
441
|
+
}
|
|
442
|
+
await ctx.setVersion(CORE_VERSION);
|
|
443
|
+
logger$1.info(`Core schema now at version ${CORE_VERSION}`);
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Default and env override for the per-statement DB timeout. PG enforces
|
|
448
|
+
* this via `statement_timeout` (server cancels), MySQL via the per-query
|
|
449
|
+
* `timeout` option (driver issues KILL QUERY). Set 0 to disable.
|
|
450
|
+
*/
|
|
451
|
+
const DB_QUERY_TIMEOUT_MS = Number(process.env.SUPALIVE_DB_QUERY_TIMEOUT_MS ?? 3e4);
|
|
452
|
+
async function initDatabase(options) {
|
|
453
|
+
const impl = createDatabase(options.DbConfig, options.workerId);
|
|
454
|
+
const supaliveDb = SupaliveDb.create({ db: impl });
|
|
455
|
+
await initCore(impl);
|
|
456
|
+
await bootstrapDbTypes(supaliveDb, options.CacheLayer, options.forceBootstrapReload ?? false);
|
|
457
|
+
return supaliveDb;
|
|
458
|
+
}
|
|
459
|
+
function createDatabase(config, workerId) {
|
|
460
|
+
const bindings = { "db": config.type };
|
|
461
|
+
if (workerId) bindings["worker"] = workerId;
|
|
462
|
+
if (config.type === "postgres") return new PgDatabase(logger$1.child(bindings), {
|
|
463
|
+
...config,
|
|
464
|
+
connectionString: config.connectionString,
|
|
465
|
+
min: config.minConnections ?? 0,
|
|
466
|
+
max: config.maxConnections ?? 20,
|
|
467
|
+
connectionTimeoutMillis: config.connectionTimeoutMillis ?? 15e3,
|
|
468
|
+
idleTimeoutMillis: config.idleTimeoutMillis ?? 3e4,
|
|
469
|
+
statement_timeout: DB_QUERY_TIMEOUT_MS > 0 ? DB_QUERY_TIMEOUT_MS : void 0
|
|
470
|
+
});
|
|
471
|
+
else return new MySqlDatabase(logger$1.child(bindings), {
|
|
472
|
+
...config,
|
|
473
|
+
connectionLimit: config.maxConnections ?? 20,
|
|
474
|
+
connectTimeout: config.connectionTimeoutMillis ?? 15e3,
|
|
475
|
+
queueLimit: config.queueLimit ?? 0,
|
|
476
|
+
queryTimeoutMs: DB_QUERY_TIMEOUT_MS
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Eagerly load column types into the apply-path cache at server start.
|
|
481
|
+
* In production, the result is cached in Redis under
|
|
482
|
+
* `supalive:schema:types:${SUPALIVE_SCHEMA_VERSION ?? "v1"}` so other
|
|
483
|
+
* instances starting cold can skip the pg_attribute round-trip. In any
|
|
484
|
+
* other env we go straight to PG every time so local schema iteration
|
|
485
|
+
* is never blocked by stale Redis state. Migrations should publish a
|
|
486
|
+
* `schema:reload` message (see {@link publishSchemaReload}) after
|
|
487
|
+
* applying DDL — every instance picks that up and re-bootstraps.
|
|
488
|
+
*/
|
|
489
|
+
async function bootstrapDbTypes(db, cache, forceReload = false) {
|
|
490
|
+
if (db.impl.dbType === "mysql") return;
|
|
491
|
+
const inProd = process.env.NODE_ENV === "production";
|
|
492
|
+
const key = `supalive:schema:types:${process.env.SUPALIVE_SCHEMA_VERSION ?? "v1"}`;
|
|
493
|
+
try {
|
|
494
|
+
await db.impl.bootstrapColumnTypes({
|
|
495
|
+
cacheKey: key,
|
|
496
|
+
redis: inProd && !forceReload ? cache : void 0
|
|
497
|
+
});
|
|
498
|
+
logger$1.info({ columnsTypes: db.impl.columnTypes }, `Bootstrapped db column types (redis=${inProd}, key=${key})`);
|
|
499
|
+
} catch (err) {
|
|
500
|
+
logger$1.error(err, "Failed to bootstrap db column types");
|
|
501
|
+
throw err;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
function initCacheLayer(config) {
|
|
505
|
+
const redis = new Redis$1(config.upstash.redisUrl, {
|
|
506
|
+
connectTimeout: config.connectionTimeout ?? 15e3,
|
|
507
|
+
maxRetriesPerRequest: config.commandMaxRetries ?? 1,
|
|
508
|
+
keepAlive: 3e3
|
|
509
|
+
});
|
|
510
|
+
const redisSub = config.createSubClient ? new Redis$1(config.upstash.redisUrl, {
|
|
511
|
+
connectTimeout: config.connectionTimeout ?? 15e3,
|
|
512
|
+
maxRetriesPerRequest: config.commandSubMaxRetries ?? 5,
|
|
513
|
+
disableClientInfo: true,
|
|
514
|
+
retryStrategy: (times) => {
|
|
515
|
+
if (times > 5) return null;
|
|
516
|
+
return Math.min(times * 200, 2e3);
|
|
517
|
+
}
|
|
518
|
+
}) : void 0;
|
|
519
|
+
return {
|
|
520
|
+
cacheLayer: new CacheLayer(redis, config.cacheTtlSeconds ?? 3600),
|
|
521
|
+
redisSubClient: redisSub
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
//#endregion
|
|
525
|
+
//#region src/server/subscription-worker.ts
|
|
526
|
+
var SubscriptionWorker = class {
|
|
527
|
+
id;
|
|
528
|
+
subscriptions = /* @__PURE__ */ new Map();
|
|
529
|
+
cache;
|
|
530
|
+
db;
|
|
531
|
+
retentionWatermark = new RetentionWatermark();
|
|
532
|
+
logger;
|
|
533
|
+
constructor(id, cache, db) {
|
|
534
|
+
this.id = id;
|
|
535
|
+
this.cache = cache;
|
|
536
|
+
this.db = db;
|
|
537
|
+
this.logger = logger$1.child({
|
|
538
|
+
name: "SUBS_WRK",
|
|
539
|
+
wid: id
|
|
540
|
+
}, { level: logLevelOf("SUBS_MANAGER_SERVER_LOG_LEVEL") });
|
|
541
|
+
}
|
|
542
|
+
size() {
|
|
543
|
+
return this.subscriptions.size;
|
|
544
|
+
}
|
|
545
|
+
has(subId) {
|
|
546
|
+
return this.subscriptions.has(subId);
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Lowest `lastSnapshotTs` across this worker's subscriptions, or `null`
|
|
550
|
+
* when there are none. Used by the dispatcher to derive a safe prune watermark.
|
|
551
|
+
*/
|
|
552
|
+
minSubscriptionTs() {
|
|
553
|
+
let min = null;
|
|
554
|
+
for (const sub of this.subscriptions.values()) if (min === null || sub.lastSnapshotTs < min) min = sub.lastSnapshotTs;
|
|
555
|
+
return min;
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Seed/repair the persisted retained watermark from the actual oldest retained
|
|
559
|
+
* commit log (`min(ts)`), then load it into memory and broadcast it. Called
|
|
560
|
+
* once at sub-manager startup — the `min(ts)` scan is off the hot path, and
|
|
561
|
+
* it corrects `metadata.min_retained_ts` even for a DB that was pruned before
|
|
562
|
+
* this feature existed. Returns the resulting watermark so the manager can
|
|
563
|
+
* broadcast it to the other workers.
|
|
564
|
+
*/
|
|
565
|
+
async refreshRetentionWatermark() {
|
|
566
|
+
const real = await this.db.getMinCommitLogTs() ?? 0n;
|
|
567
|
+
await this.db.updateMinSnapshotTimestamp(real);
|
|
568
|
+
const persisted = await this.db.getMinSnapshotTimestamp();
|
|
569
|
+
this.retentionWatermark.set(persisted);
|
|
570
|
+
await this.publishRetentionWatermark(persisted);
|
|
571
|
+
return this.retentionWatermark.get();
|
|
572
|
+
}
|
|
573
|
+
/** Adopt a watermark broadcast by the manager (in-process from the pruning
|
|
574
|
+
* worker). Monotonic, so an out-of-order message can't lower it. */
|
|
575
|
+
setRetentionWatermark(ts) {
|
|
576
|
+
this.retentionWatermark.set(ts);
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Prune commit logs older than `minRetainedTs`. Advertises the new watermark FIRST —
|
|
580
|
+
* persist it, bump our in-memory copy, and broadcast it over Redis — and only
|
|
581
|
+
* then deletes, so no reader ever trusts a cache entry whose freshness scan
|
|
582
|
+
* would include rows we're about to remove. Returns rows deleted.
|
|
583
|
+
*/
|
|
584
|
+
async prune(minRetainedTs) {
|
|
585
|
+
await this.db.updateMinSnapshotTimestamp(minRetainedTs);
|
|
586
|
+
this.retentionWatermark.set(minRetainedTs);
|
|
587
|
+
await this.publishRetentionWatermark(minRetainedTs);
|
|
588
|
+
return await this.db.pruneCommitLogsBefore(minRetainedTs);
|
|
589
|
+
}
|
|
590
|
+
/** Broadcast the watermark to app-server instances over Redis pub/sub. Workers in
|
|
591
|
+
* this process get it in-process via {@link setRetentionWatermark}. */
|
|
592
|
+
async publishRetentionWatermark(ts) {
|
|
593
|
+
try {
|
|
594
|
+
await this.cache.redis.publish(RETENTION_WATERMARK_CHANNEL, ts.toString());
|
|
595
|
+
} catch (err) {
|
|
596
|
+
this.logger.error(err, "failed to publish commit-log watermark");
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
async register(params) {
|
|
600
|
+
const { subId, cacheKey, queryName, args, queryIdentity, instanceName, lastSnapshotTs } = params;
|
|
601
|
+
this.logger.info(`registering subscription: ${subId} from ${instanceName}`);
|
|
602
|
+
const existing = this.subscriptions.get(subId);
|
|
603
|
+
if (existing && !existing.timeout) {
|
|
604
|
+
existing.instances.add(instanceName);
|
|
605
|
+
return {
|
|
606
|
+
cacheKey,
|
|
607
|
+
recompute: false,
|
|
608
|
+
readSet: existing.readSet
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
if (existing?.timeout) {
|
|
612
|
+
this.logger.info(`reactivating subscription: ${subId} from: ${instanceName}`);
|
|
613
|
+
clearTimeout(existing.timeout);
|
|
614
|
+
existing.timeout = null;
|
|
615
|
+
}
|
|
616
|
+
const metadata = await this.cache.getQueryCacheMetaData(cacheKey);
|
|
617
|
+
const freshness = await evaluateCacheFreshness(this.db, metadata, lastSnapshotTs, this.retentionWatermark.get());
|
|
618
|
+
let needsRecompute = !freshness.fresh;
|
|
619
|
+
const readSet = freshness.readSet;
|
|
620
|
+
const rawReadSet = freshness.rawReadSet;
|
|
621
|
+
if (!needsRecompute && metadata && lastSnapshotTs > metadata.lastSnapshotTs) this.cache.advanceQueryCacheMetadata(cacheKey, {
|
|
622
|
+
lastSnapshotTs,
|
|
623
|
+
version: metadata.version,
|
|
624
|
+
readSet
|
|
625
|
+
}).catch((err) => this.logger.error(err, `Failed to advance cache metadata for ${cacheKey}`));
|
|
626
|
+
let newSubscription = {
|
|
627
|
+
subId,
|
|
628
|
+
queryName,
|
|
629
|
+
args,
|
|
630
|
+
cacheKey,
|
|
631
|
+
lastSnapshotTs,
|
|
632
|
+
readSet,
|
|
633
|
+
rawReadSet,
|
|
634
|
+
instances: /* @__PURE__ */ new Set([instanceName]),
|
|
635
|
+
timeout: null
|
|
636
|
+
};
|
|
637
|
+
const createdWhileChecking = this.subscriptions.get(subId);
|
|
638
|
+
if (createdWhileChecking) {
|
|
639
|
+
if (createdWhileChecking.timeout) {
|
|
640
|
+
clearTimeout(createdWhileChecking.timeout);
|
|
641
|
+
createdWhileChecking.timeout = null;
|
|
642
|
+
}
|
|
643
|
+
if (createdWhileChecking.lastSnapshotTs > lastSnapshotTs) {
|
|
644
|
+
newSubscription = {
|
|
645
|
+
...newSubscription,
|
|
646
|
+
...createdWhileChecking,
|
|
647
|
+
instances: /* @__PURE__ */ new Set([...createdWhileChecking.instances, instanceName])
|
|
648
|
+
};
|
|
649
|
+
needsRecompute = false;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
this.subscriptions.set(subId, newSubscription);
|
|
653
|
+
this.persistRegistration(subId, {
|
|
654
|
+
queryName,
|
|
655
|
+
args,
|
|
656
|
+
queryIdentity,
|
|
657
|
+
cacheKey
|
|
658
|
+
});
|
|
659
|
+
return {
|
|
660
|
+
cacheKey,
|
|
661
|
+
recompute: needsRecompute,
|
|
662
|
+
readSet,
|
|
663
|
+
version: metadata?.version
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
async updateReadSet(params) {
|
|
667
|
+
const { cacheKey, subId, instanceName, lastSnapshotTs, readSet } = params;
|
|
668
|
+
this.logger.info(`updating subscription readSet: ${subId} from ${instanceName}`);
|
|
669
|
+
const existing = this.subscriptions.get(subId);
|
|
670
|
+
if (!existing) return { tracked: false };
|
|
671
|
+
if (lastSnapshotTs < existing.lastSnapshotTs) return { tracked: true };
|
|
672
|
+
const rawReadSet = mapReadSetToRaw(readSet);
|
|
673
|
+
this.subscriptions.set(subId, {
|
|
674
|
+
...existing,
|
|
675
|
+
readSet,
|
|
676
|
+
rawReadSet,
|
|
677
|
+
lastSnapshotTs
|
|
678
|
+
});
|
|
679
|
+
await this.cache.replaceQueryCacheMetadata(cacheKey, {
|
|
680
|
+
lastSnapshotTs,
|
|
681
|
+
version: String(lastSnapshotTs),
|
|
682
|
+
readSet
|
|
683
|
+
});
|
|
684
|
+
return { tracked: true };
|
|
685
|
+
}
|
|
686
|
+
async unregister(params, jitter = 0) {
|
|
687
|
+
const { subId, instanceName } = params;
|
|
688
|
+
this.logger.info(`unregistering subscription: ${subId} from: ${instanceName}`);
|
|
689
|
+
const sub = this.subscriptions.get(subId);
|
|
690
|
+
if (!sub) return { ok: true };
|
|
691
|
+
if (sub.timeout) clearTimeout(sub.timeout);
|
|
692
|
+
if (sub.instances.size > 1) {
|
|
693
|
+
sub.instances.delete(instanceName);
|
|
694
|
+
return { ok: true };
|
|
695
|
+
}
|
|
696
|
+
this.logger.debug(`scheduling unregister subscription: ${subId} from: ${instanceName} in 15s`);
|
|
697
|
+
sub.timeout = setTimeout(async () => {
|
|
698
|
+
sub.instances.delete(instanceName);
|
|
699
|
+
if (sub.instances.size === 0) {
|
|
700
|
+
this.logger.info(`unregistered subscription: ${subId} from: ${instanceName}`);
|
|
701
|
+
this.subscriptions.delete(subId);
|
|
702
|
+
await this.deleteRegistration(subId);
|
|
703
|
+
}
|
|
704
|
+
}, 15e3 + jitter);
|
|
705
|
+
return { ok: true };
|
|
706
|
+
}
|
|
707
|
+
async unregisters(params) {
|
|
708
|
+
this.logger.info({ subIds: params }, `scheduling unregistering subscriptions`);
|
|
709
|
+
for (const param of params) this.unregister(param, Math.floor(Math.random() * 100));
|
|
710
|
+
return params.map(() => ({ ok: true }));
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* Synchronous, CPU-bound. Scans this worker's slice of subscriptions and
|
|
714
|
+
* returns the ones affected by the writeSet.
|
|
715
|
+
*/
|
|
716
|
+
invalidate(rawWriteSet) {
|
|
717
|
+
const affected = [];
|
|
718
|
+
for (const [, sub] of this.subscriptions) {
|
|
719
|
+
if (sub.instances.size === 0) continue;
|
|
720
|
+
if (!checkWriteSetAffectsReadSet(rawWriteSet, sub.rawReadSet)) continue;
|
|
721
|
+
affected.push({
|
|
722
|
+
subId: sub.subId,
|
|
723
|
+
queryName: sub.queryName,
|
|
724
|
+
args: sub.args,
|
|
725
|
+
cacheKey: sub.cacheKey,
|
|
726
|
+
notifyInstances: Array.from(sub.instances)
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
return affected;
|
|
730
|
+
}
|
|
731
|
+
async persistRegistration(subId, record) {
|
|
732
|
+
try {
|
|
733
|
+
await this.cache.persistRegistrationRecord(subId, record);
|
|
734
|
+
} catch (err) {
|
|
735
|
+
this.logger.error(err, `[worker ${this.id}] Failed to persist registration for ${subId}`);
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
async deleteRegistration(subId) {
|
|
739
|
+
try {
|
|
740
|
+
await this.cache.deleteRegistrationRecord(subId);
|
|
741
|
+
} catch (err) {
|
|
742
|
+
this.logger.error(err, `[worker ${this.id}] Failed to delete registration for ${subId}`);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
};
|
|
746
|
+
//#endregion
|
|
747
|
+
export { RetentionWatermark as C, logger$1 as D, logLevelOf as E, serializeMapValue as O, RETENTION_WATERMARK_CHANNEL as S, isProduction as T, UnregisterSubscriptionResultSchema as _, createDatabase as a, UpdateSubscriptionReadSetParamsSchema as b, initDatabase as c, InvalidateWritesetResultSchema as d, RegisterSubscriptionBatchParamsSchema as f, UnregisterSubscriptionParamsSchema as g, RegisterSubscriptionResultSchema as h, bootstrapDbTypes as i, CacheLayer as l, RegisterSubscriptionParamsSchema as m, CORE_VERSION as n, initCacheLayer as o, RegisterSubscriptionBatchResultSchema as p, DB_QUERY_TIMEOUT_MS as r, initCore as s, SubscriptionWorker as t, InvalidateWritesetParamsSchema as u, UnregisterSubscriptionsParamsSchema as v, appInstanceId as w, UpdateSubscriptionReadSetResultSchema as x, UnregisterSubscriptionsResultSchema as y };
|
|
748
|
+
|
|
749
|
+
//# sourceMappingURL=subscription-worker-DC9v3_Xn.js.map
|