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,1777 @@
1
+ var closure = (value) => {
2
+ if (typeof value === "function") {
3
+ return (
4
+ /** @type {() => T} */
5
+ value
6
+ );
7
+ } else {
8
+ let closure2 = function() {
9
+ return value;
10
+ };
11
+ return closure2;
12
+ }
13
+ };
14
+ var globalSelf = typeof self !== "undefined" ? self : null;
15
+ var phxWindow = typeof window !== "undefined" ? window : null;
16
+ var global = globalSelf || phxWindow || globalThis;
17
+ var DEFAULT_VSN = "2.0.0";
18
+ var DEFAULT_TIMEOUT = 1e4;
19
+ var WS_CLOSE_NORMAL = 1e3;
20
+ var SOCKET_STATES = (
21
+ /** @type {const} */
22
+ { connecting: 0, open: 1, closing: 2, closed: 3 }
23
+ );
24
+ var CHANNEL_STATES = (
25
+ /** @type {const} */
26
+ {
27
+ closed: "closed",
28
+ errored: "errored",
29
+ joined: "joined",
30
+ joining: "joining",
31
+ leaving: "leaving"
32
+ }
33
+ );
34
+ var CHANNEL_EVENTS = (
35
+ /** @type {const} */
36
+ {
37
+ close: "phx_close",
38
+ error: "phx_error",
39
+ join: "phx_join",
40
+ reply: "phx_reply",
41
+ leave: "phx_leave"
42
+ }
43
+ );
44
+ var TRANSPORTS = (
45
+ /** @type {const} */
46
+ {
47
+ longpoll: "longpoll",
48
+ websocket: "websocket"
49
+ }
50
+ );
51
+ var XHR_STATES = (
52
+ /** @type {const} */
53
+ {
54
+ complete: 4
55
+ }
56
+ );
57
+ var AUTH_TOKEN_PREFIX = "base64url.bearer.phx.";
58
+ var Push = class {
59
+ /**
60
+ * Initializes the Push
61
+ * @param {Channel} channel - The Channel
62
+ * @param {ChannelEvent} event - The event, for example `"phx_join"`
63
+ * @param {() => Record<string, unknown>} payload - The payload, for example `{user_id: 123}`
64
+ * @param {number} timeout - The push timeout in milliseconds
65
+ */
66
+ constructor(channel, event, payload, timeout) {
67
+ this.channel = channel;
68
+ this.event = event;
69
+ this.payload = payload || function() {
70
+ return {};
71
+ };
72
+ this.receivedResp = null;
73
+ this.timeout = timeout;
74
+ this.timeoutTimer = null;
75
+ this.recHooks = [];
76
+ this.sent = false;
77
+ this.ref = void 0;
78
+ }
79
+ /**
80
+ *
81
+ * @param {number} timeout
82
+ */
83
+ resend(timeout) {
84
+ this.timeout = timeout;
85
+ this.reset();
86
+ this.send();
87
+ }
88
+ /**
89
+ *
90
+ */
91
+ send() {
92
+ if (this.hasReceived("timeout")) {
93
+ return;
94
+ }
95
+ this.startTimeout();
96
+ this.sent = true;
97
+ this.channel.socket.push({
98
+ topic: this.channel.topic,
99
+ event: this.event,
100
+ payload: this.payload(),
101
+ ref: this.ref,
102
+ join_ref: this.channel.joinRef()
103
+ });
104
+ }
105
+ /**
106
+ *
107
+ * @param {string} status
108
+ * @param {(response: any) => void} callback
109
+ */
110
+ receive(status, callback) {
111
+ if (this.hasReceived(status)) {
112
+ callback(this.receivedResp.response);
113
+ }
114
+ this.recHooks.push({ status, callback });
115
+ return this;
116
+ }
117
+ reset() {
118
+ this.cancelRefEvent();
119
+ this.ref = null;
120
+ this.refEvent = null;
121
+ this.receivedResp = null;
122
+ this.sent = false;
123
+ }
124
+ destroy() {
125
+ this.cancelRefEvent();
126
+ this.cancelTimeout();
127
+ }
128
+ /**
129
+ * @private
130
+ */
131
+ matchReceive({ status, response, _ref }) {
132
+ this.recHooks.filter((h) => h.status === status).forEach((h) => h.callback(response));
133
+ }
134
+ /**
135
+ * @private
136
+ */
137
+ cancelRefEvent() {
138
+ if (!this.refEvent) {
139
+ return;
140
+ }
141
+ this.channel.off(this.refEvent);
142
+ }
143
+ cancelTimeout() {
144
+ clearTimeout(this.timeoutTimer);
145
+ this.timeoutTimer = null;
146
+ }
147
+ startTimeout() {
148
+ if (this.timeoutTimer) {
149
+ this.cancelTimeout();
150
+ }
151
+ this.ref = this.channel.socket.makeRef();
152
+ this.refEvent = this.channel.replyEventName(this.ref);
153
+ this.channel.on(this.refEvent, (payload) => {
154
+ this.cancelRefEvent();
155
+ this.cancelTimeout();
156
+ this.receivedResp = payload;
157
+ this.matchReceive(payload);
158
+ });
159
+ this.timeoutTimer = setTimeout(() => {
160
+ this.trigger("timeout", {});
161
+ }, this.timeout);
162
+ }
163
+ /**
164
+ * @private
165
+ */
166
+ hasReceived(status) {
167
+ return this.receivedResp && this.receivedResp.status === status;
168
+ }
169
+ trigger(status, response) {
170
+ this.channel.trigger(this.refEvent, { status, response });
171
+ }
172
+ };
173
+ var Timer = class {
174
+ /**
175
+ * @param {() => void} callback
176
+ * @param {(tries: number) => number} timerCalc
177
+ */
178
+ constructor(callback, timerCalc) {
179
+ this.callback = callback;
180
+ this.timerCalc = timerCalc;
181
+ this.timer = void 0;
182
+ this.tries = 0;
183
+ }
184
+ reset() {
185
+ this.tries = 0;
186
+ clearTimeout(this.timer);
187
+ }
188
+ /**
189
+ * Cancels any previous scheduleTimeout and schedules callback
190
+ */
191
+ scheduleTimeout() {
192
+ clearTimeout(this.timer);
193
+ this.timer = setTimeout(() => {
194
+ this.tries = this.tries + 1;
195
+ this.callback();
196
+ }, this.timerCalc(this.tries + 1));
197
+ }
198
+ };
199
+ var Channel = class {
200
+ /**
201
+ * @param {string} topic
202
+ * @param {Params | (() => Params)} params
203
+ * @param {Socket} socket
204
+ */
205
+ constructor(topic, params, socket) {
206
+ this.state = CHANNEL_STATES.closed;
207
+ this.topic = topic;
208
+ this.params = closure(params || {});
209
+ this.socket = socket;
210
+ this.bindings = [];
211
+ this.bindingRef = 0;
212
+ this.timeout = this.socket.timeout;
213
+ this.joinedOnce = false;
214
+ this.joinPush = new Push(this, CHANNEL_EVENTS.join, this.params, this.timeout);
215
+ this.pushBuffer = [];
216
+ this.stateChangeRefs = [];
217
+ this.rejoinTimer = new Timer(() => {
218
+ if (this.socket.isConnected()) {
219
+ this.rejoin();
220
+ }
221
+ }, this.socket.rejoinAfterMs);
222
+ this.stateChangeRefs.push(this.socket.onError(() => this.rejoinTimer.reset()));
223
+ this.stateChangeRefs.push(
224
+ this.socket.onOpen(() => {
225
+ this.rejoinTimer.reset();
226
+ if (this.isErrored()) {
227
+ this.rejoin();
228
+ }
229
+ })
230
+ );
231
+ this.joinPush.receive("ok", () => {
232
+ this.state = CHANNEL_STATES.joined;
233
+ this.rejoinTimer.reset();
234
+ this.pushBuffer.forEach((pushEvent) => pushEvent.send());
235
+ this.pushBuffer = [];
236
+ });
237
+ this.joinPush.receive("error", (reason) => {
238
+ this.state = CHANNEL_STATES.errored;
239
+ if (this.socket.hasLogger()) this.socket.log("channel", `error ${this.topic}`, reason);
240
+ if (this.socket.isConnected()) {
241
+ this.rejoinTimer.scheduleTimeout();
242
+ }
243
+ });
244
+ this.onClose(() => {
245
+ this.rejoinTimer.reset();
246
+ if (this.socket.hasLogger()) this.socket.log("channel", `close ${this.topic}`);
247
+ this.state = CHANNEL_STATES.closed;
248
+ this.socket.remove(this);
249
+ });
250
+ this.onError((reason) => {
251
+ if (this.socket.hasLogger()) this.socket.log("channel", `error ${this.topic}`, reason);
252
+ if (this.isJoining()) {
253
+ this.joinPush.reset();
254
+ }
255
+ this.state = CHANNEL_STATES.errored;
256
+ if (this.socket.isConnected()) {
257
+ this.rejoinTimer.scheduleTimeout();
258
+ }
259
+ });
260
+ this.joinPush.receive("timeout", () => {
261
+ if (this.socket.hasLogger()) this.socket.log("channel", `timeout ${this.topic}`, this.joinPush.timeout);
262
+ let leavePush = new Push(this, CHANNEL_EVENTS.leave, closure({}), this.timeout);
263
+ leavePush.send();
264
+ this.state = CHANNEL_STATES.errored;
265
+ this.joinPush.reset();
266
+ if (this.socket.isConnected()) {
267
+ this.rejoinTimer.scheduleTimeout();
268
+ }
269
+ });
270
+ this.on(CHANNEL_EVENTS.reply, (payload, ref) => {
271
+ this.trigger(this.replyEventName(ref), payload);
272
+ });
273
+ }
274
+ /**
275
+ * Join the channel
276
+ * @param {number} timeout
277
+ * @returns {Push}
278
+ */
279
+ join(timeout = this.timeout) {
280
+ if (this.joinedOnce) {
281
+ throw new Error("tried to join multiple times. 'join' can only be called a single time per channel instance");
282
+ } else {
283
+ this.timeout = timeout;
284
+ this.joinedOnce = true;
285
+ this.rejoin();
286
+ return this.joinPush;
287
+ }
288
+ }
289
+ /**
290
+ * Teardown the channel.
291
+ *
292
+ * Destroys and stops related timers.
293
+ */
294
+ teardown() {
295
+ this.pushBuffer.forEach((push) => push.destroy());
296
+ this.pushBuffer = [];
297
+ this.rejoinTimer.reset();
298
+ this.joinPush.destroy();
299
+ this.state = CHANNEL_STATES.closed;
300
+ this.bindings = [];
301
+ }
302
+ /**
303
+ * Hook into channel close
304
+ * @param {ChannelBindingCallback} callback
305
+ */
306
+ onClose(callback) {
307
+ this.on(CHANNEL_EVENTS.close, callback);
308
+ }
309
+ /**
310
+ * Hook into channel errors
311
+ * @param {ChannelOnErrorCallback} callback
312
+ * @return {number}
313
+ */
314
+ onError(callback) {
315
+ return this.on(CHANNEL_EVENTS.error, (reason) => callback(reason));
316
+ }
317
+ /**
318
+ * Subscribes on channel events
319
+ *
320
+ * Subscription returns a ref counter, which can be used later to
321
+ * unsubscribe the exact event listener
322
+ *
323
+ * @example
324
+ * const ref1 = channel.on("event", do_stuff)
325
+ * const ref2 = channel.on("event", do_other_stuff)
326
+ * channel.off("event", ref1)
327
+ * // Since unsubscription, do_stuff won't fire,
328
+ * // while do_other_stuff will keep firing on the "event"
329
+ *
330
+ * @param {string} event
331
+ * @param {ChannelBindingCallback} callback
332
+ * @returns {number} ref
333
+ */
334
+ on(event, callback) {
335
+ let ref = this.bindingRef++;
336
+ this.bindings.push({ event, ref, callback });
337
+ return ref;
338
+ }
339
+ /**
340
+ * Unsubscribes off of channel events
341
+ *
342
+ * Use the ref returned from a channel.on() to unsubscribe one
343
+ * handler, or pass nothing for the ref to unsubscribe all
344
+ * handlers for the given event.
345
+ *
346
+ * @example
347
+ * // Unsubscribe the do_stuff handler
348
+ * const ref1 = channel.on("event", do_stuff)
349
+ * channel.off("event", ref1)
350
+ *
351
+ * // Unsubscribe all handlers from event
352
+ * channel.off("event")
353
+ *
354
+ * @param {string} event
355
+ * @param {number} [ref]
356
+ */
357
+ off(event, ref) {
358
+ this.bindings = this.bindings.filter((bind) => {
359
+ return !(bind.event === event && (typeof ref === "undefined" || ref === bind.ref));
360
+ });
361
+ }
362
+ /**
363
+ * @private
364
+ */
365
+ canPush() {
366
+ return this.socket.isConnected() && this.isJoined();
367
+ }
368
+ /**
369
+ * Sends a message `event` to phoenix with the payload `payload`.
370
+ * Phoenix receives this in the `handle_in(event, payload, socket)`
371
+ * function. if phoenix replies or it times out (default 10000ms),
372
+ * then optionally the reply can be received.
373
+ *
374
+ * @example
375
+ * channel.push("event")
376
+ * .receive("ok", payload => console.log("phoenix replied:", payload))
377
+ * .receive("error", err => console.log("phoenix errored", err))
378
+ * .receive("timeout", () => console.log("timed out pushing"))
379
+ * @param {string} event
380
+ * @param {Object} payload
381
+ * @param {number} [timeout]
382
+ * @returns {Push}
383
+ */
384
+ push(event, payload, timeout = this.timeout) {
385
+ payload = payload || {};
386
+ if (!this.joinedOnce) {
387
+ throw new Error(`tried to push '${event}' to '${this.topic}' before joining. Use channel.join() before pushing events`);
388
+ }
389
+ let pushEvent = new Push(this, event, function() {
390
+ return payload;
391
+ }, timeout);
392
+ if (this.canPush()) {
393
+ pushEvent.send();
394
+ } else {
395
+ pushEvent.startTimeout();
396
+ this.pushBuffer.push(pushEvent);
397
+ }
398
+ return pushEvent;
399
+ }
400
+ /** Leaves the channel
401
+ *
402
+ * Unsubscribes from server events, and
403
+ * instructs channel to terminate on server
404
+ *
405
+ * Triggers onClose() hooks
406
+ *
407
+ * To receive leave acknowledgements, use the `receive`
408
+ * hook to bind to the server ack, ie:
409
+ *
410
+ * @example
411
+ * channel.leave().receive("ok", () => alert("left!") )
412
+ *
413
+ * @param {number} timeout
414
+ * @returns {Push}
415
+ */
416
+ leave(timeout = this.timeout) {
417
+ this.rejoinTimer.reset();
418
+ this.joinPush.cancelTimeout();
419
+ this.state = CHANNEL_STATES.leaving;
420
+ let onClose = () => {
421
+ if (this.socket.hasLogger()) this.socket.log("channel", `leave ${this.topic}`);
422
+ this.trigger(CHANNEL_EVENTS.close, "leave");
423
+ };
424
+ let leavePush = new Push(this, CHANNEL_EVENTS.leave, closure({}), timeout);
425
+ leavePush.receive("ok", () => onClose()).receive("timeout", () => onClose());
426
+ leavePush.send();
427
+ if (!this.canPush()) {
428
+ leavePush.trigger("ok", {});
429
+ }
430
+ return leavePush;
431
+ }
432
+ /**
433
+ * Overridable message hook
434
+ *
435
+ * Receives all events for specialized message handling
436
+ * before dispatching to the channel callbacks.
437
+ *
438
+ * Must return the payload, modified or unmodified
439
+ * @type{ChannelOnMessage}
440
+ */
441
+ onMessage(_event, payload, _ref) {
442
+ return payload;
443
+ }
444
+ /**
445
+ * Overridable filter hook
446
+ *
447
+ * If this function returns `true`, `binding`'s callback will be called.
448
+ *
449
+ * @type{ChannelFilterBindings}
450
+ */
451
+ filterBindings(_binding, _payload, _ref) {
452
+ return true;
453
+ }
454
+ isMember(topic, event, payload, joinRef) {
455
+ if (this.topic !== topic) {
456
+ return false;
457
+ }
458
+ if (joinRef && joinRef !== this.joinRef()) {
459
+ if (this.socket.hasLogger()) this.socket.log("channel", "dropping outdated message", { topic, event, payload, joinRef });
460
+ return false;
461
+ } else {
462
+ return true;
463
+ }
464
+ }
465
+ joinRef() {
466
+ return this.joinPush.ref;
467
+ }
468
+ /**
469
+ * @private
470
+ */
471
+ rejoin(timeout = this.timeout) {
472
+ if (this.isLeaving()) {
473
+ return;
474
+ }
475
+ this.socket.leaveOpenTopic(this.topic);
476
+ this.state = CHANNEL_STATES.joining;
477
+ this.joinPush.resend(timeout);
478
+ }
479
+ /**
480
+ * @param {string} event
481
+ * @param {unknown} [payload]
482
+ * @param {?string} [ref]
483
+ * @param {?string} [joinRef]
484
+ */
485
+ trigger(event, payload, ref, joinRef) {
486
+ let handledPayload = this.onMessage(event, payload, ref, joinRef);
487
+ if (payload && !handledPayload) {
488
+ throw new Error("channel onMessage callbacks must return the payload, modified or unmodified");
489
+ }
490
+ let eventBindings = this.bindings.filter((bind) => bind.event === event && this.filterBindings(bind, payload, ref));
491
+ for (let i = 0; i < eventBindings.length; i++) {
492
+ let bind = eventBindings[i];
493
+ bind.callback(handledPayload, ref, joinRef || this.joinRef());
494
+ }
495
+ }
496
+ /**
497
+ * @param {string} ref
498
+ */
499
+ replyEventName(ref) {
500
+ return `chan_reply_${ref}`;
501
+ }
502
+ isClosed() {
503
+ return this.state === CHANNEL_STATES.closed;
504
+ }
505
+ isErrored() {
506
+ return this.state === CHANNEL_STATES.errored;
507
+ }
508
+ isJoined() {
509
+ return this.state === CHANNEL_STATES.joined;
510
+ }
511
+ isJoining() {
512
+ return this.state === CHANNEL_STATES.joining;
513
+ }
514
+ isLeaving() {
515
+ return this.state === CHANNEL_STATES.leaving;
516
+ }
517
+ };
518
+ var Ajax = class {
519
+ static request(method, endPoint, headers, body, timeout, ontimeout, callback) {
520
+ if (global.XDomainRequest) {
521
+ let req = new global.XDomainRequest();
522
+ return this.xdomainRequest(req, method, endPoint, body, timeout, ontimeout, callback);
523
+ } else if (global.XMLHttpRequest) {
524
+ let req = new global.XMLHttpRequest();
525
+ return this.xhrRequest(req, method, endPoint, headers, body, timeout, ontimeout, callback);
526
+ } else if (global.fetch && global.AbortController) {
527
+ return this.fetchRequest(method, endPoint, headers, body, timeout, ontimeout, callback);
528
+ } else {
529
+ throw new Error("No suitable XMLHttpRequest implementation found");
530
+ }
531
+ }
532
+ static fetchRequest(method, endPoint, headers, body, timeout, ontimeout, callback) {
533
+ let options = {
534
+ method,
535
+ headers,
536
+ body
537
+ };
538
+ let controller = null;
539
+ if (timeout) {
540
+ controller = new AbortController();
541
+ setTimeout(() => controller.abort(), timeout);
542
+ options.signal = controller.signal;
543
+ }
544
+ global.fetch(endPoint, options).then((response) => response.text()).then((data) => this.parseJSON(data)).then((data) => callback && callback(data)).catch((err) => {
545
+ if (err.name === "AbortError" && ontimeout) {
546
+ ontimeout();
547
+ } else {
548
+ callback && callback(null);
549
+ }
550
+ });
551
+ return controller;
552
+ }
553
+ static xdomainRequest(req, method, endPoint, body, timeout, ontimeout, callback) {
554
+ req.timeout = timeout;
555
+ req.open(method, endPoint);
556
+ req.onload = () => {
557
+ let response = this.parseJSON(req.responseText);
558
+ callback && callback(response);
559
+ };
560
+ if (ontimeout) {
561
+ req.ontimeout = ontimeout;
562
+ }
563
+ req.onprogress = () => {
564
+ };
565
+ req.send(body);
566
+ return req;
567
+ }
568
+ static xhrRequest(req, method, endPoint, headers, body, timeout, ontimeout, callback) {
569
+ req.open(method, endPoint, true);
570
+ req.timeout = timeout;
571
+ for (let [key, value] of Object.entries(headers)) {
572
+ req.setRequestHeader(key, value);
573
+ }
574
+ req.onerror = () => callback && callback(null);
575
+ req.onreadystatechange = () => {
576
+ if (req.readyState === XHR_STATES.complete && callback) {
577
+ let response = this.parseJSON(req.responseText);
578
+ callback(response);
579
+ }
580
+ };
581
+ if (ontimeout) {
582
+ req.ontimeout = ontimeout;
583
+ }
584
+ req.send(body);
585
+ return req;
586
+ }
587
+ static parseJSON(resp) {
588
+ if (!resp || resp === "") {
589
+ return null;
590
+ }
591
+ try {
592
+ return JSON.parse(resp);
593
+ } catch {
594
+ console && console.log("failed to parse JSON response", resp);
595
+ return null;
596
+ }
597
+ }
598
+ static serialize(obj, parentKey) {
599
+ let queryStr = [];
600
+ for (var key in obj) {
601
+ if (!Object.prototype.hasOwnProperty.call(obj, key)) {
602
+ continue;
603
+ }
604
+ let paramKey = parentKey ? `${parentKey}[${key}]` : key;
605
+ let paramVal = obj[key];
606
+ if (typeof paramVal === "object") {
607
+ queryStr.push(this.serialize(paramVal, paramKey));
608
+ } else {
609
+ queryStr.push(encodeURIComponent(paramKey) + "=" + encodeURIComponent(paramVal));
610
+ }
611
+ }
612
+ return queryStr.join("&");
613
+ }
614
+ static appendParams(url, params) {
615
+ if (Object.keys(params).length === 0) {
616
+ return url;
617
+ }
618
+ let prefix = url.match(/\?/) ? "&" : "?";
619
+ return `${url}${prefix}${this.serialize(params)}`;
620
+ }
621
+ };
622
+ var arrayBufferToBase64 = (buffer) => {
623
+ let binary = "";
624
+ let bytes = new Uint8Array(buffer);
625
+ let len = bytes.byteLength;
626
+ for (let i = 0; i < len; i++) {
627
+ binary += String.fromCharCode(bytes[i]);
628
+ }
629
+ return btoa(binary);
630
+ };
631
+ var LongPoll = class {
632
+ constructor(endPoint, protocols) {
633
+ if (protocols && protocols.length === 2 && protocols[1].startsWith(AUTH_TOKEN_PREFIX)) {
634
+ this.authToken = atob(protocols[1].slice(AUTH_TOKEN_PREFIX.length));
635
+ }
636
+ this.endPoint = null;
637
+ this.token = null;
638
+ this.skipHeartbeat = true;
639
+ this.reqs = /* @__PURE__ */ new Set();
640
+ this.awaitingBatchAck = false;
641
+ this.currentBatch = null;
642
+ this.currentBatchTimer = null;
643
+ this.batchBuffer = [];
644
+ this.onopen = function() {
645
+ };
646
+ this.onerror = function() {
647
+ };
648
+ this.onmessage = function() {
649
+ };
650
+ this.onclose = function() {
651
+ };
652
+ this.pollEndpoint = this.normalizeEndpoint(endPoint);
653
+ this.readyState = SOCKET_STATES.connecting;
654
+ setTimeout(() => this.poll(), 0);
655
+ }
656
+ normalizeEndpoint(endPoint) {
657
+ return endPoint.replace("ws://", "http://").replace("wss://", "https://").replace(new RegExp("(.*)/" + TRANSPORTS.websocket), "$1/" + TRANSPORTS.longpoll);
658
+ }
659
+ endpointURL() {
660
+ return Ajax.appendParams(this.pollEndpoint, { token: this.token });
661
+ }
662
+ closeAndRetry(code, reason, wasClean) {
663
+ this.close(code, reason, wasClean);
664
+ this.readyState = SOCKET_STATES.connecting;
665
+ }
666
+ ontimeout() {
667
+ this.onerror("timeout");
668
+ this.closeAndRetry(1005, "timeout", false);
669
+ }
670
+ isActive() {
671
+ return this.readyState === SOCKET_STATES.open || this.readyState === SOCKET_STATES.connecting;
672
+ }
673
+ poll() {
674
+ const headers = { "Accept": "application/json" };
675
+ if (this.authToken) {
676
+ headers["X-Phoenix-AuthToken"] = this.authToken;
677
+ }
678
+ this.ajax("GET", headers, null, () => this.ontimeout(), (resp) => {
679
+ if (resp) {
680
+ var { status, token, messages } = resp;
681
+ if (status === 410 && this.token !== null) {
682
+ this.onerror(410);
683
+ this.closeAndRetry(3410, "session_gone", false);
684
+ return;
685
+ }
686
+ this.token = token;
687
+ } else {
688
+ status = 0;
689
+ }
690
+ switch (status) {
691
+ case 200:
692
+ messages.forEach((msg) => {
693
+ setTimeout(() => this.onmessage({ data: msg }), 0);
694
+ });
695
+ this.poll();
696
+ break;
697
+ case 204:
698
+ this.poll();
699
+ break;
700
+ case 410:
701
+ this.readyState = SOCKET_STATES.open;
702
+ this.onopen({});
703
+ this.poll();
704
+ break;
705
+ case 403:
706
+ this.onerror(403);
707
+ this.close(1008, "forbidden", false);
708
+ break;
709
+ case 0:
710
+ case 500:
711
+ this.onerror(500);
712
+ this.closeAndRetry(1011, "internal server error", 500);
713
+ break;
714
+ default:
715
+ throw new Error(`unhandled poll status ${status}`);
716
+ }
717
+ });
718
+ }
719
+ // we collect all pushes within the current event loop by
720
+ // setTimeout 0, which optimizes back-to-back procedural
721
+ // pushes against an empty buffer
722
+ send(body) {
723
+ if (typeof body !== "string") {
724
+ body = arrayBufferToBase64(body);
725
+ }
726
+ if (this.currentBatch) {
727
+ this.currentBatch.push(body);
728
+ } else if (this.awaitingBatchAck) {
729
+ this.batchBuffer.push(body);
730
+ } else {
731
+ this.currentBatch = [body];
732
+ this.currentBatchTimer = setTimeout(() => {
733
+ this.batchSend(this.currentBatch);
734
+ this.currentBatch = null;
735
+ }, 0);
736
+ }
737
+ }
738
+ batchSend(messages) {
739
+ this.awaitingBatchAck = true;
740
+ this.ajax("POST", { "Content-Type": "application/x-ndjson" }, messages.join("\n"), () => this.onerror("timeout"), (resp) => {
741
+ this.awaitingBatchAck = false;
742
+ if (!resp || resp.status !== 200) {
743
+ this.onerror(resp && resp.status);
744
+ this.closeAndRetry(1011, "internal server error", false);
745
+ } else if (this.batchBuffer.length > 0) {
746
+ this.batchSend(this.batchBuffer);
747
+ this.batchBuffer = [];
748
+ }
749
+ });
750
+ }
751
+ close(code, reason, wasClean) {
752
+ for (let req of this.reqs) {
753
+ req.abort();
754
+ }
755
+ this.readyState = SOCKET_STATES.closed;
756
+ let opts = Object.assign({ code: 1e3, reason: void 0, wasClean: true }, { code, reason, wasClean });
757
+ this.batchBuffer = [];
758
+ clearTimeout(this.currentBatchTimer);
759
+ this.currentBatchTimer = null;
760
+ if (typeof CloseEvent !== "undefined") {
761
+ this.onclose(new CloseEvent("close", opts));
762
+ } else {
763
+ this.onclose(opts);
764
+ }
765
+ }
766
+ ajax(method, headers, body, onCallerTimeout, callback) {
767
+ let req;
768
+ let ontimeout = () => {
769
+ this.reqs.delete(req);
770
+ onCallerTimeout();
771
+ };
772
+ req = Ajax.request(method, this.endpointURL(), headers, body, this.timeout, ontimeout, (resp) => {
773
+ this.reqs.delete(req);
774
+ if (this.isActive()) {
775
+ callback(resp);
776
+ }
777
+ });
778
+ this.reqs.add(req);
779
+ }
780
+ };
781
+ var Presence = class _Presence {
782
+ /**
783
+ * Initializes the Presence
784
+ * @param {Channel} channel - The Channel
785
+ * @param {PresenceOptions} [opts] - The options, for example `{events: {state: "state", diff: "diff"}}`
786
+ */
787
+ constructor(channel, opts = {}) {
788
+ let events = opts.events || /** @type {PresenceEvents} */
789
+ { state: "presence_state", diff: "presence_diff" };
790
+ this.state = {};
791
+ this.pendingDiffs = [];
792
+ this.channel = channel;
793
+ this.joinRef = null;
794
+ this.caller = {
795
+ onJoin: function() {
796
+ },
797
+ onLeave: function() {
798
+ },
799
+ onSync: function() {
800
+ }
801
+ };
802
+ this.channel.on(events.state, (newState) => {
803
+ let { onJoin, onLeave, onSync } = this.caller;
804
+ this.joinRef = this.channel.joinRef();
805
+ this.state = _Presence.syncState(this.state, newState, onJoin, onLeave);
806
+ this.pendingDiffs.forEach((diff) => {
807
+ this.state = _Presence.syncDiff(this.state, diff, onJoin, onLeave);
808
+ });
809
+ this.pendingDiffs = [];
810
+ onSync();
811
+ });
812
+ this.channel.on(events.diff, (diff) => {
813
+ let { onJoin, onLeave, onSync } = this.caller;
814
+ if (this.inPendingSyncState()) {
815
+ this.pendingDiffs.push(diff);
816
+ } else {
817
+ this.state = _Presence.syncDiff(this.state, diff, onJoin, onLeave);
818
+ onSync();
819
+ }
820
+ });
821
+ }
822
+ /**
823
+ * @param {PresenceOnJoin} callback
824
+ */
825
+ onJoin(callback) {
826
+ this.caller.onJoin = callback;
827
+ }
828
+ /**
829
+ * @param {PresenceOnLeave} callback
830
+ */
831
+ onLeave(callback) {
832
+ this.caller.onLeave = callback;
833
+ }
834
+ /**
835
+ * @param {PresenceOnSync} callback
836
+ */
837
+ onSync(callback) {
838
+ this.caller.onSync = callback;
839
+ }
840
+ /**
841
+ * Returns the array of presences, with selected metadata.
842
+ *
843
+ * @template [T=PresenceState]
844
+ * @param {((key: string, obj: PresenceState) => T)} [by]
845
+ *
846
+ * @returns {T[]}
847
+ */
848
+ list(by) {
849
+ return _Presence.list(this.state, by);
850
+ }
851
+ inPendingSyncState() {
852
+ return !this.joinRef || this.joinRef !== this.channel.joinRef();
853
+ }
854
+ // lower-level public static API
855
+ /**
856
+ * Used to sync the list of presences on the server
857
+ * with the client's state. An optional `onJoin` and `onLeave` callback can
858
+ * be provided to react to changes in the client's local presences across
859
+ * disconnects and reconnects with the server.
860
+ *
861
+ * @param {Record<string, PresenceState>} currentState
862
+ * @param {Record<string, PresenceState>} newState
863
+ * @param {PresenceOnJoin} onJoin
864
+ * @param {PresenceOnLeave} onLeave
865
+ *
866
+ * @returns {Record<string, PresenceState>}
867
+ */
868
+ static syncState(currentState, newState, onJoin, onLeave) {
869
+ let state = this.clone(currentState);
870
+ let joins = {};
871
+ let leaves = {};
872
+ this.map(state, (key, presence) => {
873
+ if (!newState[key]) {
874
+ leaves[key] = presence;
875
+ }
876
+ });
877
+ this.map(newState, (key, newPresence) => {
878
+ let currentPresence = state[key];
879
+ if (currentPresence) {
880
+ let newRefs = newPresence.metas.map((m) => m.phx_ref);
881
+ let curRefs = currentPresence.metas.map((m) => m.phx_ref);
882
+ let joinedMetas = newPresence.metas.filter((m) => curRefs.indexOf(m.phx_ref) < 0);
883
+ let leftMetas = currentPresence.metas.filter((m) => newRefs.indexOf(m.phx_ref) < 0);
884
+ if (joinedMetas.length > 0) {
885
+ joins[key] = newPresence;
886
+ joins[key].metas = joinedMetas;
887
+ }
888
+ if (leftMetas.length > 0) {
889
+ leaves[key] = this.clone(currentPresence);
890
+ leaves[key].metas = leftMetas;
891
+ }
892
+ } else {
893
+ joins[key] = newPresence;
894
+ }
895
+ });
896
+ return this.syncDiff(state, { joins, leaves }, onJoin, onLeave);
897
+ }
898
+ /**
899
+ *
900
+ * Used to sync a diff of presence join and leave
901
+ * events from the server, as they happen. Like `syncState`, `syncDiff`
902
+ * accepts optional `onJoin` and `onLeave` callbacks to react to a user
903
+ * joining or leaving from a device.
904
+ *
905
+ * @param {Record<string, PresenceState>} state
906
+ * @param {PresenceDiff} diff
907
+ * @param {PresenceOnJoin} onJoin
908
+ * @param {PresenceOnLeave} onLeave
909
+ *
910
+ * @returns {Record<string, PresenceState>}
911
+ */
912
+ static syncDiff(state, diff, onJoin, onLeave) {
913
+ let { joins, leaves } = this.clone(diff);
914
+ if (!onJoin) {
915
+ onJoin = function() {
916
+ };
917
+ }
918
+ if (!onLeave) {
919
+ onLeave = function() {
920
+ };
921
+ }
922
+ this.map(joins, (key, newPresence) => {
923
+ let currentPresence = state[key];
924
+ state[key] = this.clone(newPresence);
925
+ if (currentPresence) {
926
+ let joinedRefs = state[key].metas.map((m) => m.phx_ref);
927
+ let curMetas = currentPresence.metas.filter((m) => joinedRefs.indexOf(m.phx_ref) < 0);
928
+ state[key].metas.unshift(...curMetas);
929
+ }
930
+ onJoin(key, currentPresence, newPresence);
931
+ });
932
+ this.map(leaves, (key, leftPresence) => {
933
+ let currentPresence = state[key];
934
+ if (!currentPresence) {
935
+ return;
936
+ }
937
+ let refsToRemove = leftPresence.metas.map((m) => m.phx_ref);
938
+ currentPresence.metas = currentPresence.metas.filter((p) => {
939
+ return refsToRemove.indexOf(p.phx_ref) < 0;
940
+ });
941
+ onLeave(key, currentPresence, leftPresence);
942
+ if (currentPresence.metas.length === 0) {
943
+ delete state[key];
944
+ }
945
+ });
946
+ return state;
947
+ }
948
+ /**
949
+ * Returns the array of presences, with selected metadata.
950
+ *
951
+ * @template [T=PresenceState]
952
+ * @param {Record<string, PresenceState>} presences
953
+ * @param {((key: string, obj: PresenceState) => T)} [chooser]
954
+ *
955
+ * @returns {T[]}
956
+ */
957
+ static list(presences, chooser) {
958
+ if (!chooser) {
959
+ chooser = function(key, pres) {
960
+ return pres;
961
+ };
962
+ }
963
+ return this.map(presences, (key, presence) => {
964
+ return chooser(key, presence);
965
+ });
966
+ }
967
+ // private
968
+ /**
969
+ * @template T
970
+ * @param {Record<string, PresenceState>} obj
971
+ * @param {(key: string, obj: PresenceState) => T} func
972
+ */
973
+ static map(obj, func) {
974
+ return Object.getOwnPropertyNames(obj).map((key) => func(key, obj[key]));
975
+ }
976
+ /**
977
+ * @template T
978
+ * @param {T} obj
979
+ * @returns {T}
980
+ */
981
+ static clone(obj) {
982
+ return JSON.parse(JSON.stringify(obj));
983
+ }
984
+ };
985
+ var serializer_default = {
986
+ HEADER_LENGTH: 1,
987
+ META_LENGTH: 4,
988
+ KINDS: { push: 0, reply: 1, broadcast: 2 },
989
+ /**
990
+ * @template T
991
+ * @param {Message<Record<string, any>>} msg
992
+ * @param {(msg: ArrayBuffer | string) => T} callback
993
+ * @returns {T}
994
+ */
995
+ encode(msg, callback) {
996
+ if (msg.payload.constructor === ArrayBuffer) {
997
+ return callback(this.binaryEncode(msg));
998
+ } else {
999
+ let payload = [msg.join_ref, msg.ref, msg.topic, msg.event, msg.payload];
1000
+ return callback(JSON.stringify(payload));
1001
+ }
1002
+ },
1003
+ /**
1004
+ * @template T
1005
+ * @param {ArrayBuffer | string} rawPayload
1006
+ * @param {(msg: Message<unknown>) => T} callback
1007
+ * @returns {T}
1008
+ */
1009
+ decode(rawPayload, callback) {
1010
+ if (rawPayload.constructor === ArrayBuffer) {
1011
+ return callback(this.binaryDecode(rawPayload));
1012
+ } else {
1013
+ let [join_ref, ref, topic, event, payload] = JSON.parse(rawPayload);
1014
+ return callback({ join_ref, ref, topic, event, payload });
1015
+ }
1016
+ },
1017
+ /** @private */
1018
+ binaryEncode(message) {
1019
+ let { join_ref, ref, event, topic, payload } = message;
1020
+ let metaLength = this.META_LENGTH + join_ref.length + ref.length + topic.length + event.length;
1021
+ let header = new ArrayBuffer(this.HEADER_LENGTH + metaLength);
1022
+ let view = new DataView(header);
1023
+ let offset = 0;
1024
+ view.setUint8(offset++, this.KINDS.push);
1025
+ view.setUint8(offset++, join_ref.length);
1026
+ view.setUint8(offset++, ref.length);
1027
+ view.setUint8(offset++, topic.length);
1028
+ view.setUint8(offset++, event.length);
1029
+ Array.from(join_ref, (char) => view.setUint8(offset++, char.charCodeAt(0)));
1030
+ Array.from(ref, (char) => view.setUint8(offset++, char.charCodeAt(0)));
1031
+ Array.from(topic, (char) => view.setUint8(offset++, char.charCodeAt(0)));
1032
+ Array.from(event, (char) => view.setUint8(offset++, char.charCodeAt(0)));
1033
+ var combined = new Uint8Array(header.byteLength + payload.byteLength);
1034
+ combined.set(new Uint8Array(header), 0);
1035
+ combined.set(new Uint8Array(payload), header.byteLength);
1036
+ return combined.buffer;
1037
+ },
1038
+ /**
1039
+ * @private
1040
+ */
1041
+ binaryDecode(buffer) {
1042
+ let view = new DataView(buffer);
1043
+ let kind = view.getUint8(0);
1044
+ let decoder = new TextDecoder();
1045
+ switch (kind) {
1046
+ case this.KINDS.push:
1047
+ return this.decodePush(buffer, view, decoder);
1048
+ case this.KINDS.reply:
1049
+ return this.decodeReply(buffer, view, decoder);
1050
+ case this.KINDS.broadcast:
1051
+ return this.decodeBroadcast(buffer, view, decoder);
1052
+ }
1053
+ },
1054
+ /** @private */
1055
+ decodePush(buffer, view, decoder) {
1056
+ let joinRefSize = view.getUint8(1);
1057
+ let topicSize = view.getUint8(2);
1058
+ let eventSize = view.getUint8(3);
1059
+ let offset = this.HEADER_LENGTH + this.META_LENGTH - 1;
1060
+ let joinRef = decoder.decode(buffer.slice(offset, offset + joinRefSize));
1061
+ offset = offset + joinRefSize;
1062
+ let topic = decoder.decode(buffer.slice(offset, offset + topicSize));
1063
+ offset = offset + topicSize;
1064
+ let event = decoder.decode(buffer.slice(offset, offset + eventSize));
1065
+ offset = offset + eventSize;
1066
+ let data = buffer.slice(offset, buffer.byteLength);
1067
+ return { join_ref: joinRef, ref: null, topic, event, payload: data };
1068
+ },
1069
+ /** @private */
1070
+ decodeReply(buffer, view, decoder) {
1071
+ let joinRefSize = view.getUint8(1);
1072
+ let refSize = view.getUint8(2);
1073
+ let topicSize = view.getUint8(3);
1074
+ let eventSize = view.getUint8(4);
1075
+ let offset = this.HEADER_LENGTH + this.META_LENGTH;
1076
+ let joinRef = decoder.decode(buffer.slice(offset, offset + joinRefSize));
1077
+ offset = offset + joinRefSize;
1078
+ let ref = decoder.decode(buffer.slice(offset, offset + refSize));
1079
+ offset = offset + refSize;
1080
+ let topic = decoder.decode(buffer.slice(offset, offset + topicSize));
1081
+ offset = offset + topicSize;
1082
+ let event = decoder.decode(buffer.slice(offset, offset + eventSize));
1083
+ offset = offset + eventSize;
1084
+ let data = buffer.slice(offset, buffer.byteLength);
1085
+ let payload = { status: event, response: data };
1086
+ return { join_ref: joinRef, ref, topic, event: CHANNEL_EVENTS.reply, payload };
1087
+ },
1088
+ /** @private */
1089
+ decodeBroadcast(buffer, view, decoder) {
1090
+ let topicSize = view.getUint8(1);
1091
+ let eventSize = view.getUint8(2);
1092
+ let offset = this.HEADER_LENGTH + 2;
1093
+ let topic = decoder.decode(buffer.slice(offset, offset + topicSize));
1094
+ offset = offset + topicSize;
1095
+ let event = decoder.decode(buffer.slice(offset, offset + eventSize));
1096
+ offset = offset + eventSize;
1097
+ let data = buffer.slice(offset, buffer.byteLength);
1098
+ return { join_ref: null, ref: null, topic, event, payload: data };
1099
+ }
1100
+ };
1101
+ var Socket = class {
1102
+ /** Initializes the Socket *
1103
+ *
1104
+ * For IE8 support use an ES5-shim (https://github.com/es-shims/es5-shim)
1105
+ *
1106
+ * @constructor
1107
+ * @param {string} endPoint - The string WebSocket endpoint, ie, `"ws://example.com/socket"`,
1108
+ * `"wss://example.com"`
1109
+ * `"/socket"` (inherited host & protocol)
1110
+ * @param {SocketOptions} [opts] - Optional configuration
1111
+ */
1112
+ constructor(endPoint, opts = {}) {
1113
+ this.stateChangeCallbacks = { open: [], close: [], error: [], message: [] };
1114
+ this.channels = [];
1115
+ this.sendBuffer = [];
1116
+ this.ref = 0;
1117
+ this.fallbackRef = null;
1118
+ this.timeout = opts.timeout || DEFAULT_TIMEOUT;
1119
+ this.transport = opts.transport || global.WebSocket || LongPoll;
1120
+ this.conn = void 0;
1121
+ this.primaryPassedHealthCheck = false;
1122
+ this.longPollFallbackMs = opts.longPollFallbackMs;
1123
+ this.fallbackTimer = null;
1124
+ let envSessionStorage = null;
1125
+ try {
1126
+ envSessionStorage = global && global.sessionStorage;
1127
+ } catch {
1128
+ }
1129
+ this.sessionStore = opts.sessionStorage || envSessionStorage;
1130
+ this.establishedConnections = 0;
1131
+ this.defaultEncoder = serializer_default.encode.bind(serializer_default);
1132
+ this.defaultDecoder = serializer_default.decode.bind(serializer_default);
1133
+ this.closeWasClean = true;
1134
+ this.disconnecting = false;
1135
+ this.binaryType = opts.binaryType || "arraybuffer";
1136
+ this.connectClock = 1;
1137
+ this.pageHidden = false;
1138
+ this.encode = void 0;
1139
+ this.decode = void 0;
1140
+ if (this.transport !== LongPoll) {
1141
+ this.encode = opts.encode || this.defaultEncoder;
1142
+ this.decode = opts.decode || this.defaultDecoder;
1143
+ } else {
1144
+ this.encode = this.defaultEncoder;
1145
+ this.decode = this.defaultDecoder;
1146
+ }
1147
+ let awaitingConnectionOnPageShow = null;
1148
+ if (phxWindow && phxWindow.addEventListener) {
1149
+ phxWindow.addEventListener("pagehide", (_e) => {
1150
+ if (this.conn) {
1151
+ this.disconnect();
1152
+ awaitingConnectionOnPageShow = this.connectClock;
1153
+ }
1154
+ });
1155
+ phxWindow.addEventListener("pageshow", (_e) => {
1156
+ if (awaitingConnectionOnPageShow === this.connectClock) {
1157
+ awaitingConnectionOnPageShow = null;
1158
+ this.connect();
1159
+ }
1160
+ });
1161
+ phxWindow.addEventListener("visibilitychange", () => {
1162
+ if (document.visibilityState === "hidden") {
1163
+ this.pageHidden = true;
1164
+ } else {
1165
+ this.pageHidden = false;
1166
+ if (!this.isConnected() && !this.closeWasClean) {
1167
+ this.teardown(() => this.connect());
1168
+ }
1169
+ }
1170
+ });
1171
+ }
1172
+ this.heartbeatIntervalMs = opts.heartbeatIntervalMs || 3e4;
1173
+ this.autoSendHeartbeat = opts.autoSendHeartbeat ?? true;
1174
+ this.heartbeatCallback = opts.heartbeatCallback ?? (() => {
1175
+ });
1176
+ this.rejoinAfterMs = (tries) => {
1177
+ if (opts.rejoinAfterMs) {
1178
+ return opts.rejoinAfterMs(tries);
1179
+ } else {
1180
+ return [1e3, 2e3, 5e3][tries - 1] || 1e4;
1181
+ }
1182
+ };
1183
+ this.reconnectAfterMs = (tries) => {
1184
+ if (opts.reconnectAfterMs) {
1185
+ return opts.reconnectAfterMs(tries);
1186
+ } else {
1187
+ return [10, 50, 100, 150, 200, 250, 500, 1e3, 2e3][tries - 1] || 5e3;
1188
+ }
1189
+ };
1190
+ this.logger = opts.logger || null;
1191
+ if (!this.logger && opts.debug) {
1192
+ this.logger = (kind, msg, data) => {
1193
+ console.log(`${kind}: ${msg}`, data);
1194
+ };
1195
+ }
1196
+ this.longpollerTimeout = opts.longpollerTimeout || 2e4;
1197
+ this.params = closure(opts.params || {});
1198
+ this.endPoint = `${endPoint}/${TRANSPORTS.websocket}`;
1199
+ this.vsn = opts.vsn || DEFAULT_VSN;
1200
+ this.heartbeatTimeoutTimer = null;
1201
+ this.heartbeatTimer = null;
1202
+ this.heartbeatSentAt = null;
1203
+ this.pendingHeartbeatRef = null;
1204
+ this.reconnectTimer = new Timer(() => {
1205
+ if (this.pageHidden) {
1206
+ this.log("Not reconnecting as page is hidden!");
1207
+ this.teardown();
1208
+ return;
1209
+ }
1210
+ this.teardown(async () => {
1211
+ if (opts.beforeReconnect) await opts.beforeReconnect();
1212
+ this.connect();
1213
+ });
1214
+ }, this.reconnectAfterMs);
1215
+ this.authToken = opts.authToken;
1216
+ }
1217
+ /**
1218
+ * Returns the LongPoll transport reference
1219
+ */
1220
+ getLongPollTransport() {
1221
+ return LongPoll;
1222
+ }
1223
+ /**
1224
+ * Disconnects and replaces the active transport
1225
+ *
1226
+ * @param {SocketTransport} newTransport - The new transport class to instantiate
1227
+ *
1228
+ */
1229
+ replaceTransport(newTransport) {
1230
+ this.connectClock++;
1231
+ this.closeWasClean = true;
1232
+ clearTimeout(this.fallbackTimer);
1233
+ this.reconnectTimer.reset();
1234
+ if (this.conn) {
1235
+ this.conn.close();
1236
+ this.conn = null;
1237
+ }
1238
+ this.transport = newTransport;
1239
+ }
1240
+ /**
1241
+ * Returns the socket protocol
1242
+ *
1243
+ * @returns {"wss" | "ws"}
1244
+ */
1245
+ protocol() {
1246
+ return location.protocol.match(/^https/) ? "wss" : "ws";
1247
+ }
1248
+ /**
1249
+ * The fully qualified socket url
1250
+ *
1251
+ * @returns {string}
1252
+ */
1253
+ endPointURL() {
1254
+ let uri = Ajax.appendParams(
1255
+ Ajax.appendParams(this.endPoint, this.params()),
1256
+ { vsn: this.vsn }
1257
+ );
1258
+ if (uri.charAt(0) !== "/") {
1259
+ return uri;
1260
+ }
1261
+ if (uri.charAt(1) === "/") {
1262
+ return `${this.protocol()}:${uri}`;
1263
+ }
1264
+ return `${this.protocol()}://${location.host}${uri}`;
1265
+ }
1266
+ /**
1267
+ * Disconnects the socket
1268
+ *
1269
+ * See https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent#Status_codes for valid status codes.
1270
+ *
1271
+ * @param {() => void} [callback] - Optional callback which is called after socket is disconnected.
1272
+ * @param {number} [code] - A status code for disconnection (Optional).
1273
+ * @param {string} [reason] - A textual description of the reason to disconnect. (Optional)
1274
+ */
1275
+ disconnect(callback, code, reason) {
1276
+ this.connectClock++;
1277
+ this.disconnecting = true;
1278
+ this.closeWasClean = true;
1279
+ clearTimeout(this.fallbackTimer);
1280
+ this.reconnectTimer.reset();
1281
+ this.teardown(() => {
1282
+ this.disconnecting = false;
1283
+ callback && callback();
1284
+ }, code, reason);
1285
+ }
1286
+ /**
1287
+ * @param {Params} [params] - [DEPRECATED] The params to send when connecting, for example `{user_id: userToken}`
1288
+ *
1289
+ * Passing params to connect is deprecated; pass them in the Socket constructor instead:
1290
+ * `new Socket("/socket", {params: {user_id: userToken}})`.
1291
+ */
1292
+ connect(params) {
1293
+ if (params) {
1294
+ console && console.log("passing params to connect is deprecated. Instead pass :params to the Socket constructor");
1295
+ this.params = closure(params);
1296
+ }
1297
+ if (this.conn && !this.disconnecting) {
1298
+ return;
1299
+ }
1300
+ if (this.longPollFallbackMs && this.transport !== LongPoll) {
1301
+ this.connectWithFallback(LongPoll, this.longPollFallbackMs);
1302
+ } else {
1303
+ this.transportConnect();
1304
+ }
1305
+ }
1306
+ /**
1307
+ * Logs the message. Override `this.logger` for specialized logging. noops by default
1308
+ * @param {string} kind
1309
+ * @param {string} msg
1310
+ * @param {Object} data
1311
+ */
1312
+ log(kind, msg, data) {
1313
+ this.logger && this.logger(kind, msg, data);
1314
+ }
1315
+ /**
1316
+ * Returns true if a logger has been set on this socket.
1317
+ */
1318
+ hasLogger() {
1319
+ return this.logger !== null;
1320
+ }
1321
+ /**
1322
+ * Registers callbacks for connection open events
1323
+ *
1324
+ * @example socket.onOpen(function(){ console.info("the socket was opened") })
1325
+ *
1326
+ * @param {SocketOnOpen} callback
1327
+ */
1328
+ onOpen(callback) {
1329
+ let ref = this.makeRef();
1330
+ this.stateChangeCallbacks.open.push([ref, callback]);
1331
+ return ref;
1332
+ }
1333
+ /**
1334
+ * Registers callbacks for connection close events
1335
+ * @param {SocketOnClose} callback
1336
+ * @returns {string}
1337
+ */
1338
+ onClose(callback) {
1339
+ let ref = this.makeRef();
1340
+ this.stateChangeCallbacks.close.push([ref, callback]);
1341
+ return ref;
1342
+ }
1343
+ /**
1344
+ * Registers callbacks for connection error events
1345
+ *
1346
+ * @example socket.onError(function(error){ alert("An error occurred") })
1347
+ *
1348
+ * @param {SocketOnError} callback
1349
+ * @returns {string}
1350
+ */
1351
+ onError(callback) {
1352
+ let ref = this.makeRef();
1353
+ this.stateChangeCallbacks.error.push([ref, callback]);
1354
+ return ref;
1355
+ }
1356
+ /**
1357
+ * Registers callbacks for connection message events
1358
+ * @param {SocketOnMessage} callback
1359
+ * @returns {string}
1360
+ */
1361
+ onMessage(callback) {
1362
+ let ref = this.makeRef();
1363
+ this.stateChangeCallbacks.message.push([ref, callback]);
1364
+ return ref;
1365
+ }
1366
+ /**
1367
+ * Sets a callback that receives lifecycle events for internal heartbeat messages.
1368
+ * Useful for instrumenting connection health (e.g. sent/ok/timeout/disconnected).
1369
+ * @param {HeartbeatCallback} callback
1370
+ */
1371
+ onHeartbeat(callback) {
1372
+ this.heartbeatCallback = callback;
1373
+ }
1374
+ /**
1375
+ * Pings the server and invokes the callback with the RTT in milliseconds
1376
+ * @param {(timeDelta: number) => void} callback
1377
+ *
1378
+ * Returns true if the ping was pushed or false if unable to be pushed.
1379
+ */
1380
+ ping(callback) {
1381
+ if (!this.isConnected()) {
1382
+ return false;
1383
+ }
1384
+ let ref = this.makeRef();
1385
+ let startTime = Date.now();
1386
+ this.push({ topic: "phoenix", event: "heartbeat", payload: {}, ref });
1387
+ let onMsgRef = this.onMessage((msg) => {
1388
+ if (msg.ref === ref) {
1389
+ this.off([onMsgRef]);
1390
+ callback(Date.now() - startTime);
1391
+ }
1392
+ });
1393
+ return true;
1394
+ }
1395
+ /**
1396
+ * @private
1397
+ *
1398
+ * @param {Function}
1399
+ */
1400
+ transportName(transport) {
1401
+ switch (transport) {
1402
+ case LongPoll:
1403
+ return "LongPoll";
1404
+ default:
1405
+ return transport.name;
1406
+ }
1407
+ }
1408
+ /**
1409
+ * @private
1410
+ */
1411
+ transportConnect() {
1412
+ this.connectClock++;
1413
+ this.closeWasClean = false;
1414
+ let protocols = void 0;
1415
+ if (this.authToken) {
1416
+ protocols = ["phoenix", `${AUTH_TOKEN_PREFIX}${btoa(this.authToken).replace(/=/g, "")}`];
1417
+ }
1418
+ this.conn = new this.transport(this.endPointURL(), protocols);
1419
+ this.conn.binaryType = this.binaryType;
1420
+ this.conn.timeout = this.longpollerTimeout;
1421
+ this.conn.onopen = () => this.onConnOpen();
1422
+ this.conn.onerror = (error) => this.onConnError(error);
1423
+ this.conn.onmessage = (event) => this.onConnMessage(event);
1424
+ this.conn.onclose = (event) => this.onConnClose(event);
1425
+ }
1426
+ getSession(key) {
1427
+ return this.sessionStore && this.sessionStore.getItem(key);
1428
+ }
1429
+ storeSession(key, val) {
1430
+ this.sessionStore && this.sessionStore.setItem(key, val);
1431
+ }
1432
+ connectWithFallback(fallbackTransport, fallbackThreshold = 2500) {
1433
+ clearTimeout(this.fallbackTimer);
1434
+ let established = false;
1435
+ let primaryTransport = true;
1436
+ let openRef, errorRef;
1437
+ let fallbackTransportName = this.transportName(fallbackTransport);
1438
+ let fallback = (reason) => {
1439
+ this.log("transport", `falling back to ${fallbackTransportName}...`, reason);
1440
+ this.off([openRef, errorRef]);
1441
+ primaryTransport = false;
1442
+ this.replaceTransport(fallbackTransport);
1443
+ this.transportConnect();
1444
+ };
1445
+ if (this.getSession(`phx:fallback:${fallbackTransportName}`)) {
1446
+ return fallback("memorized");
1447
+ }
1448
+ this.fallbackTimer = setTimeout(fallback, fallbackThreshold);
1449
+ errorRef = this.onError((reason) => {
1450
+ this.log("transport", "error", reason);
1451
+ if (primaryTransport && !established) {
1452
+ clearTimeout(this.fallbackTimer);
1453
+ fallback(reason);
1454
+ }
1455
+ });
1456
+ if (this.fallbackRef) {
1457
+ this.off([this.fallbackRef]);
1458
+ }
1459
+ this.fallbackRef = this.onOpen(() => {
1460
+ established = true;
1461
+ if (!primaryTransport) {
1462
+ let fallbackTransportName2 = this.transportName(fallbackTransport);
1463
+ if (!this.primaryPassedHealthCheck) {
1464
+ this.storeSession(`phx:fallback:${fallbackTransportName2}`, "true");
1465
+ }
1466
+ return this.log("transport", `established ${fallbackTransportName2} fallback`);
1467
+ }
1468
+ clearTimeout(this.fallbackTimer);
1469
+ this.fallbackTimer = setTimeout(fallback, fallbackThreshold);
1470
+ this.ping((rtt) => {
1471
+ this.log("transport", "connected to primary after", rtt);
1472
+ this.primaryPassedHealthCheck = true;
1473
+ clearTimeout(this.fallbackTimer);
1474
+ });
1475
+ });
1476
+ this.transportConnect();
1477
+ }
1478
+ clearHeartbeats() {
1479
+ clearTimeout(this.heartbeatTimer);
1480
+ clearTimeout(this.heartbeatTimeoutTimer);
1481
+ }
1482
+ onConnOpen() {
1483
+ if (this.hasLogger()) this.log("transport", `connected to ${this.endPointURL()}`);
1484
+ this.closeWasClean = false;
1485
+ this.disconnecting = false;
1486
+ this.establishedConnections++;
1487
+ this.flushSendBuffer();
1488
+ this.reconnectTimer.reset();
1489
+ if (this.autoSendHeartbeat) {
1490
+ this.resetHeartbeat();
1491
+ }
1492
+ this.triggerStateCallbacks("open");
1493
+ }
1494
+ /**
1495
+ * @private
1496
+ */
1497
+ heartbeatTimeout() {
1498
+ if (this.pendingHeartbeatRef) {
1499
+ this.pendingHeartbeatRef = null;
1500
+ this.heartbeatSentAt = null;
1501
+ if (this.hasLogger()) {
1502
+ this.log("transport", "heartbeat timeout. Attempting to re-establish connection");
1503
+ }
1504
+ try {
1505
+ this.heartbeatCallback("timeout");
1506
+ } catch (e) {
1507
+ this.log("error", "error in heartbeat callback", e);
1508
+ }
1509
+ this.triggerChanError(new Error("heartbeat timeout"));
1510
+ this.closeWasClean = false;
1511
+ this.teardown(() => this.reconnectTimer.scheduleTimeout(), WS_CLOSE_NORMAL, "heartbeat timeout");
1512
+ }
1513
+ }
1514
+ resetHeartbeat() {
1515
+ if (this.conn && this.conn.skipHeartbeat) {
1516
+ return;
1517
+ }
1518
+ this.pendingHeartbeatRef = null;
1519
+ this.clearHeartbeats();
1520
+ this.heartbeatTimer = setTimeout(() => this.sendHeartbeat(), this.heartbeatIntervalMs);
1521
+ }
1522
+ teardown(callback, code, reason) {
1523
+ if (!this.conn) {
1524
+ return callback && callback();
1525
+ }
1526
+ const connToClose = this.conn;
1527
+ this.waitForBufferDone(connToClose, () => {
1528
+ if (code) {
1529
+ connToClose.close(code, reason || "");
1530
+ } else {
1531
+ connToClose.close();
1532
+ }
1533
+ this.waitForSocketClosed(connToClose, () => {
1534
+ if (this.conn === connToClose) {
1535
+ this.conn.onopen = function() {
1536
+ };
1537
+ this.conn.onerror = function() {
1538
+ };
1539
+ this.conn.onmessage = function() {
1540
+ };
1541
+ this.conn.onclose = function() {
1542
+ };
1543
+ this.conn = null;
1544
+ }
1545
+ callback && callback();
1546
+ });
1547
+ });
1548
+ }
1549
+ waitForBufferDone(conn, callback, tries = 1) {
1550
+ if (tries === 5 || !conn.bufferedAmount) {
1551
+ callback();
1552
+ return;
1553
+ }
1554
+ setTimeout(() => {
1555
+ this.waitForBufferDone(conn, callback, tries + 1);
1556
+ }, 150 * tries);
1557
+ }
1558
+ waitForSocketClosed(conn, callback, tries = 1) {
1559
+ if (tries === 5 || conn.readyState === SOCKET_STATES.closed) {
1560
+ callback();
1561
+ return;
1562
+ }
1563
+ setTimeout(() => {
1564
+ this.waitForSocketClosed(conn, callback, tries + 1);
1565
+ }, 150 * tries);
1566
+ }
1567
+ /**
1568
+ * @param {CloseEvent} event
1569
+ */
1570
+ onConnClose(event) {
1571
+ if (this.conn) this.conn.onclose = () => {
1572
+ };
1573
+ if (this.hasLogger()) this.log("transport", "close", event);
1574
+ this.triggerChanError(event);
1575
+ this.clearHeartbeats();
1576
+ if (!this.closeWasClean) {
1577
+ this.reconnectTimer.scheduleTimeout();
1578
+ }
1579
+ this.triggerStateCallbacks("close", event);
1580
+ }
1581
+ /**
1582
+ * @private
1583
+ * @param {Event} error
1584
+ */
1585
+ onConnError(error) {
1586
+ if (this.hasLogger()) this.log("transport", "error", error);
1587
+ let transportBefore = this.transport;
1588
+ let establishedBefore = this.establishedConnections;
1589
+ this.triggerStateCallbacks("error", error, transportBefore, establishedBefore);
1590
+ if (transportBefore === this.transport || establishedBefore > 0) {
1591
+ this.triggerChanError(error);
1592
+ }
1593
+ }
1594
+ /**
1595
+ * @private
1596
+ * @param {unknown} [reason] underlying close/error event forwarded to channel error listeners
1597
+ */
1598
+ triggerChanError(reason) {
1599
+ this.channels.forEach((channel) => {
1600
+ if (!(channel.isErrored() || channel.isLeaving() || channel.isClosed())) {
1601
+ channel.trigger(CHANNEL_EVENTS.error, reason);
1602
+ }
1603
+ });
1604
+ }
1605
+ /**
1606
+ * @returns {string}
1607
+ */
1608
+ connectionState() {
1609
+ switch (this.conn && this.conn.readyState) {
1610
+ case SOCKET_STATES.connecting:
1611
+ return "connecting";
1612
+ case SOCKET_STATES.open:
1613
+ return "open";
1614
+ case SOCKET_STATES.closing:
1615
+ return "closing";
1616
+ default:
1617
+ return "closed";
1618
+ }
1619
+ }
1620
+ /**
1621
+ * @returns {boolean}
1622
+ */
1623
+ isConnected() {
1624
+ return this.connectionState() === "open";
1625
+ }
1626
+ /**
1627
+ *
1628
+ * @param {Channel} channel
1629
+ */
1630
+ remove(channel) {
1631
+ this.off(channel.stateChangeRefs);
1632
+ this.channels = this.channels.filter((c) => c !== channel);
1633
+ }
1634
+ /**
1635
+ * Removes `onOpen`, `onClose`, `onError,` and `onMessage` registrations.
1636
+ *
1637
+ * @param {string[]} refs - list of refs returned by calls to
1638
+ * `onOpen`, `onClose`, `onError,` and `onMessage`
1639
+ */
1640
+ off(refs) {
1641
+ for (let key in this.stateChangeCallbacks) {
1642
+ this.stateChangeCallbacks[key] = this.stateChangeCallbacks[key].filter(([ref]) => {
1643
+ return refs.indexOf(ref) === -1;
1644
+ });
1645
+ }
1646
+ }
1647
+ /**
1648
+ * Initiates a new channel for the given topic
1649
+ *
1650
+ * @param {string} topic
1651
+ * @param {Params | (() => Params)} [chanParams]- Parameters for the channel
1652
+ * @returns {Channel}
1653
+ */
1654
+ channel(topic, chanParams = {}) {
1655
+ let chan = new Channel(topic, chanParams, this);
1656
+ this.channels.push(chan);
1657
+ return chan;
1658
+ }
1659
+ /**
1660
+ * @param {Message<Record<string, any>>} data
1661
+ */
1662
+ push(data) {
1663
+ if (this.hasLogger()) {
1664
+ let { topic, event, payload, ref, join_ref } = data;
1665
+ this.log("push", `${topic} ${event} (${join_ref}, ${ref})`, payload);
1666
+ }
1667
+ if (this.isConnected()) {
1668
+ this.encode(data, (result) => this.conn.send(result));
1669
+ } else {
1670
+ this.sendBuffer.push(() => this.encode(data, (result) => this.conn.send(result)));
1671
+ }
1672
+ }
1673
+ /**
1674
+ * Return the next message ref, accounting for overflows
1675
+ * @returns {string}
1676
+ */
1677
+ makeRef() {
1678
+ let newRef = this.ref + 1;
1679
+ if (newRef === this.ref) {
1680
+ this.ref = 0;
1681
+ } else {
1682
+ this.ref = newRef;
1683
+ }
1684
+ return this.ref.toString();
1685
+ }
1686
+ sendHeartbeat() {
1687
+ if (!this.isConnected()) {
1688
+ try {
1689
+ this.heartbeatCallback("disconnected");
1690
+ } catch (e) {
1691
+ this.log("error", "error in heartbeat callback", e);
1692
+ }
1693
+ return;
1694
+ }
1695
+ if (this.pendingHeartbeatRef) {
1696
+ this.heartbeatTimeout();
1697
+ return;
1698
+ }
1699
+ this.pendingHeartbeatRef = this.makeRef();
1700
+ this.heartbeatSentAt = Date.now();
1701
+ this.push({ topic: "phoenix", event: "heartbeat", payload: {}, ref: this.pendingHeartbeatRef });
1702
+ try {
1703
+ this.heartbeatCallback("sent");
1704
+ } catch (e) {
1705
+ this.log("error", "error in heartbeat callback", e);
1706
+ }
1707
+ this.heartbeatTimeoutTimer = setTimeout(() => this.heartbeatTimeout(), this.heartbeatIntervalMs);
1708
+ }
1709
+ flushSendBuffer() {
1710
+ if (this.isConnected() && this.sendBuffer.length > 0) {
1711
+ this.sendBuffer.forEach((callback) => callback());
1712
+ this.sendBuffer = [];
1713
+ }
1714
+ }
1715
+ /**
1716
+ * @param {MessageEvent<any>} rawMessage
1717
+ */
1718
+ onConnMessage(rawMessage) {
1719
+ this.decode(rawMessage.data, (msg) => {
1720
+ let { topic, event, payload, ref, join_ref } = msg;
1721
+ if (ref && ref === this.pendingHeartbeatRef) {
1722
+ const latency = this.heartbeatSentAt ? Date.now() - this.heartbeatSentAt : void 0;
1723
+ this.clearHeartbeats();
1724
+ try {
1725
+ this.heartbeatCallback(payload.status === "ok" ? "ok" : "error", latency);
1726
+ } catch (e) {
1727
+ this.log("error", "error in heartbeat callback", e);
1728
+ }
1729
+ this.pendingHeartbeatRef = null;
1730
+ this.heartbeatSentAt = null;
1731
+ if (this.autoSendHeartbeat) {
1732
+ this.heartbeatTimer = setTimeout(() => this.sendHeartbeat(), this.heartbeatIntervalMs);
1733
+ }
1734
+ }
1735
+ if (this.hasLogger()) this.log("receive", `${payload.status || ""} ${topic} ${event} ${ref && "(" + ref + ")" || ""}`.trim(), payload);
1736
+ for (let i = 0; i < this.channels.length; i++) {
1737
+ const channel = this.channels[i];
1738
+ if (!channel.isMember(topic, event, payload, join_ref)) {
1739
+ continue;
1740
+ }
1741
+ channel.trigger(event, payload, ref, join_ref);
1742
+ }
1743
+ this.triggerStateCallbacks("message", msg);
1744
+ });
1745
+ }
1746
+ /**
1747
+ * @private
1748
+ * @template {keyof SocketStateChangeCallbacks} K
1749
+ * @param {K} event
1750
+ * @param {...Parameters<SocketStateChangeCallbacks[K][number][1]>} args
1751
+ * @returns {void}
1752
+ */
1753
+ triggerStateCallbacks(event, ...args) {
1754
+ try {
1755
+ this.stateChangeCallbacks[event].forEach(([_, callback]) => {
1756
+ try {
1757
+ callback(...args);
1758
+ } catch (e) {
1759
+ this.log("error", `error in ${event} callback`, e);
1760
+ }
1761
+ });
1762
+ } catch (e) {
1763
+ this.log("error", `error triggering ${event} callbacks`, e);
1764
+ }
1765
+ }
1766
+ leaveOpenTopic(topic) {
1767
+ let dupChannel = this.channels.find((c) => c.topic === topic && (c.isJoined() || c.isJoining()));
1768
+ if (dupChannel) {
1769
+ if (this.hasLogger()) this.log("transport", `leaving duplicate topic "${topic}"`);
1770
+ dupChannel.leave();
1771
+ }
1772
+ }
1773
+ };
1774
+ export {
1775
+ Presence as P,
1776
+ Socket as S
1777
+ };