tanstack_start_ts 1.0.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.
Files changed (336) hide show
  1. package/.wrangler/deploy/config.json +1 -0
  2. package/bunfig.toml +6 -0
  3. package/components.json +22 -0
  4. package/config.json +0 -0
  5. package/dist/client/.assetsignore +2 -0
  6. package/dist/client/assets/ProductCard-DbIkJAE-.js +1 -0
  7. package/dist/client/assets/about-AskxOruL.js +1 -0
  8. package/dist/client/assets/admin-BZVcAQM3.js +1 -0
  9. package/dist/client/assets/admin.functions--RdVcuBx.js +1 -0
  10. package/dist/client/assets/admin.login-QgrF_9Fp.js +1 -0
  11. package/dist/client/assets/affiliate-disclosure-BIAsA-HO.js +1 -0
  12. package/dist/client/assets/categories-D0N418mK.js +1 -0
  13. package/dist/client/assets/category._slug-aCaQm14E.js +1 -0
  14. package/dist/client/assets/contact-PhvO-V15.js +1 -0
  15. package/dist/client/assets/faq-BsiHWPM8.js +1 -0
  16. package/dist/client/assets/hero-bg-BP2eVUIX.jpg +0 -0
  17. package/dist/client/assets/index-BU9rnkF3.js +1 -0
  18. package/dist/client/assets/index-BpJWZkva.js +1 -0
  19. package/dist/client/assets/index-vRX-zAyq.js +1 -0
  20. package/dist/client/assets/login-DteE0ZGp.js +1 -0
  21. package/dist/client/assets/logo-pSNfLJQk.png +0 -0
  22. package/dist/client/assets/privacy-B_Pu7040.js +1 -0
  23. package/dist/client/assets/product-links-BkZ41Gv3.js +1 -0
  24. package/dist/client/assets/product._id-BVUysCW-.js +1 -0
  25. package/dist/client/assets/products.functions-cGzRziKO.js +1 -0
  26. package/dist/client/assets/profile-CveRcKq2.js +1 -0
  27. package/dist/client/assets/reset-password-ySEjItX_.js +1 -0
  28. package/dist/client/assets/saved-CHtdQDJF.js +1 -0
  29. package/dist/client/assets/search-CXWfET1y.js +1 -0
  30. package/dist/client/assets/signup-CEx90iuV.js +1 -0
  31. package/dist/client/assets/styles-DrNJG0BO.css +1 -0
  32. package/dist/client/assets/terms-VqJ9kX9b.js +1 -0
  33. package/dist/client/assets/update-password-C-d0ix5e.js +1 -0
  34. package/dist/client/assets/vendor-aria-hidden-DvXkyWUv.js +1 -0
  35. package/dist/client/assets/vendor-class-variance-authority-5VPnzWs2.js +1 -0
  36. package/dist/client/assets/vendor-clsx-B-dksMZM.js +1 -0
  37. package/dist/client/assets/vendor-cookie-es-CS0aJGDi.js +1 -0
  38. package/dist/client/assets/vendor-detect-node-es-l0sNRNKZ.js +1 -0
  39. package/dist/client/assets/vendor-floating-ui-core-BlUy28sp.js +1 -0
  40. package/dist/client/assets/vendor-floating-ui-dom-BxK0hn2R.js +1 -0
  41. package/dist/client/assets/vendor-floating-ui-react-dom-Bas3975S.js +1 -0
  42. package/dist/client/assets/vendor-floating-ui-utils-BfYUAVcw.js +1 -0
  43. package/dist/client/assets/vendor-framer-motion-BMdL-cuX.js +9 -0
  44. package/dist/client/assets/vendor-get-nonce-C-Z93AgS.js +1 -0
  45. package/dist/client/assets/vendor-iceberg-js-tWD4K6Lg.js +1 -0
  46. package/dist/client/assets/vendor-lovable.dev-cloud-auth-js-VuzqtJVg.js +1 -0
  47. package/dist/client/assets/vendor-lucide-react-b5K2fehp.js +1 -0
  48. package/dist/client/assets/vendor-motion-dom-BETJamZt.js +1 -0
  49. package/dist/client/assets/vendor-motion-utils-BuWewJbj.js +1 -0
  50. package/dist/client/assets/vendor-radix-ui-primitive-Dc_FVRD7.js +1 -0
  51. package/dist/client/assets/vendor-radix-ui-react-accordion-C22Rgxe9.js +1 -0
  52. package/dist/client/assets/vendor-radix-ui-react-arrow-DMHj2mKI.js +1 -0
  53. package/dist/client/assets/vendor-radix-ui-react-avatar-CVPBkFXg.js +1 -0
  54. package/dist/client/assets/vendor-radix-ui-react-collapsible-BvM-4sKX.js +1 -0
  55. package/dist/client/assets/vendor-radix-ui-react-collection-D9KtqmHm.js +1 -0
  56. package/dist/client/assets/vendor-radix-ui-react-compose-refs-Cvq0AS8Z.js +1 -0
  57. package/dist/client/assets/vendor-radix-ui-react-context-CAqqn5Nx.js +1 -0
  58. package/dist/client/assets/vendor-radix-ui-react-dialog-DZ01vOLq.js +5 -0
  59. package/dist/client/assets/vendor-radix-ui-react-direction-DxZwNuei.js +1 -0
  60. package/dist/client/assets/vendor-radix-ui-react-dismissable-layer-Dqgrs55Y.js +1 -0
  61. package/dist/client/assets/vendor-radix-ui-react-dropdown-menu-0uzvrqkn.js +1 -0
  62. package/dist/client/assets/vendor-radix-ui-react-focus-guards-DgWoZ-fP.js +1 -0
  63. package/dist/client/assets/vendor-radix-ui-react-focus-scope-BLIu5QaL.js +1 -0
  64. package/dist/client/assets/vendor-radix-ui-react-id-bpga_rLa.js +1 -0
  65. package/dist/client/assets/vendor-radix-ui-react-menu-D0qf2r6_.js +1 -0
  66. package/dist/client/assets/vendor-radix-ui-react-popper-BafIylxU.js +1 -0
  67. package/dist/client/assets/vendor-radix-ui-react-portal-BnAsfNCS.js +1 -0
  68. package/dist/client/assets/vendor-radix-ui-react-presence-C-f3UKQ2.js +1 -0
  69. package/dist/client/assets/vendor-radix-ui-react-primitive-zTHwXNoz.js +1 -0
  70. package/dist/client/assets/vendor-radix-ui-react-roving-focus-jyJB8K2E.js +1 -0
  71. package/dist/client/assets/vendor-radix-ui-react-slot-6LXHJrHl.js +1 -0
  72. package/dist/client/assets/vendor-radix-ui-react-use-callback-ref-E91aPc6s.js +1 -0
  73. package/dist/client/assets/vendor-radix-ui-react-use-controllable-state-Ca3eMtxa.js +1 -0
  74. package/dist/client/assets/vendor-radix-ui-react-use-effect-event-CPeX4A3c.js +1 -0
  75. package/dist/client/assets/vendor-radix-ui-react-use-escape-keydown-7n3YsXFo.js +1 -0
  76. package/dist/client/assets/vendor-radix-ui-react-use-is-hydrated-C1PY1qNv.js +1 -0
  77. package/dist/client/assets/vendor-radix-ui-react-use-layout-effect-B3AcGWPy.js +1 -0
  78. package/dist/client/assets/vendor-radix-ui-react-use-size-CXS04sct.js +1 -0
  79. package/dist/client/assets/vendor-react-dom-BnNs-kzm.js +9 -0
  80. package/dist/client/assets/vendor-react-gJPiVnX5.js +1 -0
  81. package/dist/client/assets/vendor-react-remove-scroll-DHKl-IMP.js +4 -0
  82. package/dist/client/assets/vendor-react-remove-scroll-bar-CSjdInc2.js +38 -0
  83. package/dist/client/assets/vendor-react-style-singleton-BqHpkgXn.js +1 -0
  84. package/dist/client/assets/vendor-scheduler-7OC5HNn7.js +1 -0
  85. package/dist/client/assets/vendor-seroval-B_Fur-nl.js +3 -0
  86. package/dist/client/assets/vendor-seroval-plugins-CBHnPkZJ.js +1 -0
  87. package/dist/client/assets/vendor-sonner-71-LdGG1.js +1 -0
  88. package/dist/client/assets/vendor-supabase-auth-js-DWrN-bIx.js +18 -0
  89. package/dist/client/assets/vendor-supabase-functions-js-uY_V-TxC.js +1 -0
  90. package/dist/client/assets/vendor-supabase-phoenix-BzEf37Ve.js +2 -0
  91. package/dist/client/assets/vendor-supabase-postgrest-js-C4rBWbCx.js +4 -0
  92. package/dist/client/assets/vendor-supabase-realtime-js-D6BlOYKE.js +23 -0
  93. package/dist/client/assets/vendor-supabase-storage-js-BG98L3Zz.js +1 -0
  94. package/dist/client/assets/vendor-supabase-supabase-js-DCCzdwBJ.js +1 -0
  95. package/dist/client/assets/vendor-tailwind-merge-Ct12j0u0.js +1 -0
  96. package/dist/client/assets/vendor-tanstack-history-C617CaxG.js +1 -0
  97. package/dist/client/assets/vendor-tanstack-query-core-7wuJJ5ZL.js +1 -0
  98. package/dist/client/assets/vendor-tanstack-react-query-HImzo8sX.js +1 -0
  99. package/dist/client/assets/vendor-tanstack-react-router-sIZLK-LU.js +1 -0
  100. package/dist/client/assets/vendor-tanstack-react-start-client-GiYCfWmf.js +1 -0
  101. package/dist/client/assets/vendor-tanstack-react-store-EvTi3ahh.js +1 -0
  102. package/dist/client/assets/vendor-tanstack-router-core-Cr7bYUZv.js +1 -0
  103. package/dist/client/assets/vendor-tanstack-start-client-core-C-00BBOu.js +2 -0
  104. package/dist/client/assets/vendor-tanstack-start-fn-stubs-l0sNRNKZ.js +1 -0
  105. package/dist/client/assets/vendor-tanstack-store-BC7mA7pq.js +1 -0
  106. package/dist/client/assets/vendor-tslib-Du-meQkk.js +1 -0
  107. package/dist/client/assets/vendor-use-callback-ref-C_fIAtot.js +1 -0
  108. package/dist/client/assets/vendor-use-sidecar-Bh0DDN6h.js +1 -0
  109. package/dist/client/assets/vendor-use-sync-external-store-ZvKHXaIn.js +1 -0
  110. package/dist/client/assets/vendor-vercel-analytics-DwPM5BWs.js +1 -0
  111. package/dist/client/assets/vendor-zod-By9teAtI.js +1 -0
  112. package/dist/client/robots.txt +2 -0
  113. package/dist/server/.dev.vars +5 -0
  114. package/dist/server/.vite/manifest.json +2528 -0
  115. package/dist/server/assets/ProductCard-CUPXy5Eo.js +149 -0
  116. package/dist/server/assets/_tanstack-start-manifest_v-do7vTWFD.js +4 -0
  117. package/dist/server/assets/about-TfKQw0Ga.js +28 -0
  118. package/dist/server/assets/admin-DspfJOJk.js +578 -0
  119. package/dist/server/assets/admin.functions-B78ppWLR.js +645 -0
  120. package/dist/server/assets/admin.functions-BWlKBoTL.js +93 -0
  121. package/dist/server/assets/admin.login-CV7QfeA6.js +139 -0
  122. package/dist/server/assets/affiliate-disclosure-B1wI1cDb.js +86 -0
  123. package/dist/server/assets/auth-middleware-Cn49MidW.js +62 -0
  124. package/dist/server/assets/categories-Z7jnAYZP.js +108 -0
  125. package/dist/server/assets/category._slug-D0XY3FGK.js +112 -0
  126. package/dist/server/assets/contact-IzyONsXs.js +104 -0
  127. package/dist/server/assets/faq-aRhB_CR3.js +133 -0
  128. package/dist/server/assets/hero-bg-BP2eVUIX.jpg +0 -0
  129. package/dist/server/assets/index-BTPHbXw9.js +221 -0
  130. package/dist/server/assets/index-ByJkHkrU.js +30 -0
  131. package/dist/server/assets/login-Dvy5Dm0f.js +175 -0
  132. package/dist/server/assets/logo-pSNfLJQk.png +0 -0
  133. package/dist/server/assets/privacy-B6Wiez1P.js +93 -0
  134. package/dist/server/assets/product-links-CGYEPP56.js +16 -0
  135. package/dist/server/assets/product._id-BpRa-1z0.js +231 -0
  136. package/dist/server/assets/products.functions-DSlmibYN.js +209 -0
  137. package/dist/server/assets/products.functions-DlHkRiqi.js +24 -0
  138. package/dist/server/assets/profile-B0NWzVAZ.js +314 -0
  139. package/dist/server/assets/reset-password-CY-rmqMr.js +115 -0
  140. package/dist/server/assets/saved-7FA6Dbom.js +126 -0
  141. package/dist/server/assets/search-Yw5c_fZa.js +329 -0
  142. package/dist/server/assets/signup-UPzgZo4i.js +143 -0
  143. package/dist/server/assets/styles-DrNJG0BO.css +1 -0
  144. package/dist/server/assets/terms-CMnX95bP.js +89 -0
  145. package/dist/server/assets/update-password-Cr94ea8n.js +131 -0
  146. package/dist/server/assets/vendor-aria-hidden-DPa16MWu.js +122 -0
  147. package/dist/server/assets/vendor-class-variance-authority-0YxJPB9Y.js +44 -0
  148. package/dist/server/assets/vendor-cloudflare-unenv-preset-ya0VEFBz.js +250 -0
  149. package/dist/server/assets/vendor-clsx-DgYk2OaC.js +16 -0
  150. package/dist/server/assets/vendor-cookie-es-DAoofYiI.js +44 -0
  151. package/dist/server/assets/vendor-detect-node-es-l0sNRNKZ.js +1 -0
  152. package/dist/server/assets/vendor-floating-ui-core-3tkK0THV.js +726 -0
  153. package/dist/server/assets/vendor-floating-ui-dom-C-cPtgJv.js +626 -0
  154. package/dist/server/assets/vendor-floating-ui-react-dom-CRG6gBpH.js +319 -0
  155. package/dist/server/assets/vendor-floating-ui-utils-DmXANH-E.js +320 -0
  156. package/dist/server/assets/vendor-framer-motion-X4zAkX3J.js +1979 -0
  157. package/dist/server/assets/vendor-get-nonce-DiSj3EHl.js +9 -0
  158. package/dist/server/assets/vendor-h3-v2-CCobnLY5.js +287 -0
  159. package/dist/server/assets/vendor-iceberg-js-bHCkXyJn.js +534 -0
  160. package/dist/server/assets/vendor-isbot-CZ7WjwVs.js +21 -0
  161. package/dist/server/assets/vendor-lovable.dev-cloud-auth-js-BE03njZw.js +180 -0
  162. package/dist/server/assets/vendor-lucide-react-Ddew6HYb.js +458 -0
  163. package/dist/server/assets/vendor-motion-dom-D2MTwGIG.js +5983 -0
  164. package/dist/server/assets/vendor-motion-utils-LJlIFN6m.js +161 -0
  165. package/dist/server/assets/vendor-radix-ui-primitive-B-mNdDrH.js +11 -0
  166. package/dist/server/assets/vendor-radix-ui-react-accordion-1Izf6x00.js +308 -0
  167. package/dist/server/assets/vendor-radix-ui-react-arrow-B882lnFK.js +23 -0
  168. package/dist/server/assets/vendor-radix-ui-react-avatar-BVgZt2Ab.js +209 -0
  169. package/dist/server/assets/vendor-radix-ui-react-collapsible-DCBbMZiS.js +147 -0
  170. package/dist/server/assets/vendor-radix-ui-react-collection-BZ2srfgU.js +150 -0
  171. package/dist/server/assets/vendor-radix-ui-react-compose-refs-D3qsKVk1.js +39 -0
  172. package/dist/server/assets/vendor-radix-ui-react-context-BVoNDLue.js +78 -0
  173. package/dist/server/assets/vendor-radix-ui-react-dialog-DlxMaNYK.js +406 -0
  174. package/dist/server/assets/vendor-radix-ui-react-direction-Dt_WDL1t.js +9 -0
  175. package/dist/server/assets/vendor-radix-ui-react-dismissable-layer-CjsuPohV.js +210 -0
  176. package/dist/server/assets/vendor-radix-ui-react-dropdown-menu-DVxKumY8.js +263 -0
  177. package/dist/server/assets/vendor-radix-ui-react-focus-guards-D_6NoePE.js +29 -0
  178. package/dist/server/assets/vendor-radix-ui-react-focus-scope-DEIhTJJH.js +206 -0
  179. package/dist/server/assets/vendor-radix-ui-react-id-DFFpgh6m.js +14 -0
  180. package/dist/server/assets/vendor-radix-ui-react-menu-CiTMLwjT.js +893 -0
  181. package/dist/server/assets/vendor-radix-ui-react-popper-23Ye2Vyc.js +286 -0
  182. package/dist/server/assets/vendor-radix-ui-react-portal-CZCH5uPk.js +16 -0
  183. package/dist/server/assets/vendor-radix-ui-react-presence-CaAULlDU.js +128 -0
  184. package/dist/server/assets/vendor-radix-ui-react-primitive-BeOk3UYa.js +124 -0
  185. package/dist/server/assets/vendor-radix-ui-react-roving-focus-DES9GR8l.js +224 -0
  186. package/dist/server/assets/vendor-radix-ui-react-slot-DUhZbzoH.js +103 -0
  187. package/dist/server/assets/vendor-radix-ui-react-use-callback-ref-BynBgohw.js +11 -0
  188. package/dist/server/assets/vendor-radix-ui-react-use-controllable-state-C9KpT6DG.js +69 -0
  189. package/dist/server/assets/vendor-radix-ui-react-use-effect-event-gpNY2xjS.js +1 -0
  190. package/dist/server/assets/vendor-radix-ui-react-use-escape-keydown-CcYRQ2pp.js +17 -0
  191. package/dist/server/assets/vendor-radix-ui-react-use-is-hydrated-D_LcBPXY.js +15 -0
  192. package/dist/server/assets/vendor-radix-ui-react-use-layout-effect-1LNLXAjr.js +6 -0
  193. package/dist/server/assets/vendor-radix-ui-react-use-size-D6fiKJQo.js +39 -0
  194. package/dist/server/assets/vendor-react-DvBrY0qp.js +511 -0
  195. package/dist/server/assets/vendor-react-dom-yvMLPM0j.js +10484 -0
  196. package/dist/server/assets/vendor-react-remove-scroll-BNtiEvVN.js +328 -0
  197. package/dist/server/assets/vendor-react-remove-scroll-bar-hLqRASRk.js +82 -0
  198. package/dist/server/assets/vendor-react-style-singleton-BXjcXskB.js +69 -0
  199. package/dist/server/assets/vendor-rou3-3NaGPdI8.js +8 -0
  200. package/dist/server/assets/vendor-seroval-dJyC-Zhz.js +1775 -0
  201. package/dist/server/assets/vendor-seroval-plugins-Pq_U2meB.js +58 -0
  202. package/dist/server/assets/vendor-sonner-CqbjhsRh.js +1086 -0
  203. package/dist/server/assets/vendor-srvx-BA-baEX9.js +6 -0
  204. package/dist/server/assets/vendor-supabase-auth-js-D4xjVprw.js +7602 -0
  205. package/dist/server/assets/vendor-supabase-functions-js-sWy4UYn1.js +322 -0
  206. package/dist/server/assets/vendor-supabase-phoenix-Bw3Uh2Nn.js +1777 -0
  207. package/dist/server/assets/vendor-supabase-postgrest-js-AO-BXa7I.js +4938 -0
  208. package/dist/server/assets/vendor-supabase-realtime-js-BtdNgJbm.js +2111 -0
  209. package/dist/server/assets/vendor-supabase-storage-js-Dk_MrPYO.js +2679 -0
  210. package/dist/server/assets/vendor-supabase-supabase-js-D1EEtG3j.js +697 -0
  211. package/dist/server/assets/vendor-tailwind-merge-BHb_obmC.js +3255 -0
  212. package/dist/server/assets/vendor-tanstack-history-C4pKJmkt.js +204 -0
  213. package/dist/server/assets/vendor-tanstack-query-core-PwwTR5ld.js +2552 -0
  214. package/dist/server/assets/vendor-tanstack-react-query-hhHzXAK1.js +190 -0
  215. package/dist/server/assets/vendor-tanstack-react-router-XzqpA65A.js +1120 -0
  216. package/dist/server/assets/vendor-tanstack-react-start-RvWUpvat.js +37 -0
  217. package/dist/server/assets/vendor-tanstack-react-start-client-gpNY2xjS.js +1 -0
  218. package/dist/server/assets/vendor-tanstack-react-start-server-uj_Y9pEN.js +15 -0
  219. package/dist/server/assets/vendor-tanstack-react-store-gpNY2xjS.js +1 -0
  220. package/dist/server/assets/vendor-tanstack-router-core-6wywV3KN.js +4252 -0
  221. package/dist/server/assets/vendor-tanstack-start-client-core-DoOKV2pA.js +1741 -0
  222. package/dist/server/assets/vendor-tanstack-start-fn-stubs-l0sNRNKZ.js +1 -0
  223. package/dist/server/assets/vendor-tanstack-start-server-core-CsAstXv7.js +1421 -0
  224. package/dist/server/assets/vendor-tanstack-start-storage-context-DgH9hIJT.js +17 -0
  225. package/dist/server/assets/vendor-tanstack-store-l0sNRNKZ.js +1 -0
  226. package/dist/server/assets/vendor-tslib-_8ICaZ64.js +67 -0
  227. package/dist/server/assets/vendor-unenv-DUvF4YIF.js +544 -0
  228. package/dist/server/assets/vendor-use-callback-ref-DMFDRvmi.js +66 -0
  229. package/dist/server/assets/vendor-use-sidecar-DG1tHua4.js +106 -0
  230. package/dist/server/assets/vendor-use-sync-external-store-rZ8vi0It.js +64 -0
  231. package/dist/server/assets/vendor-vercel-analytics-oP8BDp0L.js +168 -0
  232. package/dist/server/assets/vendor-zod-BRyQdbC-.js +3580 -0
  233. package/dist/server/index.js +158 -0
  234. package/dist/server/wrangler.json +1 -0
  235. package/enable-powershell.ps1 +7 -0
  236. package/eslint.config.js +41 -0
  237. package/lint.bat +4 -0
  238. package/package.json +95 -0
  239. package/public/robots.txt +2 -0
  240. package/run-npm-build.cjs +20 -0
  241. package/run-npm-build.js +20 -0
  242. package/src/assets/hero-bg.jpg +0 -0
  243. package/src/assets/logo.png +0 -0
  244. package/src/components/scrollsy/Footer.tsx +68 -0
  245. package/src/components/scrollsy/LiveTicker.tsx +31 -0
  246. package/src/components/scrollsy/Logo.tsx +28 -0
  247. package/src/components/scrollsy/Nav.tsx +255 -0
  248. package/src/components/scrollsy/ProductCard.tsx +190 -0
  249. package/src/components/scrollsy/ProductFilters.tsx +226 -0
  250. package/src/components/scrollsy/SupportWidget.tsx +197 -0
  251. package/src/components/ui/accordion.tsx +51 -0
  252. package/src/components/ui/alert-dialog.tsx +115 -0
  253. package/src/components/ui/alert.tsx +49 -0
  254. package/src/components/ui/aspect-ratio.tsx +5 -0
  255. package/src/components/ui/avatar.tsx +47 -0
  256. package/src/components/ui/badge.tsx +32 -0
  257. package/src/components/ui/breadcrumb.tsx +101 -0
  258. package/src/components/ui/button.tsx +49 -0
  259. package/src/components/ui/calendar.tsx +177 -0
  260. package/src/components/ui/card.tsx +55 -0
  261. package/src/components/ui/carousel.tsx +240 -0
  262. package/src/components/ui/chart.tsx +331 -0
  263. package/src/components/ui/checkbox.tsx +26 -0
  264. package/src/components/ui/collapsible.tsx +11 -0
  265. package/src/components/ui/command.tsx +143 -0
  266. package/src/components/ui/context-menu.tsx +187 -0
  267. package/src/components/ui/dialog.tsx +104 -0
  268. package/src/components/ui/drawer.tsx +98 -0
  269. package/src/components/ui/dropdown-menu.tsx +188 -0
  270. package/src/components/ui/form.tsx +171 -0
  271. package/src/components/ui/hover-card.tsx +27 -0
  272. package/src/components/ui/input-otp.tsx +69 -0
  273. package/src/components/ui/input.tsx +22 -0
  274. package/src/components/ui/label.tsx +21 -0
  275. package/src/components/ui/menubar.tsx +229 -0
  276. package/src/components/ui/navigation-menu.tsx +120 -0
  277. package/src/components/ui/pagination.tsx +98 -0
  278. package/src/components/ui/popover.tsx +31 -0
  279. package/src/components/ui/progress.tsx +25 -0
  280. package/src/components/ui/radio-group.tsx +36 -0
  281. package/src/components/ui/resizable.tsx +37 -0
  282. package/src/components/ui/scroll-area.tsx +44 -0
  283. package/src/components/ui/select.tsx +152 -0
  284. package/src/components/ui/separator.tsx +24 -0
  285. package/src/components/ui/sheet.tsx +122 -0
  286. package/src/components/ui/sidebar.tsx +744 -0
  287. package/src/components/ui/skeleton.tsx +7 -0
  288. package/src/components/ui/slider.tsx +23 -0
  289. package/src/components/ui/sonner.tsx +23 -0
  290. package/src/components/ui/switch.tsx +27 -0
  291. package/src/components/ui/table.tsx +94 -0
  292. package/src/components/ui/tabs.tsx +53 -0
  293. package/src/components/ui/textarea.tsx +21 -0
  294. package/src/components/ui/toggle-group.tsx +57 -0
  295. package/src/components/ui/toggle.tsx +42 -0
  296. package/src/components/ui/tooltip.tsx +32 -0
  297. package/src/hooks/use-auth.ts +26 -0
  298. package/src/hooks/use-mobile.tsx +19 -0
  299. package/src/integrations/lovable/index.ts +41 -0
  300. package/src/lib/admin.functions.ts +564 -0
  301. package/src/lib/error-capture.ts +27 -0
  302. package/src/lib/error-page.ts +30 -0
  303. package/src/lib/product-links.ts +39 -0
  304. package/src/lib/products.functions.ts +101 -0
  305. package/src/lib/utils.ts +6 -0
  306. package/src/routeTree.gen.ts +480 -0
  307. package/src/router.tsx +16 -0
  308. package/src/routes/__root.tsx +177 -0
  309. package/src/routes/about.tsx +66 -0
  310. package/src/routes/admin.login.tsx +95 -0
  311. package/src/routes/admin.tsx +811 -0
  312. package/src/routes/affiliate-disclosure.tsx +35 -0
  313. package/src/routes/categories.tsx +57 -0
  314. package/src/routes/category.$slug.tsx +51 -0
  315. package/src/routes/contact.tsx +69 -0
  316. package/src/routes/faq.tsx +63 -0
  317. package/src/routes/index.tsx +269 -0
  318. package/src/routes/login.tsx +160 -0
  319. package/src/routes/privacy.tsx +39 -0
  320. package/src/routes/product.$id.tsx +212 -0
  321. package/src/routes/profile.tsx +393 -0
  322. package/src/routes/reset-password.tsx +71 -0
  323. package/src/routes/saved.tsx +83 -0
  324. package/src/routes/search.tsx +136 -0
  325. package/src/routes/signup.tsx +108 -0
  326. package/src/routes/sitemap[.]xml.ts +34 -0
  327. package/src/routes/terms.tsx +40 -0
  328. package/src/routes/update-password.tsx +91 -0
  329. package/src/server.ts +80 -0
  330. package/src/start.ts +24 -0
  331. package/src/styles.css +333 -0
  332. package/terminal-test-output.txt +1 -0
  333. package/tsconfig.json +27 -0
  334. package/vercel.json +26 -0
  335. package/vite.config.ts +38 -0
  336. package/wrangler.jsonc +7 -0
@@ -0,0 +1,2111 @@
1
+ import { P as Presence, S as Socket } from "./vendor-supabase-phoenix-Bw3Uh2Nn.js";
2
+ class WebSocketFactory {
3
+ /**
4
+ * Static-only utility – prevent instantiation.
5
+ */
6
+ constructor() {
7
+ }
8
+ static detectEnvironment() {
9
+ var _a;
10
+ if (typeof WebSocket !== "undefined") {
11
+ return { type: "native", wsConstructor: WebSocket };
12
+ }
13
+ const gt = globalThis;
14
+ if (typeof globalThis !== "undefined" && typeof gt.WebSocket !== "undefined") {
15
+ return { type: "native", wsConstructor: gt.WebSocket };
16
+ }
17
+ const gl = typeof global !== "undefined" ? global : void 0;
18
+ if (gl && typeof gl.WebSocket !== "undefined") {
19
+ return { type: "native", wsConstructor: gl.WebSocket };
20
+ }
21
+ if (typeof globalThis !== "undefined" && typeof gt.WebSocketPair !== "undefined" && typeof globalThis.WebSocket === "undefined") {
22
+ return {
23
+ type: "cloudflare",
24
+ error: "Cloudflare Workers detected. WebSocket clients are not supported in Cloudflare Workers.",
25
+ workaround: "Use Cloudflare Workers WebSocket API for server-side WebSocket handling, or deploy to a different runtime."
26
+ };
27
+ }
28
+ if (typeof globalThis !== "undefined" && gt.EdgeRuntime || typeof navigator !== "undefined" && ((_a = navigator.userAgent) === null || _a === void 0 ? void 0 : _a.includes("Vercel-Edge"))) {
29
+ return {
30
+ type: "unsupported",
31
+ error: "Edge runtime detected (Vercel Edge/Netlify Edge). WebSockets are not supported in edge functions.",
32
+ workaround: "Use serverless functions or a different deployment target for WebSocket functionality."
33
+ };
34
+ }
35
+ const _process = globalThis["process"];
36
+ if (_process) {
37
+ const processVersions = _process["versions"];
38
+ if (processVersions && processVersions["node"]) {
39
+ const versionString = processVersions["node"];
40
+ const nodeVersion = parseInt(versionString.replace(/^v/, "").split(".")[0]);
41
+ if (nodeVersion >= 22) {
42
+ if (typeof globalThis.WebSocket !== "undefined") {
43
+ return { type: "native", wsConstructor: globalThis.WebSocket };
44
+ }
45
+ return {
46
+ type: "unsupported",
47
+ error: `Node.js ${nodeVersion} detected but native WebSocket not found.`,
48
+ workaround: "Provide a WebSocket implementation via the transport option."
49
+ };
50
+ }
51
+ return {
52
+ type: "unsupported",
53
+ error: `Node.js ${nodeVersion} detected without native WebSocket support.`,
54
+ workaround: 'For Node.js < 22, install "ws" package and provide it via the transport option:\nimport ws from "ws"\nnew RealtimeClient(url, { transport: ws })'
55
+ };
56
+ }
57
+ }
58
+ return {
59
+ type: "unsupported",
60
+ error: "Unknown JavaScript runtime without WebSocket support.",
61
+ workaround: "Ensure you're running in a supported environment (browser, Node.js, Deno) or provide a custom WebSocket implementation."
62
+ };
63
+ }
64
+ /**
65
+ * Returns the best available WebSocket constructor for the current runtime.
66
+ *
67
+ * @category Realtime
68
+ *
69
+ * @example Example with error handling
70
+ * ```ts
71
+ * try {
72
+ * const WS = WebSocketFactory.getWebSocketConstructor()
73
+ * const socket = new WS('wss://example.com/socket')
74
+ * } catch (error) {
75
+ * console.error('WebSocket not available in this environment.', error)
76
+ * }
77
+ * ```
78
+ */
79
+ static getWebSocketConstructor() {
80
+ const env = this.detectEnvironment();
81
+ if (env.wsConstructor) {
82
+ return env.wsConstructor;
83
+ }
84
+ let errorMessage = env.error || "WebSocket not supported in this environment.";
85
+ if (env.workaround) {
86
+ errorMessage += `
87
+
88
+ Suggested solution: ${env.workaround}`;
89
+ }
90
+ throw new Error(errorMessage);
91
+ }
92
+ /**
93
+ * Detects whether the runtime can establish WebSocket connections.
94
+ *
95
+ * @category Realtime
96
+ *
97
+ * @example Example in a Node.js script
98
+ * ```ts
99
+ * if (!WebSocketFactory.isWebSocketSupported()) {
100
+ * console.error('WebSockets are required for this script.')
101
+ * process.exitCode = 1
102
+ * }
103
+ * ```
104
+ */
105
+ static isWebSocketSupported() {
106
+ try {
107
+ const env = this.detectEnvironment();
108
+ return env.type === "native" || env.type === "ws";
109
+ } catch (_a) {
110
+ return false;
111
+ }
112
+ }
113
+ }
114
+ const version = "2.106.1";
115
+ const DEFAULT_VERSION = `realtime-js/${version}`;
116
+ const VSN_1_0_0 = "1.0.0";
117
+ const VSN_2_0_0 = "2.0.0";
118
+ const DEFAULT_VSN = VSN_2_0_0;
119
+ const DEFAULT_TIMEOUT = 1e4;
120
+ const MAX_PUSH_BUFFER_SIZE = 100;
121
+ const CHANNEL_STATES = {
122
+ closed: "closed",
123
+ errored: "errored",
124
+ joined: "joined",
125
+ joining: "joining",
126
+ leaving: "leaving"
127
+ };
128
+ const CHANNEL_EVENTS = {
129
+ close: "phx_close",
130
+ error: "phx_error",
131
+ join: "phx_join",
132
+ leave: "phx_leave",
133
+ access_token: "access_token"
134
+ };
135
+ const CONNECTION_STATE = {
136
+ connecting: "connecting",
137
+ closing: "closing",
138
+ closed: "closed"
139
+ };
140
+ class Serializer {
141
+ constructor(allowedMetadataKeys) {
142
+ this.HEADER_LENGTH = 1;
143
+ this.USER_BROADCAST_PUSH_META_LENGTH = 6;
144
+ this.KINDS = { userBroadcastPush: 3, userBroadcast: 4 };
145
+ this.BINARY_ENCODING = 0;
146
+ this.JSON_ENCODING = 1;
147
+ this.BROADCAST_EVENT = "broadcast";
148
+ this.allowedMetadataKeys = [];
149
+ this.allowedMetadataKeys = allowedMetadataKeys !== null && allowedMetadataKeys !== void 0 ? allowedMetadataKeys : [];
150
+ }
151
+ encode(msg, callback) {
152
+ if (msg.event === this.BROADCAST_EVENT && !(msg.payload instanceof ArrayBuffer) && typeof msg.payload.event === "string") {
153
+ return callback(this._binaryEncodeUserBroadcastPush(msg));
154
+ }
155
+ let payload = [msg.join_ref, msg.ref, msg.topic, msg.event, msg.payload];
156
+ return callback(JSON.stringify(payload));
157
+ }
158
+ _binaryEncodeUserBroadcastPush(message) {
159
+ var _a;
160
+ if (this._isArrayBuffer((_a = message.payload) === null || _a === void 0 ? void 0 : _a.payload)) {
161
+ return this._encodeBinaryUserBroadcastPush(message);
162
+ } else {
163
+ return this._encodeJsonUserBroadcastPush(message);
164
+ }
165
+ }
166
+ _encodeBinaryUserBroadcastPush(message) {
167
+ var _a, _b;
168
+ const userPayload = (_b = (_a = message.payload) === null || _a === void 0 ? void 0 : _a.payload) !== null && _b !== void 0 ? _b : new ArrayBuffer(0);
169
+ return this._encodeUserBroadcastPush(message, this.BINARY_ENCODING, userPayload);
170
+ }
171
+ _encodeJsonUserBroadcastPush(message) {
172
+ var _a, _b;
173
+ const userPayload = (_b = (_a = message.payload) === null || _a === void 0 ? void 0 : _a.payload) !== null && _b !== void 0 ? _b : {};
174
+ const encoder = new TextEncoder();
175
+ const encodedUserPayload = encoder.encode(JSON.stringify(userPayload)).buffer;
176
+ return this._encodeUserBroadcastPush(message, this.JSON_ENCODING, encodedUserPayload);
177
+ }
178
+ _encodeUserBroadcastPush(message, encodingType, encodedPayload) {
179
+ var _a, _b;
180
+ const topic = message.topic;
181
+ const ref = (_a = message.ref) !== null && _a !== void 0 ? _a : "";
182
+ const joinRef = (_b = message.join_ref) !== null && _b !== void 0 ? _b : "";
183
+ const userEvent = message.payload.event;
184
+ const rest = this.allowedMetadataKeys ? this._pick(message.payload, this.allowedMetadataKeys) : {};
185
+ const metadata = Object.keys(rest).length === 0 ? "" : JSON.stringify(rest);
186
+ if (joinRef.length > 255) {
187
+ throw new Error(`joinRef length ${joinRef.length} exceeds maximum of 255`);
188
+ }
189
+ if (ref.length > 255) {
190
+ throw new Error(`ref length ${ref.length} exceeds maximum of 255`);
191
+ }
192
+ if (topic.length > 255) {
193
+ throw new Error(`topic length ${topic.length} exceeds maximum of 255`);
194
+ }
195
+ if (userEvent.length > 255) {
196
+ throw new Error(`userEvent length ${userEvent.length} exceeds maximum of 255`);
197
+ }
198
+ if (metadata.length > 255) {
199
+ throw new Error(`metadata length ${metadata.length} exceeds maximum of 255`);
200
+ }
201
+ const metaLength = this.USER_BROADCAST_PUSH_META_LENGTH + joinRef.length + ref.length + topic.length + userEvent.length + metadata.length;
202
+ const header = new ArrayBuffer(this.HEADER_LENGTH + metaLength);
203
+ let view = new DataView(header);
204
+ let offset = 0;
205
+ view.setUint8(offset++, this.KINDS.userBroadcastPush);
206
+ view.setUint8(offset++, joinRef.length);
207
+ view.setUint8(offset++, ref.length);
208
+ view.setUint8(offset++, topic.length);
209
+ view.setUint8(offset++, userEvent.length);
210
+ view.setUint8(offset++, metadata.length);
211
+ view.setUint8(offset++, encodingType);
212
+ Array.from(joinRef, (char) => view.setUint8(offset++, char.charCodeAt(0)));
213
+ Array.from(ref, (char) => view.setUint8(offset++, char.charCodeAt(0)));
214
+ Array.from(topic, (char) => view.setUint8(offset++, char.charCodeAt(0)));
215
+ Array.from(userEvent, (char) => view.setUint8(offset++, char.charCodeAt(0)));
216
+ Array.from(metadata, (char) => view.setUint8(offset++, char.charCodeAt(0)));
217
+ var combined = new Uint8Array(header.byteLength + encodedPayload.byteLength);
218
+ combined.set(new Uint8Array(header), 0);
219
+ combined.set(new Uint8Array(encodedPayload), header.byteLength);
220
+ return combined.buffer;
221
+ }
222
+ decode(rawPayload, callback) {
223
+ if (this._isArrayBuffer(rawPayload)) {
224
+ let result = this._binaryDecode(rawPayload);
225
+ return callback(result);
226
+ }
227
+ if (typeof rawPayload === "string") {
228
+ const jsonPayload = JSON.parse(rawPayload);
229
+ const [join_ref, ref, topic, event, payload] = jsonPayload;
230
+ return callback({ join_ref, ref, topic, event, payload });
231
+ }
232
+ return callback({});
233
+ }
234
+ _binaryDecode(buffer) {
235
+ const view = new DataView(buffer);
236
+ const kind = view.getUint8(0);
237
+ const decoder = new TextDecoder();
238
+ switch (kind) {
239
+ case this.KINDS.userBroadcast:
240
+ return this._decodeUserBroadcast(buffer, view, decoder);
241
+ }
242
+ }
243
+ _decodeUserBroadcast(buffer, view, decoder) {
244
+ const topicSize = view.getUint8(1);
245
+ const userEventSize = view.getUint8(2);
246
+ const metadataSize = view.getUint8(3);
247
+ const payloadEncoding = view.getUint8(4);
248
+ let offset = this.HEADER_LENGTH + 4;
249
+ const topic = decoder.decode(buffer.slice(offset, offset + topicSize));
250
+ offset = offset + topicSize;
251
+ const userEvent = decoder.decode(buffer.slice(offset, offset + userEventSize));
252
+ offset = offset + userEventSize;
253
+ const metadata = decoder.decode(buffer.slice(offset, offset + metadataSize));
254
+ offset = offset + metadataSize;
255
+ const payload = buffer.slice(offset, buffer.byteLength);
256
+ const parsedPayload = payloadEncoding === this.JSON_ENCODING ? JSON.parse(decoder.decode(payload)) : payload;
257
+ const data = {
258
+ type: this.BROADCAST_EVENT,
259
+ event: userEvent,
260
+ payload: parsedPayload
261
+ };
262
+ if (metadataSize > 0) {
263
+ data["meta"] = JSON.parse(metadata);
264
+ }
265
+ return { join_ref: null, ref: null, topic, event: this.BROADCAST_EVENT, payload: data };
266
+ }
267
+ _isArrayBuffer(buffer) {
268
+ var _a;
269
+ return buffer instanceof ArrayBuffer || ((_a = buffer === null || buffer === void 0 ? void 0 : buffer.constructor) === null || _a === void 0 ? void 0 : _a.name) === "ArrayBuffer";
270
+ }
271
+ _pick(obj, keys) {
272
+ if (!obj || typeof obj !== "object") {
273
+ return {};
274
+ }
275
+ return Object.fromEntries(Object.entries(obj).filter(([key]) => keys.includes(key)));
276
+ }
277
+ }
278
+ var PostgresTypes;
279
+ (function(PostgresTypes2) {
280
+ PostgresTypes2["abstime"] = "abstime";
281
+ PostgresTypes2["bool"] = "bool";
282
+ PostgresTypes2["date"] = "date";
283
+ PostgresTypes2["daterange"] = "daterange";
284
+ PostgresTypes2["float4"] = "float4";
285
+ PostgresTypes2["float8"] = "float8";
286
+ PostgresTypes2["int2"] = "int2";
287
+ PostgresTypes2["int4"] = "int4";
288
+ PostgresTypes2["int4range"] = "int4range";
289
+ PostgresTypes2["int8"] = "int8";
290
+ PostgresTypes2["int8range"] = "int8range";
291
+ PostgresTypes2["json"] = "json";
292
+ PostgresTypes2["jsonb"] = "jsonb";
293
+ PostgresTypes2["money"] = "money";
294
+ PostgresTypes2["numeric"] = "numeric";
295
+ PostgresTypes2["oid"] = "oid";
296
+ PostgresTypes2["reltime"] = "reltime";
297
+ PostgresTypes2["text"] = "text";
298
+ PostgresTypes2["time"] = "time";
299
+ PostgresTypes2["timestamp"] = "timestamp";
300
+ PostgresTypes2["timestamptz"] = "timestamptz";
301
+ PostgresTypes2["timetz"] = "timetz";
302
+ PostgresTypes2["tsrange"] = "tsrange";
303
+ PostgresTypes2["tstzrange"] = "tstzrange";
304
+ })(PostgresTypes || (PostgresTypes = {}));
305
+ const convertChangeData = (columns, record, options = {}) => {
306
+ var _a;
307
+ const skipTypes = (_a = options.skipTypes) !== null && _a !== void 0 ? _a : [];
308
+ if (!record) {
309
+ return {};
310
+ }
311
+ return Object.keys(record).reduce((acc, rec_key) => {
312
+ acc[rec_key] = convertColumn(rec_key, columns, record, skipTypes);
313
+ return acc;
314
+ }, {});
315
+ };
316
+ const convertColumn = (columnName, columns, record, skipTypes) => {
317
+ const column = columns.find((x) => x.name === columnName);
318
+ const colType = column === null || column === void 0 ? void 0 : column.type;
319
+ const value = record[columnName];
320
+ if (colType && !skipTypes.includes(colType)) {
321
+ return convertCell(colType, value);
322
+ }
323
+ return noop(value);
324
+ };
325
+ const convertCell = (type, value) => {
326
+ if (type.charAt(0) === "_") {
327
+ const dataType = type.slice(1, type.length);
328
+ return toArray(value, dataType);
329
+ }
330
+ switch (type) {
331
+ case PostgresTypes.bool:
332
+ return toBoolean(value);
333
+ case PostgresTypes.float4:
334
+ case PostgresTypes.float8:
335
+ case PostgresTypes.int2:
336
+ case PostgresTypes.int4:
337
+ case PostgresTypes.int8:
338
+ case PostgresTypes.numeric:
339
+ case PostgresTypes.oid:
340
+ return toNumber(value);
341
+ case PostgresTypes.json:
342
+ case PostgresTypes.jsonb:
343
+ return toJson(value);
344
+ case PostgresTypes.timestamp:
345
+ return toTimestampString(value);
346
+ // Format to be consistent with PostgREST
347
+ case PostgresTypes.abstime:
348
+ // To allow users to cast it based on Timezone
349
+ case PostgresTypes.date:
350
+ // To allow users to cast it based on Timezone
351
+ case PostgresTypes.daterange:
352
+ case PostgresTypes.int4range:
353
+ case PostgresTypes.int8range:
354
+ case PostgresTypes.money:
355
+ case PostgresTypes.reltime:
356
+ // To allow users to cast it based on Timezone
357
+ case PostgresTypes.text:
358
+ case PostgresTypes.time:
359
+ // To allow users to cast it based on Timezone
360
+ case PostgresTypes.timestamptz:
361
+ // To allow users to cast it based on Timezone
362
+ case PostgresTypes.timetz:
363
+ // To allow users to cast it based on Timezone
364
+ case PostgresTypes.tsrange:
365
+ case PostgresTypes.tstzrange:
366
+ return noop(value);
367
+ default:
368
+ return noop(value);
369
+ }
370
+ };
371
+ const noop = (value) => {
372
+ return value;
373
+ };
374
+ const toBoolean = (value) => {
375
+ switch (value) {
376
+ case "t":
377
+ return true;
378
+ case "f":
379
+ return false;
380
+ default:
381
+ return value;
382
+ }
383
+ };
384
+ const toNumber = (value) => {
385
+ if (typeof value === "string") {
386
+ const parsedValue = parseFloat(value);
387
+ if (!Number.isNaN(parsedValue)) {
388
+ return parsedValue;
389
+ }
390
+ }
391
+ return value;
392
+ };
393
+ const toJson = (value) => {
394
+ if (typeof value === "string") {
395
+ try {
396
+ return JSON.parse(value);
397
+ } catch (_a) {
398
+ return value;
399
+ }
400
+ }
401
+ return value;
402
+ };
403
+ const toArray = (value, type) => {
404
+ if (typeof value !== "string") {
405
+ return value;
406
+ }
407
+ const lastIdx = value.length - 1;
408
+ const closeBrace = value[lastIdx];
409
+ const openBrace = value[0];
410
+ if (openBrace === "{" && closeBrace === "}") {
411
+ let arr;
412
+ const valTrim = value.slice(1, lastIdx);
413
+ try {
414
+ arr = JSON.parse("[" + valTrim + "]");
415
+ } catch (_) {
416
+ arr = valTrim ? valTrim.split(",") : [];
417
+ }
418
+ return arr.map((val) => convertCell(type, val));
419
+ }
420
+ return value;
421
+ };
422
+ const toTimestampString = (value) => {
423
+ if (typeof value === "string") {
424
+ return value.replace(" ", "T");
425
+ }
426
+ return value;
427
+ };
428
+ const httpEndpointURL = (socketUrl) => {
429
+ const wsUrl = new URL(socketUrl);
430
+ wsUrl.protocol = wsUrl.protocol.replace(/^ws/i, "http");
431
+ wsUrl.pathname = wsUrl.pathname.replace(/\/+$/, "").replace(/\/socket\/websocket$/i, "").replace(/\/socket$/i, "").replace(/\/websocket$/i, "");
432
+ if (wsUrl.pathname === "" || wsUrl.pathname === "/") {
433
+ wsUrl.pathname = "/api/broadcast";
434
+ } else {
435
+ wsUrl.pathname = wsUrl.pathname + "/api/broadcast";
436
+ }
437
+ return wsUrl.href;
438
+ };
439
+ class PresenceAdapter {
440
+ constructor(channel, opts) {
441
+ const phoenixOptions = phoenixPresenceOptions(opts);
442
+ this.presence = new Presence(channel.getChannel(), phoenixOptions);
443
+ this.presence.onJoin((key, currentPresence, newPresence) => {
444
+ const onJoinPayload = PresenceAdapter.onJoinPayload(key, currentPresence, newPresence);
445
+ channel.getChannel().trigger("presence", onJoinPayload);
446
+ });
447
+ this.presence.onLeave((key, currentPresence, leftPresence) => {
448
+ const onLeavePayload = PresenceAdapter.onLeavePayload(key, currentPresence, leftPresence);
449
+ channel.getChannel().trigger("presence", onLeavePayload);
450
+ });
451
+ this.presence.onSync(() => {
452
+ channel.getChannel().trigger("presence", { event: "sync" });
453
+ });
454
+ }
455
+ get state() {
456
+ return PresenceAdapter.transformState(this.presence.state);
457
+ }
458
+ /**
459
+ * @private
460
+ * Remove 'metas' key
461
+ * Change 'phx_ref' to 'presence_ref'
462
+ * Remove 'phx_ref' and 'phx_ref_prev'
463
+ *
464
+ * @example Transform state
465
+ * // returns {
466
+ * abc123: [
467
+ * { presence_ref: '2', user_id: 1 },
468
+ * { presence_ref: '3', user_id: 2 }
469
+ * ]
470
+ * }
471
+ * RealtimePresence.transformState({
472
+ * abc123: {
473
+ * metas: [
474
+ * { phx_ref: '2', phx_ref_prev: '1' user_id: 1 },
475
+ * { phx_ref: '3', user_id: 2 }
476
+ * ]
477
+ * }
478
+ * })
479
+ *
480
+ */
481
+ static transformState(state) {
482
+ state = cloneState(state);
483
+ return Object.getOwnPropertyNames(state).reduce((newState, key) => {
484
+ const presences = state[key];
485
+ newState[key] = transformState(presences);
486
+ return newState;
487
+ }, {});
488
+ }
489
+ static onJoinPayload(key, currentPresence, newPresence) {
490
+ const currentPresences = parseCurrentPresences(currentPresence);
491
+ const newPresences = transformState(newPresence);
492
+ return {
493
+ event: "join",
494
+ key,
495
+ currentPresences,
496
+ newPresences
497
+ };
498
+ }
499
+ static onLeavePayload(key, currentPresence, leftPresence) {
500
+ const currentPresences = parseCurrentPresences(currentPresence);
501
+ const leftPresences = transformState(leftPresence);
502
+ return {
503
+ event: "leave",
504
+ key,
505
+ currentPresences,
506
+ leftPresences
507
+ };
508
+ }
509
+ }
510
+ function transformState(presences) {
511
+ return presences.metas.map((presence) => {
512
+ presence["presence_ref"] = presence["phx_ref"];
513
+ delete presence["phx_ref"];
514
+ delete presence["phx_ref_prev"];
515
+ return presence;
516
+ });
517
+ }
518
+ function cloneState(state) {
519
+ return JSON.parse(JSON.stringify(state));
520
+ }
521
+ function phoenixPresenceOptions(opts) {
522
+ return (opts === null || opts === void 0 ? void 0 : opts.events) && { events: opts.events };
523
+ }
524
+ function parseCurrentPresences(currentPresences) {
525
+ return (currentPresences === null || currentPresences === void 0 ? void 0 : currentPresences.metas) ? transformState(currentPresences) : [];
526
+ }
527
+ var REALTIME_PRESENCE_LISTEN_EVENTS;
528
+ (function(REALTIME_PRESENCE_LISTEN_EVENTS2) {
529
+ REALTIME_PRESENCE_LISTEN_EVENTS2["SYNC"] = "sync";
530
+ REALTIME_PRESENCE_LISTEN_EVENTS2["JOIN"] = "join";
531
+ REALTIME_PRESENCE_LISTEN_EVENTS2["LEAVE"] = "leave";
532
+ })(REALTIME_PRESENCE_LISTEN_EVENTS || (REALTIME_PRESENCE_LISTEN_EVENTS = {}));
533
+ class RealtimePresence {
534
+ get state() {
535
+ return this.presenceAdapter.state;
536
+ }
537
+ /**
538
+ * Creates a Presence helper that keeps the local presence state in sync with the server.
539
+ *
540
+ * @param channel - The realtime channel to bind to.
541
+ * @param opts - Optional custom event names, e.g. `{ events: { state: 'state', diff: 'diff' } }`.
542
+ *
543
+ * @category Realtime
544
+ *
545
+ * @example Example for a presence channel
546
+ * ```ts
547
+ * const presence = new RealtimePresence(channel)
548
+ *
549
+ * channel.on('presence', ({ event, key }) => {
550
+ * console.log(`Presence ${event} on ${key}`)
551
+ * })
552
+ * ```
553
+ */
554
+ constructor(channel, opts) {
555
+ this.channel = channel;
556
+ this.presenceAdapter = new PresenceAdapter(this.channel.channelAdapter, opts);
557
+ }
558
+ }
559
+ function normalizeChannelError(reason) {
560
+ if (reason instanceof Error) {
561
+ return reason;
562
+ }
563
+ if (typeof reason === "string") {
564
+ return new Error(reason);
565
+ }
566
+ if (reason && typeof reason === "object") {
567
+ const obj = reason;
568
+ if (typeof obj.code === "number") {
569
+ const detail = typeof obj.reason === "string" && obj.reason ? ` (${obj.reason})` : "";
570
+ return new Error(`socket closed: ${obj.code}${detail}`, { cause: reason });
571
+ }
572
+ return new Error("channel error: transport failure", { cause: reason });
573
+ }
574
+ return new Error("channel error: connection lost");
575
+ }
576
+ class ChannelAdapter {
577
+ constructor(socket, topic, params) {
578
+ const phoenixParams = phoenixChannelParams(params);
579
+ this.channel = socket.getSocket().channel(topic, phoenixParams);
580
+ this.socket = socket;
581
+ }
582
+ get state() {
583
+ return this.channel.state;
584
+ }
585
+ set state(state) {
586
+ this.channel.state = state;
587
+ }
588
+ get joinedOnce() {
589
+ return this.channel.joinedOnce;
590
+ }
591
+ get joinPush() {
592
+ return this.channel.joinPush;
593
+ }
594
+ get rejoinTimer() {
595
+ return this.channel.rejoinTimer;
596
+ }
597
+ on(event, callback) {
598
+ return this.channel.on(event, callback);
599
+ }
600
+ off(event, refNumber) {
601
+ this.channel.off(event, refNumber);
602
+ }
603
+ subscribe(timeout) {
604
+ return this.channel.join(timeout);
605
+ }
606
+ unsubscribe(timeout) {
607
+ return this.channel.leave(timeout);
608
+ }
609
+ teardown() {
610
+ this.channel.teardown();
611
+ }
612
+ onClose(callback) {
613
+ this.channel.onClose(callback);
614
+ }
615
+ onError(callback) {
616
+ return this.channel.onError(callback);
617
+ }
618
+ push(event, payload, timeout) {
619
+ let push;
620
+ try {
621
+ push = this.channel.push(event, payload, timeout);
622
+ } catch (error) {
623
+ throw new Error(`tried to push '${event}' to '${this.channel.topic}' before joining. Use channel.subscribe() before pushing events`);
624
+ }
625
+ if (this.channel.pushBuffer.length > MAX_PUSH_BUFFER_SIZE) {
626
+ const removedPush = this.channel.pushBuffer.shift();
627
+ removedPush.cancelTimeout();
628
+ this.socket.log("channel", `discarded push due to buffer overflow: ${removedPush.event}`, removedPush.payload());
629
+ }
630
+ return push;
631
+ }
632
+ updateJoinPayload(payload) {
633
+ const oldPayload = this.channel.joinPush.payload();
634
+ this.channel.joinPush.payload = () => Object.assign(Object.assign({}, oldPayload), payload);
635
+ }
636
+ canPush() {
637
+ return this.socket.isConnected() && this.state === CHANNEL_STATES.joined;
638
+ }
639
+ isJoined() {
640
+ return this.state === CHANNEL_STATES.joined;
641
+ }
642
+ isJoining() {
643
+ return this.state === CHANNEL_STATES.joining;
644
+ }
645
+ isClosed() {
646
+ return this.state === CHANNEL_STATES.closed;
647
+ }
648
+ isLeaving() {
649
+ return this.state === CHANNEL_STATES.leaving;
650
+ }
651
+ updateFilterBindings(filterBindings) {
652
+ this.channel.filterBindings = filterBindings;
653
+ }
654
+ updatePayloadTransform(callback) {
655
+ this.channel.onMessage = callback;
656
+ }
657
+ /**
658
+ * @internal
659
+ */
660
+ getChannel() {
661
+ return this.channel;
662
+ }
663
+ }
664
+ function phoenixChannelParams(options) {
665
+ return {
666
+ config: Object.assign({
667
+ broadcast: { ack: false, self: false },
668
+ presence: { key: "", enabled: false },
669
+ private: false
670
+ }, options.config)
671
+ };
672
+ }
673
+ var REALTIME_POSTGRES_CHANGES_LISTEN_EVENT;
674
+ (function(REALTIME_POSTGRES_CHANGES_LISTEN_EVENT2) {
675
+ REALTIME_POSTGRES_CHANGES_LISTEN_EVENT2["ALL"] = "*";
676
+ REALTIME_POSTGRES_CHANGES_LISTEN_EVENT2["INSERT"] = "INSERT";
677
+ REALTIME_POSTGRES_CHANGES_LISTEN_EVENT2["UPDATE"] = "UPDATE";
678
+ REALTIME_POSTGRES_CHANGES_LISTEN_EVENT2["DELETE"] = "DELETE";
679
+ })(REALTIME_POSTGRES_CHANGES_LISTEN_EVENT || (REALTIME_POSTGRES_CHANGES_LISTEN_EVENT = {}));
680
+ var REALTIME_LISTEN_TYPES;
681
+ (function(REALTIME_LISTEN_TYPES2) {
682
+ REALTIME_LISTEN_TYPES2["BROADCAST"] = "broadcast";
683
+ REALTIME_LISTEN_TYPES2["PRESENCE"] = "presence";
684
+ REALTIME_LISTEN_TYPES2["POSTGRES_CHANGES"] = "postgres_changes";
685
+ REALTIME_LISTEN_TYPES2["SYSTEM"] = "system";
686
+ })(REALTIME_LISTEN_TYPES || (REALTIME_LISTEN_TYPES = {}));
687
+ var REALTIME_SUBSCRIBE_STATES;
688
+ (function(REALTIME_SUBSCRIBE_STATES2) {
689
+ REALTIME_SUBSCRIBE_STATES2["SUBSCRIBED"] = "SUBSCRIBED";
690
+ REALTIME_SUBSCRIBE_STATES2["TIMED_OUT"] = "TIMED_OUT";
691
+ REALTIME_SUBSCRIBE_STATES2["CLOSED"] = "CLOSED";
692
+ REALTIME_SUBSCRIBE_STATES2["CHANNEL_ERROR"] = "CHANNEL_ERROR";
693
+ })(REALTIME_SUBSCRIBE_STATES || (REALTIME_SUBSCRIBE_STATES = {}));
694
+ class RealtimeChannel {
695
+ get state() {
696
+ return this.channelAdapter.state;
697
+ }
698
+ set state(state) {
699
+ this.channelAdapter.state = state;
700
+ }
701
+ get joinedOnce() {
702
+ return this.channelAdapter.joinedOnce;
703
+ }
704
+ get timeout() {
705
+ return this.socket.timeout;
706
+ }
707
+ get joinPush() {
708
+ return this.channelAdapter.joinPush;
709
+ }
710
+ get rejoinTimer() {
711
+ return this.channelAdapter.rejoinTimer;
712
+ }
713
+ /**
714
+ * Creates a channel that can broadcast messages, sync presence, and listen to Postgres changes.
715
+ *
716
+ * The topic determines which realtime stream you are subscribing to. Config options let you
717
+ * enable acknowledgement for broadcasts, presence tracking, or private channels.
718
+ *
719
+ * @category Realtime
720
+ *
721
+ * @example Using supabase-js (recommended)
722
+ * ```ts
723
+ * import { createClient } from '@supabase/supabase-js'
724
+ *
725
+ * const supabase = createClient('https://xyzcompany.supabase.co', 'your-publishable-key')
726
+ * const channel = supabase.channel('room1')
727
+ * channel
728
+ * .on('broadcast', { event: 'cursor-pos' }, (payload) => console.log(payload))
729
+ * .subscribe()
730
+ * ```
731
+ *
732
+ * @example Standalone import for bundle-sensitive environments
733
+ * ```ts
734
+ * import RealtimeClient from '@supabase/realtime-js'
735
+ *
736
+ * const client = new RealtimeClient('https://xyzcompany.supabase.co/realtime/v1', {
737
+ * params: { apikey: 'your-publishable-key' },
738
+ * })
739
+ * const channel = new RealtimeChannel('realtime:public:messages', { config: {} }, client)
740
+ * ```
741
+ */
742
+ constructor(topic, params = { config: {} }, socket) {
743
+ var _a, _b;
744
+ this.topic = topic;
745
+ this.params = params;
746
+ this.socket = socket;
747
+ this.bindings = {};
748
+ this.subTopic = topic.replace(/^realtime:/i, "");
749
+ this.params.config = Object.assign({
750
+ broadcast: { ack: false, self: false },
751
+ presence: { key: "", enabled: false },
752
+ private: false
753
+ }, params.config);
754
+ this.channelAdapter = new ChannelAdapter(this.socket.socketAdapter, topic, this.params);
755
+ this.presence = new RealtimePresence(this);
756
+ this._onClose(() => {
757
+ this.socket._remove(this);
758
+ });
759
+ this._updateFilterTransform();
760
+ this.broadcastEndpointURL = httpEndpointURL(this.socket.socketAdapter.endPointURL());
761
+ this.private = this.params.config.private || false;
762
+ if (!this.private && ((_b = (_a = this.params.config) === null || _a === void 0 ? void 0 : _a.broadcast) === null || _b === void 0 ? void 0 : _b.replay)) {
763
+ throw new Error(`tried to use replay on public channel '${this.topic}'. It must be a private channel.`);
764
+ }
765
+ }
766
+ /**
767
+ * Subscribe registers your client with the server
768
+ * @category Realtime
769
+ */
770
+ subscribe(callback, timeout = this.timeout) {
771
+ var _a, _b, _c;
772
+ if (!this.socket.isConnected()) {
773
+ this.socket.connect();
774
+ }
775
+ if (this.channelAdapter.isClosed()) {
776
+ const { config: { broadcast, presence, private: isPrivate } } = this.params;
777
+ const postgres_changes = (_b = (_a = this.bindings.postgres_changes) === null || _a === void 0 ? void 0 : _a.map((r) => r.filter)) !== null && _b !== void 0 ? _b : [];
778
+ const presence_enabled = !!this.bindings[REALTIME_LISTEN_TYPES.PRESENCE] && this.bindings[REALTIME_LISTEN_TYPES.PRESENCE].length > 0 || ((_c = this.params.config.presence) === null || _c === void 0 ? void 0 : _c.enabled) === true;
779
+ const accessTokenPayload = {};
780
+ const config = {
781
+ broadcast,
782
+ presence: Object.assign(Object.assign({}, presence), { enabled: presence_enabled }),
783
+ postgres_changes,
784
+ private: isPrivate
785
+ };
786
+ if (this.socket.accessTokenValue) {
787
+ accessTokenPayload.access_token = this.socket.accessTokenValue;
788
+ }
789
+ this._onError((reason) => {
790
+ callback === null || callback === void 0 ? void 0 : callback(REALTIME_SUBSCRIBE_STATES.CHANNEL_ERROR, normalizeChannelError(reason));
791
+ });
792
+ this._onClose(() => callback === null || callback === void 0 ? void 0 : callback(REALTIME_SUBSCRIBE_STATES.CLOSED));
793
+ this.updateJoinPayload(Object.assign({ config }, accessTokenPayload));
794
+ this._updateFilterMessage();
795
+ this.channelAdapter.subscribe(timeout).receive("ok", async ({ postgres_changes: postgres_changes2 }) => {
796
+ if (!this.socket._isManualToken()) {
797
+ this.socket.setAuth();
798
+ }
799
+ if (postgres_changes2 === void 0) {
800
+ callback === null || callback === void 0 ? void 0 : callback(REALTIME_SUBSCRIBE_STATES.SUBSCRIBED);
801
+ return;
802
+ }
803
+ this._updatePostgresBindings(postgres_changes2, callback);
804
+ }).receive("error", (error) => {
805
+ this.state = CHANNEL_STATES.errored;
806
+ const message = Object.values(error).join(", ") || "error";
807
+ callback === null || callback === void 0 ? void 0 : callback(REALTIME_SUBSCRIBE_STATES.CHANNEL_ERROR, new Error(message, { cause: error }));
808
+ }).receive("timeout", () => {
809
+ callback === null || callback === void 0 ? void 0 : callback(REALTIME_SUBSCRIBE_STATES.TIMED_OUT);
810
+ });
811
+ }
812
+ return this;
813
+ }
814
+ _updatePostgresBindings(postgres_changes, callback) {
815
+ var _a;
816
+ const clientPostgresBindings = this.bindings.postgres_changes;
817
+ const bindingsLen = (_a = clientPostgresBindings === null || clientPostgresBindings === void 0 ? void 0 : clientPostgresBindings.length) !== null && _a !== void 0 ? _a : 0;
818
+ const newPostgresBindings = [];
819
+ for (let i = 0; i < bindingsLen; i++) {
820
+ const clientPostgresBinding = clientPostgresBindings[i];
821
+ const { filter: { event, schema, table, filter } } = clientPostgresBinding;
822
+ const serverPostgresFilter = postgres_changes && postgres_changes[i];
823
+ if (serverPostgresFilter && serverPostgresFilter.event === event && RealtimeChannel.isFilterValueEqual(serverPostgresFilter.schema, schema) && RealtimeChannel.isFilterValueEqual(serverPostgresFilter.table, table) && RealtimeChannel.isFilterValueEqual(serverPostgresFilter.filter, filter)) {
824
+ newPostgresBindings.push(Object.assign(Object.assign({}, clientPostgresBinding), { id: serverPostgresFilter.id }));
825
+ } else {
826
+ this.unsubscribe();
827
+ this.state = CHANNEL_STATES.errored;
828
+ callback === null || callback === void 0 ? void 0 : callback(REALTIME_SUBSCRIBE_STATES.CHANNEL_ERROR, new Error("mismatch between server and client bindings for postgres changes"));
829
+ return;
830
+ }
831
+ }
832
+ this.bindings.postgres_changes = newPostgresBindings;
833
+ if (this.state != CHANNEL_STATES.errored && callback) {
834
+ callback(REALTIME_SUBSCRIBE_STATES.SUBSCRIBED);
835
+ }
836
+ }
837
+ /**
838
+ * Returns the current presence state for this channel.
839
+ *
840
+ * The shape is a map keyed by presence key (for example a user id) where each entry contains the
841
+ * tracked metadata for that user.
842
+ *
843
+ * @category Realtime
844
+ */
845
+ presenceState() {
846
+ return this.presence.state;
847
+ }
848
+ /**
849
+ * Sends the supplied payload to the presence tracker so other subscribers can see that this
850
+ * client is online. Use `untrack` to stop broadcasting presence for the same key.
851
+ *
852
+ * @category Realtime
853
+ */
854
+ async track(payload, opts = {}) {
855
+ return await this.send({
856
+ type: "presence",
857
+ event: "track",
858
+ payload
859
+ }, opts.timeout || this.timeout);
860
+ }
861
+ /**
862
+ * Removes the current presence state for this client.
863
+ *
864
+ * @category Realtime
865
+ */
866
+ async untrack(opts = {}) {
867
+ return await this.send({
868
+ type: "presence",
869
+ event: "untrack"
870
+ }, opts);
871
+ }
872
+ /**
873
+ * Listen to realtime events on this channel.
874
+ * @category Realtime
875
+ *
876
+ * @remarks
877
+ * - By default, Broadcast and Presence are enabled for all projects.
878
+ * - By default, listening to database changes is disabled for new projects due to database performance and security concerns. You can turn it on by managing Realtime's [replication](/docs/guides/api#realtime-api-overview).
879
+ * - You can receive the "previous" data for updates and deletes by setting the table's `REPLICA IDENTITY` to `FULL` (e.g., `ALTER TABLE your_table REPLICA IDENTITY FULL;`).
880
+ * - Row level security is not applied to delete statements. When RLS is enabled and replica identity is set to full, only the primary key is sent to clients.
881
+ *
882
+ * @example Listen to broadcast messages
883
+ * ```js
884
+ * const channel = supabase.channel("room1")
885
+ *
886
+ * channel.on("broadcast", { event: "cursor-pos" }, (payload) => {
887
+ * console.log("Cursor position received!", payload);
888
+ * }).subscribe((status) => {
889
+ * if (status === "SUBSCRIBED") {
890
+ * channel.send({
891
+ * type: "broadcast",
892
+ * event: "cursor-pos",
893
+ * payload: { x: Math.random(), y: Math.random() },
894
+ * });
895
+ * }
896
+ * });
897
+ * ```
898
+ *
899
+ * @example Listen to presence sync
900
+ * ```js
901
+ * const channel = supabase.channel('room1')
902
+ * channel
903
+ * .on('presence', { event: 'sync' }, () => {
904
+ * console.log('Synced presence state: ', channel.presenceState())
905
+ * })
906
+ * .subscribe(async (status) => {
907
+ * if (status === 'SUBSCRIBED') {
908
+ * await channel.track({ online_at: new Date().toISOString() })
909
+ * }
910
+ * })
911
+ * ```
912
+ *
913
+ * @example Listen to presence join
914
+ * ```js
915
+ * const channel = supabase.channel('room1')
916
+ * channel
917
+ * .on('presence', { event: 'join' }, ({ newPresences }) => {
918
+ * console.log('Newly joined presences: ', newPresences)
919
+ * })
920
+ * .subscribe(async (status) => {
921
+ * if (status === 'SUBSCRIBED') {
922
+ * await channel.track({ online_at: new Date().toISOString() })
923
+ * }
924
+ * })
925
+ * ```
926
+ *
927
+ * @example Listen to presence leave
928
+ * ```js
929
+ * const channel = supabase.channel('room1')
930
+ * channel
931
+ * .on('presence', { event: 'leave' }, ({ leftPresences }) => {
932
+ * console.log('Newly left presences: ', leftPresences)
933
+ * })
934
+ * .subscribe(async (status) => {
935
+ * if (status === 'SUBSCRIBED') {
936
+ * await channel.track({ online_at: new Date().toISOString() })
937
+ * await channel.untrack()
938
+ * }
939
+ * })
940
+ * ```
941
+ *
942
+ * @example Listen to all database changes
943
+ * ```js
944
+ * supabase
945
+ * .channel('room1')
946
+ * .on('postgres_changes', { event: '*', schema: '*' }, payload => {
947
+ * console.log('Change received!', payload)
948
+ * })
949
+ * .subscribe()
950
+ * ```
951
+ *
952
+ * @example Listen to a specific table
953
+ * ```js
954
+ * supabase
955
+ * .channel('room1')
956
+ * .on('postgres_changes', { event: '*', schema: 'public', table: 'countries' }, payload => {
957
+ * console.log('Change received!', payload)
958
+ * })
959
+ * .subscribe()
960
+ * ```
961
+ *
962
+ * @example Listen to inserts
963
+ * ```js
964
+ * supabase
965
+ * .channel('room1')
966
+ * .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'countries' }, payload => {
967
+ * console.log('Change received!', payload)
968
+ * })
969
+ * .subscribe()
970
+ * ```
971
+ *
972
+ * @exampleDescription Listen to updates
973
+ * By default, Supabase will send only the updated record. If you want to receive the previous values as well you can
974
+ * enable full replication for the table you are listening to:
975
+ *
976
+ * ```sql
977
+ * alter table "your_table" replica identity full;
978
+ * ```
979
+ *
980
+ * @example Listen to updates
981
+ * ```js
982
+ * supabase
983
+ * .channel('room1')
984
+ * .on('postgres_changes', { event: 'UPDATE', schema: 'public', table: 'countries' }, payload => {
985
+ * console.log('Change received!', payload)
986
+ * })
987
+ * .subscribe()
988
+ * ```
989
+ *
990
+ * @exampleDescription Listen to deletes
991
+ * By default, Supabase does not send deleted records. If you want to receive the deleted record you can
992
+ * enable full replication for the table you are listening to:
993
+ *
994
+ * ```sql
995
+ * alter table "your_table" replica identity full;
996
+ * ```
997
+ *
998
+ * @example Listen to deletes
999
+ * ```js
1000
+ * supabase
1001
+ * .channel('room1')
1002
+ * .on('postgres_changes', { event: 'DELETE', schema: 'public', table: 'countries' }, payload => {
1003
+ * console.log('Change received!', payload)
1004
+ * })
1005
+ * .subscribe()
1006
+ * ```
1007
+ *
1008
+ * @exampleDescription Listen to multiple events
1009
+ * You can chain listeners if you want to listen to multiple events for each table.
1010
+ *
1011
+ * @example Listen to multiple events
1012
+ * ```js
1013
+ * supabase
1014
+ * .channel('room1')
1015
+ * .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'countries' }, handleRecordInserted)
1016
+ * .on('postgres_changes', { event: 'DELETE', schema: 'public', table: 'countries' }, handleRecordDeleted)
1017
+ * .subscribe()
1018
+ * ```
1019
+ *
1020
+ * @exampleDescription Listen to row level changes
1021
+ * You can listen to individual rows using the format `{table}:{col}=eq.{val}` - where `{col}` is the column name, and `{val}` is the value which you want to match.
1022
+ *
1023
+ * @example Listen to row level changes
1024
+ * ```js
1025
+ * supabase
1026
+ * .channel('room1')
1027
+ * .on('postgres_changes', { event: 'UPDATE', schema: 'public', table: 'countries', filter: 'id=eq.200' }, handleRecordUpdated)
1028
+ * .subscribe()
1029
+ * ```
1030
+ */
1031
+ on(type, filter, callback) {
1032
+ const stateCheck = this.channelAdapter.isJoined() || this.channelAdapter.isJoining();
1033
+ const typeCheck = type === REALTIME_LISTEN_TYPES.PRESENCE || type === REALTIME_LISTEN_TYPES.POSTGRES_CHANGES;
1034
+ if (stateCheck && typeCheck) {
1035
+ this.socket.log("channel", `cannot add \`${type}\` callbacks for ${this.topic} after \`subscribe()\`.`);
1036
+ throw new Error(`cannot add \`${type}\` callbacks for ${this.topic} after \`subscribe()\`.`);
1037
+ }
1038
+ return this._on(type, filter, callback);
1039
+ }
1040
+ /**
1041
+ * Sends a broadcast message explicitly via REST API.
1042
+ *
1043
+ * This method always uses the REST API endpoint regardless of WebSocket connection state.
1044
+ * Useful when you want to guarantee REST delivery or when gradually migrating from implicit REST fallback.
1045
+ *
1046
+ * @param event The name of the broadcast event
1047
+ * @param payload Payload to be sent (required)
1048
+ * @param opts Options including timeout
1049
+ * @returns Promise resolving to object with success status, and error details if failed
1050
+ *
1051
+ * @category Realtime
1052
+ */
1053
+ async httpSend(event, payload, opts = {}) {
1054
+ var _a;
1055
+ if (payload === void 0 || payload === null) {
1056
+ return Promise.reject(new Error("Payload is required for httpSend()"));
1057
+ }
1058
+ const headers = {
1059
+ apikey: this.socket.apiKey ? this.socket.apiKey : "",
1060
+ "Content-Type": "application/json"
1061
+ };
1062
+ if (this.socket.accessTokenValue) {
1063
+ headers["Authorization"] = `Bearer ${this.socket.accessTokenValue}`;
1064
+ }
1065
+ const options = {
1066
+ method: "POST",
1067
+ headers,
1068
+ body: JSON.stringify({
1069
+ messages: [
1070
+ {
1071
+ topic: this.subTopic,
1072
+ event,
1073
+ payload,
1074
+ private: this.private
1075
+ }
1076
+ ]
1077
+ })
1078
+ };
1079
+ const response = await this._fetchWithTimeout(this.broadcastEndpointURL, options, (_a = opts.timeout) !== null && _a !== void 0 ? _a : this.timeout);
1080
+ if (response.status === 202) {
1081
+ return { success: true };
1082
+ }
1083
+ let errorMessage = response.statusText;
1084
+ try {
1085
+ const errorBody = await response.json();
1086
+ errorMessage = errorBody.error || errorBody.message || errorMessage;
1087
+ } catch (_b) {
1088
+ }
1089
+ return Promise.reject(new Error(errorMessage));
1090
+ }
1091
+ /**
1092
+ * Sends a message into the channel.
1093
+ *
1094
+ * @param args Arguments to send to channel
1095
+ * @param args.type The type of event to send
1096
+ * @param args.event The name of the event being sent
1097
+ * @param args.payload Payload to be sent
1098
+ * @param opts Options to be used during the send process
1099
+ *
1100
+ * @category Realtime
1101
+ *
1102
+ * @remarks
1103
+ * - When using REST you don't need to subscribe to the channel
1104
+ * - REST calls are only available from 2.37.0 onwards
1105
+ * - If you create a channel only to send a REST broadcast, remove it from
1106
+ * the client when the send completes
1107
+ *
1108
+ * @example Send a message via websocket
1109
+ * ```js
1110
+ * const channel = supabase.channel('room1')
1111
+ *
1112
+ * channel.subscribe((status) => {
1113
+ * if (status === 'SUBSCRIBED') {
1114
+ * channel.send({
1115
+ * type: 'broadcast',
1116
+ * event: 'cursor-pos',
1117
+ * payload: { x: Math.random(), y: Math.random() },
1118
+ * })
1119
+ * }
1120
+ * })
1121
+ * ```
1122
+ *
1123
+ * @exampleResponse Send a message via websocket
1124
+ * ```js
1125
+ * ok | timed out | error
1126
+ * ```
1127
+ *
1128
+ * @example Send a message via REST
1129
+ * ```js
1130
+ * const channel = supabase.channel('room1')
1131
+ *
1132
+ * try {
1133
+ * await channel.httpSend('cursor-pos', { x: Math.random(), y: Math.random() })
1134
+ * } finally {
1135
+ * await supabase.removeChannel(channel)
1136
+ * }
1137
+ * ```
1138
+ */
1139
+ async send(args, opts = {}) {
1140
+ var _a, _b;
1141
+ if (!this.channelAdapter.canPush() && args.type === "broadcast") {
1142
+ console.warn("Realtime send() is automatically falling back to REST API. This behavior will be deprecated in the future. Please use httpSend() explicitly for REST delivery.");
1143
+ const { event, payload: endpoint_payload } = args;
1144
+ const headers = {
1145
+ apikey: this.socket.apiKey ? this.socket.apiKey : "",
1146
+ "Content-Type": "application/json"
1147
+ };
1148
+ if (this.socket.accessTokenValue) {
1149
+ headers["Authorization"] = `Bearer ${this.socket.accessTokenValue}`;
1150
+ }
1151
+ const options = {
1152
+ method: "POST",
1153
+ headers,
1154
+ body: JSON.stringify({
1155
+ messages: [
1156
+ {
1157
+ topic: this.subTopic,
1158
+ event,
1159
+ payload: endpoint_payload,
1160
+ private: this.private
1161
+ }
1162
+ ]
1163
+ })
1164
+ };
1165
+ try {
1166
+ const response = await this._fetchWithTimeout(this.broadcastEndpointURL, options, (_a = opts.timeout) !== null && _a !== void 0 ? _a : this.timeout);
1167
+ await ((_b = response.body) === null || _b === void 0 ? void 0 : _b.cancel());
1168
+ return response.ok ? "ok" : "error";
1169
+ } catch (error) {
1170
+ if (error instanceof Error && error.name === "AbortError") {
1171
+ return "timed out";
1172
+ } else {
1173
+ return "error";
1174
+ }
1175
+ }
1176
+ } else {
1177
+ return new Promise((resolve) => {
1178
+ var _a2, _b2, _c;
1179
+ const push = this.channelAdapter.push(args.type, args, opts.timeout || this.timeout);
1180
+ if (args.type === "broadcast" && !((_c = (_b2 = (_a2 = this.params) === null || _a2 === void 0 ? void 0 : _a2.config) === null || _b2 === void 0 ? void 0 : _b2.broadcast) === null || _c === void 0 ? void 0 : _c.ack)) {
1181
+ resolve("ok");
1182
+ }
1183
+ push.receive("ok", () => resolve("ok"));
1184
+ push.receive("error", () => resolve("error"));
1185
+ push.receive("timeout", () => resolve("timed out"));
1186
+ });
1187
+ }
1188
+ }
1189
+ /**
1190
+ * Updates the payload that will be sent the next time the channel joins (reconnects).
1191
+ * Useful for rotating access tokens or updating config without re-creating the channel.
1192
+ *
1193
+ * @category Realtime
1194
+ */
1195
+ updateJoinPayload(payload) {
1196
+ this.channelAdapter.updateJoinPayload(payload);
1197
+ }
1198
+ /**
1199
+ * Leaves the channel.
1200
+ *
1201
+ * Unsubscribes from server events, and instructs channel to terminate on server.
1202
+ * Triggers onClose() hooks.
1203
+ *
1204
+ * To receive leave acknowledgements, use the a `receive` hook to bind to the server ack, ie:
1205
+ * channel.unsubscribe().receive("ok", () => alert("left!") )
1206
+ *
1207
+ * @category Realtime
1208
+ */
1209
+ async unsubscribe(timeout = this.timeout) {
1210
+ return new Promise((resolve) => {
1211
+ this.channelAdapter.unsubscribe(timeout).receive("ok", () => resolve("ok")).receive("timeout", () => resolve("timed out")).receive("error", () => resolve("error"));
1212
+ });
1213
+ }
1214
+ /**
1215
+ * Destroys and stops related timers.
1216
+ *
1217
+ * @category Realtime
1218
+ */
1219
+ teardown() {
1220
+ this.channelAdapter.teardown();
1221
+ }
1222
+ /** @internal */
1223
+ async _fetchWithTimeout(url, options, timeout) {
1224
+ const controller = new AbortController();
1225
+ const id = setTimeout(() => controller.abort(), timeout);
1226
+ const response = await this.socket.fetch(url, Object.assign(Object.assign({}, options), { signal: controller.signal }));
1227
+ clearTimeout(id);
1228
+ return response;
1229
+ }
1230
+ /** @internal */
1231
+ _on(type, filter, callback) {
1232
+ const typeLower = type.toLocaleLowerCase();
1233
+ const ref = this.channelAdapter.on(type, callback);
1234
+ const binding = {
1235
+ type: typeLower,
1236
+ filter,
1237
+ callback,
1238
+ ref
1239
+ };
1240
+ if (this.bindings[typeLower]) {
1241
+ this.bindings[typeLower].push(binding);
1242
+ } else {
1243
+ this.bindings[typeLower] = [binding];
1244
+ }
1245
+ this._updateFilterMessage();
1246
+ return this;
1247
+ }
1248
+ /**
1249
+ * Registers a callback that will be executed when the channel closes.
1250
+ *
1251
+ * @internal
1252
+ */
1253
+ _onClose(callback) {
1254
+ this.channelAdapter.onClose(callback);
1255
+ }
1256
+ /**
1257
+ * Registers a callback that will be executed when the channel encounteres an error.
1258
+ *
1259
+ * @internal
1260
+ */
1261
+ _onError(callback) {
1262
+ this.channelAdapter.onError(callback);
1263
+ }
1264
+ /** @internal */
1265
+ _updateFilterMessage() {
1266
+ this.channelAdapter.updateFilterBindings((binding, payload, ref) => {
1267
+ var _a, _b, _c, _d, _e, _f, _g;
1268
+ const typeLower = binding.event.toLocaleLowerCase();
1269
+ if (this._notThisChannelEvent(typeLower, ref)) {
1270
+ return false;
1271
+ }
1272
+ const bind = (_a = this.bindings[typeLower]) === null || _a === void 0 ? void 0 : _a.find((bind2) => bind2.ref === binding.ref);
1273
+ if (!bind) {
1274
+ return true;
1275
+ }
1276
+ if (["broadcast", "presence", "postgres_changes"].includes(typeLower)) {
1277
+ if ("id" in bind) {
1278
+ const bindId = bind.id;
1279
+ const bindEvent = (_b = bind.filter) === null || _b === void 0 ? void 0 : _b.event;
1280
+ return bindId && ((_c = payload.ids) === null || _c === void 0 ? void 0 : _c.includes(bindId)) && (bindEvent === "*" || (bindEvent === null || bindEvent === void 0 ? void 0 : bindEvent.toLocaleLowerCase()) === ((_d = payload.data) === null || _d === void 0 ? void 0 : _d.type.toLocaleLowerCase()));
1281
+ } else {
1282
+ const bindEvent = (_f = (_e = bind === null || bind === void 0 ? void 0 : bind.filter) === null || _e === void 0 ? void 0 : _e.event) === null || _f === void 0 ? void 0 : _f.toLocaleLowerCase();
1283
+ return bindEvent === "*" || bindEvent === ((_g = payload === null || payload === void 0 ? void 0 : payload.event) === null || _g === void 0 ? void 0 : _g.toLocaleLowerCase());
1284
+ }
1285
+ } else {
1286
+ return bind.type.toLocaleLowerCase() === typeLower;
1287
+ }
1288
+ });
1289
+ }
1290
+ /** @internal */
1291
+ _notThisChannelEvent(event, ref) {
1292
+ const { close, error, leave, join } = CHANNEL_EVENTS;
1293
+ const events = [close, error, leave, join];
1294
+ return ref && events.includes(event) && ref !== this.joinPush.ref;
1295
+ }
1296
+ /** @internal */
1297
+ _updateFilterTransform() {
1298
+ this.channelAdapter.updatePayloadTransform((event, payload, ref) => {
1299
+ if (typeof payload === "object" && "ids" in payload) {
1300
+ const postgresChanges = payload.data;
1301
+ const { schema, table, commit_timestamp, type, errors } = postgresChanges;
1302
+ const enrichedPayload = {
1303
+ schema,
1304
+ table,
1305
+ commit_timestamp,
1306
+ eventType: type,
1307
+ new: {},
1308
+ old: {},
1309
+ errors
1310
+ };
1311
+ return Object.assign(Object.assign({}, enrichedPayload), this._getPayloadRecords(postgresChanges));
1312
+ }
1313
+ return payload;
1314
+ });
1315
+ }
1316
+ copyBindings(other) {
1317
+ if (this.joinedOnce) {
1318
+ throw new Error("cannot copy bindings into joined channel");
1319
+ }
1320
+ for (const kind in other.bindings) {
1321
+ for (const binding of other.bindings[kind]) {
1322
+ this._on(binding.type, binding.filter, binding.callback);
1323
+ }
1324
+ }
1325
+ }
1326
+ /**
1327
+ * Compares two optional filter values for equality.
1328
+ * Treats undefined, null, and empty string as equivalent empty values.
1329
+ * @internal
1330
+ */
1331
+ static isFilterValueEqual(serverValue, clientValue) {
1332
+ const normalizedServer = serverValue !== null && serverValue !== void 0 ? serverValue : void 0;
1333
+ const normalizedClient = clientValue !== null && clientValue !== void 0 ? clientValue : void 0;
1334
+ return normalizedServer === normalizedClient;
1335
+ }
1336
+ /** @internal */
1337
+ _getPayloadRecords(payload) {
1338
+ const records = {
1339
+ new: {},
1340
+ old: {}
1341
+ };
1342
+ if (payload.type === "INSERT" || payload.type === "UPDATE") {
1343
+ records.new = convertChangeData(payload.columns, payload.record);
1344
+ }
1345
+ if (payload.type === "UPDATE" || payload.type === "DELETE") {
1346
+ records.old = convertChangeData(payload.columns, payload.old_record);
1347
+ }
1348
+ return records;
1349
+ }
1350
+ }
1351
+ class SocketAdapter {
1352
+ constructor(endPoint, options) {
1353
+ this.socket = new Socket(endPoint, options);
1354
+ }
1355
+ get timeout() {
1356
+ return this.socket.timeout;
1357
+ }
1358
+ get endPoint() {
1359
+ return this.socket.endPoint;
1360
+ }
1361
+ get transport() {
1362
+ return this.socket.transport;
1363
+ }
1364
+ get heartbeatIntervalMs() {
1365
+ return this.socket.heartbeatIntervalMs;
1366
+ }
1367
+ get heartbeatCallback() {
1368
+ return this.socket.heartbeatCallback;
1369
+ }
1370
+ set heartbeatCallback(callback) {
1371
+ this.socket.heartbeatCallback = callback;
1372
+ }
1373
+ get heartbeatTimer() {
1374
+ return this.socket.heartbeatTimer;
1375
+ }
1376
+ get pendingHeartbeatRef() {
1377
+ return this.socket.pendingHeartbeatRef;
1378
+ }
1379
+ get reconnectTimer() {
1380
+ return this.socket.reconnectTimer;
1381
+ }
1382
+ get vsn() {
1383
+ return this.socket.vsn;
1384
+ }
1385
+ get encode() {
1386
+ return this.socket.encode;
1387
+ }
1388
+ get decode() {
1389
+ return this.socket.decode;
1390
+ }
1391
+ get reconnectAfterMs() {
1392
+ return this.socket.reconnectAfterMs;
1393
+ }
1394
+ get sendBuffer() {
1395
+ return this.socket.sendBuffer;
1396
+ }
1397
+ get stateChangeCallbacks() {
1398
+ return this.socket.stateChangeCallbacks;
1399
+ }
1400
+ connect() {
1401
+ this.socket.connect();
1402
+ }
1403
+ disconnect(callback, code, reason, timeout = 1e4) {
1404
+ return new Promise((resolve) => {
1405
+ setTimeout(() => resolve("timeout"), timeout);
1406
+ this.socket.disconnect(() => {
1407
+ callback();
1408
+ resolve("ok");
1409
+ }, code, reason);
1410
+ });
1411
+ }
1412
+ push(data) {
1413
+ this.socket.push(data);
1414
+ }
1415
+ log(kind, msg, data) {
1416
+ this.socket.log(kind, msg, data);
1417
+ }
1418
+ makeRef() {
1419
+ return this.socket.makeRef();
1420
+ }
1421
+ onOpen(callback) {
1422
+ this.socket.onOpen(callback);
1423
+ }
1424
+ onClose(callback) {
1425
+ this.socket.onClose(callback);
1426
+ }
1427
+ onError(callback) {
1428
+ this.socket.onError(callback);
1429
+ }
1430
+ onMessage(callback) {
1431
+ this.socket.onMessage(callback);
1432
+ }
1433
+ isConnected() {
1434
+ return this.socket.isConnected();
1435
+ }
1436
+ isConnecting() {
1437
+ return this.socket.connectionState() == CONNECTION_STATE.connecting;
1438
+ }
1439
+ isDisconnecting() {
1440
+ return this.socket.connectionState() == CONNECTION_STATE.closing;
1441
+ }
1442
+ connectionState() {
1443
+ return this.socket.connectionState();
1444
+ }
1445
+ endPointURL() {
1446
+ return this.socket.endPointURL();
1447
+ }
1448
+ sendHeartbeat() {
1449
+ this.socket.sendHeartbeat();
1450
+ }
1451
+ /**
1452
+ * @internal
1453
+ */
1454
+ getSocket() {
1455
+ return this.socket;
1456
+ }
1457
+ }
1458
+ const CONNECTION_TIMEOUTS = {
1459
+ HEARTBEAT_INTERVAL: 25e3
1460
+ };
1461
+ const RECONNECT_INTERVALS = [1e3, 2e3, 5e3, 1e4];
1462
+ const DEFAULT_RECONNECT_FALLBACK = 1e4;
1463
+ function createMemorySessionStorage() {
1464
+ const store = /* @__PURE__ */ new Map();
1465
+ return {
1466
+ get length() {
1467
+ return store.size;
1468
+ },
1469
+ clear() {
1470
+ store.clear();
1471
+ },
1472
+ getItem(key) {
1473
+ return store.has(key) ? store.get(key) : null;
1474
+ },
1475
+ key(index) {
1476
+ var _a;
1477
+ return (_a = Array.from(store.keys())[index]) !== null && _a !== void 0 ? _a : null;
1478
+ },
1479
+ removeItem(key) {
1480
+ store.delete(key);
1481
+ },
1482
+ setItem(key, value) {
1483
+ store.set(key, String(value));
1484
+ }
1485
+ };
1486
+ }
1487
+ function resolveSessionStorage() {
1488
+ try {
1489
+ if (typeof globalThis !== "undefined" && globalThis.sessionStorage) {
1490
+ return globalThis.sessionStorage;
1491
+ }
1492
+ } catch (_a) {
1493
+ }
1494
+ return createMemorySessionStorage();
1495
+ }
1496
+ const WORKER_SCRIPT = `
1497
+ addEventListener("message", (e) => {
1498
+ if (e.data.event === "start") {
1499
+ setInterval(() => postMessage({ event: "keepAlive" }), e.data.interval);
1500
+ }
1501
+ });`;
1502
+ class RealtimeClient {
1503
+ get endPoint() {
1504
+ return this.socketAdapter.endPoint;
1505
+ }
1506
+ get timeout() {
1507
+ return this.socketAdapter.timeout;
1508
+ }
1509
+ get transport() {
1510
+ return this.socketAdapter.transport;
1511
+ }
1512
+ get heartbeatCallback() {
1513
+ return this.socketAdapter.heartbeatCallback;
1514
+ }
1515
+ get heartbeatIntervalMs() {
1516
+ return this.socketAdapter.heartbeatIntervalMs;
1517
+ }
1518
+ get heartbeatTimer() {
1519
+ if (this.worker) {
1520
+ return this._workerHeartbeatTimer;
1521
+ }
1522
+ return this.socketAdapter.heartbeatTimer;
1523
+ }
1524
+ get pendingHeartbeatRef() {
1525
+ if (this.worker) {
1526
+ return this._pendingWorkerHeartbeatRef;
1527
+ }
1528
+ return this.socketAdapter.pendingHeartbeatRef;
1529
+ }
1530
+ get reconnectTimer() {
1531
+ return this.socketAdapter.reconnectTimer;
1532
+ }
1533
+ get vsn() {
1534
+ return this.socketAdapter.vsn;
1535
+ }
1536
+ get encode() {
1537
+ return this.socketAdapter.encode;
1538
+ }
1539
+ get decode() {
1540
+ return this.socketAdapter.decode;
1541
+ }
1542
+ get reconnectAfterMs() {
1543
+ return this.socketAdapter.reconnectAfterMs;
1544
+ }
1545
+ get sendBuffer() {
1546
+ return this.socketAdapter.sendBuffer;
1547
+ }
1548
+ get stateChangeCallbacks() {
1549
+ return this.socketAdapter.stateChangeCallbacks;
1550
+ }
1551
+ /**
1552
+ * Initializes the Socket.
1553
+ *
1554
+ * @param endPoint The string WebSocket endpoint, ie, "ws://example.com/socket", "wss://example.com", "/socket" (inherited host & protocol)
1555
+ * @param httpEndpoint The string HTTP endpoint, ie, "https://example.com", "/" (inherited host & protocol)
1556
+ * @param options.transport The Websocket Transport, for example WebSocket. This can be a custom implementation
1557
+ * @param options.timeout The default timeout in milliseconds to trigger push timeouts.
1558
+ * @param options.params The optional params to pass when connecting.
1559
+ * @param options.headers Deprecated: headers cannot be set on websocket connections and this option will be removed in the future.
1560
+ * @param options.heartbeatIntervalMs The millisec interval to send a heartbeat message.
1561
+ * @param options.heartbeatCallback The optional function to handle heartbeat status and latency.
1562
+ * @param options.logger The optional function for specialized logging, ie: logger: (kind, msg, data) => { console.log(`${kind}: ${msg}`, data) }
1563
+ * @param options.logLevel Sets the log level for Realtime
1564
+ * @param options.encode The function to encode outgoing messages. Defaults to JSON: (payload, callback) => callback(JSON.stringify(payload))
1565
+ * @param options.decode The function to decode incoming messages. Defaults to Serializer's decode.
1566
+ * @param options.reconnectAfterMs he optional function that returns the millsec reconnect interval. Defaults to stepped backoff off.
1567
+ * @param options.worker Use Web Worker to set a side flow. Defaults to false.
1568
+ * @param options.workerUrl The URL of the worker script. Defaults to https://realtime.supabase.com/worker.js that includes a heartbeat event call to keep the connection alive.
1569
+ * @param options.vsn The protocol version to use when connecting. Supported versions are "1.0.0" and "2.0.0". Defaults to "2.0.0".
1570
+ *
1571
+ * @category Realtime
1572
+ *
1573
+ * @example Using supabase-js (recommended)
1574
+ * ```ts
1575
+ * import { createClient } from '@supabase/supabase-js'
1576
+ *
1577
+ * const supabase = createClient('https://xyzcompany.supabase.co', 'your-publishable-key')
1578
+ * const channel = supabase.channel('room1')
1579
+ * channel
1580
+ * .on('broadcast', { event: 'cursor-pos' }, (payload) => console.log(payload))
1581
+ * .subscribe()
1582
+ * ```
1583
+ *
1584
+ * @example Standalone import for bundle-sensitive environments
1585
+ * ```ts
1586
+ * import RealtimeClient from '@supabase/realtime-js'
1587
+ *
1588
+ * const client = new RealtimeClient('https://xyzcompany.supabase.co/realtime/v1', {
1589
+ * params: { apikey: 'your-publishable-key' },
1590
+ * })
1591
+ * client.connect()
1592
+ * ```
1593
+ */
1594
+ constructor(endPoint, options) {
1595
+ var _a;
1596
+ this.channels = new Array();
1597
+ this.accessTokenValue = null;
1598
+ this.accessToken = null;
1599
+ this.apiKey = null;
1600
+ this.httpEndpoint = "";
1601
+ this.headers = {};
1602
+ this.params = {};
1603
+ this.ref = 0;
1604
+ this.serializer = new Serializer();
1605
+ this._manuallySetToken = false;
1606
+ this._authPromise = null;
1607
+ this._workerHeartbeatTimer = void 0;
1608
+ this._pendingWorkerHeartbeatRef = null;
1609
+ this._pendingDisconnectTimer = null;
1610
+ this._disconnectOnEmptyChannelsAfterMs = 0;
1611
+ this._resolveFetch = (customFetch) => {
1612
+ if (customFetch) {
1613
+ return (...args) => customFetch(...args);
1614
+ }
1615
+ return (...args) => fetch(...args);
1616
+ };
1617
+ if (!((_a = options === null || options === void 0 ? void 0 : options.params) === null || _a === void 0 ? void 0 : _a.apikey)) {
1618
+ throw new Error("API key is required to connect to Realtime");
1619
+ }
1620
+ this.apiKey = options.params.apikey;
1621
+ const socketAdapterOptions = this._initializeOptions(options);
1622
+ this.socketAdapter = new SocketAdapter(endPoint, socketAdapterOptions);
1623
+ this.httpEndpoint = httpEndpointURL(endPoint);
1624
+ this.fetch = this._resolveFetch(options === null || options === void 0 ? void 0 : options.fetch);
1625
+ }
1626
+ /**
1627
+ * Connects the socket, unless already connected.
1628
+ *
1629
+ * @category Realtime
1630
+ */
1631
+ connect() {
1632
+ if (this.isConnecting() || this.isDisconnecting() || this.isConnected()) {
1633
+ return;
1634
+ }
1635
+ if (this.accessToken && !this._authPromise) {
1636
+ this._setAuthSafely("connect");
1637
+ }
1638
+ this._setupConnectionHandlers();
1639
+ try {
1640
+ this.socketAdapter.connect();
1641
+ } catch (error) {
1642
+ const errorMessage = error.message;
1643
+ if (errorMessage.includes("Node.js")) {
1644
+ throw new Error(`${errorMessage}
1645
+
1646
+ To use Realtime in Node.js, you need to provide a WebSocket implementation:
1647
+
1648
+ Option 1: Use Node.js 22+ which has native WebSocket support
1649
+ Option 2: Install and provide the "ws" package:
1650
+
1651
+ npm install ws
1652
+
1653
+ import ws from "ws"
1654
+ const client = new RealtimeClient(url, {
1655
+ ...options,
1656
+ transport: ws
1657
+ })`);
1658
+ }
1659
+ throw new Error(`WebSocket not available: ${errorMessage}`);
1660
+ }
1661
+ this._handleNodeJsRaceCondition();
1662
+ }
1663
+ /**
1664
+ * Returns the URL of the websocket.
1665
+ * @returns string The URL of the websocket.
1666
+ *
1667
+ * @category Realtime
1668
+ */
1669
+ endpointURL() {
1670
+ return this.socketAdapter.endPointURL();
1671
+ }
1672
+ /**
1673
+ * Disconnects the socket.
1674
+ *
1675
+ * @param code A numeric status code to send on disconnect.
1676
+ * @param reason A custom reason for the disconnect.
1677
+ *
1678
+ * @category Realtime
1679
+ */
1680
+ async disconnect(code, reason) {
1681
+ this._cancelPendingDisconnect();
1682
+ if (this.isDisconnecting()) {
1683
+ return "ok";
1684
+ }
1685
+ return await this.socketAdapter.disconnect(() => {
1686
+ clearInterval(this._workerHeartbeatTimer);
1687
+ this._terminateWorker();
1688
+ }, code, reason);
1689
+ }
1690
+ /**
1691
+ * Returns all created channels
1692
+ *
1693
+ * @category Realtime
1694
+ */
1695
+ getChannels() {
1696
+ return this.channels;
1697
+ }
1698
+ /**
1699
+ * Unsubscribes, removes and tears down a single channel
1700
+ * @param channel A RealtimeChannel instance
1701
+ *
1702
+ * @category Realtime
1703
+ */
1704
+ async removeChannel(channel) {
1705
+ const status = await channel.unsubscribe();
1706
+ if (status === "ok") {
1707
+ channel.teardown();
1708
+ }
1709
+ return status;
1710
+ }
1711
+ /**
1712
+ * Unsubscribes, removes and tears down all channels
1713
+ *
1714
+ * @category Realtime
1715
+ */
1716
+ async removeAllChannels() {
1717
+ const promises = this.channels.map(async (channel) => {
1718
+ const result2 = await channel.unsubscribe();
1719
+ channel.teardown();
1720
+ return result2;
1721
+ });
1722
+ const result = await Promise.all(promises);
1723
+ await this.disconnect();
1724
+ return result;
1725
+ }
1726
+ /**
1727
+ * Logs the message.
1728
+ *
1729
+ * For customized logging, `this.logger` can be overridden in Client constructor.
1730
+ *
1731
+ * @category Realtime
1732
+ */
1733
+ log(kind, msg, data) {
1734
+ this.socketAdapter.log(kind, msg, data);
1735
+ }
1736
+ /**
1737
+ * Returns the current state of the socket.
1738
+ *
1739
+ * @category Realtime
1740
+ */
1741
+ connectionState() {
1742
+ return this.socketAdapter.connectionState() || CONNECTION_STATE.closed;
1743
+ }
1744
+ /**
1745
+ * Returns `true` is the connection is open.
1746
+ *
1747
+ * @category Realtime
1748
+ */
1749
+ isConnected() {
1750
+ return this.socketAdapter.isConnected();
1751
+ }
1752
+ /**
1753
+ * Returns `true` if the connection is currently connecting.
1754
+ *
1755
+ * @category Realtime
1756
+ */
1757
+ isConnecting() {
1758
+ return this.socketAdapter.isConnecting();
1759
+ }
1760
+ /**
1761
+ * Returns `true` if the connection is currently disconnecting.
1762
+ *
1763
+ * @category Realtime
1764
+ */
1765
+ isDisconnecting() {
1766
+ return this.socketAdapter.isDisconnecting();
1767
+ }
1768
+ /**
1769
+ * Creates (or reuses) a {@link RealtimeChannel} for the provided topic.
1770
+ *
1771
+ * Topics are automatically prefixed with `realtime:` to match the Realtime service.
1772
+ * If a channel with the same topic already exists it will be returned instead of creating
1773
+ * a duplicate connection.
1774
+ *
1775
+ * @category Realtime
1776
+ */
1777
+ channel(topic, params = { config: {} }) {
1778
+ const realtimeTopic = `realtime:${topic}`;
1779
+ const exists = this.getChannels().find((c) => c.topic === realtimeTopic);
1780
+ if (!exists) {
1781
+ const chan = new RealtimeChannel(`realtime:${topic}`, params, this);
1782
+ this._cancelPendingDisconnect();
1783
+ this.channels.push(chan);
1784
+ return chan;
1785
+ } else {
1786
+ return exists;
1787
+ }
1788
+ }
1789
+ /**
1790
+ * Push out a message if the socket is connected.
1791
+ *
1792
+ * If the socket is not connected, the message gets enqueued within a local buffer, and sent out when a connection is next established.
1793
+ *
1794
+ * @category Realtime
1795
+ */
1796
+ push(data) {
1797
+ this.socketAdapter.push(data);
1798
+ }
1799
+ /**
1800
+ * Sets the JWT access token used for channel subscription authorization and Realtime RLS.
1801
+ *
1802
+ * If param is null it will use the `accessToken` callback function or the token set on the client.
1803
+ *
1804
+ * On callback used, it will set the value of the token internal to the client.
1805
+ *
1806
+ * When a token is explicitly provided, it will be preserved across channel operations
1807
+ * (including removeChannel and resubscribe). The `accessToken` callback will not be
1808
+ * invoked until `setAuth()` is called without arguments.
1809
+ *
1810
+ * @param token A JWT string to override the token set on the client.
1811
+ *
1812
+ * @example Setting the authorization header
1813
+ * // Use a manual token (preserved across resubscribes, ignores accessToken callback)
1814
+ * client.realtime.setAuth('my-custom-jwt')
1815
+ *
1816
+ * // Switch back to using the accessToken callback
1817
+ * client.realtime.setAuth()
1818
+ *
1819
+ * @category Realtime
1820
+ */
1821
+ async setAuth(token = null) {
1822
+ this._authPromise = this._performAuth(token);
1823
+ try {
1824
+ await this._authPromise;
1825
+ } finally {
1826
+ this._authPromise = null;
1827
+ }
1828
+ }
1829
+ /**
1830
+ * Returns true if the current access token was explicitly set via setAuth(token),
1831
+ * false if it was obtained via the accessToken callback.
1832
+ * @internal
1833
+ */
1834
+ _isManualToken() {
1835
+ return this._manuallySetToken;
1836
+ }
1837
+ /**
1838
+ * Sends a heartbeat message if the socket is connected.
1839
+ *
1840
+ * @category Realtime
1841
+ */
1842
+ async sendHeartbeat() {
1843
+ this.socketAdapter.sendHeartbeat();
1844
+ }
1845
+ /**
1846
+ * Sets a callback that receives lifecycle events for internal heartbeat messages.
1847
+ * Useful for instrumenting connection health (e.g. sent/ok/timeout/disconnected).
1848
+ *
1849
+ * @category Realtime
1850
+ */
1851
+ onHeartbeat(callback) {
1852
+ this.socketAdapter.heartbeatCallback = this._wrapHeartbeatCallback(callback);
1853
+ }
1854
+ /**
1855
+ * Return the next message ref, accounting for overflows
1856
+ *
1857
+ * @internal
1858
+ */
1859
+ _makeRef() {
1860
+ return this.socketAdapter.makeRef();
1861
+ }
1862
+ /**
1863
+ * Removes a channel from RealtimeClient
1864
+ *
1865
+ * @param channel An open subscription.
1866
+ *
1867
+ * @internal
1868
+ */
1869
+ _remove(channel) {
1870
+ this.channels = this.channels.filter((c) => c.topic !== channel.topic);
1871
+ if (this.channels.length === 0) {
1872
+ this.log("transport", "no channels remaining, scheduling disconnect");
1873
+ this._schedulePendingDisconnect();
1874
+ }
1875
+ }
1876
+ /** @internal */
1877
+ _schedulePendingDisconnect() {
1878
+ this._cancelPendingDisconnect();
1879
+ if (this._disconnectOnEmptyChannelsAfterMs === 0) {
1880
+ this.log("transport", "disconnecting immediately - no channels");
1881
+ this.disconnect();
1882
+ return;
1883
+ }
1884
+ this._pendingDisconnectTimer = setTimeout(() => {
1885
+ this._pendingDisconnectTimer = null;
1886
+ if (this.channels.length === 0) {
1887
+ this.log("transport", "deferred disconnect fired - no channels, disconnecting");
1888
+ this.disconnect();
1889
+ }
1890
+ }, this._disconnectOnEmptyChannelsAfterMs);
1891
+ this.log("transport", `deferred disconnect scheduled in ${this._disconnectOnEmptyChannelsAfterMs}ms`);
1892
+ }
1893
+ /** @internal */
1894
+ _cancelPendingDisconnect() {
1895
+ if (this._pendingDisconnectTimer !== null) {
1896
+ this.log("transport", "pending disconnect cancelled - channel activity detected");
1897
+ clearTimeout(this._pendingDisconnectTimer);
1898
+ this._pendingDisconnectTimer = null;
1899
+ }
1900
+ }
1901
+ /**
1902
+ * Perform the actual auth operation
1903
+ * @internal
1904
+ */
1905
+ async _performAuth(token = null) {
1906
+ let tokenToSend;
1907
+ let isManualToken = false;
1908
+ if (token) {
1909
+ tokenToSend = token;
1910
+ isManualToken = true;
1911
+ } else if (this.accessToken) {
1912
+ try {
1913
+ tokenToSend = await this.accessToken();
1914
+ } catch (e) {
1915
+ this.log("error", "Error fetching access token from callback", e);
1916
+ tokenToSend = this.accessTokenValue;
1917
+ }
1918
+ } else {
1919
+ tokenToSend = this.accessTokenValue;
1920
+ }
1921
+ if (isManualToken) {
1922
+ this._manuallySetToken = true;
1923
+ } else if (this.accessToken) {
1924
+ this._manuallySetToken = false;
1925
+ }
1926
+ if (this.accessTokenValue != tokenToSend) {
1927
+ this.accessTokenValue = tokenToSend;
1928
+ this.channels.forEach((channel) => {
1929
+ const payload = {
1930
+ access_token: tokenToSend,
1931
+ version: DEFAULT_VERSION
1932
+ };
1933
+ tokenToSend && channel.updateJoinPayload(payload);
1934
+ if (channel.joinedOnce && channel.channelAdapter.isJoined()) {
1935
+ channel.channelAdapter.push(CHANNEL_EVENTS.access_token, {
1936
+ access_token: tokenToSend
1937
+ });
1938
+ }
1939
+ });
1940
+ }
1941
+ }
1942
+ /**
1943
+ * Wait for any in-flight auth operations to complete
1944
+ * @internal
1945
+ */
1946
+ async _waitForAuthIfNeeded() {
1947
+ if (this._authPromise) {
1948
+ await this._authPromise;
1949
+ }
1950
+ }
1951
+ /**
1952
+ * Safely call setAuth with standardized error handling
1953
+ * @internal
1954
+ */
1955
+ _setAuthSafely(context = "general") {
1956
+ if (!this._isManualToken()) {
1957
+ this.setAuth().catch((e) => {
1958
+ this.log("error", `Error setting auth in ${context}`, e);
1959
+ });
1960
+ }
1961
+ }
1962
+ /** @internal */
1963
+ _setupConnectionHandlers() {
1964
+ this.socketAdapter.onOpen(() => {
1965
+ const authPromise = this._authPromise || (this.accessToken && !this.accessTokenValue ? this.setAuth() : Promise.resolve());
1966
+ authPromise.catch((e) => {
1967
+ this.log("error", "error waiting for auth on connect", e);
1968
+ });
1969
+ if (this.worker && !this.workerRef) {
1970
+ this._startWorkerHeartbeat();
1971
+ }
1972
+ });
1973
+ this.socketAdapter.onClose(() => {
1974
+ if (this.worker && this.workerRef) {
1975
+ this._terminateWorker();
1976
+ }
1977
+ });
1978
+ this.socketAdapter.onMessage((message) => {
1979
+ if (message.ref && message.ref === this._pendingWorkerHeartbeatRef) {
1980
+ this._pendingWorkerHeartbeatRef = null;
1981
+ }
1982
+ });
1983
+ }
1984
+ /** @internal */
1985
+ _handleNodeJsRaceCondition() {
1986
+ if (this.socketAdapter.isConnected()) {
1987
+ this.socketAdapter.getSocket().onConnOpen();
1988
+ }
1989
+ }
1990
+ /** @internal */
1991
+ _wrapHeartbeatCallback(heartbeatCallback) {
1992
+ return (status, latency) => {
1993
+ if (status == "sent")
1994
+ this._setAuthSafely();
1995
+ if (heartbeatCallback)
1996
+ heartbeatCallback(status, latency);
1997
+ };
1998
+ }
1999
+ /** @internal */
2000
+ _startWorkerHeartbeat() {
2001
+ if (this.workerUrl) {
2002
+ this.log("worker", `starting worker for from ${this.workerUrl}`);
2003
+ } else {
2004
+ this.log("worker", `starting default worker`);
2005
+ }
2006
+ const objectUrl = this._workerObjectUrl(this.workerUrl);
2007
+ this.workerRef = new Worker(objectUrl);
2008
+ this.workerRef.onerror = (error) => {
2009
+ this.log("worker", "worker error", error.message);
2010
+ this._terminateWorker();
2011
+ this.disconnect();
2012
+ };
2013
+ this.workerRef.onmessage = (event) => {
2014
+ if (event.data.event === "keepAlive") {
2015
+ this.sendHeartbeat();
2016
+ }
2017
+ };
2018
+ this.workerRef.postMessage({
2019
+ event: "start",
2020
+ interval: this.heartbeatIntervalMs
2021
+ });
2022
+ }
2023
+ /**
2024
+ * Terminate the Web Worker and clear the reference
2025
+ * @internal
2026
+ */
2027
+ _terminateWorker() {
2028
+ if (this.workerRef) {
2029
+ this.log("worker", "terminating worker");
2030
+ this.workerRef.terminate();
2031
+ this.workerRef = void 0;
2032
+ }
2033
+ }
2034
+ /** @internal */
2035
+ _workerObjectUrl(url) {
2036
+ let result_url;
2037
+ if (url) {
2038
+ result_url = url;
2039
+ } else {
2040
+ const blob = new Blob([WORKER_SCRIPT], { type: "application/javascript" });
2041
+ result_url = URL.createObjectURL(blob);
2042
+ }
2043
+ return result_url;
2044
+ }
2045
+ /**
2046
+ * Initialize socket options with defaults
2047
+ * @internal
2048
+ */
2049
+ _initializeOptions(options) {
2050
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
2051
+ this.worker = (_a = options === null || options === void 0 ? void 0 : options.worker) !== null && _a !== void 0 ? _a : false;
2052
+ this.accessToken = (_b = options === null || options === void 0 ? void 0 : options.accessToken) !== null && _b !== void 0 ? _b : null;
2053
+ const result = {};
2054
+ result.timeout = (_c = options === null || options === void 0 ? void 0 : options.timeout) !== null && _c !== void 0 ? _c : DEFAULT_TIMEOUT;
2055
+ result.heartbeatIntervalMs = (_d = options === null || options === void 0 ? void 0 : options.heartbeatIntervalMs) !== null && _d !== void 0 ? _d : CONNECTION_TIMEOUTS.HEARTBEAT_INTERVAL;
2056
+ this._disconnectOnEmptyChannelsAfterMs = (_e = options === null || options === void 0 ? void 0 : options.disconnectOnEmptyChannelsAfterMs) !== null && _e !== void 0 ? _e : 2 * ((_f = options === null || options === void 0 ? void 0 : options.heartbeatIntervalMs) !== null && _f !== void 0 ? _f : CONNECTION_TIMEOUTS.HEARTBEAT_INTERVAL);
2057
+ result.transport = (_g = options === null || options === void 0 ? void 0 : options.transport) !== null && _g !== void 0 ? _g : WebSocketFactory.getWebSocketConstructor();
2058
+ result.params = options === null || options === void 0 ? void 0 : options.params;
2059
+ result.logger = options === null || options === void 0 ? void 0 : options.logger;
2060
+ result.heartbeatCallback = this._wrapHeartbeatCallback(options === null || options === void 0 ? void 0 : options.heartbeatCallback);
2061
+ result.sessionStorage = (_h = options === null || options === void 0 ? void 0 : options.sessionStorage) !== null && _h !== void 0 ? _h : resolveSessionStorage();
2062
+ result.reconnectAfterMs = (_j = options === null || options === void 0 ? void 0 : options.reconnectAfterMs) !== null && _j !== void 0 ? _j : ((tries) => {
2063
+ return RECONNECT_INTERVALS[tries - 1] || DEFAULT_RECONNECT_FALLBACK;
2064
+ });
2065
+ let defaultEncode;
2066
+ let defaultDecode;
2067
+ const vsn = (_k = options === null || options === void 0 ? void 0 : options.vsn) !== null && _k !== void 0 ? _k : DEFAULT_VSN;
2068
+ switch (vsn) {
2069
+ case VSN_1_0_0:
2070
+ defaultEncode = (payload, callback) => {
2071
+ return callback(JSON.stringify(payload));
2072
+ };
2073
+ defaultDecode = (payload, callback) => {
2074
+ return callback(JSON.parse(payload));
2075
+ };
2076
+ break;
2077
+ case VSN_2_0_0:
2078
+ defaultEncode = this.serializer.encode.bind(this.serializer);
2079
+ defaultDecode = this.serializer.decode.bind(this.serializer);
2080
+ break;
2081
+ default:
2082
+ throw new Error(`Unsupported serializer version: ${result.vsn}`);
2083
+ }
2084
+ result.vsn = vsn;
2085
+ result.encode = (_l = options === null || options === void 0 ? void 0 : options.encode) !== null && _l !== void 0 ? _l : defaultEncode;
2086
+ result.decode = (_m = options === null || options === void 0 ? void 0 : options.decode) !== null && _m !== void 0 ? _m : defaultDecode;
2087
+ result.beforeReconnect = this._reconnectAuth.bind(this);
2088
+ if ((options === null || options === void 0 ? void 0 : options.logLevel) || (options === null || options === void 0 ? void 0 : options.log_level)) {
2089
+ this.logLevel = options.logLevel || options.log_level;
2090
+ result.params = Object.assign(Object.assign({}, result.params), { log_level: this.logLevel });
2091
+ }
2092
+ if (this.worker) {
2093
+ if (typeof window !== "undefined" && !window.Worker) {
2094
+ throw new Error("Web Worker is not supported");
2095
+ }
2096
+ this.workerUrl = options === null || options === void 0 ? void 0 : options.workerUrl;
2097
+ result.autoSendHeartbeat = !this.worker;
2098
+ }
2099
+ return result;
2100
+ }
2101
+ /** @internal */
2102
+ async _reconnectAuth() {
2103
+ await this._waitForAuthIfNeeded();
2104
+ if (!this.isConnected()) {
2105
+ this.connect();
2106
+ }
2107
+ }
2108
+ }
2109
+ export {
2110
+ RealtimeClient as R
2111
+ };