mongoku 2.0.4 → 2.1.1

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 (426) hide show
  1. package/README.md +18 -4
  2. package/build/client/_app/immutable/assets/0.egX7ddQL.css +1 -0
  3. package/build/client/_app/immutable/assets/0.egX7ddQL.css.br +0 -0
  4. package/build/client/_app/immutable/assets/0.egX7ddQL.css.gz +0 -0
  5. package/build/client/_app/immutable/assets/10.59aTjJn9.css +1 -0
  6. package/build/client/_app/immutable/assets/10.59aTjJn9.css.br +0 -0
  7. package/build/client/_app/immutable/assets/10.59aTjJn9.css.gz +0 -0
  8. package/build/client/_app/immutable/assets/11.CEtFGlZU.css +1 -0
  9. package/build/client/_app/immutable/assets/11.CEtFGlZU.css.br +1 -0
  10. package/build/client/_app/immutable/assets/11.CEtFGlZU.css.gz +0 -0
  11. package/build/client/_app/immutable/assets/12.BdCOhvz0.css +1 -0
  12. package/build/client/_app/immutable/assets/12.BdCOhvz0.css.br +0 -0
  13. package/build/client/_app/immutable/assets/12.BdCOhvz0.css.gz +0 -0
  14. package/build/client/_app/immutable/assets/JsonValue.BEbzuWqZ.css +1 -0
  15. package/build/client/_app/immutable/assets/JsonValue.BEbzuWqZ.css.br +0 -0
  16. package/build/client/_app/immutable/assets/JsonValue.BEbzuWqZ.css.gz +0 -0
  17. package/build/client/_app/immutable/assets/Modal.DIIFkbGB.css +1 -0
  18. package/build/client/_app/immutable/assets/Modal.DIIFkbGB.css.br +0 -0
  19. package/build/client/_app/immutable/assets/Modal.DIIFkbGB.css.gz +0 -0
  20. package/build/client/_app/immutable/assets/Panel.B3aWupye.css +1 -0
  21. package/build/client/_app/immutable/assets/Panel.B3aWupye.css.br +0 -0
  22. package/build/client/_app/immutable/assets/Panel.B3aWupye.css.gz +0 -0
  23. package/build/client/_app/immutable/chunks/3iRu_dUj.js +2 -0
  24. package/build/client/_app/immutable/chunks/3iRu_dUj.js.br +0 -0
  25. package/build/client/_app/immutable/chunks/3iRu_dUj.js.gz +0 -0
  26. package/build/client/_app/immutable/chunks/{ChWB6xnu.js → 4l_AWZos.js} +1 -1
  27. package/build/client/_app/immutable/chunks/4l_AWZos.js.br +0 -0
  28. package/build/client/_app/immutable/chunks/4l_AWZos.js.gz +0 -0
  29. package/build/client/_app/immutable/chunks/5nAxkTTP.js +1 -0
  30. package/build/client/_app/immutable/chunks/5nAxkTTP.js.br +5 -0
  31. package/build/client/_app/immutable/chunks/5nAxkTTP.js.gz +0 -0
  32. package/build/client/_app/immutable/chunks/BBg-V8FE.js +1 -0
  33. package/build/client/_app/immutable/chunks/BBg-V8FE.js.br +0 -0
  34. package/build/client/_app/immutable/chunks/BBg-V8FE.js.gz +0 -0
  35. package/build/client/_app/immutable/chunks/BE8UzJuY.js +1 -0
  36. package/build/client/_app/immutable/chunks/BE8UzJuY.js.br +0 -0
  37. package/build/client/_app/immutable/chunks/BE8UzJuY.js.gz +0 -0
  38. package/build/client/_app/immutable/chunks/BUNgwIS0.js +1 -0
  39. package/build/client/_app/immutable/chunks/BUNgwIS0.js.br +0 -0
  40. package/build/client/_app/immutable/chunks/BUNgwIS0.js.gz +0 -0
  41. package/build/client/_app/immutable/chunks/BjzB4NFq.js +1 -0
  42. package/build/client/_app/immutable/chunks/BjzB4NFq.js.br +0 -0
  43. package/build/client/_app/immutable/chunks/BjzB4NFq.js.gz +0 -0
  44. package/build/client/_app/immutable/chunks/BtCOrwSt.js +1 -0
  45. package/build/client/_app/immutable/chunks/BtCOrwSt.js.br +0 -0
  46. package/build/client/_app/immutable/chunks/BtCOrwSt.js.gz +0 -0
  47. package/build/client/_app/immutable/chunks/BvKY81hz.js +1 -0
  48. package/build/client/_app/immutable/chunks/BvKY81hz.js.br +0 -0
  49. package/build/client/_app/immutable/chunks/BvKY81hz.js.gz +0 -0
  50. package/build/client/_app/immutable/chunks/{DQkpHJGc.js → C0PCwpqt.js} +1 -1
  51. package/build/client/_app/immutable/chunks/C0PCwpqt.js.br +0 -0
  52. package/build/client/_app/immutable/chunks/C0PCwpqt.js.gz +0 -0
  53. package/build/client/_app/immutable/chunks/C82Rp5eQ.js +1 -0
  54. package/build/client/_app/immutable/chunks/C82Rp5eQ.js.br +0 -0
  55. package/build/client/_app/immutable/chunks/C82Rp5eQ.js.gz +0 -0
  56. package/build/client/_app/immutable/chunks/CEvYYWlm.js +2 -0
  57. package/build/client/_app/immutable/chunks/CEvYYWlm.js.br +0 -0
  58. package/build/client/_app/immutable/chunks/CEvYYWlm.js.gz +0 -0
  59. package/build/client/_app/immutable/chunks/CT5SFbzp.js +1 -0
  60. package/build/client/_app/immutable/chunks/CT5SFbzp.js.br +0 -0
  61. package/build/client/_app/immutable/chunks/CT5SFbzp.js.gz +0 -0
  62. package/build/client/_app/immutable/chunks/CcyPStn-.js +1 -0
  63. package/build/client/_app/immutable/chunks/CcyPStn-.js.br +0 -0
  64. package/build/client/_app/immutable/chunks/CcyPStn-.js.gz +0 -0
  65. package/build/client/_app/immutable/chunks/Cx2cA4gg.js +1 -0
  66. package/build/client/_app/immutable/chunks/Cx2cA4gg.js.br +0 -0
  67. package/build/client/_app/immutable/chunks/Cx2cA4gg.js.gz +0 -0
  68. package/build/client/_app/immutable/chunks/D5ccpaXt.js +1 -0
  69. package/build/client/_app/immutable/chunks/D5ccpaXt.js.br +0 -0
  70. package/build/client/_app/immutable/chunks/D5ccpaXt.js.gz +0 -0
  71. package/build/client/_app/immutable/chunks/D64wQeYi.js +1 -0
  72. package/build/client/_app/immutable/chunks/D64wQeYi.js.br +0 -0
  73. package/build/client/_app/immutable/chunks/D64wQeYi.js.gz +0 -0
  74. package/build/client/_app/immutable/chunks/D7E46CWw.js +1 -0
  75. package/build/client/_app/immutable/chunks/D7E46CWw.js.br +0 -0
  76. package/build/client/_app/immutable/chunks/D7E46CWw.js.gz +0 -0
  77. package/build/client/_app/immutable/chunks/DR9xdhsg.js +1 -0
  78. package/build/client/_app/immutable/chunks/DR9xdhsg.js.br +0 -0
  79. package/build/client/_app/immutable/chunks/DR9xdhsg.js.gz +0 -0
  80. package/build/client/_app/immutable/chunks/DVJuGan7.js +1 -0
  81. package/build/client/_app/immutable/chunks/DVJuGan7.js.br +0 -0
  82. package/build/client/_app/immutable/chunks/DVJuGan7.js.gz +0 -0
  83. package/build/client/_app/immutable/chunks/Dx86XS0G.js +1 -0
  84. package/build/client/_app/immutable/chunks/Dx86XS0G.js.br +4 -0
  85. package/build/client/_app/immutable/chunks/Dx86XS0G.js.gz +0 -0
  86. package/build/client/_app/immutable/chunks/lkkUcQuO.js +29 -0
  87. package/build/client/_app/immutable/chunks/lkkUcQuO.js.br +0 -0
  88. package/build/client/_app/immutable/chunks/lkkUcQuO.js.gz +0 -0
  89. package/build/client/_app/immutable/chunks/nVJvgG3c.js +4 -0
  90. package/build/client/_app/immutable/chunks/nVJvgG3c.js.br +0 -0
  91. package/build/client/_app/immutable/chunks/nVJvgG3c.js.gz +0 -0
  92. package/build/client/_app/immutable/entry/app.g5qLQ5x2.js +2 -0
  93. package/build/client/_app/immutable/entry/app.g5qLQ5x2.js.br +0 -0
  94. package/build/client/_app/immutable/entry/app.g5qLQ5x2.js.gz +0 -0
  95. package/build/client/_app/immutable/entry/start.C1uqw3sp.js +1 -0
  96. package/build/client/_app/immutable/entry/start.C1uqw3sp.js.br +2 -0
  97. package/build/client/_app/immutable/entry/start.C1uqw3sp.js.gz +0 -0
  98. package/build/client/_app/immutable/nodes/0.CD9yR-49.js +5 -0
  99. package/build/client/_app/immutable/nodes/0.CD9yR-49.js.br +0 -0
  100. package/build/client/_app/immutable/nodes/0.CD9yR-49.js.gz +0 -0
  101. package/build/client/_app/immutable/nodes/1.DztuiMqq.js +1 -0
  102. package/build/client/_app/immutable/nodes/1.DztuiMqq.js.br +0 -0
  103. package/build/client/_app/immutable/nodes/1.DztuiMqq.js.gz +0 -0
  104. package/build/client/_app/immutable/nodes/10.CWMFKPcE.js +2 -0
  105. package/build/client/_app/immutable/nodes/10.CWMFKPcE.js.br +0 -0
  106. package/build/client/_app/immutable/nodes/10.CWMFKPcE.js.gz +0 -0
  107. package/build/client/_app/immutable/nodes/11.-Y7Cu3Uv.js +1 -0
  108. package/build/client/_app/immutable/nodes/11.-Y7Cu3Uv.js.br +0 -0
  109. package/build/client/_app/immutable/nodes/11.-Y7Cu3Uv.js.gz +0 -0
  110. package/build/client/_app/immutable/nodes/12.wxif1TtN.js +1 -0
  111. package/build/client/_app/immutable/nodes/12.wxif1TtN.js.br +0 -0
  112. package/build/client/_app/immutable/nodes/12.wxif1TtN.js.gz +0 -0
  113. package/build/client/_app/immutable/nodes/13.CpyTaRSN.js +66 -0
  114. package/build/client/_app/immutable/nodes/13.CpyTaRSN.js.br +0 -0
  115. package/build/client/_app/immutable/nodes/13.CpyTaRSN.js.gz +0 -0
  116. package/build/client/_app/immutable/nodes/2.DwwrLLW4.js +1 -0
  117. package/build/client/_app/immutable/nodes/2.DwwrLLW4.js.br +1 -0
  118. package/build/client/_app/immutable/nodes/2.DwwrLLW4.js.gz +0 -0
  119. package/build/client/_app/immutable/nodes/3.t20GootO.js +1 -0
  120. package/build/client/_app/immutable/nodes/3.t20GootO.js.br +0 -0
  121. package/build/client/_app/immutable/nodes/3.t20GootO.js.gz +0 -0
  122. package/build/client/_app/immutable/nodes/4.CXHjkPtf.js +1 -0
  123. package/build/client/_app/immutable/nodes/4.CXHjkPtf.js.br +0 -0
  124. package/build/client/_app/immutable/nodes/4.CXHjkPtf.js.gz +0 -0
  125. package/build/client/_app/immutable/nodes/5.C9tcr5B0.js +1 -0
  126. package/build/client/_app/immutable/nodes/5.C9tcr5B0.js.br +0 -0
  127. package/build/client/_app/immutable/nodes/5.C9tcr5B0.js.gz +0 -0
  128. package/build/client/_app/immutable/nodes/7.DoT-dNUk.js +1 -0
  129. package/build/client/_app/immutable/nodes/7.DoT-dNUk.js.br +0 -0
  130. package/build/client/_app/immutable/nodes/7.DoT-dNUk.js.gz +0 -0
  131. package/build/client/_app/immutable/nodes/8.BFPkGTSl.js +1 -0
  132. package/build/client/_app/immutable/nodes/8.BFPkGTSl.js.br +0 -0
  133. package/build/client/_app/immutable/nodes/8.BFPkGTSl.js.gz +0 -0
  134. package/build/client/_app/immutable/nodes/9.Bk397TaK.js +2 -0
  135. package/build/client/_app/immutable/nodes/9.Bk397TaK.js.br +0 -0
  136. package/build/client/_app/immutable/nodes/9.Bk397TaK.js.gz +0 -0
  137. package/build/client/_app/version.json +1 -1
  138. package/build/client/_app/version.json.br +0 -0
  139. package/build/client/_app/version.json.gz +0 -0
  140. package/build/handler.js +14 -0
  141. package/build/server/chunks/{0-Cb5ytlMI.js → 0-hDOo8HzQ.js} +7 -6
  142. package/build/server/chunks/0-hDOo8HzQ.js.map +1 -0
  143. package/build/server/chunks/1-Dsw_dVjH.js +9 -0
  144. package/build/server/chunks/1-Dsw_dVjH.js.map +1 -0
  145. package/build/server/chunks/10-Xy0rxLNm.js +213 -0
  146. package/build/server/chunks/10-Xy0rxLNm.js.map +1 -0
  147. package/build/server/chunks/11-DBYsQ3ww.js +42 -0
  148. package/build/server/chunks/11-DBYsQ3ww.js.map +1 -0
  149. package/build/server/chunks/12-D4aSEhYN.js +102 -0
  150. package/build/server/chunks/12-D4aSEhYN.js.map +1 -0
  151. package/build/server/chunks/13-CNu_Hz8r.js +52 -0
  152. package/build/server/chunks/13-CNu_Hz8r.js.map +1 -0
  153. package/build/server/chunks/2-ClkERMhY.js +24 -0
  154. package/build/server/chunks/2-ClkERMhY.js.map +1 -0
  155. package/build/server/chunks/3-CTpqmxdo.js +25 -0
  156. package/build/server/chunks/3-CTpqmxdo.js.map +1 -0
  157. package/build/server/chunks/4-CUH4fZn8.js +25 -0
  158. package/build/server/chunks/4-CUH4fZn8.js.map +1 -0
  159. package/build/server/chunks/5-BSEdxfut.js +25 -0
  160. package/build/server/chunks/5-BSEdxfut.js.map +1 -0
  161. package/build/server/chunks/{2-B39zPvzn.js → 6-ifXBeMPA.js} +2 -2
  162. package/build/server/chunks/{2-B39zPvzn.js.map → 6-ifXBeMPA.js.map} +1 -1
  163. package/build/server/chunks/7-CJJMTAtJ.js +82 -0
  164. package/build/server/chunks/7-CJJMTAtJ.js.map +1 -0
  165. package/build/server/chunks/{4-DzHoLo__.js → 8-jBgxYwFg.js} +19 -10
  166. package/build/server/chunks/8-jBgxYwFg.js.map +1 -0
  167. package/build/server/chunks/{5-CCWbCDpk.js → 9-U8SAVx43.js} +7 -8
  168. package/build/server/chunks/9-U8SAVx43.js.map +1 -0
  169. package/build/server/chunks/JsonValue-B5gcBFcA.js +290 -0
  170. package/build/server/chunks/JsonValue-B5gcBFcA.js.map +1 -0
  171. package/build/server/chunks/Modal-zVnoAfFx.js +36 -0
  172. package/build/server/chunks/Modal-zVnoAfFx.js.map +1 -0
  173. package/build/server/chunks/{Panel-Bz0b85EW.js → Panel-yg5YKL4d.js} +4 -3
  174. package/build/server/chunks/Panel-yg5YKL4d.js.map +1 -0
  175. package/build/server/chunks/PrettyJson-mXYQacEL.js +137 -0
  176. package/build/server/chunks/PrettyJson-mXYQacEL.js.map +1 -0
  177. package/build/server/chunks/Tooltip-DflJLumT.js +38 -0
  178. package/build/server/chunks/Tooltip-DflJLumT.js.map +1 -0
  179. package/build/server/chunks/TooltipTable-BPMzcmqQ.js +60 -0
  180. package/build/server/chunks/TooltipTable-BPMzcmqQ.js.map +1 -0
  181. package/build/server/chunks/_layout.svelte-DMm1Ill8.js +168 -0
  182. package/build/server/chunks/_layout.svelte-DMm1Ill8.js.map +1 -0
  183. package/build/server/chunks/_page.svelte-B-dLNs2Q.js +199 -0
  184. package/build/server/chunks/_page.svelte-B-dLNs2Q.js.map +1 -0
  185. package/build/server/chunks/{_page.svelte-FLzHOuyK.js → _page.svelte-BBpDrOEz.js} +40 -22
  186. package/build/server/chunks/_page.svelte-BBpDrOEz.js.map +1 -0
  187. package/build/server/chunks/_page.svelte-C9OCv4Hv.js +204 -0
  188. package/build/server/chunks/_page.svelte-C9OCv4Hv.js.map +1 -0
  189. package/build/server/chunks/{_page.svelte-w9cxGvUf.js → _page.svelte-CvWJ35oO.js} +33 -13
  190. package/build/server/chunks/_page.svelte-CvWJ35oO.js.map +1 -0
  191. package/build/server/chunks/_page.svelte-DYHUokXG.js +297 -0
  192. package/build/server/chunks/_page.svelte-DYHUokXG.js.map +1 -0
  193. package/build/server/chunks/{_page.svelte-FIp-IsOo.js → _page.svelte-Ds1-yUh2.js} +64 -13
  194. package/build/server/chunks/_page.svelte-Ds1-yUh2.js.map +1 -0
  195. package/build/server/chunks/{_page.svelte-jxFKbZdN.js → _page.svelte-DzPMpozq.js} +9 -6
  196. package/build/server/chunks/_page.svelte-DzPMpozq.js.map +1 -0
  197. package/build/server/chunks/_server.ts-06lGoPp8.js +8 -0
  198. package/build/server/chunks/_server.ts-06lGoPp8.js.map +1 -0
  199. package/build/server/chunks/async-lVJA8xJZ.js +9 -0
  200. package/build/server/chunks/async-lVJA8xJZ.js.map +1 -0
  201. package/build/server/chunks/client-BFlyU7ZU.js +7 -0
  202. package/build/server/chunks/{client-bj7sePQc.js.map → client-BFlyU7ZU.js.map} +1 -1
  203. package/build/server/chunks/{client2-BX4-xbM4.js → client2-DYaMKWrc.js} +4 -4
  204. package/build/server/chunks/{client2-BX4-xbM4.js.map → client2-DYaMKWrc.js.map} +1 -1
  205. package/build/server/chunks/{async-BfR0vYHo.js → context-C22hLSHK.js} +2 -8
  206. package/build/server/chunks/context-C22hLSHK.js.map +1 -0
  207. package/build/server/chunks/error.svelte-BENdaVOT.js +19 -0
  208. package/build/server/chunks/error.svelte-BENdaVOT.js.map +1 -0
  209. package/build/server/chunks/event-DVH-6ISX.js.map +1 -1
  210. package/build/server/chunks/hooks.server-CagAPNr2.js +40 -0
  211. package/build/server/chunks/hooks.server-CagAPNr2.js.map +1 -0
  212. package/build/server/chunks/{index-EKt9-9bV.js → index-DFXVwu6p.js} +2 -2
  213. package/build/server/chunks/{index-EKt9-9bV.js.map → index-DFXVwu6p.js.map} +1 -1
  214. package/build/server/chunks/index-Djsj11qr.js.map +1 -1
  215. package/build/server/chunks/index-server-Bf-hP5gL.js +5 -0
  216. package/build/server/chunks/index-server-Bf-hP5gL.js.map +1 -0
  217. package/build/server/chunks/{routing-DcR4fCSD.js → index2-DBFlGzWV.js} +23 -100
  218. package/build/server/chunks/index2-DBFlGzWV.js.map +1 -0
  219. package/build/server/chunks/{index3-DquTjlmp.js → index3-CoOO2o9t.js} +6 -6
  220. package/build/server/chunks/index3-CoOO2o9t.js.map +1 -0
  221. package/build/server/chunks/jsonParser-CraFXJs8.js +174 -0
  222. package/build/server/chunks/jsonParser-CraFXJs8.js.map +1 -0
  223. package/build/server/chunks/layout.svelte-CJcHX-Na.js +10 -0
  224. package/build/server/chunks/layout.svelte-CJcHX-Na.js.map +1 -0
  225. package/build/server/chunks/logger-D71iWOkl.js +36 -0
  226. package/build/server/chunks/logger-D71iWOkl.js.map +1 -0
  227. package/build/server/chunks/{mongo-dLmCShL_.js → mongo-BogiTfnG.js} +54 -12
  228. package/build/server/chunks/mongo-BogiTfnG.js.map +1 -0
  229. package/build/server/chunks/remote-xxtqbu-BJDSUh3k.js +17 -0
  230. package/build/server/chunks/remote-xxtqbu-BJDSUh3k.js.map +1 -0
  231. package/build/server/chunks/routing-e10vGH37.js +81 -0
  232. package/build/server/chunks/routing-e10vGH37.js.map +1 -0
  233. package/build/server/chunks/{server2-BiqGvkCy.js → server2-_mGVuBoG.js} +2 -2
  234. package/build/server/chunks/{server2-BiqGvkCy.js.map → server2-_mGVuBoG.js.map} +1 -1
  235. package/build/server/chunks/servers.remote-C2HuT43p.js +690 -0
  236. package/build/server/chunks/servers.remote-C2HuT43p.js.map +1 -0
  237. package/build/server/chunks/shared-Buki-xt5.js +506 -0
  238. package/build/server/chunks/shared-Buki-xt5.js.map +1 -0
  239. package/build/server/chunks/{state.svelte-CRHA9yov.js → state.svelte-C8IWmp_n.js} +2 -2
  240. package/build/server/chunks/{state.svelte-CRHA9yov.js.map → state.svelte-C8IWmp_n.js.map} +1 -1
  241. package/build/server/chunks/{utils-DGYJFmnf.js → utils-kjxf7BZO.js} +2 -2
  242. package/build/server/chunks/{utils-DGYJFmnf.js.map → utils-kjxf7BZO.js.map} +1 -1
  243. package/build/server/index.js +189 -610
  244. package/build/server/index.js.map +1 -1
  245. package/build/server/manifest.js +45 -18
  246. package/build/server/manifest.js.map +1 -1
  247. package/package.json +13 -2
  248. package/src/api/servers.remote.ts +381 -20
  249. package/src/app.css +98 -3
  250. package/src/app.html +15 -0
  251. package/src/hooks.server.ts +18 -1
  252. package/src/lib/actions/jsonTextarea.ts +395 -0
  253. package/src/lib/components/Breadcrumbs.svelte +7 -58
  254. package/src/lib/components/JsonValue.svelte +279 -85
  255. package/src/lib/components/Modal.svelte +59 -0
  256. package/src/lib/components/OriginWarning.svelte +109 -0
  257. package/src/lib/components/PageSwitcher.svelte +37 -0
  258. package/src/lib/components/Panel.svelte +1 -1
  259. package/src/lib/components/PrettyJson.svelte +112 -36
  260. package/src/lib/components/SearchBox.svelte +161 -97
  261. package/src/lib/components/ThemeSwitcher.svelte +66 -0
  262. package/src/lib/components/Tooltip.svelte +83 -0
  263. package/src/lib/components/TooltipTable.svelte +45 -102
  264. package/src/lib/server/HostsManager.ts +4 -0
  265. package/src/lib/server/aggregation.ts +62 -0
  266. package/src/lib/server/mongo.ts +78 -15
  267. package/src/lib/types.ts +60 -0
  268. package/src/lib/utils/isEmptyObject.ts +6 -0
  269. package/src/lib/utils/jsonParser.ts +9 -1
  270. package/src/lib/utils/logger.ts +42 -0
  271. package/src/lib/utils/omit.ts +3 -0
  272. package/src/routes/+layout.server.ts +2 -1
  273. package/src/routes/+layout.svelte +15 -2
  274. package/src/routes/favicon.ico/+server.ts +8 -0
  275. package/src/routes/servers/+page.server.ts +23 -10
  276. package/src/routes/servers/+page.svelte +44 -10
  277. package/src/routes/servers/[server]/databases/+layout.ts +8 -0
  278. package/src/routes/servers/[server]/databases/+page.server.ts +15 -4
  279. package/src/routes/servers/[server]/databases/[database]/collections/+layout.ts +9 -0
  280. package/src/routes/servers/[server]/databases/[database]/collections/+page.server.ts +0 -2
  281. package/src/routes/servers/[server]/databases/[database]/collections/+page.svelte +67 -8
  282. package/src/routes/servers/[server]/databases/[database]/collections/[collection]/+layout.ts +9 -0
  283. package/src/routes/servers/[server]/databases/[database]/collections/[collection]/documents/+page.server.ts +217 -0
  284. package/src/routes/servers/[server]/databases/[database]/collections/[collection]/documents/+page.svelte +342 -0
  285. package/src/routes/servers/[server]/databases/[database]/collections/[collection]/documents/+page.ts +10 -0
  286. package/src/routes/servers/[server]/databases/[database]/collections/[collection]/documents/[document]/+layout.ts +9 -0
  287. package/src/routes/servers/[server]/databases/[database]/collections/[collection]/documents/[document]/+page.server.ts +15 -12
  288. package/src/routes/servers/[server]/databases/[database]/collections/[collection]/documents/[document]/+page.svelte +81 -7
  289. package/src/routes/servers/[server]/databases/[database]/collections/[collection]/indexes/+page.server.ts +88 -0
  290. package/src/routes/servers/[server]/databases/[database]/collections/[collection]/indexes/+page.svelte +333 -0
  291. package/src/routes/servers/[server]/databases/[database]/collections/[collection]/indexes/+page.ts +10 -0
  292. package/src/routes/servers/[server]/databases/[database]/collections/[collection]/mappings/+page.server.ts +18 -0
  293. package/src/routes/servers/[server]/databases/[database]/collections/[collection]/mappings/+page.svelte +378 -0
  294. package/src/routes/servers/[server]/databases/[database]/collections/[collection]/mappings/+page.ts +10 -0
  295. package/src/tests/api/aggregation.test.ts +125 -0
  296. package/build/client/_app/immutable/assets/0.CEsPYTp2.css +0 -1
  297. package/build/client/_app/immutable/assets/0.CEsPYTp2.css.br +0 -0
  298. package/build/client/_app/immutable/assets/0.CEsPYTp2.css.gz +0 -0
  299. package/build/client/_app/immutable/assets/6.DawdmtJd.css +0 -1
  300. package/build/client/_app/immutable/assets/6.DawdmtJd.css.br +0 -2
  301. package/build/client/_app/immutable/assets/6.DawdmtJd.css.gz +0 -0
  302. package/build/client/_app/immutable/assets/Panel.BDHMtO-3.css +0 -1
  303. package/build/client/_app/immutable/assets/Panel.BDHMtO-3.css.br +0 -0
  304. package/build/client/_app/immutable/assets/Panel.BDHMtO-3.css.gz +0 -0
  305. package/build/client/_app/immutable/assets/PrettyJson.CtngcfyW.css +0 -1
  306. package/build/client/_app/immutable/assets/PrettyJson.CtngcfyW.css.br +0 -0
  307. package/build/client/_app/immutable/assets/PrettyJson.CtngcfyW.css.gz +0 -0
  308. package/build/client/_app/immutable/chunks/B2-iEFN3.js +0 -2
  309. package/build/client/_app/immutable/chunks/B2-iEFN3.js.br +0 -0
  310. package/build/client/_app/immutable/chunks/B2-iEFN3.js.gz +0 -0
  311. package/build/client/_app/immutable/chunks/B5y2vsNr.js +0 -1
  312. package/build/client/_app/immutable/chunks/B5y2vsNr.js.br +0 -0
  313. package/build/client/_app/immutable/chunks/B5y2vsNr.js.gz +0 -0
  314. package/build/client/_app/immutable/chunks/BN_N9-2s.js +0 -1
  315. package/build/client/_app/immutable/chunks/BN_N9-2s.js.br +0 -0
  316. package/build/client/_app/immutable/chunks/BN_N9-2s.js.gz +0 -0
  317. package/build/client/_app/immutable/chunks/C1z4TjN7.js +0 -1
  318. package/build/client/_app/immutable/chunks/C1z4TjN7.js.br +0 -0
  319. package/build/client/_app/immutable/chunks/C1z4TjN7.js.gz +0 -0
  320. package/build/client/_app/immutable/chunks/CQBaNlA9.js +0 -1
  321. package/build/client/_app/immutable/chunks/CQBaNlA9.js.br +0 -0
  322. package/build/client/_app/immutable/chunks/CQBaNlA9.js.gz +0 -0
  323. package/build/client/_app/immutable/chunks/CVoOGazw.js +0 -4
  324. package/build/client/_app/immutable/chunks/CVoOGazw.js.br +0 -0
  325. package/build/client/_app/immutable/chunks/CVoOGazw.js.gz +0 -0
  326. package/build/client/_app/immutable/chunks/CapOg2jD.js +0 -1
  327. package/build/client/_app/immutable/chunks/CapOg2jD.js.br +0 -0
  328. package/build/client/_app/immutable/chunks/CapOg2jD.js.gz +0 -0
  329. package/build/client/_app/immutable/chunks/ChWB6xnu.js.br +0 -0
  330. package/build/client/_app/immutable/chunks/ChWB6xnu.js.gz +0 -0
  331. package/build/client/_app/immutable/chunks/CqnBT2zJ.js +0 -1
  332. package/build/client/_app/immutable/chunks/CqnBT2zJ.js.br +0 -0
  333. package/build/client/_app/immutable/chunks/CqnBT2zJ.js.gz +0 -0
  334. package/build/client/_app/immutable/chunks/D069mncP.js +0 -1
  335. package/build/client/_app/immutable/chunks/D069mncP.js.br +0 -0
  336. package/build/client/_app/immutable/chunks/D069mncP.js.gz +0 -0
  337. package/build/client/_app/immutable/chunks/DACrOfV_.js +0 -14
  338. package/build/client/_app/immutable/chunks/DACrOfV_.js.br +0 -0
  339. package/build/client/_app/immutable/chunks/DACrOfV_.js.gz +0 -0
  340. package/build/client/_app/immutable/chunks/DQkpHJGc.js.br +0 -0
  341. package/build/client/_app/immutable/chunks/DQkpHJGc.js.gz +0 -0
  342. package/build/client/_app/immutable/chunks/DSDD_hFT.js +0 -1
  343. package/build/client/_app/immutable/chunks/DSDD_hFT.js.br +0 -0
  344. package/build/client/_app/immutable/chunks/DSDD_hFT.js.gz +0 -0
  345. package/build/client/_app/immutable/chunks/D_aTX_ol.js +0 -1
  346. package/build/client/_app/immutable/chunks/D_aTX_ol.js.br +0 -0
  347. package/build/client/_app/immutable/chunks/D_aTX_ol.js.gz +0 -0
  348. package/build/client/_app/immutable/chunks/Dg3qHExF.js +0 -1
  349. package/build/client/_app/immutable/chunks/Dg3qHExF.js.br +0 -0
  350. package/build/client/_app/immutable/chunks/Dg3qHExF.js.gz +0 -0
  351. package/build/client/_app/immutable/chunks/Dt6-JRym.js +0 -2
  352. package/build/client/_app/immutable/chunks/Dt6-JRym.js.br +0 -0
  353. package/build/client/_app/immutable/chunks/Dt6-JRym.js.gz +0 -0
  354. package/build/client/_app/immutable/chunks/QoKxaG0e.js +0 -1
  355. package/build/client/_app/immutable/chunks/QoKxaG0e.js.br +0 -2
  356. package/build/client/_app/immutable/chunks/QoKxaG0e.js.gz +0 -0
  357. package/build/client/_app/immutable/chunks/rtveiEyS.js +0 -1
  358. package/build/client/_app/immutable/chunks/rtveiEyS.js.br +0 -0
  359. package/build/client/_app/immutable/chunks/rtveiEyS.js.gz +0 -0
  360. package/build/client/_app/immutable/entry/app.Cc1FNLNH.js +0 -2
  361. package/build/client/_app/immutable/entry/app.Cc1FNLNH.js.br +0 -0
  362. package/build/client/_app/immutable/entry/app.Cc1FNLNH.js.gz +0 -0
  363. package/build/client/_app/immutable/entry/start.CwqlbFyy.js +0 -1
  364. package/build/client/_app/immutable/entry/start.CwqlbFyy.js.br +0 -2
  365. package/build/client/_app/immutable/entry/start.CwqlbFyy.js.gz +0 -0
  366. package/build/client/_app/immutable/nodes/0.wBQEpdjZ.js +0 -1
  367. package/build/client/_app/immutable/nodes/0.wBQEpdjZ.js.br +0 -0
  368. package/build/client/_app/immutable/nodes/0.wBQEpdjZ.js.gz +0 -0
  369. package/build/client/_app/immutable/nodes/1.K6-n7D0b.js +0 -1
  370. package/build/client/_app/immutable/nodes/1.K6-n7D0b.js.br +0 -0
  371. package/build/client/_app/immutable/nodes/1.K6-n7D0b.js.gz +0 -0
  372. package/build/client/_app/immutable/nodes/3.DkGcIF98.js +0 -1
  373. package/build/client/_app/immutable/nodes/3.DkGcIF98.js.br +0 -0
  374. package/build/client/_app/immutable/nodes/3.DkGcIF98.js.gz +0 -0
  375. package/build/client/_app/immutable/nodes/4.C_NxbT98.js +0 -1
  376. package/build/client/_app/immutable/nodes/4.C_NxbT98.js.br +0 -0
  377. package/build/client/_app/immutable/nodes/4.C_NxbT98.js.gz +0 -0
  378. package/build/client/_app/immutable/nodes/5.CFvfYaLM.js +0 -1
  379. package/build/client/_app/immutable/nodes/5.CFvfYaLM.js.br +0 -0
  380. package/build/client/_app/immutable/nodes/5.CFvfYaLM.js.gz +0 -0
  381. package/build/client/_app/immutable/nodes/6.h34Zyorq.js +0 -1
  382. package/build/client/_app/immutable/nodes/6.h34Zyorq.js.br +0 -0
  383. package/build/client/_app/immutable/nodes/6.h34Zyorq.js.gz +0 -0
  384. package/build/client/_app/immutable/nodes/7.BVJmNbU5.js +0 -1
  385. package/build/client/_app/immutable/nodes/7.BVJmNbU5.js.br +0 -0
  386. package/build/client/_app/immutable/nodes/7.BVJmNbU5.js.gz +0 -0
  387. package/build/server/chunks/0-Cb5ytlMI.js.map +0 -1
  388. package/build/server/chunks/1-Cpb7zRtJ.js +0 -9
  389. package/build/server/chunks/1-Cpb7zRtJ.js.map +0 -1
  390. package/build/server/chunks/3-B_DkgZkc.js +0 -69
  391. package/build/server/chunks/3-B_DkgZkc.js.map +0 -1
  392. package/build/server/chunks/4-DzHoLo__.js.map +0 -1
  393. package/build/server/chunks/5-CCWbCDpk.js.map +0 -1
  394. package/build/server/chunks/6-Dok8svjB.js +0 -202
  395. package/build/server/chunks/6-Dok8svjB.js.map +0 -1
  396. package/build/server/chunks/7-CmgJSG2j.js +0 -42
  397. package/build/server/chunks/7-CmgJSG2j.js.map +0 -1
  398. package/build/server/chunks/Panel-Bz0b85EW.js.map +0 -1
  399. package/build/server/chunks/PrettyJson-CX6-dNsW.js +0 -291
  400. package/build/server/chunks/PrettyJson-CX6-dNsW.js.map +0 -1
  401. package/build/server/chunks/TooltipTable-0z4HkHlH.js +0 -17
  402. package/build/server/chunks/TooltipTable-0z4HkHlH.js.map +0 -1
  403. package/build/server/chunks/_layout.svelte-UiDiCQEz.js +0 -111
  404. package/build/server/chunks/_layout.svelte-UiDiCQEz.js.map +0 -1
  405. package/build/server/chunks/_page.svelte-FIp-IsOo.js.map +0 -1
  406. package/build/server/chunks/_page.svelte-FLzHOuyK.js.map +0 -1
  407. package/build/server/chunks/_page.svelte-jxFKbZdN.js.map +0 -1
  408. package/build/server/chunks/_page.svelte-k8avSQW1.js +0 -215
  409. package/build/server/chunks/_page.svelte-k8avSQW1.js.map +0 -1
  410. package/build/server/chunks/_page.svelte-w9cxGvUf.js.map +0 -1
  411. package/build/server/chunks/async-BfR0vYHo.js.map +0 -1
  412. package/build/server/chunks/client-bj7sePQc.js +0 -7
  413. package/build/server/chunks/error.svelte-D5sIJv3P.js +0 -18
  414. package/build/server/chunks/error.svelte-D5sIJv3P.js.map +0 -1
  415. package/build/server/chunks/hooks.server-_TKfdzGA.js +0 -26
  416. package/build/server/chunks/hooks.server-_TKfdzGA.js.map +0 -1
  417. package/build/server/chunks/index3-DquTjlmp.js.map +0 -1
  418. package/build/server/chunks/mongo-dLmCShL_.js.map +0 -1
  419. package/build/server/chunks/remote-xxtqbu-BFzaWXy0.js +0 -234
  420. package/build/server/chunks/remote-xxtqbu-BFzaWXy0.js.map +0 -1
  421. package/build/server/chunks/routing-DcR4fCSD.js.map +0 -1
  422. package/src/routes/servers/[server]/databases/[database]/collections/[collection]/+page.server.ts +0 -106
  423. package/src/routes/servers/[server]/databases/[database]/collections/[collection]/+page.svelte +0 -174
  424. /package/build/client/_app/immutable/assets/{3.CRKE8WvY.css → 7.CRKE8WvY.css} +0 -0
  425. /package/build/client/_app/immutable/assets/{3.CRKE8WvY.css.br → 7.CRKE8WvY.css.br} +0 -0
  426. /package/build/client/_app/immutable/assets/{3.CRKE8WvY.css.gz → 7.CRKE8WvY.css.gz} +0 -0
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
- import { tick, type Snippet } from "svelte";
2
+ import type { Snippet } from "svelte";
3
+ import Tooltip from "./Tooltip.svelte";
3
4
 
4
5
  interface TableColumn {
5
6
  header: string;
@@ -24,17 +25,6 @@
24
25
  } = $props();
25
26
 
26
27
  let showTooltip = $state(false);
27
- let tooltipElement = $state<HTMLDivElement>();
28
- let containerElement = $state<HTMLDivElement>();
29
-
30
- let tooltipPosition = $state({
31
- left: "",
32
- right: "",
33
- top: "",
34
- bottom: "",
35
- marginTop: "",
36
- marginBottom: "",
37
- });
38
28
 
39
29
  function handleMouseEnter() {
40
30
  showTooltip = true;
@@ -43,95 +33,48 @@
43
33
  function handleMouseLeave() {
44
34
  showTooltip = false;
45
35
  }
46
-
47
- $effect(() => {
48
- if (showTooltip && tooltipElement && containerElement) {
49
- tick().then(() => {
50
- if (!containerElement || !tooltipElement) return;
51
-
52
- const tooltipRect = tooltipElement.getBoundingClientRect();
53
- const viewportWidth = window.innerWidth;
54
- const viewportHeight = window.innerHeight;
55
-
56
- // Reset positioning
57
- tooltipPosition = {
58
- left: "",
59
- right: "",
60
- top: "",
61
- bottom: "",
62
- marginTop: "",
63
- marginBottom: "",
64
- };
65
-
66
- // Position horizontally
67
- if (tooltipRect.right > viewportWidth) {
68
- tooltipPosition.right = "0";
69
- } else {
70
- tooltipPosition.left = "0";
71
- }
72
-
73
- // Position vertically
74
- if (tooltipRect.bottom > viewportHeight) {
75
- tooltipPosition.bottom = "100%";
76
- tooltipPosition.marginBottom = "5px";
77
- } else {
78
- tooltipPosition.top = "100%";
79
- tooltipPosition.marginTop = "5px";
80
- }
81
- });
82
- }
83
- });
84
36
  </script>
85
37
 
86
- <div class="relative inline-block" bind:this={containerElement}>
87
- <button class="dotted text-center" onmouseenter={handleMouseEnter} onmouseleave={handleMouseLeave}>
88
- {@render children?.()}
89
- </button>
90
- {#if showTooltip}
91
- <div
92
- class="absolute bg-[var(--color-2)] border border-[var(--color-3)] rounded p-0 z-[1000] whitespace-nowrap shadow-lg"
93
- bind:this={tooltipElement}
94
- style:left={tooltipPosition.left}
95
- style:right={tooltipPosition.right}
96
- style:top={tooltipPosition.top}
97
- style:bottom={tooltipPosition.bottom}
98
- style:margin-top={tooltipPosition.marginTop}
99
- style:margin-bottom={tooltipPosition.marginBottom}
100
- >
101
- <table class="w-full border-collapse text-base font-medium">
102
- {#if !hideHeader}
103
- <thead>
104
- <tr>
105
- {#each columns as column, index (index)}
106
- <th
107
- class="px-2 py-1 border-b border-[var(--color-3)] bg-[var(--color-4)] font-bold"
108
- class:text-left={column.align === "left" || !column.align}
109
- class:text-right={column.align === "right"}
110
- class:text-center={column.align === "center"}
111
- >
112
- {column.header}
113
- </th>
114
- {/each}
115
- </tr>
116
- </thead>
117
- {/if}
118
- <tbody>
119
- {#each rows as row, index (index)}
120
- <tr>
121
- {#each columns as column, index (index)}
122
- <td
123
- class="px-2 py-1 border-b border-[var(--color-3)]"
124
- class:text-left={column.align === "left" || !column.align}
125
- class:text-right={column.align === "right"}
126
- class:text-center={column.align === "center"}
127
- >
128
- {row[column.key]}
129
- </td>
130
- {/each}
131
- </tr>
132
- {/each}
133
- </tbody>
134
- </table>
135
- </div>
136
- {/if}
137
- </div>
38
+ <Tooltip show={showTooltip} tooltipClass="p-0 whitespace-nowrap">
39
+ {#snippet trigger()}
40
+ <button class="dotted text-center" onmouseenter={handleMouseEnter} onmouseleave={handleMouseLeave}>
41
+ {@render children?.()}
42
+ </button>
43
+ {/snippet}
44
+ {#snippet content()}
45
+ <table class="w-full border-collapse text-base font-medium">
46
+ {#if !hideHeader}
47
+ <thead>
48
+ <tr>
49
+ {#each columns as column, index (index)}
50
+ <th
51
+ class="px-2 py-1 border-b border-[var(--color-3)] bg-[var(--color-4)] font-bold"
52
+ class:text-left={column.align === "left" || !column.align}
53
+ class:text-right={column.align === "right"}
54
+ class:text-center={column.align === "center"}
55
+ >
56
+ {column.header}
57
+ </th>
58
+ {/each}
59
+ </tr>
60
+ </thead>
61
+ {/if}
62
+ <tbody>
63
+ {#each rows as row, index (index)}
64
+ <tr>
65
+ {#each columns as column, index (index)}
66
+ <td
67
+ class="px-2 py-1 border-b border-[var(--color-3)]"
68
+ class:text-left={column.align === "left" || !column.align}
69
+ class:text-right={column.align === "right"}
70
+ class:text-center={column.align === "center"}
71
+ >
72
+ {row[column.key]}
73
+ </td>
74
+ {/each}
75
+ </tr>
76
+ {/each}
77
+ </tbody>
78
+ </table>
79
+ {/snippet}
80
+ </Tooltip>
@@ -74,6 +74,10 @@ export class HostsManager {
74
74
  return Array.from(this._hosts).map(([hostPath, id]) => ({ path: hostPath, _id: id }));
75
75
  }
76
76
 
77
+ getHost(name: string): string | undefined {
78
+ return this._hosts.get(name);
79
+ }
80
+
77
81
  async add(hostPath: string): Promise<string> {
78
82
  // Use existing ID if host already exists, generate new one if not
79
83
  let id = this._hosts.get(hostPath);
@@ -0,0 +1,62 @@
1
+ export const ALLOWED_AGGREGATION_STAGES = new Set([
2
+ "$addFields",
3
+ "$bucket",
4
+ "$bucketAuto",
5
+ "$collStats",
6
+ "$count",
7
+ "$densify",
8
+ "$documents",
9
+ "$facet",
10
+ "$fill",
11
+ "$geoNear",
12
+ "$graphLookup",
13
+ "$group",
14
+ "$indexStats",
15
+ "$limit",
16
+ "$listClusterCatalog",
17
+ "$listSampledQueries",
18
+ "$listSearchIndexes",
19
+ "$listSessions",
20
+ "$lookup",
21
+ "$match",
22
+ "$project",
23
+ "$querySettings",
24
+ "$queryStats",
25
+ "$rankFusion",
26
+ "$redact",
27
+ "$replaceRoot",
28
+ "$replaceWith",
29
+ "$sample",
30
+ "$search",
31
+ "$searchMeta",
32
+ "$set",
33
+ "$setWindowFields",
34
+ "$skip",
35
+ "$sort",
36
+ "$sortByCount",
37
+ "$unionWith",
38
+ "$unset",
39
+ "$unwind",
40
+ "$vectorSearch",
41
+ ]);
42
+
43
+ export function validateAggregationPipeline(pipeline: unknown[]): void {
44
+ for (let i = 0; i < pipeline.length; i++) {
45
+ const stage = pipeline[i];
46
+ if (!stage || typeof stage !== "object") {
47
+ throw new Error(`Invalid stage at index ${i}: must be an object`);
48
+ }
49
+
50
+ const stageKeys = Object.keys(stage);
51
+ if (stageKeys.length !== 1) {
52
+ throw new Error(`Invalid stage at index ${i}: must have exactly one key, found ${stageKeys.length}`);
53
+ }
54
+
55
+ const stageOperator = stageKeys[0];
56
+ if (!ALLOWED_AGGREGATION_STAGES.has(stageOperator)) {
57
+ throw new Error(
58
+ `Disallowed stage operator at index ${i}: "${stageOperator}". Only allowed stages are permitted, to avoid future write stages like '$merge' or '$out'.`,
59
+ );
60
+ }
61
+ }
62
+ }
@@ -1,4 +1,5 @@
1
- import type { CollectionJSON } from "$lib/types";
1
+ import type { CollectionJSON, CollectionMappings, Mappings } from "$lib/types";
2
+ import { logger } from "$lib/utils/logger";
2
3
  import { MongoClient, type Collection } from "mongodb";
3
4
  import { URL } from "url";
4
5
  import { HostsManager } from "./HostsManager";
@@ -87,18 +88,48 @@ export async function getCollectionJson(
87
88
  };
88
89
  }
89
90
 
91
+ class MongoClientWithMappings extends MongoClient {
92
+ mappings: Record<string, Record<string, Mappings>> = {};
93
+
94
+ async getMappings(dbName: string, collectionName: string, opts?: { forceRefresh?: boolean }): Promise<Mappings> {
95
+ if (opts?.forceRefresh || !this.mappings[dbName]?.[collectionName]) {
96
+ const mappings = await this.db(dbName)
97
+ .collection<CollectionMappings>("mongoku.mappings")
98
+ .findOne({ _id: collectionName });
99
+ this.mappings[dbName] ??= {};
100
+ this.mappings[dbName][collectionName] = mappings?.mappings ?? {};
101
+ }
102
+ return this.mappings[dbName][collectionName];
103
+ }
104
+ clearMappingsCache(dbName: string, collectionName: string) {
105
+ delete this.mappings[dbName][collectionName];
106
+ }
107
+ }
108
+
90
109
  class MongoConnections {
91
110
  /**
92
111
  * Todo: better system where we can have mutiple servers with same hostname, and labels for each server that
93
112
  * would be displayed in the UI instead of the hostname.
94
113
  */
95
- private clients: Map<string, MongoClient> = new Map();
114
+ private clients: Map<string, MongoClientWithMappings> = new Map();
96
115
  private clientIds: Map<string, string> = new Map(); // hostname -> _id
97
116
  private hostsManager: HostsManager;
98
- private countTimeout = parseInt(process.env.MONGOKU_COUNT_TIMEOUT!, 10) || 5000;
117
+ private countTimeout = parseInt(process.env.MONGOKU_COUNT_TIMEOUT!, 10) || 30_000;
118
+ private queryTimeout = process.env.MONGOKU_QUERY_TIMEOUT
119
+ ? parseInt(process.env.MONGOKU_QUERY_TIMEOUT, 10)
120
+ : undefined;
121
+ private excludedDatabases: Set<string>;
99
122
 
100
123
  constructor() {
101
124
  this.hostsManager = new HostsManager();
125
+ // Parse MONGOKU_EXCLUDE_DATABASES env var (comma-separated list)
126
+ const excludeEnv = process.env.MONGOKU_EXCLUDE_DATABASES || "";
127
+ this.excludedDatabases = new Set(
128
+ excludeEnv
129
+ .split(",")
130
+ .map((db) => db.trim())
131
+ .filter((db) => db.length > 0),
132
+ );
102
133
  }
103
134
 
104
135
  async initialize() {
@@ -113,20 +144,20 @@ class MongoConnections {
113
144
  const hostname = url.host || host.path;
114
145
 
115
146
  if (!this.clients.has(hostname)) {
116
- const client = new MongoClient(urlStr);
147
+ const client = new MongoClientWithMappings(urlStr);
117
148
  this.clients.set(hostname, client);
118
149
  this.clientIds.set(hostname, host._id);
119
150
  }
120
151
  } catch (err) {
121
- console.error(`Failed to parse URL for host ${host.path}:`, err);
152
+ logger.error(`Failed to parse URL for host ${host.path}:`, err);
122
153
  }
123
154
  }
124
155
  }
125
156
 
126
- getClient(name: string): MongoClient {
157
+ getClient(name: string): MongoClientWithMappings {
127
158
  const client = this.clients.get(name) || this.clients.get(`${name}:27017`);
128
159
  if (!client) {
129
- throw new Error("Server does not exist");
160
+ throw new Error(`Client not found: ${name}`);
130
161
  }
131
162
  return client;
132
163
  }
@@ -141,16 +172,21 @@ class MongoConnections {
141
172
  }));
142
173
  }
143
174
 
144
- getCollection(serverName: string, databaseName: string, collectionName: string) {
145
- const client = this.getClient(serverName);
146
- const db = client.db(databaseName);
147
- return db.collection(collectionName);
148
- }
149
-
150
175
  getCountTimeout() {
151
176
  return this.countTimeout;
152
177
  }
153
178
 
179
+ getQueryTimeout() {
180
+ return this.queryTimeout;
181
+ }
182
+
183
+ filterDatabases<T extends { name: string }>(databases: T[]): T[] {
184
+ if (this.excludedDatabases.size === 0) {
185
+ return databases;
186
+ }
187
+ return databases.filter((db) => !this.excludedDatabases.has(db.name));
188
+ }
189
+
154
190
  async addServer(hostPath: string) {
155
191
  const id = await this.hostsManager.add(hostPath);
156
192
 
@@ -161,21 +197,48 @@ class MongoConnections {
161
197
  const hostname = url.host || hostPath;
162
198
 
163
199
  if (!this.clients.has(hostname)) {
164
- const client = new MongoClient(urlStr);
200
+ const client = new MongoClientWithMappings(urlStr);
165
201
  this.clients.set(hostname, client);
166
202
  this.clientIds.set(hostname, id);
167
203
  }
168
204
  } catch (err) {
169
- console.error(`Failed to parse URL for host ${hostPath}:`, err);
205
+ logger.error(`Failed to parse URL for host ${hostPath}:`, err);
170
206
  throw err;
171
207
  }
172
208
  }
173
209
 
174
210
  async removeServer(name: string) {
175
211
  await this.hostsManager.remove(name);
212
+
213
+ this.clients
214
+ .get(name)
215
+ ?.close()
216
+ .catch((err) => logger.error(`Error closing client ${name}:`, err));
176
217
  this.clients.delete(name);
177
218
  this.clientIds.delete(name);
178
219
  }
220
+
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
+
229
+ // 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));
233
+ }
234
+
235
+ // Create a new client
236
+ const newClient = new MongoClientWithMappings(connectionString);
237
+ this.clients.set(name, newClient);
238
+
239
+ // Test the connection
240
+ await newClient.connect();
241
+ }
179
242
  }
180
243
 
181
244
  // Singleton instance
package/src/lib/types.ts CHANGED
@@ -54,3 +54,63 @@ export interface CollectionJSON {
54
54
  size: number;
55
55
  }>;
56
56
  }
57
+
58
+ export const ALLOWED_AGGREGATION_STAGES = new Set([
59
+ "$addFields",
60
+ "$bucket",
61
+ "$bucketAuto",
62
+ "$collStats",
63
+ "$count",
64
+ "$densify",
65
+ "$documents",
66
+ "$facet",
67
+ "$fill",
68
+ "$geoNear",
69
+ "$graphLookup",
70
+ "$group",
71
+ "$indexStats",
72
+ "$limit",
73
+ "$listClusterCatalog",
74
+ "$listSampledQueries",
75
+ "$listSearchIndexes",
76
+ "$listSessions",
77
+ "$lookup",
78
+ "$match",
79
+ "$project",
80
+ "$querySettings",
81
+ "$queryStats",
82
+ "$rankFusion",
83
+ "$redact",
84
+ "$replaceRoot",
85
+ "$replaceWith",
86
+ "$sample",
87
+ "$search",
88
+ "$searchMeta",
89
+ "$set",
90
+ "$setWindowFields",
91
+ "$skip",
92
+ "$sort",
93
+ "$sortByCount",
94
+ "$unionWith",
95
+ "$unset",
96
+ "$unwind",
97
+ "$vectorSearch",
98
+ ]);
99
+
100
+ /**
101
+ * A single mapping target - defines which collection and field to lookup
102
+ */
103
+ export interface MappingTarget {
104
+ collection: string;
105
+ on: string;
106
+ }
107
+
108
+ export type Mappings = Record<string, MappingTarget[] | MappingTarget>;
109
+
110
+ /**
111
+ * Collection mappings document structure as stored in mongoku.mappings
112
+ */
113
+ export interface CollectionMappings {
114
+ _id: string; // collection name
115
+ mappings: Mappings;
116
+ }
@@ -0,0 +1,6 @@
1
+ export function isEmptyObject(obj: object): boolean {
2
+ for (const key in obj) {
3
+ return false;
4
+ }
5
+ return true;
6
+ }
@@ -98,6 +98,9 @@ function buildObject(node: Node | Expression): unknown {
98
98
  if (node.name === "undefined") {
99
99
  return undefined;
100
100
  }
101
+ if (node.name === "Infinity") {
102
+ return Infinity;
103
+ }
101
104
  throw `Unknown identifier: ${node.name}`;
102
105
  }
103
106
 
@@ -106,7 +109,7 @@ function buildObject(node: Node | Expression): unknown {
106
109
  }
107
110
  }
108
111
 
109
- export function parseJSON(text: string): unknown {
112
+ export function parseJSON(text: string, opts?: { allowArray?: boolean }): unknown {
110
113
  const tree = parseScript(`var __JSON__ = ${text};`, {
111
114
  tolerant: true,
112
115
  });
@@ -117,6 +120,11 @@ export function parseJSON(text: string): unknown {
117
120
  }
118
121
 
119
122
  const objExpression = varDeclaration.declarations[0].init;
123
+
124
+ if (opts?.allowArray && objExpression?.type === "ArrayExpression") {
125
+ return buildObject(objExpression);
126
+ }
127
+
120
128
  if (objExpression?.type !== "ObjectExpression") {
121
129
  throw new Error("Expected ObjectExpression but received: " + objExpression?.type);
122
130
  }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Logger class that wraps console methods for centralized logging
3
+ */
4
+ class Logger {
5
+ /**
6
+ * Log an informational message
7
+ */
8
+ log(...args: unknown[]): void {
9
+ console.log(...args);
10
+ }
11
+
12
+ /**
13
+ * Log an informational message (alias for log)
14
+ */
15
+ info(...args: unknown[]): void {
16
+ console.log(...args);
17
+ }
18
+
19
+ /**
20
+ * Log an error message
21
+ */
22
+ error(...args: unknown[]): void {
23
+ console.error(...args);
24
+ }
25
+
26
+ /**
27
+ * Log a warning message
28
+ */
29
+ warn(...args: unknown[]): void {
30
+ console.warn(...args);
31
+ }
32
+
33
+ /**
34
+ * Log a debug message
35
+ */
36
+ debug(...args: unknown[]): void {
37
+ console.debug(...args);
38
+ }
39
+ }
40
+
41
+ // Export a singleton instance
42
+ export const logger = new Logger();
@@ -0,0 +1,3 @@
1
+ export function omit<T extends object, K extends keyof T>(obj: T, keys: K[]): Omit<T, K> {
2
+ return Object.fromEntries(Object.entries(obj).filter(([key]) => !keys.includes(key as K))) as Omit<T, K>;
3
+ }
@@ -1,7 +1,8 @@
1
1
  import type { LayoutServerLoad } from "./$types";
2
2
 
3
- export const load: LayoutServerLoad = async () => {
3
+ export const load: LayoutServerLoad = async (event) => {
4
4
  return {
5
5
  readOnly: process.env.MONGOKU_READ_ONLY_MODE === "true",
6
+ serverOrigin: event.url.origin,
6
7
  };
7
8
  };
@@ -2,17 +2,30 @@
2
2
  import { resolve } from "$app/paths";
3
3
  import Breadcrumbs from "$lib/components/Breadcrumbs.svelte";
4
4
  import Notifications from "$lib/components/Notifications.svelte";
5
+ import OriginWarning from "$lib/components/OriginWarning.svelte";
6
+ import PageSwitcher from "$lib/components/PageSwitcher.svelte";
7
+ import ThemeSwitcher from "$lib/components/ThemeSwitcher.svelte";
5
8
  import "../app.css";
6
9
 
7
- let { children } = $props();
10
+ let { children, data } = $props();
8
11
  </script>
9
12
 
13
+ <svelte:head>
14
+ <title>Mongoku</title>
15
+ </svelte:head>
16
+
10
17
  <div style="min-height: 100vh">
11
18
  <nav class="navbar px-6 py-4 flex items-center">
12
19
  <a href={resolve("/")} class="text-2xl font-medium">Mongoku</a>
13
20
  <Breadcrumbs />
21
+ <div class="ml-auto flex items-center gap-2">
22
+ <PageSwitcher class="" />
23
+ <ThemeSwitcher />
24
+ </div>
14
25
  </nav>
15
26
 
27
+ <OriginWarning serverOrigin={data.serverOrigin} readOnly={data.readOnly} />
28
+
16
29
  <div class="px-6 py-6 flex flex-col gap-6">
17
30
  <Notifications />
18
31
  {@render children()}
@@ -21,7 +34,7 @@
21
34
 
22
35
  <style lang="postcss">
23
36
  .navbar {
24
- background-color: var(--color-2);
37
+ background-color: var(--light-background);
25
38
  border-bottom: var(--border);
26
39
  }
27
40
  </style>
@@ -0,0 +1,8 @@
1
+ import type { RequestHandler } from "./$types";
2
+
3
+ // No official icon yet, avoid sveltekite errors
4
+ export const GET: RequestHandler = async () => {
5
+ return new Response(null, {
6
+ status: 404,
7
+ });
8
+ };
@@ -1,5 +1,6 @@
1
1
  import { getMongo } from "$lib/server/mongo";
2
2
  import type { DatabaseStats } from "$lib/types";
3
+ import { logger } from "$lib/utils/logger";
3
4
  import type { PageServerLoad } from "./$types";
4
5
 
5
6
  export const load: PageServerLoad = async () => {
@@ -12,16 +13,24 @@ export const load: PageServerLoad = async () => {
12
13
  try {
13
14
  const adminDb = client.db("test").admin();
14
15
  const results = await adminDb.listDatabases();
16
+ const filteredDatabases = mongo.filterDatabases(results.databases);
15
17
  const collectionsCount = await Promise.all(
16
- results.databases.map(async (d) => {
18
+ filteredDatabases.map(async (d) => {
17
19
  const db = client.db(d.name);
18
- const dbStats = (await db.stats()) as DatabaseStats;
20
+ const dbStats: Pick<DatabaseStats, "collections"> = await (db.stats() as Promise<DatabaseStats>).catch(
21
+ () => {
22
+ logger.error(`Error getting stats for database ${d.name} on server ${name}`);
23
+ return {
24
+ collections: 0,
25
+ };
26
+ },
27
+ );
19
28
  return dbStats.collections;
20
29
  }),
21
30
  );
22
31
 
23
32
  return {
24
- databases: results.databases.map((d, index) => ({
33
+ databases: filteredDatabases.map((d, index) => ({
25
34
  name: d.name,
26
35
  size: d.sizeOnDisk ?? 0,
27
36
  collections: collectionsCount[index],
@@ -29,6 +38,7 @@ export const load: PageServerLoad = async () => {
29
38
  size: results.totalSize ?? 0,
30
39
  };
31
40
  } catch (err) {
41
+ logger.error(`Error getting details for server ${name}:`, err);
32
42
  return {
33
43
  error: {
34
44
  code: err instanceof Error && "code" in err ? err.code : undefined,
@@ -37,13 +47,16 @@ export const load: PageServerLoad = async () => {
37
47
  },
38
48
  };
39
49
  }
40
- })().catch((err) => ({
41
- error: {
42
- code: err instanceof Error && "code" in err ? err.code : undefined,
43
- name: err instanceof Error ? err.name : "Error",
44
- message: err instanceof Error ? err.message : String(err),
45
- },
46
- })),
50
+ })().catch((err) => {
51
+ logger.error(`Error getting details for server ${name}:`, err);
52
+ return {
53
+ error: {
54
+ code: err instanceof Error && "code" in err ? err.code : undefined,
55
+ name: err instanceof Error ? err.name : "Error",
56
+ message: err instanceof Error ? err.message : String(err),
57
+ },
58
+ };
59
+ }),
47
60
  }));
48
61
 
49
62
  servers.sort((a, b) => a.name.localeCompare(b.name));