mongoku 2.2.4 → 2.4.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 (398) hide show
  1. package/build/client/_app/immutable/assets/0.C-Y-CVnr.css +1 -0
  2. package/build/client/_app/immutable/assets/0.C-Y-CVnr.css.br +0 -0
  3. package/build/client/_app/immutable/assets/0.C-Y-CVnr.css.gz +0 -0
  4. package/build/client/_app/immutable/assets/10.BrydhPds.css +1 -0
  5. package/build/client/_app/immutable/assets/10.BrydhPds.css.br +0 -0
  6. package/build/client/_app/immutable/assets/10.BrydhPds.css.gz +0 -0
  7. package/build/client/_app/immutable/assets/12.I1sSDJ6i.css +1 -0
  8. package/build/client/_app/immutable/assets/12.I1sSDJ6i.css.br +0 -0
  9. package/build/client/_app/immutable/assets/12.I1sSDJ6i.css.gz +0 -0
  10. package/build/client/_app/immutable/assets/Modal.zD4dMMyk.css +1 -0
  11. package/build/client/_app/immutable/assets/Modal.zD4dMMyk.css.br +0 -0
  12. package/build/client/_app/immutable/assets/Modal.zD4dMMyk.css.gz +0 -0
  13. package/build/client/_app/immutable/chunks/0oUK0vJa.js +1 -0
  14. package/build/client/_app/immutable/chunks/0oUK0vJa.js.br +0 -0
  15. package/build/client/_app/immutable/chunks/0oUK0vJa.js.gz +0 -0
  16. package/build/client/_app/immutable/chunks/3xIOsPOb.js +16 -0
  17. package/build/client/_app/immutable/chunks/3xIOsPOb.js.br +0 -0
  18. package/build/client/_app/immutable/chunks/3xIOsPOb.js.gz +0 -0
  19. package/build/client/_app/immutable/chunks/B83FMsIQ.js +24 -0
  20. package/build/client/_app/immutable/chunks/B83FMsIQ.js.br +0 -0
  21. package/build/client/_app/immutable/chunks/B83FMsIQ.js.gz +0 -0
  22. package/build/client/_app/immutable/chunks/BGXqurs_.js +1 -0
  23. package/build/client/_app/immutable/chunks/BGXqurs_.js.br +0 -0
  24. package/build/client/_app/immutable/chunks/BGXqurs_.js.gz +0 -0
  25. package/build/client/_app/immutable/chunks/BPbCnJEo.js +1 -0
  26. package/build/client/_app/immutable/chunks/BPbCnJEo.js.br +0 -0
  27. package/build/client/_app/immutable/chunks/BPbCnJEo.js.gz +0 -0
  28. package/build/client/_app/immutable/chunks/BXUq66wC.js +1 -0
  29. package/build/client/_app/immutable/chunks/BXUq66wC.js.br +0 -0
  30. package/build/client/_app/immutable/chunks/BXUq66wC.js.gz +0 -0
  31. package/build/client/_app/immutable/chunks/BZY48V2X.js +14 -0
  32. package/build/client/_app/immutable/chunks/BZY48V2X.js.br +0 -0
  33. package/build/client/_app/immutable/chunks/BZY48V2X.js.gz +0 -0
  34. package/build/client/_app/immutable/chunks/Bq7qZpXP.js +1 -0
  35. package/build/client/_app/immutable/chunks/Bq7qZpXP.js.br +0 -0
  36. package/build/client/_app/immutable/chunks/Bq7qZpXP.js.gz +0 -0
  37. package/build/client/_app/immutable/chunks/BxoAxRg6.js +1 -0
  38. package/build/client/_app/immutable/chunks/BxoAxRg6.js.br +0 -0
  39. package/build/client/_app/immutable/chunks/BxoAxRg6.js.gz +0 -0
  40. package/build/client/_app/immutable/chunks/ByCRZ7zS.js +2 -0
  41. package/build/client/_app/immutable/chunks/ByCRZ7zS.js.br +0 -0
  42. package/build/client/_app/immutable/chunks/ByCRZ7zS.js.gz +0 -0
  43. package/build/client/_app/immutable/chunks/{D4iRRB8h.js → C1g0HmEj.js} +1 -1
  44. package/build/client/_app/immutable/chunks/C1g0HmEj.js.br +0 -0
  45. package/build/client/_app/immutable/chunks/C1g0HmEj.js.gz +0 -0
  46. package/build/client/_app/immutable/chunks/DGtnJf56.js +1 -0
  47. package/build/client/_app/immutable/chunks/DGtnJf56.js.br +0 -0
  48. package/build/client/_app/immutable/chunks/DGtnJf56.js.gz +0 -0
  49. package/build/client/_app/immutable/chunks/{DR9xdhsg.js → DIw4Wyr4.js} +1 -1
  50. package/build/client/_app/immutable/chunks/DIw4Wyr4.js.br +0 -0
  51. package/build/client/_app/immutable/chunks/DIw4Wyr4.js.gz +0 -0
  52. package/build/client/_app/immutable/chunks/Dn0_-jEe.js +1 -0
  53. package/build/client/_app/immutable/chunks/Dn0_-jEe.js.br +0 -0
  54. package/build/client/_app/immutable/chunks/Dn0_-jEe.js.gz +0 -0
  55. package/build/client/_app/immutable/chunks/UJuWD2W4.js +1 -0
  56. package/build/client/_app/immutable/chunks/UJuWD2W4.js.br +0 -0
  57. package/build/client/_app/immutable/chunks/UJuWD2W4.js.gz +0 -0
  58. package/build/client/_app/immutable/chunks/{Dx56OlI-.js → _Sxqiax7.js} +1 -1
  59. package/build/client/_app/immutable/chunks/_Sxqiax7.js.br +0 -0
  60. package/build/client/_app/immutable/chunks/_Sxqiax7.js.gz +0 -0
  61. package/build/client/_app/immutable/chunks/_kKBJjiB.js +1 -0
  62. package/build/client/_app/immutable/chunks/_kKBJjiB.js.br +0 -0
  63. package/build/client/_app/immutable/chunks/_kKBJjiB.js.gz +0 -0
  64. package/build/client/_app/immutable/chunks/pj4OZpZf.js +4 -0
  65. package/build/client/_app/immutable/chunks/pj4OZpZf.js.br +0 -0
  66. package/build/client/_app/immutable/chunks/pj4OZpZf.js.gz +0 -0
  67. package/build/client/_app/immutable/chunks/reNJcONQ.js +1 -0
  68. package/build/client/_app/immutable/chunks/reNJcONQ.js.br +0 -0
  69. package/build/client/_app/immutable/chunks/reNJcONQ.js.gz +0 -0
  70. package/build/client/_app/immutable/entry/app.DV8my7lq.js +2 -0
  71. package/build/client/_app/immutable/entry/app.DV8my7lq.js.br +0 -0
  72. package/build/client/_app/immutable/entry/app.DV8my7lq.js.gz +0 -0
  73. package/build/client/_app/immutable/entry/start.CHeMkIYN.js +1 -0
  74. package/build/client/_app/immutable/entry/start.CHeMkIYN.js.br +0 -0
  75. package/build/client/_app/immutable/entry/start.CHeMkIYN.js.gz +0 -0
  76. package/build/client/_app/immutable/nodes/0.CNNOoOHl.js +1 -0
  77. package/build/client/_app/immutable/nodes/0.CNNOoOHl.js.br +0 -0
  78. package/build/client/_app/immutable/nodes/0.CNNOoOHl.js.gz +0 -0
  79. package/build/client/_app/immutable/nodes/1.C-65KEEJ.js +1 -0
  80. package/build/client/_app/immutable/nodes/1.C-65KEEJ.js.br +0 -0
  81. package/build/client/_app/immutable/nodes/1.C-65KEEJ.js.gz +0 -0
  82. package/build/client/_app/immutable/nodes/10.BQ-b15Yh.js +1 -0
  83. package/build/client/_app/immutable/nodes/10.BQ-b15Yh.js.br +0 -0
  84. package/build/client/_app/immutable/nodes/10.BQ-b15Yh.js.gz +0 -0
  85. package/build/client/_app/immutable/nodes/11.iU-GIxdi.js +1 -0
  86. package/build/client/_app/immutable/nodes/11.iU-GIxdi.js.br +0 -0
  87. package/build/client/_app/immutable/nodes/11.iU-GIxdi.js.gz +0 -0
  88. package/build/client/_app/immutable/nodes/12.BneOFPb1.js +1 -0
  89. package/build/client/_app/immutable/nodes/12.BneOFPb1.js.br +0 -0
  90. package/build/client/_app/immutable/nodes/12.BneOFPb1.js.gz +0 -0
  91. package/build/client/_app/immutable/nodes/13.BsUY4XVc.js +66 -0
  92. package/build/client/_app/immutable/nodes/13.BsUY4XVc.js.br +0 -0
  93. package/build/client/_app/immutable/nodes/13.BsUY4XVc.js.gz +0 -0
  94. package/build/client/_app/immutable/nodes/{2.DwwrLLW4.js → 2.DqvBb3C7.js} +1 -1
  95. package/build/client/_app/immutable/nodes/2.DqvBb3C7.js.br +0 -0
  96. package/build/client/_app/immutable/nodes/2.DqvBb3C7.js.gz +0 -0
  97. package/build/client/_app/immutable/nodes/{3.t20GootO.js → 3.27swwcG4.js} +1 -1
  98. package/build/client/_app/immutable/nodes/3.27swwcG4.js.br +0 -0
  99. package/build/client/_app/immutable/nodes/3.27swwcG4.js.gz +0 -0
  100. package/build/client/_app/immutable/nodes/{4.CXHjkPtf.js → 4.CcholrFe.js} +1 -1
  101. package/build/client/_app/immutable/nodes/4.CcholrFe.js.br +0 -0
  102. package/build/client/_app/immutable/nodes/4.CcholrFe.js.gz +0 -0
  103. package/build/client/_app/immutable/nodes/{5.C9tcr5B0.js → 5.CzudN9q-.js} +1 -1
  104. package/build/client/_app/immutable/nodes/5.CzudN9q-.js.br +0 -0
  105. package/build/client/_app/immutable/nodes/5.CzudN9q-.js.gz +0 -0
  106. package/build/client/_app/immutable/nodes/7.S2O-z1Ox.js +1 -0
  107. package/build/client/_app/immutable/nodes/7.S2O-z1Ox.js.br +0 -0
  108. package/build/client/_app/immutable/nodes/7.S2O-z1Ox.js.gz +0 -0
  109. package/build/client/_app/immutable/nodes/8.aa4EbN0k.js +1 -0
  110. package/build/client/_app/immutable/nodes/8.aa4EbN0k.js.br +0 -0
  111. package/build/client/_app/immutable/nodes/8.aa4EbN0k.js.gz +0 -0
  112. package/build/client/_app/immutable/nodes/9.9dZgqvLb.js +2 -0
  113. package/build/client/_app/immutable/nodes/9.9dZgqvLb.js.br +0 -0
  114. package/build/client/_app/immutable/nodes/9.9dZgqvLb.js.gz +0 -0
  115. package/build/client/_app/version.json +1 -1
  116. package/build/client/_app/version.json.br +0 -0
  117. package/build/client/_app/version.json.gz +0 -0
  118. package/build/server/chunks/0-BHG1s0_H.js +22 -0
  119. package/build/server/chunks/0-BHG1s0_H.js.map +1 -0
  120. package/build/server/chunks/1-Xz1zN5FT.js +9 -0
  121. package/build/server/chunks/1-Xz1zN5FT.js.map +1 -0
  122. package/build/server/chunks/{10-DGUQMXHt.js → 10-CaYvpZVK.js} +6 -5
  123. package/build/server/chunks/10-CaYvpZVK.js.map +1 -0
  124. package/build/server/chunks/{11-CxBnyyqR.js → 11-uJK96PLt.js} +6 -5
  125. package/build/server/chunks/11-uJK96PLt.js.map +1 -0
  126. package/build/server/chunks/{12-K_JVUnsk.js → 12-CvEEILKx.js} +14 -13
  127. package/build/server/chunks/12-CvEEILKx.js.map +1 -0
  128. package/build/server/chunks/{13-Cay35aHK.js → 13-Cvk7ClFs.js} +6 -5
  129. package/build/server/chunks/{13-Cay35aHK.js.map → 13-Cvk7ClFs.js.map} +1 -1
  130. package/build/server/chunks/{2-ClkERMhY.js → 2-BheEgghx.js} +2 -2
  131. package/build/server/chunks/{2-ClkERMhY.js.map → 2-BheEgghx.js.map} +1 -1
  132. package/build/server/chunks/{3-CTpqmxdo.js → 3-BwrTscBH.js} +2 -2
  133. package/build/server/chunks/{3-CTpqmxdo.js.map → 3-BwrTscBH.js.map} +1 -1
  134. package/build/server/chunks/{4-CUH4fZn8.js → 4-D28kbpdN.js} +2 -2
  135. package/build/server/chunks/{4-CUH4fZn8.js.map → 4-D28kbpdN.js.map} +1 -1
  136. package/build/server/chunks/{5-BSEdxfut.js → 5--wY8V1OC.js} +2 -2
  137. package/build/server/chunks/{5-BSEdxfut.js.map → 5--wY8V1OC.js.map} +1 -1
  138. package/build/server/chunks/{7-DvU-_ADW.js → 7-DTmi6ASF.js} +6 -5
  139. package/build/server/chunks/7-DTmi6ASF.js.map +1 -0
  140. package/build/server/chunks/{8-CA3-CJtS.js → 8-CHIpUo4j.js} +6 -5
  141. package/build/server/chunks/8-CHIpUo4j.js.map +1 -0
  142. package/build/server/chunks/{9-jMOS3lPS.js → 9-C3nw_taL.js} +6 -5
  143. package/build/server/chunks/9-C3nw_taL.js.map +1 -0
  144. package/build/server/chunks/{JsonValue-WMdIUvRM.js → JsonValue-DiECF6Zd.js} +11 -4
  145. package/build/server/chunks/JsonValue-DiECF6Zd.js.map +1 -0
  146. package/build/server/chunks/{Modal-zVnoAfFx.js → Modal-BzZ9u6V6.js} +3 -3
  147. package/build/server/chunks/Modal-BzZ9u6V6.js.map +1 -0
  148. package/build/server/chunks/Panel-DEP08QXV.js +48 -0
  149. package/build/server/chunks/Panel-DEP08QXV.js.map +1 -0
  150. package/build/server/chunks/{PrettyJson-D3CylSVd.js → PrettyJson-ElzPxPF4.js} +55 -40
  151. package/build/server/chunks/PrettyJson-ElzPxPF4.js.map +1 -0
  152. package/build/server/chunks/Tooltip-DK6Aok7l.js +35 -0
  153. package/build/server/chunks/Tooltip-DK6Aok7l.js.map +1 -0
  154. package/build/server/chunks/{TooltipTable-DCu3GLqO.js → TooltipTable-DUYKVtrh.js} +3 -3
  155. package/build/server/chunks/{TooltipTable-DCu3GLqO.js.map → TooltipTable-DUYKVtrh.js.map} +1 -1
  156. package/build/server/chunks/_layout.svelte-CCi6mq1k.js +159 -0
  157. package/build/server/chunks/_layout.svelte-CCi6mq1k.js.map +1 -0
  158. package/build/server/chunks/{_page.svelte-C-13GpOe.js → _page.svelte-B4BL5PJR.js} +18 -16
  159. package/build/server/chunks/_page.svelte-B4BL5PJR.js.map +1 -0
  160. package/build/server/chunks/{_page.svelte-BRxX_vQR.js → _page.svelte-BUheieJ5.js} +26 -15
  161. package/build/server/chunks/_page.svelte-BUheieJ5.js.map +1 -0
  162. package/build/server/chunks/{_page.svelte-BBHqwhWF.js → _page.svelte-Bj297hp1.js} +16 -15
  163. package/build/server/chunks/_page.svelte-Bj297hp1.js.map +1 -0
  164. package/build/server/chunks/{_page.svelte-2w3fCax2.js → _page.svelte-BvjNfjgw.js} +14 -14
  165. package/build/server/chunks/{_page.svelte-2w3fCax2.js.map → _page.svelte-BvjNfjgw.js.map} +1 -1
  166. package/build/server/chunks/_page.svelte-DDe4hyAB.js +387 -0
  167. package/build/server/chunks/_page.svelte-DDe4hyAB.js.map +1 -0
  168. package/build/server/chunks/{_page.svelte-Ca9u_35e.js → _page.svelte-DEe2Kbbw.js} +72 -12
  169. package/build/server/chunks/_page.svelte-DEe2Kbbw.js.map +1 -0
  170. package/build/server/chunks/_page.svelte-DJFPwyij.js +323 -0
  171. package/build/server/chunks/_page.svelte-DJFPwyij.js.map +1 -0
  172. package/build/server/chunks/client-Cp5ag8tA.js +7 -0
  173. package/build/server/chunks/{client-BFlyU7ZU.js.map → client-Cp5ag8tA.js.map} +1 -1
  174. package/build/server/chunks/{client2-DYaMKWrc.js → client2-Dos6p_Xm.js} +3 -4
  175. package/build/server/chunks/{client2-DYaMKWrc.js.map → client2-Dos6p_Xm.js.map} +1 -1
  176. package/build/server/chunks/{error.svelte-BENdaVOT.js → error.svelte-BBEhCLUJ.js} +6 -7
  177. package/build/server/chunks/{error.svelte-BENdaVOT.js.map → error.svelte-BBEhCLUJ.js.map} +1 -1
  178. package/build/server/chunks/{index2-DBFlGzWV.js → index2-DzKnqQNM.js} +2 -2
  179. package/build/server/chunks/{index2-DBFlGzWV.js.map → index2-DzKnqQNM.js.map} +1 -1
  180. package/build/server/chunks/{index3-CoOO2o9t.js → index3-DANRthiW.js} +2 -2
  181. package/build/server/chunks/{index3-CoOO2o9t.js.map → index3-DANRthiW.js.map} +1 -1
  182. package/build/server/chunks/{mongo-Db8Vgimy.js → mongo-BHk5yAj9.js} +90 -19
  183. package/build/server/chunks/mongo-BHk5yAj9.js.map +1 -0
  184. package/build/server/chunks/{remote-xxtqbu-AjxdDZZ_.js → remote-xxtqbu-DBe3CqEJ.js} +6 -6
  185. package/build/server/chunks/remote-xxtqbu-DBe3CqEJ.js.map +1 -0
  186. package/build/server/chunks/{server2-_mGVuBoG.js → server2-YmCaJGWy.js} +2 -2
  187. package/build/server/chunks/{server2-_mGVuBoG.js.map → server2-YmCaJGWy.js.map} +1 -1
  188. package/build/server/chunks/{servers.remote-DrkuAWHP.js → servers.remote-HDmNH7n4.js} +245 -15
  189. package/build/server/chunks/servers.remote-HDmNH7n4.js.map +1 -0
  190. package/build/server/chunks/{shared-Buki-xt5.js → shared-CQd3A1I4.js} +2 -2
  191. package/build/server/chunks/{shared-Buki-xt5.js.map → shared-CQd3A1I4.js.map} +1 -1
  192. package/build/server/chunks/{state.svelte-C8IWmp_n.js → state.svelte-Dm0prnTp.js} +2 -2
  193. package/build/server/chunks/{state.svelte-C8IWmp_n.js.map → state.svelte-Dm0prnTp.js.map} +1 -1
  194. package/build/server/chunks/{event-DVH-6ISX.js → utils-D1ahxout.js} +39 -2
  195. package/build/server/chunks/utils-D1ahxout.js.map +1 -0
  196. package/build/server/index.js +5 -6
  197. package/build/server/index.js.map +1 -1
  198. package/build/server/manifest.js +15 -15
  199. package/build/server/manifest.js.map +1 -1
  200. package/package.json +3 -2
  201. package/src/api/servers.remote.ts +275 -11
  202. package/src/app.css +178 -135
  203. package/src/app.html +23 -10
  204. package/src/lib/actions/portal.ts +42 -0
  205. package/src/lib/components/Breadcrumbs.svelte +20 -60
  206. package/src/lib/components/JsonValue.svelte +30 -1
  207. package/src/lib/components/Modal.svelte +5 -5
  208. package/src/lib/components/Notifications.svelte +42 -21
  209. package/src/lib/components/PageSwitcher.svelte +16 -10
  210. package/src/lib/components/Panel.svelte +19 -15
  211. package/src/lib/components/PrettyJson.svelte +102 -90
  212. package/src/lib/components/ReplicaSetSelector.svelte +144 -0
  213. package/src/lib/components/SearchBox.svelte +117 -96
  214. package/src/lib/components/ThemeSwitcher.svelte +191 -36
  215. package/src/lib/components/Tooltip.svelte +23 -14
  216. package/src/lib/server/mongo.ts +129 -26
  217. package/src/lib/utils/formatSignificantDigits.ts +30 -0
  218. package/src/lib/utils/formatTimeAgo.ts +20 -0
  219. package/src/lib/utils/hostnames.ts +86 -0
  220. package/src/lib/utils/jsonParser.ts +50 -0
  221. package/src/lib/utils/longestCommonSuffix.ts +47 -0
  222. package/src/lib/utils/sum.ts +10 -0
  223. package/src/routes/+layout.svelte +36 -17
  224. package/src/routes/servers/+page.svelte +6 -7
  225. package/src/routes/servers/[server]/databases/+page.svelte +71 -2
  226. package/src/routes/servers/[server]/databases/[database]/collections/+page.svelte +13 -3
  227. package/src/routes/servers/[server]/databases/[database]/collections/[collection]/documents/+page.svelte +292 -57
  228. package/src/routes/servers/[server]/databases/[database]/collections/[collection]/indexes/+page.server.ts +8 -8
  229. package/src/routes/servers/[server]/databases/[database]/collections/[collection]/indexes/+page.svelte +628 -105
  230. package/src/routes/servers/[server]/databases/[database]/collections/[collection]/mappings/+page.svelte +26 -12
  231. package/build/client/_app/immutable/assets/0.COnAcXN4.css +0 -1
  232. package/build/client/_app/immutable/assets/0.COnAcXN4.css.br +0 -0
  233. package/build/client/_app/immutable/assets/0.COnAcXN4.css.gz +0 -0
  234. package/build/client/_app/immutable/assets/10.59aTjJn9.css +0 -1
  235. package/build/client/_app/immutable/assets/10.59aTjJn9.css.br +0 -0
  236. package/build/client/_app/immutable/assets/10.59aTjJn9.css.gz +0 -0
  237. package/build/client/_app/immutable/assets/12.BdCOhvz0.css +0 -1
  238. package/build/client/_app/immutable/assets/12.BdCOhvz0.css.br +0 -0
  239. package/build/client/_app/immutable/assets/12.BdCOhvz0.css.gz +0 -0
  240. package/build/client/_app/immutable/assets/Modal.DIIFkbGB.css +0 -1
  241. package/build/client/_app/immutable/assets/Modal.DIIFkbGB.css.br +0 -0
  242. package/build/client/_app/immutable/assets/Modal.DIIFkbGB.css.gz +0 -0
  243. package/build/client/_app/immutable/assets/Panel.B3aWupye.css +0 -1
  244. package/build/client/_app/immutable/assets/Panel.B3aWupye.css.br +0 -0
  245. package/build/client/_app/immutable/assets/Panel.B3aWupye.css.gz +0 -0
  246. package/build/client/_app/immutable/assets/cuprum-cyrillic-400-normal.Cnibl3-L.woff2 +0 -0
  247. package/build/client/_app/immutable/assets/cuprum-cyrillic-400-normal.RKIjpA76.woff +0 -0
  248. package/build/client/_app/immutable/assets/cuprum-cyrillic-ext-400-normal.CT5q4ZVh.woff2 +0 -0
  249. package/build/client/_app/immutable/assets/cuprum-cyrillic-ext-400-normal.iCCFJ4Gn.woff +0 -0
  250. package/build/client/_app/immutable/assets/cuprum-latin-400-normal.Cbwtr8a4.woff +0 -0
  251. package/build/client/_app/immutable/assets/cuprum-latin-400-normal.CjFvNwMJ.woff2 +0 -0
  252. package/build/client/_app/immutable/assets/cuprum-latin-ext-400-normal.BWTJtpjo.woff2 +0 -0
  253. package/build/client/_app/immutable/assets/cuprum-latin-ext-400-normal.BZXayy47.woff +0 -0
  254. package/build/client/_app/immutable/assets/cuprum-vietnamese-400-normal.uXRi1gw5.woff +0 -0
  255. package/build/client/_app/immutable/assets/rajdhani-devanagari-400-normal.BdIzgbsr.woff +0 -0
  256. package/build/client/_app/immutable/assets/rajdhani-devanagari-400-normal.CTuj2HZW.woff2 +0 -0
  257. package/build/client/_app/immutable/assets/rajdhani-latin-400-normal.C6_q4usG.woff +0 -0
  258. package/build/client/_app/immutable/assets/rajdhani-latin-400-normal.CurJOxDW.woff2 +0 -0
  259. package/build/client/_app/immutable/assets/rajdhani-latin-ext-400-normal.DACPYgMx.woff2 +0 -0
  260. package/build/client/_app/immutable/assets/rajdhani-latin-ext-400-normal.Der7ynDE.woff +0 -0
  261. package/build/client/_app/immutable/chunks/3iRu_dUj.js +0 -2
  262. package/build/client/_app/immutable/chunks/3iRu_dUj.js.br +0 -0
  263. package/build/client/_app/immutable/chunks/3iRu_dUj.js.gz +0 -0
  264. package/build/client/_app/immutable/chunks/5nAxkTTP.js +0 -1
  265. package/build/client/_app/immutable/chunks/5nAxkTTP.js.br +0 -5
  266. package/build/client/_app/immutable/chunks/5nAxkTTP.js.gz +0 -0
  267. package/build/client/_app/immutable/chunks/BBg-V8FE.js +0 -1
  268. package/build/client/_app/immutable/chunks/BBg-V8FE.js.br +0 -0
  269. package/build/client/_app/immutable/chunks/BBg-V8FE.js.gz +0 -0
  270. package/build/client/_app/immutable/chunks/BE8UzJuY.js +0 -1
  271. package/build/client/_app/immutable/chunks/BE8UzJuY.js.br +0 -0
  272. package/build/client/_app/immutable/chunks/BE8UzJuY.js.gz +0 -0
  273. package/build/client/_app/immutable/chunks/BQEBQyfZ.js +0 -1
  274. package/build/client/_app/immutable/chunks/BQEBQyfZ.js.br +0 -0
  275. package/build/client/_app/immutable/chunks/BQEBQyfZ.js.gz +0 -0
  276. package/build/client/_app/immutable/chunks/BUNgwIS0.js +0 -1
  277. package/build/client/_app/immutable/chunks/BUNgwIS0.js.br +0 -0
  278. package/build/client/_app/immutable/chunks/BUNgwIS0.js.gz +0 -0
  279. package/build/client/_app/immutable/chunks/BvKY81hz.js +0 -1
  280. package/build/client/_app/immutable/chunks/BvKY81hz.js.br +0 -0
  281. package/build/client/_app/immutable/chunks/BvKY81hz.js.gz +0 -0
  282. package/build/client/_app/immutable/chunks/C0PCwpqt.js +0 -23
  283. package/build/client/_app/immutable/chunks/C0PCwpqt.js.br +0 -0
  284. package/build/client/_app/immutable/chunks/C0PCwpqt.js.gz +0 -0
  285. package/build/client/_app/immutable/chunks/C0rm4mmq.js +0 -1
  286. package/build/client/_app/immutable/chunks/C0rm4mmq.js.br +0 -0
  287. package/build/client/_app/immutable/chunks/C0rm4mmq.js.gz +0 -0
  288. package/build/client/_app/immutable/chunks/C2sjtvBO.js +0 -1
  289. package/build/client/_app/immutable/chunks/C2sjtvBO.js.br +0 -0
  290. package/build/client/_app/immutable/chunks/C2sjtvBO.js.gz +0 -0
  291. package/build/client/_app/immutable/chunks/C82Rp5eQ.js +0 -1
  292. package/build/client/_app/immutable/chunks/C82Rp5eQ.js.br +0 -0
  293. package/build/client/_app/immutable/chunks/C82Rp5eQ.js.gz +0 -0
  294. package/build/client/_app/immutable/chunks/CGSOl_q_.js +0 -4
  295. package/build/client/_app/immutable/chunks/CGSOl_q_.js.br +0 -0
  296. package/build/client/_app/immutable/chunks/CGSOl_q_.js.gz +0 -0
  297. package/build/client/_app/immutable/chunks/CjNnAkTB.js +0 -1
  298. package/build/client/_app/immutable/chunks/CjNnAkTB.js.br +0 -0
  299. package/build/client/_app/immutable/chunks/CjNnAkTB.js.gz +0 -0
  300. package/build/client/_app/immutable/chunks/Cx2cA4gg.js +0 -1
  301. package/build/client/_app/immutable/chunks/Cx2cA4gg.js.br +0 -0
  302. package/build/client/_app/immutable/chunks/Cx2cA4gg.js.gz +0 -0
  303. package/build/client/_app/immutable/chunks/D4iRRB8h.js.br +0 -0
  304. package/build/client/_app/immutable/chunks/D4iRRB8h.js.gz +0 -0
  305. package/build/client/_app/immutable/chunks/D5ccpaXt.js +0 -1
  306. package/build/client/_app/immutable/chunks/D5ccpaXt.js.br +0 -0
  307. package/build/client/_app/immutable/chunks/D5ccpaXt.js.gz +0 -0
  308. package/build/client/_app/immutable/chunks/D7E46CWw.js +0 -1
  309. package/build/client/_app/immutable/chunks/D7E46CWw.js.br +0 -0
  310. package/build/client/_app/immutable/chunks/D7E46CWw.js.gz +0 -0
  311. package/build/client/_app/immutable/chunks/DR9xdhsg.js.br +0 -0
  312. package/build/client/_app/immutable/chunks/DR9xdhsg.js.gz +0 -0
  313. package/build/client/_app/immutable/chunks/DVRQRZnh.js +0 -1
  314. package/build/client/_app/immutable/chunks/DVRQRZnh.js.br +0 -0
  315. package/build/client/_app/immutable/chunks/DVRQRZnh.js.gz +0 -0
  316. package/build/client/_app/immutable/chunks/DcPEQ0_V.js +0 -29
  317. package/build/client/_app/immutable/chunks/DcPEQ0_V.js.br +0 -0
  318. package/build/client/_app/immutable/chunks/DcPEQ0_V.js.gz +0 -0
  319. package/build/client/_app/immutable/chunks/Dx56OlI-.js.br +0 -2
  320. package/build/client/_app/immutable/chunks/Dx56OlI-.js.gz +0 -0
  321. package/build/client/_app/immutable/chunks/PXh00dfp.js +0 -2
  322. package/build/client/_app/immutable/chunks/PXh00dfp.js.br +0 -0
  323. package/build/client/_app/immutable/chunks/PXh00dfp.js.gz +0 -0
  324. package/build/client/_app/immutable/entry/app.DrdSPfGo.js +0 -2
  325. package/build/client/_app/immutable/entry/app.DrdSPfGo.js.br +0 -0
  326. package/build/client/_app/immutable/entry/app.DrdSPfGo.js.gz +0 -0
  327. package/build/client/_app/immutable/entry/start.DGG3CpnK.js +0 -1
  328. package/build/client/_app/immutable/entry/start.DGG3CpnK.js.br +0 -2
  329. package/build/client/_app/immutable/entry/start.DGG3CpnK.js.gz +0 -0
  330. package/build/client/_app/immutable/nodes/0.kCLtccjl.js +0 -5
  331. package/build/client/_app/immutable/nodes/0.kCLtccjl.js.br +0 -0
  332. package/build/client/_app/immutable/nodes/0.kCLtccjl.js.gz +0 -0
  333. package/build/client/_app/immutable/nodes/1.Dr8p9JHT.js +0 -1
  334. package/build/client/_app/immutable/nodes/1.Dr8p9JHT.js.br +0 -3
  335. package/build/client/_app/immutable/nodes/1.Dr8p9JHT.js.gz +0 -0
  336. package/build/client/_app/immutable/nodes/10.B4uwvHd0.js +0 -2
  337. package/build/client/_app/immutable/nodes/10.B4uwvHd0.js.br +0 -0
  338. package/build/client/_app/immutable/nodes/10.B4uwvHd0.js.gz +0 -0
  339. package/build/client/_app/immutable/nodes/11.qfhS2VqU.js +0 -1
  340. package/build/client/_app/immutable/nodes/11.qfhS2VqU.js.br +0 -0
  341. package/build/client/_app/immutable/nodes/11.qfhS2VqU.js.gz +0 -0
  342. package/build/client/_app/immutable/nodes/12.DkZDCIfS.js +0 -1
  343. package/build/client/_app/immutable/nodes/12.DkZDCIfS.js.br +0 -0
  344. package/build/client/_app/immutable/nodes/12.DkZDCIfS.js.gz +0 -0
  345. package/build/client/_app/immutable/nodes/13.DFVzMgyY.js +0 -66
  346. package/build/client/_app/immutable/nodes/13.DFVzMgyY.js.br +0 -0
  347. package/build/client/_app/immutable/nodes/13.DFVzMgyY.js.gz +0 -0
  348. package/build/client/_app/immutable/nodes/2.DwwrLLW4.js.br +0 -1
  349. package/build/client/_app/immutable/nodes/2.DwwrLLW4.js.gz +0 -0
  350. package/build/client/_app/immutable/nodes/3.t20GootO.js.br +0 -0
  351. package/build/client/_app/immutable/nodes/3.t20GootO.js.gz +0 -0
  352. package/build/client/_app/immutable/nodes/4.CXHjkPtf.js.br +0 -0
  353. package/build/client/_app/immutable/nodes/4.CXHjkPtf.js.gz +0 -0
  354. package/build/client/_app/immutable/nodes/5.C9tcr5B0.js.br +0 -0
  355. package/build/client/_app/immutable/nodes/5.C9tcr5B0.js.gz +0 -0
  356. package/build/client/_app/immutable/nodes/7.D14iWySv.js +0 -1
  357. package/build/client/_app/immutable/nodes/7.D14iWySv.js.br +0 -0
  358. package/build/client/_app/immutable/nodes/7.D14iWySv.js.gz +0 -0
  359. package/build/client/_app/immutable/nodes/8.BSXe_VNA.js +0 -1
  360. package/build/client/_app/immutable/nodes/8.BSXe_VNA.js.br +0 -0
  361. package/build/client/_app/immutable/nodes/8.BSXe_VNA.js.gz +0 -0
  362. package/build/client/_app/immutable/nodes/9.BXMJq3Z_.js +0 -2
  363. package/build/client/_app/immutable/nodes/9.BXMJq3Z_.js.br +0 -0
  364. package/build/client/_app/immutable/nodes/9.BXMJq3Z_.js.gz +0 -0
  365. package/build/server/chunks/0-BozXjQlk.js +0 -22
  366. package/build/server/chunks/0-BozXjQlk.js.map +0 -1
  367. package/build/server/chunks/1-C_LPMO7A.js +0 -9
  368. package/build/server/chunks/1-C_LPMO7A.js.map +0 -1
  369. package/build/server/chunks/10-DGUQMXHt.js.map +0 -1
  370. package/build/server/chunks/11-CxBnyyqR.js.map +0 -1
  371. package/build/server/chunks/12-K_JVUnsk.js.map +0 -1
  372. package/build/server/chunks/7-DvU-_ADW.js.map +0 -1
  373. package/build/server/chunks/8-CA3-CJtS.js.map +0 -1
  374. package/build/server/chunks/9-jMOS3lPS.js.map +0 -1
  375. package/build/server/chunks/JsonValue-WMdIUvRM.js.map +0 -1
  376. package/build/server/chunks/Modal-zVnoAfFx.js.map +0 -1
  377. package/build/server/chunks/Panel-yg5YKL4d.js +0 -38
  378. package/build/server/chunks/Panel-yg5YKL4d.js.map +0 -1
  379. package/build/server/chunks/PrettyJson-D3CylSVd.js.map +0 -1
  380. package/build/server/chunks/Tooltip-ys6l541_.js +0 -28
  381. package/build/server/chunks/Tooltip-ys6l541_.js.map +0 -1
  382. package/build/server/chunks/_layout.svelte-DMm1Ill8.js +0 -168
  383. package/build/server/chunks/_layout.svelte-DMm1Ill8.js.map +0 -1
  384. package/build/server/chunks/_page.svelte-BBHqwhWF.js.map +0 -1
  385. package/build/server/chunks/_page.svelte-BRxX_vQR.js.map +0 -1
  386. package/build/server/chunks/_page.svelte-C-13GpOe.js.map +0 -1
  387. package/build/server/chunks/_page.svelte-Ca9u_35e.js.map +0 -1
  388. package/build/server/chunks/_page.svelte-Cm_vgRRR.js +0 -206
  389. package/build/server/chunks/_page.svelte-Cm_vgRRR.js.map +0 -1
  390. package/build/server/chunks/_page.svelte-DoOBFRSo.js +0 -299
  391. package/build/server/chunks/_page.svelte-DoOBFRSo.js.map +0 -1
  392. package/build/server/chunks/client-BFlyU7ZU.js +0 -7
  393. package/build/server/chunks/event-DVH-6ISX.js.map +0 -1
  394. package/build/server/chunks/mongo-Db8Vgimy.js.map +0 -1
  395. package/build/server/chunks/remote-xxtqbu-AjxdDZZ_.js.map +0 -1
  396. package/build/server/chunks/servers.remote-DrkuAWHP.js.map +0 -1
  397. package/build/server/chunks/utils-kjxf7BZO.js +0 -39
  398. package/build/server/chunks/utils-kjxf7BZO.js.map +0 -1
@@ -1,5 +1,6 @@
1
1
  import { logger } from "$lib/server/logger";
2
2
  import type { CollectionJSON, CollectionMappings, Mappings } from "$lib/types";
3
+ import { resolveSrv } from "dns/promises";
3
4
  import { MongoClient, type Collection } from "mongodb";
4
5
  import { URL } from "url";
5
6
  import { HostsManager } from "./HostsManager";
@@ -88,8 +89,52 @@ export async function getCollectionJson(
88
89
  };
89
90
  }
90
91
 
92
+ /**
93
+ * Extract node hosts from a MongoDB connection string
94
+ * Handles both mongodb:// and mongodb+srv:// formats
95
+ */
96
+ export async function extractNodesFromConnectionString(connectionString: string): Promise<string[]> {
97
+ const url = new URL(connectionString);
98
+
99
+ if (url.protocol === "mongodb+srv:") {
100
+ // For SRV, resolve DNS records
101
+ const hostname = url.hostname;
102
+ const srvRecords = await resolveSrv(`_mongodb._tcp.${hostname}`);
103
+ return srvRecords
104
+ .sort((a, b) => a.priority - b.priority || b.weight - a.weight)
105
+ .map((record) => `${record.name}:${record.port}`)
106
+ .sort();
107
+ }
108
+ if (url.protocol === "mongodb:") {
109
+ // For standard mongodb://, extract hosts from the connection string
110
+ // Format: mongodb://[username:password@]host1[:port1][,host2[:port2],...]/[database][?options]
111
+ const hostsString = url.host;
112
+ if (!hostsString) {
113
+ throw new Error("No hosts found in connection string");
114
+ }
115
+
116
+ // Split by comma to get all hosts and sort lexically
117
+ return hostsString
118
+ .split(",")
119
+ .map((host) => host.trim())
120
+ .filter((host) => host.length > 0)
121
+ .sort();
122
+ }
123
+ throw new TypeError(`Unsupported protocol: ${url.protocol}`);
124
+ }
125
+
91
126
  class MongoClientWithMappings extends MongoClient {
127
+ url: string;
92
128
  mappings: Record<string, Record<string, Mappings>> = {};
129
+ _id: string;
130
+ name: string;
131
+
132
+ constructor(url: string, _id: string, name: string) {
133
+ super(url);
134
+ this.url = url;
135
+ this._id = _id;
136
+ this.name = name;
137
+ }
93
138
 
94
139
  async getMappings(dbName: string, collectionName: string, opts?: { forceRefresh?: boolean }): Promise<Mappings> {
95
140
  if (opts?.forceRefresh || !this.mappings[dbName]?.[collectionName]) {
@@ -111,7 +156,7 @@ class MongoConnections {
111
156
  * Todo: better system where we can have mutiple servers with same hostname, and labels for each server that
112
157
  * would be displayed in the UI instead of the hostname.
113
158
  */
114
- private clients: Map<string, MongoClientWithMappings> = new Map();
159
+ private clients: Map<string, MongoClientWithMappings> = new Map(); // _id -> MongoClientWithMappings
115
160
  private clientIds: Map<string, string> = new Map(); // hostname -> _id
116
161
  private hostsManager: HostsManager;
117
162
  private countTimeout = parseInt(process.env.MONGOKU_COUNT_TIMEOUT!, 10) || 30_000;
@@ -144,8 +189,8 @@ class MongoConnections {
144
189
  const hostname = url.host || host.path;
145
190
 
146
191
  if (!this.clients.has(hostname)) {
147
- const client = new MongoClientWithMappings(urlStr);
148
- this.clients.set(hostname, client);
192
+ const client = new MongoClientWithMappings(urlStr, host._id, hostname);
193
+ this.clients.set(host._id, client);
149
194
  this.clientIds.set(hostname, host._id);
150
195
  }
151
196
  } catch (err) {
@@ -155,7 +200,11 @@ class MongoConnections {
155
200
  }
156
201
 
157
202
  getClient(name: string): MongoClientWithMappings {
158
- const client = this.clients.get(name) || this.clients.get(`${name}:27017`);
203
+ const clientId = this.clientIds.get(name) || this.clientIds.get(`${name}:27017`);
204
+ if (!clientId) {
205
+ throw new Error(`Client not found: ${name}`);
206
+ }
207
+ const client = this.clients.get(clientId);
159
208
  if (!client) {
160
209
  throw new Error(`Client not found: ${name}`);
161
210
  }
@@ -163,13 +212,11 @@ class MongoConnections {
163
212
  }
164
213
 
165
214
  listClients(): Array<{ name: string; _id: string; client: MongoClient }> {
166
- return Array.from(this.clients.entries())
167
- .filter(([, client]) => client instanceof MongoClient)
168
- .map(([name, client]) => ({
169
- name,
170
- _id: this.clientIds.get(name) || "",
171
- client: client as MongoClient,
172
- }));
215
+ return Array.from(this.clients.values()).map((client) => ({
216
+ name: client.name,
217
+ _id: client._id,
218
+ client: client as MongoClient,
219
+ }));
173
220
  }
174
221
 
175
222
  getCountTimeout() {
@@ -197,8 +244,8 @@ class MongoConnections {
197
244
  const hostname = url.host || hostPath;
198
245
 
199
246
  if (!this.clients.has(hostname)) {
200
- const client = new MongoClientWithMappings(urlStr);
201
- this.clients.set(hostname, client);
247
+ const client = new MongoClientWithMappings(urlStr, id, hostname);
248
+ this.clients.set(id, client);
202
249
  this.clientIds.set(hostname, id);
203
250
  }
204
251
  } catch (err) {
@@ -218,27 +265,83 @@ class MongoConnections {
218
265
  this.clientIds.delete(name);
219
266
  }
220
267
 
221
- async reconnectClient(name: string) {
222
- // Try to find the connection string with the same logic as getClient
223
- const connectionString = this.hostsManager.getHost(name);
224
-
225
- if (!connectionString) {
226
- throw new Error(`Connection string not found for client: ${name}`);
227
- }
228
-
268
+ async reconnectClient(id: string) {
229
269
  // Close the old client
230
- const oldClient = this.clients.get(name);
231
- if (oldClient) {
232
- oldClient.close()?.catch((err) => logger.error(`Error closing old client ${name}:`, err));
270
+ const oldClient = this.clients.get(id);
271
+ if (!oldClient) {
272
+ throw new Error(`Client not found: ${id}`);
233
273
  }
234
274
 
275
+ oldClient.close().catch((err) => logger.error(`Error closing old client ${id}:`, err));
276
+
235
277
  // Create a new client
236
- const newClient = new MongoClientWithMappings(connectionString);
237
- this.clients.set(name, newClient);
278
+ const newClient = new MongoClientWithMappings(oldClient.url, id, oldClient.name);
279
+ this.clients.set(id, newClient);
238
280
 
239
281
  // Test the connection
240
282
  await newClient.connect();
241
283
  }
284
+
285
+ /**
286
+ * Get the list of nodes from a server's connection string
287
+ */
288
+ async getServerNodes(serverId: string): Promise<string[]> {
289
+ const client = this.getClient(serverId);
290
+ return extractNodesFromConnectionString(client.url);
291
+ }
292
+
293
+ /**
294
+ * Fetch index stats from a specific node using directConnection
295
+ */
296
+ async getIndexStatsFromNode(
297
+ serverId: string,
298
+ node: string,
299
+ database: string,
300
+ collection: string,
301
+ ): Promise<Record<string, { ops: number; since: Date; host: string }>> {
302
+ const client = this.getClient(serverId);
303
+ const url = new URL(client.url);
304
+
305
+ // Build direct connection URL
306
+ // Keep credentials and other params, but set the host to the specific node
307
+ const directUrl = new URL(url.toString());
308
+ directUrl.protocol = "mongodb:";
309
+ directUrl.host = node;
310
+ directUrl.searchParams.set("directConnection", "true");
311
+
312
+ // Keep TLS if it was in the original URL
313
+ if (url.searchParams.has("tls") || url.searchParams.has("ssl") || url.protocol === "mongodb+srv:") {
314
+ directUrl.searchParams.set("tls", "true");
315
+ }
316
+
317
+ // Create a temporary client for this specific node
318
+ let nodeClient: MongoClient | null = null;
319
+ // todo: use await using when possible
320
+ try {
321
+ nodeClient = new MongoClient(directUrl.toString());
322
+ await nodeClient.connect();
323
+
324
+ const coll = nodeClient.db(database).collection(collection);
325
+ const statsResult = await coll.aggregate([{ $indexStats: {} }]).toArray();
326
+
327
+ const indexStats = Object.fromEntries(
328
+ statsResult.map((stat) => [
329
+ stat.name,
330
+ {
331
+ ops: stat.accesses?.ops || 0,
332
+ since: stat.accesses?.since || new Date(),
333
+ host: stat.host || node,
334
+ },
335
+ ]),
336
+ );
337
+
338
+ return indexStats;
339
+ } finally {
340
+ if (nodeClient) {
341
+ await nodeClient.close();
342
+ }
343
+ }
344
+ }
242
345
  }
243
346
 
244
347
  // Singleton instance
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Format a number with significant digits
3
+ * @param value The number to format
4
+ * @param digits Number of significant digits (default: 3)
5
+ * @returns Formatted string with appropriate suffix (k, M, B)
6
+ */
7
+ export function formatSignificantDigits(value: number, digits = 3): string {
8
+ if (value === 0) return "0";
9
+
10
+ const absValue = Math.abs(value);
11
+ const sign = value < 0 ? "-" : "";
12
+
13
+ // Determine the order of magnitude
14
+ if (absValue >= 1_000_000_000) {
15
+ // Billions
16
+ const billions = absValue / 1_000_000_000;
17
+ return `${sign}${billions.toPrecision(digits)}B`;
18
+ } else if (absValue >= 1_000_000) {
19
+ // Millions
20
+ const millions = absValue / 1_000_000;
21
+ return `${sign}${millions.toPrecision(digits)}M`;
22
+ } else if (absValue >= 1_000) {
23
+ // Thousands
24
+ const thousands = absValue / 1_000;
25
+ return `${sign}${thousands.toPrecision(digits)}k`;
26
+ } else {
27
+ // Less than 1000
28
+ return `${sign}${absValue.toPrecision(Math.min(digits, Math.ceil(Math.log10(absValue + 1))))}`;
29
+ }
30
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Format a timestamp as relative time ago (e.g., "5m 30s ago", "2h 15m ago")
3
+ */
4
+ export function formatTimeAgo(timestamp: Date | null): string {
5
+ if (!timestamp) return "";
6
+
7
+ const now = new Date();
8
+ const elapsed = now.getTime() - timestamp.getTime();
9
+ const seconds = Math.floor(elapsed / 1000);
10
+ const minutes = Math.floor(seconds / 60);
11
+ const hours = Math.floor(minutes / 60);
12
+
13
+ if (hours > 0) {
14
+ return `${hours}h ${minutes % 60}m ago`;
15
+ } else if (minutes > 0) {
16
+ return `${minutes}m ${seconds % 60}s ago`;
17
+ } else {
18
+ return `${seconds}s ago`;
19
+ }
20
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Find the common prefix of an array of strings
3
+ */
4
+ export function findCommonPrefix(strings: string[]): string {
5
+ if (strings.length === 0) return "";
6
+ if (strings.length === 1) return "";
7
+
8
+ let prefix = strings[0];
9
+ for (let i = 1; i < strings.length; i++) {
10
+ while (strings[i].indexOf(prefix) !== 0) {
11
+ prefix = prefix.substring(0, prefix.length - 1);
12
+ if (prefix === "") return "";
13
+ }
14
+ }
15
+ return prefix;
16
+ }
17
+
18
+ /**
19
+ * Find the common suffix of an array of strings
20
+ */
21
+ export function findCommonSuffix(strings: string[]): string {
22
+ if (strings.length === 0) return "";
23
+ if (strings.length === 1) return "";
24
+
25
+ // Reverse all strings, find common prefix, then reverse back
26
+ const reversed = strings.map((s) => s.split("").reverse().join(""));
27
+ const reversedPrefix = findCommonPrefix(reversed);
28
+ return reversedPrefix.split("").reverse().join("");
29
+ }
30
+
31
+ /**
32
+ * Extract the unique part of a hostname by removing common prefix and suffix
33
+ * Returns the shortened form with "..." markers
34
+ */
35
+ export function shortenHostname(hostname: string, commonPrefix: string, commonSuffix: string): string {
36
+ if (!commonPrefix && !commonSuffix) {
37
+ return hostname;
38
+ }
39
+
40
+ let result = hostname;
41
+
42
+ // Remove prefix
43
+ if (commonPrefix && result.startsWith(commonPrefix)) {
44
+ result = result.slice(commonPrefix.length);
45
+ }
46
+
47
+ // Remove suffix
48
+ if (commonSuffix && result.endsWith(commonSuffix)) {
49
+ result = result.slice(0, -commonSuffix.length);
50
+ }
51
+
52
+ // If nothing left, return the original
53
+ if (result.length === 0) {
54
+ return hostname;
55
+ }
56
+
57
+ // Add ellipsis markers
58
+ const hasPrefix = commonPrefix.length > 0;
59
+ const hasSuffix = commonSuffix.length > 0;
60
+
61
+ if (hasPrefix && hasSuffix) {
62
+ return `…${result}…`;
63
+ } else if (hasPrefix) {
64
+ return `…${result}`;
65
+ } else if (hasSuffix) {
66
+ return `${result}…`;
67
+ }
68
+
69
+ return result;
70
+ }
71
+
72
+ /**
73
+ * Get shortened hostnames for a list of hosts
74
+ * Returns an object mapping full hostname to shortened version
75
+ */
76
+ export function getShortenedHostnames(hosts: string[]): Record<string, string> {
77
+ if (hosts.length <= 1) {
78
+ // No need to shorten if only one host
79
+ return Object.fromEntries(hosts.map((h) => [h, h]));
80
+ }
81
+
82
+ const commonPrefix = findCommonPrefix(hosts);
83
+ const commonSuffix = findCommonSuffix(hosts);
84
+
85
+ return Object.fromEntries(hosts.map((host) => [host, shortenHostname(host, commonPrefix, commonSuffix)]));
86
+ }
@@ -141,3 +141,53 @@ export function parseJSON(text: string, opts?: { allowArray?: boolean }): unknow
141
141
 
142
142
  return buildObject(objExpression);
143
143
  }
144
+
145
+ /**
146
+ * Serializes an object to a string format that can be parsed back with parseJSON.
147
+ * Handles MongoDB special types like ObjectId, Date, and RegExp.
148
+ */
149
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
150
+ export function serializeForEditing(obj: any, depth = 0): string {
151
+ const indent = "\t".repeat(depth);
152
+ const nextIndent = "\t".repeat(depth + 1);
153
+
154
+ if (obj === null) return "null";
155
+ if (obj === undefined) return "undefined";
156
+ if (typeof obj === "string") return JSON.stringify(obj);
157
+ if (typeof obj === "number") return obj.toString();
158
+ if (typeof obj === "boolean") return obj.toString();
159
+
160
+ if (Array.isArray(obj)) {
161
+ if (obj.length === 0) return "[]";
162
+ const items = obj.map((item) => `${nextIndent}${serializeForEditing(item, depth + 1)}`).join(",\n");
163
+ return `[\n${items}\n${indent}]`;
164
+ }
165
+
166
+ if (typeof obj === "object") {
167
+ // Handle special MongoDB types
168
+ if (obj.$type === "ObjectId") {
169
+ return `new ObjectId("${obj.$value}")`;
170
+ }
171
+ if (obj.$type === "Date") {
172
+ return `new Date("${obj.$value}")`;
173
+ }
174
+ if (obj.$type === "RegExp") {
175
+ return `new RegExp("${obj.$value.$pattern}", "${obj.$value.$flags}")`;
176
+ }
177
+
178
+ // Handle regular objects
179
+ const keys = Object.keys(obj);
180
+ if (keys.length === 0) return "{}";
181
+
182
+ const pairs = keys
183
+ .map((key) => {
184
+ const value = serializeForEditing(obj[key], depth + 1);
185
+ return `${nextIndent}${JSON.stringify(key)}: ${value}`;
186
+ })
187
+ .join(",\n");
188
+
189
+ return `{\n${pairs}\n${indent}}`;
190
+ }
191
+
192
+ return JSON.stringify(obj);
193
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Find the longest common suffix between two strings
3
+ */
4
+ export function longestCommonSuffix(str1: string, str2: string): string {
5
+ if (str1.length < str2.length && str2.endsWith(str1)) {
6
+ return str1;
7
+ }
8
+
9
+ if (str2.length < str1.length && str1.endsWith(str2)) {
10
+ return str2;
11
+ }
12
+
13
+ let suffix = "";
14
+ let i = str1.length - 1;
15
+ let j = str2.length - 1;
16
+
17
+ while (i >= 0 && j >= 0 && str1[i] === str2[j]) {
18
+ suffix = str1.slice(i);
19
+ i--;
20
+ j--;
21
+ }
22
+
23
+ return suffix;
24
+ }
25
+
26
+ /**
27
+ * Find which string in an array has the longest common suffix with a target string
28
+ * Returns the matching string or null if no good match is found
29
+ */
30
+ export function findBestSuffixMatch(target: string, candidates: string[]): string | null {
31
+ if (!target || candidates.length === 0) return null;
32
+
33
+ let bestMatch: string | null = null;
34
+ let longestSuffixLength = 0;
35
+
36
+ for (const candidate of candidates) {
37
+ const commonSuffix = longestCommonSuffix(target, candidate);
38
+ if (commonSuffix.length > longestSuffixLength) {
39
+ longestSuffixLength = commonSuffix.length;
40
+ bestMatch = candidate;
41
+ } else if (commonSuffix.length === longestSuffixLength) {
42
+ bestMatch = null;
43
+ }
44
+ }
45
+
46
+ return bestMatch;
47
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Sum an array of numbers
3
+ */
4
+ export function sum(numbers: number[]): number {
5
+ let total = 0;
6
+ for (const num of numbers) {
7
+ total += num;
8
+ }
9
+ return total;
10
+ }
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { resolve } from "$app/paths";
3
+ import { createPortal } from "$lib/actions/portal";
3
4
  import Breadcrumbs from "$lib/components/Breadcrumbs.svelte";
4
5
  import Notifications from "$lib/components/Notifications.svelte";
5
6
  import OriginWarning from "$lib/components/OriginWarning.svelte";
@@ -15,26 +16,44 @@
15
16
  </svelte:head>
16
17
 
17
18
  <div style="min-height: 100vh">
18
- <nav class="navbar px-6 py-4 flex items-center">
19
- <a href={resolve("/")} class="text-2xl font-medium">Mongoku</a>
20
- <Breadcrumbs />
21
- <div class="ml-auto flex items-center gap-2">
22
- <PageSwitcher class="" />
23
- <ThemeSwitcher />
19
+ <!-- App bar -->
20
+ <header class="sticky top-0 z-50 border-b border-[var(--border-color)] bg-[var(--background-color)]/80">
21
+ <div class="max-w-[96rem] mx-auto px-4 sm:px-6 lg:px-8">
22
+ <div class="h-14 flex items-center gap-3">
23
+ <!-- Logo -->
24
+ <a href={resolve("/")} class="inline-flex items-center gap-2 group no-underline hover:no-underline">
25
+ <span
26
+ class="inline-flex items-center justify-center w-7 h-7 rounded-md bg-black dark:bg-white text-white dark:text-black text-sm font-semibold select-none"
27
+ >
28
+ M
29
+ </span>
30
+ <span class="text-lg font-semibold tracking-tight" style="color: var(--text);">Mongoku</span>
31
+ </a>
32
+
33
+ <div class="hidden md:block w-px h-5 bg-[var(--border-color)]"></div>
34
+
35
+ <!-- Breadcrumbs -->
36
+ <Breadcrumbs />
37
+
38
+ <div class="ml-auto flex items-center gap-2">
39
+ <!-- View tabs -->
40
+ <PageSwitcher class="" />
41
+ <ThemeSwitcher />
42
+ </div>
43
+ </div>
24
44
  </div>
25
- </nav>
45
+ </header>
26
46
 
27
47
  <OriginWarning serverOrigin={data.serverOrigin} readOnly={data.readOnly} />
28
48
 
29
- <div class="px-6 py-6 flex flex-col gap-6">
49
+ <!-- Main -->
50
+ <main class="max-w-[96rem] mx-auto px-4 sm:px-6 lg:px-8 py-6 md:py-10">
30
51
  <Notifications />
31
- {@render children()}
32
- </div>
33
- </div>
52
+ <div class="flex flex-col gap-6">
53
+ {@render children()}
54
+ </div>
55
+ </main>
34
56
 
35
- <style lang="postcss">
36
- .navbar {
37
- background-color: var(--light-background);
38
- border-bottom: var(--border);
39
- }
40
- </style>
57
+ <!-- Portal container for tooltips and other overlay content -->
58
+ <div use:createPortal></div>
59
+ </div>
@@ -73,17 +73,16 @@
73
73
  }
74
74
 
75
75
  async function retryServerConnection(server: Server) {
76
- const name = serverName(server.name);
77
- retryingServers.add(name);
76
+ retryingServers.add(server._id);
78
77
 
79
78
  try {
80
- await retryConnection(name);
79
+ await retryConnection(server._id);
81
80
  notificationStore.notifySuccess("Connection restored successfully");
82
81
  await invalidateAll();
83
82
  } catch (error) {
84
83
  notificationStore.notifyError(error, "Failed to retry connection");
85
84
  } finally {
86
- retryingServers.delete(name);
85
+ retryingServers.delete(server._id);
87
86
  }
88
87
  }
89
88
  </script>
@@ -171,16 +170,16 @@
171
170
  {/if}
172
171
  {/await}
173
172
  </td>
174
- <td style="width: 200px">
173
+ <td style="width: 250px">
175
174
  <div class="flex gap-2 justify-end">
176
175
  {#await server.details then details}
177
176
  {#if "error" in details && details.error}
178
177
  <button
179
178
  class="btn btn-default btn-sm -my-2 hidden group-hover:inline"
180
179
  onclick={() => retryServerConnection(server)}
181
- disabled={retryingServers.has(serverName(server.name))}
180
+ disabled={retryingServers.has(server._id)}
182
181
  >
183
- {retryingServers.has(serverName(server.name)) ? "Retrying..." : "Retry"}
182
+ {retryingServers.has(server._id) ? "Retrying..." : "Retry"}
184
183
  </button>
185
184
  {/if}
186
185
  {/await}
@@ -1,11 +1,51 @@
1
1
  <script lang="ts">
2
+ import { dropDatabase as dropDatabaseCommand } from "$api/servers.remote";
3
+ import { invalidateAll } from "$app/navigation";
2
4
  import { resolve } from "$app/paths";
5
+ import Modal from "$lib/components/Modal.svelte";
3
6
  import Panel from "$lib/components/Panel.svelte";
4
7
  import TooltipTable from "$lib/components/TooltipTable.svelte";
8
+ import { notificationStore } from "$lib/stores/notifications.svelte";
5
9
  import { formatBytes } from "$lib/utils/filters";
6
10
  import type { PageData } from "./$types";
7
11
 
8
12
  let { data }: { data: PageData } = $props();
13
+
14
+ type Database = PageData["databases"][number];
15
+
16
+ let showDropModal = $state(false);
17
+ let databaseToDrop = $state<Database | null>(null);
18
+ let isDropping = $state(false);
19
+
20
+ function openDropModal(database: Database) {
21
+ databaseToDrop = database;
22
+ showDropModal = true;
23
+ }
24
+
25
+ function closeDropModal() {
26
+ showDropModal = false;
27
+ databaseToDrop = null;
28
+ isDropping = false;
29
+ }
30
+
31
+ async function confirmDrop() {
32
+ if (!databaseToDrop || isDropping) return;
33
+
34
+ isDropping = true;
35
+ try {
36
+ await dropDatabaseCommand({
37
+ server: data.server,
38
+ database: databaseToDrop.name,
39
+ });
40
+ notificationStore.notifySuccess(`Database "${databaseToDrop.name}" dropped successfully`);
41
+ closeDropModal();
42
+ // Reload the page to get updated databases
43
+ await invalidateAll();
44
+ } catch (error) {
45
+ notificationStore.notifyError(error, "Failed to drop database");
46
+ isDropping = false;
47
+ }
48
+ }
9
49
  </script>
10
50
 
11
51
  <Panel title="Databases on {data.server}">
@@ -15,12 +55,13 @@
15
55
  <th>Name</th>
16
56
  <th>Collections</th>
17
57
  <th>Size</th>
58
+ <th></th>
18
59
  </tr>
19
60
  </thead>
20
61
  <tbody>
21
62
  {#if data.databases && data.databases.length > 0}
22
63
  {#each data.databases as database (database.name)}
23
- <tr>
64
+ <tr class="group">
24
65
  <td>
25
66
  <a
26
67
  href={resolve(
@@ -74,11 +115,23 @@
74
115
  </TooltipTable>
75
116
  {/if}
76
117
  </td>
118
+ <td style="width: 100px">
119
+ <div class="flex justify-end">
120
+ {#if !data.readOnly}
121
+ <button
122
+ class="btn btn-outline-danger btn-sm -my-2 hidden group-hover:inline"
123
+ onclick={() => openDropModal(database)}
124
+ >
125
+ Drop
126
+ </button>
127
+ {/if}
128
+ </div>
129
+ </td>
77
130
  </tr>
78
131
  {/each}
79
132
  {:else}
80
133
  <tr>
81
- <td colspan="3">
134
+ <td colspan="4">
82
135
  <div class="text-center">No databases...</div>
83
136
  </td>
84
137
  </tr>
@@ -86,3 +139,19 @@
86
139
  </tbody>
87
140
  </table>
88
141
  </Panel>
142
+
143
+ <Modal show={showDropModal} onclose={closeDropModal} title="Drop Database">
144
+ <p>
145
+ Are you sure you want to drop the database <strong>{databaseToDrop?.name}</strong>? This action cannot be undone.
146
+ </p>
147
+ {#snippet footer()}
148
+ <button class="btn btn-default btn-sm" onclick={closeDropModal} disabled={isDropping}>Cancel</button>
149
+ <button class="btn btn-outline-danger btn-sm" onclick={confirmDrop} disabled={isDropping}>
150
+ {#if isDropping}
151
+ Dropping...
152
+ {:else}
153
+ Drop Database
154
+ {/if}
155
+ </button>
156
+ {/snippet}
157
+ </Modal>