wiki-viewer 1.9.0 → 1.10.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 (236) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +3 -0
  3. package/.next/standalone/.next/build-manifest.json +5 -5
  4. package/.next/standalone/.next/routes-manifest.json +22 -0
  5. package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +2 -2
  6. package/.next/standalone/.next/server/app/_global-error/page.js +1 -1
  7. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  11. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  12. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  13. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +2 -2
  16. package/.next/standalone/.next/server/app/_not-found/page.js +1 -1
  17. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  18. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  19. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  20. package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
  21. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  22. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  23. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  24. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  25. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  26. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  27. package/.next/standalone/.next/server/app/api/agent/activity/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/agent/admin/agents/[agentId]/revoke/route.js +1 -1
  29. package/.next/standalone/.next/server/app/api/agent/admin/agents/[agentId]/revoke/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/agent/admin/agents/route.js +1 -1
  31. package/.next/standalone/.next/server/app/api/agent/admin/agents/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/api/agent/events/[...path]/route.js +3 -4
  33. package/.next/standalone/.next/server/app/api/agent/events/[...path]/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/agent/files/[...path]/route.js +10 -11
  35. package/.next/standalone/.next/server/app/api/agent/files/[...path]/route.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route.js +4 -5
  37. package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route.js.nft.json +1 -1
  38. package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/api/agent/fs/move/route.js +3 -4
  40. package/.next/standalone/.next/server/app/api/agent/fs/move/route.js.nft.json +1 -1
  41. package/.next/standalone/.next/server/app/api/agent/fs/search/route.js +1 -1
  42. package/.next/standalone/.next/server/app/api/agent/fs/search/route.js.nft.json +1 -1
  43. package/.next/standalone/.next/server/app/api/agent/internal/span/route.js +3 -4
  44. package/.next/standalone/.next/server/app/api/agent/internal/span/route.js.nft.json +1 -1
  45. package/.next/standalone/.next/server/app/api/agent/settings/route.js.nft.json +1 -1
  46. package/.next/standalone/.next/server/app/api/agent/sidecar/[...path]/route.js +3 -4
  47. package/.next/standalone/.next/server/app/api/agent/sidecar/[...path]/route.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/api/app-proxy/[...path]/route.js +1 -1
  49. package/.next/standalone/.next/server/app/api/app-proxy/[...path]/route.js.nft.json +1 -1
  50. package/.next/standalone/.next/server/app/api/assets/[...path]/route.js.nft.json +1 -1
  51. package/.next/standalone/.next/server/app/api/auth/[...all]/route.js +1 -1
  52. package/.next/standalone/.next/server/app/api/auth/[...all]/route.js.nft.json +1 -1
  53. package/.next/standalone/.next/server/app/api/share/[token]/route/app-paths-manifest.json +3 -0
  54. package/.next/standalone/.next/server/app/api/share/[token]/route/build-manifest.json +9 -0
  55. package/.next/standalone/.next/server/app/api/share/[token]/route/server-reference-manifest.json +4 -0
  56. package/.next/standalone/.next/server/app/api/share/[token]/route.js +14 -0
  57. package/.next/standalone/.next/server/app/api/share/[token]/route.js.map +5 -0
  58. package/.next/standalone/.next/server/app/api/share/[token]/route.js.nft.json +1 -0
  59. package/.next/standalone/.next/server/app/api/share/[token]/route_client-reference-manifest.js +3 -0
  60. package/.next/standalone/.next/server/app/api/share/route/app-paths-manifest.json +3 -0
  61. package/.next/standalone/.next/server/app/api/share/route/build-manifest.json +9 -0
  62. package/.next/standalone/.next/server/app/api/share/route/server-reference-manifest.json +4 -0
  63. package/.next/standalone/.next/server/app/api/share/route.js +14 -0
  64. package/.next/standalone/.next/server/app/api/share/route.js.map +5 -0
  65. package/.next/standalone/.next/server/app/api/share/route.js.nft.json +1 -0
  66. package/.next/standalone/.next/server/app/api/share/route_client-reference-manifest.js +3 -0
  67. package/.next/standalone/.next/server/app/api/system/browse/route.js.nft.json +1 -1
  68. package/.next/standalone/.next/server/app/api/system/clear-root/route.js.nft.json +1 -1
  69. package/.next/standalone/.next/server/app/api/system/reveal/route.js.nft.json +1 -1
  70. package/.next/standalone/.next/server/app/api/system/root-status/route.js.nft.json +1 -1
  71. package/.next/standalone/.next/server/app/api/system/set-root/route.js +2 -2
  72. package/.next/standalone/.next/server/app/api/system/set-root/route.js.nft.json +1 -1
  73. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route.js.nft.json +1 -1
  74. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route.js.nft.json +1 -1
  75. package/.next/standalone/.next/server/app/api/system/workspaces/route.js.nft.json +1 -1
  76. package/.next/standalone/.next/server/app/api/upload/[...path]/route.js.nft.json +1 -1
  77. package/.next/standalone/.next/server/app/api/wiki/app/route.js.nft.json +1 -1
  78. package/.next/standalone/.next/server/app/api/wiki/content/route.js.nft.json +1 -1
  79. package/.next/standalone/.next/server/app/api/wiki/download/route.js.nft.json +1 -1
  80. package/.next/standalone/.next/server/app/api/wiki/file/route.js.nft.json +1 -1
  81. package/.next/standalone/.next/server/app/api/wiki/folder/route.js.nft.json +1 -1
  82. package/.next/standalone/.next/server/app/api/wiki/move/route.js.nft.json +1 -1
  83. package/.next/standalone/.next/server/app/api/wiki/new-file/route.js.nft.json +1 -1
  84. package/.next/standalone/.next/server/app/api/wiki/page/route.js.nft.json +1 -1
  85. package/.next/standalone/.next/server/app/api/wiki/presence/route.js.nft.json +1 -1
  86. package/.next/standalone/.next/server/app/api/wiki/route.js.nft.json +1 -1
  87. package/.next/standalone/.next/server/app/api/wiki/search/route.js.nft.json +1 -1
  88. package/.next/standalone/.next/server/app/api/wiki/slugs/route.js.nft.json +1 -1
  89. package/.next/standalone/.next/server/app/api/wiki/upload/route.js.nft.json +1 -1
  90. package/.next/standalone/.next/server/app/api/wiki/watch/route.js +1 -1
  91. package/.next/standalone/.next/server/app/api/wiki/watch/route.js.nft.json +1 -1
  92. package/.next/standalone/.next/server/app/index.html +1 -1
  93. package/.next/standalone/.next/server/app/index.rsc +3 -3
  94. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  95. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +3 -3
  96. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  97. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
  98. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  99. package/.next/standalone/.next/server/app/page/build-manifest.json +2 -2
  100. package/.next/standalone/.next/server/app/page.js +1 -1
  101. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  102. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  103. package/.next/standalone/.next/server/app/s/[token]/page/app-paths-manifest.json +3 -0
  104. package/.next/standalone/.next/server/app/s/[token]/page/build-manifest.json +16 -0
  105. package/.next/standalone/.next/server/app/s/[token]/page/next-font-manifest.json +10 -0
  106. package/.next/standalone/.next/server/app/s/[token]/page/react-loadable-manifest.json +1 -0
  107. package/.next/standalone/.next/server/app/s/[token]/page/server-reference-manifest.json +4 -0
  108. package/.next/standalone/.next/server/app/s/[token]/page.js +14 -0
  109. package/.next/standalone/.next/server/app/s/[token]/page.js.map +5 -0
  110. package/.next/standalone/.next/server/app/s/[token]/page.js.nft.json +1 -0
  111. package/.next/standalone/.next/server/app/s/[token]/page_client-reference-manifest.js +3 -0
  112. package/.next/standalone/.next/server/app/signin/page/build-manifest.json +2 -2
  113. package/.next/standalone/.next/server/app/signin/page.js +2 -2
  114. package/.next/standalone/.next/server/app/signin/page.js.nft.json +1 -1
  115. package/.next/standalone/.next/server/app/signin/page_client-reference-manifest.js +1 -1
  116. package/.next/standalone/.next/server/app-paths-manifest.json +3 -0
  117. package/.next/standalone/.next/server/chunks/0dti_kysely_dist_esm_0u.fq2l._.js +1 -1
  118. package/.next/standalone/.next/server/chunks/0p91_next_dist_esm_build_templates_app-route_0d2jbo5.js +1 -1
  119. package/.next/standalone/.next/server/chunks/[root-of-the-server]__01hp8ax._.js +1 -1
  120. package/.next/standalone/.next/server/chunks/[root-of-the-server]__02scxiu._.js +3 -0
  121. package/.next/standalone/.next/server/chunks/[root-of-the-server]__07nnfjx._.js +16 -0
  122. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__12q8ch8._.js → [root-of-the-server]__08n~vj1._.js} +2 -2
  123. package/.next/standalone/.next/server/chunks/[root-of-the-server]__09s9qkd._.js +1 -1
  124. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__12ee_s6._.js → [root-of-the-server]__0bfl4v7._.js} +2 -2
  125. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0n3i3vu._.js +16 -0
  126. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ncjv3e._.js +3 -0
  127. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0s8ovh5._.js +3 -0
  128. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0~.-3yk._.js → [root-of-the-server]__0x3m4up._.js} +2 -2
  129. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0yzle76._.js +20 -0
  130. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0z.pwwj._.js +20 -0
  131. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zgb.q2._.js +3 -0
  132. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__00qu86p._.js → [root-of-the-server]__0zq0rlw._.js} +2 -2
  133. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0-inabx._.js → [root-of-the-server]__12y5z5j._.js} +2 -2
  134. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_share_[token]_route_actions_0~m-o26.js +3 -0
  135. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_share_route_actions_0gz4h.j.js +3 -0
  136. package/.next/standalone/.next/server/chunks/node_modules__pnpm_0aj5g-w._.js +1 -1
  137. package/.next/standalone/.next/server/chunks/src_lib_auth_admin_ts_0g4i6v_._.js +3 -0
  138. package/.next/standalone/.next/server/chunks/ssr/08s9_dagre-d3-es_src_dagre_index_0iwjukf.js +1 -1
  139. package/.next/standalone/.next/server/chunks/ssr/0p91_next_dist_esm_build_templates_app-page_0p1dt3f.js +4 -0
  140. package/.next/standalone/.next/server/chunks/ssr/{0~w0_katex_dist_katex_mjs_0hyln.b._.js → 0~w0_katex_dist_katex_mjs_03gdxkb._.js} +1 -1
  141. package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_diagram-OG6HWLK6_mjs_0t5sus6._.js +1 -1
  142. package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_erDiagram-TEJ5UH35_mjs_0v6rnqy._.js +1 -1
  143. package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_sankeyDiagram-5OEKKPKP_mjs_11ifrnu._.js +1 -1
  144. package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_mermaid_core_mjs_0hj_n-~._.js +1 -1
  145. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__00lk0r~._.js → [root-of-the-server]__06mzg2t._.js} +2 -2
  146. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oh...2._.js +3 -0
  147. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0osa2xb._.js +3 -0
  148. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__02twzph._.js → [root-of-the-server]__0xwdc44._.js} +2 -2
  149. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0du58sw._.js → [root-of-the-server]__0~2q.a0._.js} +2 -2
  150. package/.next/standalone/.next/server/chunks/ssr/_0r9zg10._.js +115 -0
  151. package/.next/standalone/.next/server/chunks/ssr/_0wmhtx3._.js +3 -0
  152. package/.next/standalone/.next/server/chunks/ssr/_0~a9dyk._.js +115 -0
  153. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_s_[token]_page_actions_0bubzp7.js +3 -0
  154. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0s4yn43._.js → node_modules__pnpm_0-w6~h.._.js} +1 -1
  155. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0fh.6ir._.js → node_modules__pnpm_0.eeqiu._.js} +2 -2
  156. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0d~ida~._.js → node_modules__pnpm_016w5te._.js} +1 -1
  157. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0iikbcy._.js → node_modules__pnpm_04o4n28._.js} +1 -1
  158. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0elpfsb._.js → node_modules__pnpm_05bngu6._.js} +2 -2
  159. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0xa.ko1._.js → node_modules__pnpm_05cs0sp._.js} +1 -1
  160. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_05~w-ok._.js → node_modules__pnpm_05w~588._.js} +1 -1
  161. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_00y7foi._.js → node_modules__pnpm_05~bobn._.js} +2 -2
  162. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0arbjru._.js → node_modules__pnpm_07jyfax._.js} +1 -1
  163. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0s8fvbn._.js → node_modules__pnpm_07s54yb._.js} +1 -1
  164. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0c7u76a._.js → node_modules__pnpm_09ygxyg._.js} +2 -2
  165. package/.next/standalone/.next/server/chunks/ssr/node_modules__pnpm_0aq-myi._.js +1 -1
  166. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_12.ymhl._.js → node_modules__pnpm_0dx-.0x._.js} +1 -1
  167. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0beormu._.js → node_modules__pnpm_0e.k7ds._.js} +2 -2
  168. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_03.1jli._.js → node_modules__pnpm_0fvoxey._.js} +1 -1
  169. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0.kyqfq._.js → node_modules__pnpm_0klv8-e._.js} +1 -1
  170. package/.next/standalone/.next/server/chunks/ssr/node_modules__pnpm_0lzb-n~._.js +1 -1
  171. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0.~goq~._.js → node_modules__pnpm_0m4c6iy._.js} +2 -2
  172. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0dbr7c2._.js → node_modules__pnpm_0ms-2au._.js} +1 -1
  173. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0vyv.lz._.js → node_modules__pnpm_0nni9e7._.js} +1 -1
  174. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_09d5yyu._.js → node_modules__pnpm_0oihvhk._.js} +1 -1
  175. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0b5fla7._.js → node_modules__pnpm_0q0mf37._.js} +2 -2
  176. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_03z3na-._.js → node_modules__pnpm_0q2jvgv._.js} +1 -1
  177. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0mvih7b._.js → node_modules__pnpm_0qy4lz-._.js} +2 -2
  178. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_09eo8jh._.js → node_modules__pnpm_0uea699._.js} +2 -2
  179. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0qd2ovj._.js → node_modules__pnpm_0xxpa5a._.js} +2 -2
  180. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0adm8h6._.js → node_modules__pnpm_0z4ojf1._.js} +1 -1
  181. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0tq8zs6._.js → node_modules__pnpm_11u67yf._.js} +1 -1
  182. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0fm6wcx._.js → node_modules__pnpm_13fk5i4._.js} +1 -1
  183. package/.next/standalone/.next/server/chunks/ssr/src_app_page_tsx_0ss2.w7._.js +19 -0
  184. package/.next/standalone/.next/server/edge/chunks/0p91_next_dist_0nh.6nc._.js +1 -1
  185. package/.next/standalone/.next/server/middleware-build-manifest.js +5 -5
  186. package/.next/standalone/.next/server/middleware-manifest.json +1 -1
  187. package/.next/standalone/.next/server/next-font-manifest.js +1 -1
  188. package/.next/standalone/.next/server/next-font-manifest.json +3 -0
  189. package/.next/standalone/.next/server/pages/404.html +1 -1
  190. package/.next/standalone/.next/server/pages/500.html +1 -1
  191. package/.next/standalone/.next/static/chunks/03zepg.10g9nk.js +21 -0
  192. package/.next/standalone/.next/static/chunks/07pa3l2g0aoxc.css +2 -0
  193. package/.next/standalone/.next/static/chunks/07rj172u~.3lw.js +113 -0
  194. package/.next/standalone/.next/static/chunks/0cre2g95gqnc_.js +1 -0
  195. package/.next/standalone/.next/static/chunks/{144e01xuvhx~x.js → 0g5dv59skfo1z.js} +1 -1
  196. package/.next/standalone/.next/static/chunks/0l794ei7~55us.js +17 -0
  197. package/.next/standalone/.next/static/chunks/{14n5cp8rr-k_b.js → 0qiz7kkyaxa93.js} +1 -1
  198. package/.next/standalone/.next/static/chunks/0r9y0mkr29ns6.js +113 -0
  199. package/.next/standalone/.next/static/chunks/0vhw1us0pjfdy.js +1 -0
  200. package/.next/standalone/.next/static/chunks/{06iw_iy5e90d4.js → 0vp-ahhagxptc.js} +1 -1
  201. package/.next/standalone/.next/static/chunks/0xpx9ekm-~h19.js +1 -0
  202. package/.next/standalone/.next/static/chunks/{0b84.439zffwm.js → 0yhis._5rr6tc.js} +1 -1
  203. package/.next/standalone/.next/static/chunks/139g2hzko-flp.js +1 -0
  204. package/.next/standalone/.next/static/chunks/{turbopack-0lf4~b-ofzbm6.js → turbopack-12~z-mr7b9b50.js} +1 -1
  205. package/.next/standalone/README.md +1 -0
  206. package/.next/standalone/bin/wiki-viewer.js +7 -0
  207. package/.next/standalone/package.json +1 -1
  208. package/.next/standalone/src/app/api/share/[token]/route.ts +269 -0
  209. package/.next/standalone/src/app/api/share/route.ts +127 -0
  210. package/.next/standalone/src/app/globals.css +2 -0
  211. package/.next/standalone/src/app/page.tsx +21 -0
  212. package/.next/standalone/src/app/s/[token]/page.tsx +357 -0
  213. package/.next/standalone/src/components/share-dialog.tsx +307 -0
  214. package/.next/standalone/src/components/ui/switch.tsx +1 -1
  215. package/.next/standalone/src/lib/shared-docs/db.ts +177 -0
  216. package/.next/standalone/src/middleware.ts +1 -0
  217. package/.next/standalone/tsconfig.tsbuildinfo +1 -1
  218. package/README.md +1 -0
  219. package/bin/wiki-viewer.js +7 -0
  220. package/package.json +1 -1
  221. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-244bv._.js +0 -16
  222. package/.next/standalone/.next/server/chunks/[root-of-the-server]__012753j._.js +0 -3
  223. package/.next/standalone/.next/server/chunks/[root-of-the-server]__03p0ob1._.js +0 -16
  224. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0gda_iu._.js +0 -3
  225. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0jk1uf4._.js +0 -3
  226. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0nd.b_c._.js +0 -3
  227. package/.next/standalone/.next/server/chunks/[root-of-the-server]__13aid91._.js +0 -3
  228. package/.next/standalone/.next/server/chunks/ssr/_0pqaawz._.js +0 -131
  229. package/.next/standalone/.next/static/chunks/09-jtayuhrq~b.js +0 -1
  230. package/.next/standalone/.next/static/chunks/0vp2gi~fq70je.js +0 -21
  231. package/.next/standalone/.next/static/chunks/125_k3o0s4cid.js +0 -129
  232. package/.next/standalone/.next/static/chunks/135c~rq_ux73w.js +0 -1
  233. package/.next/standalone/.next/static/chunks/167ph4xws_-61.css +0 -2
  234. /package/.next/standalone/.next/static/{YQHDns_jLqFd_bbnLafs0 → 30WI22NYlyxn2Cei0x9Om}/_buildManifest.js +0 -0
  235. /package/.next/standalone/.next/static/{YQHDns_jLqFd_bbnLafs0 → 30WI22NYlyxn2Cei0x9Om}/_clientMiddlewareManifest.js +0 -0
  236. /package/.next/standalone/.next/static/{YQHDns_jLqFd_bbnLafs0 → 30WI22NYlyxn2Cei0x9Om}/_ssgManifest.js +0 -0
@@ -0,0 +1,357 @@
1
+ "use client";
2
+
3
+ import {
4
+ AlertCircle,
5
+ Eye,
6
+ Lock,
7
+ Loader2,
8
+ FileText,
9
+ Copy,
10
+ Check,
11
+ ChevronDown,
12
+ Link,
13
+ } from "lucide-react";
14
+ import { useCallback, useEffect, useState } from "react";
15
+ import { Button } from "@/components/ui/button";
16
+ import { Input } from "@/components/ui/input";
17
+ import { Card } from "@/components/ui/card";
18
+ import {
19
+ DropdownMenu,
20
+ DropdownMenuContent,
21
+ DropdownMenuItem,
22
+ DropdownMenuSeparator,
23
+ DropdownMenuTrigger,
24
+ } from "@/components/ui/dropdown-menu";
25
+ import { ThemeProvider } from "@/components/theme-provider";
26
+ import { KBEditor } from "@/components/editor/editor";
27
+ import { useEditorStore } from "@/stores/editor-store";
28
+ import { ViewWidthToggle } from "@/components/view-width-toggle";
29
+ import { ThemeToggle } from "@/components/theme-toggle";
30
+
31
+ type ShareState =
32
+ | { kind: "loading" }
33
+ | { kind: "password"; message: string }
34
+ | { kind: "error"; title: string; message: string }
35
+ | { kind: "content"; content: string; filename: string; viewCount: number };
36
+
37
+ export default function SharedPage({
38
+ params,
39
+ }: {
40
+ params: Promise<{ token: string }>;
41
+ }) {
42
+ const [token, setToken] = useState<string | null>(null);
43
+ const [state, setState] = useState<ShareState>({ kind: "loading" });
44
+ const [password, setPassword] = useState("");
45
+ const [verifying, setVerifying] = useState(false);
46
+ const [pwdError, setPwdError] = useState(false);
47
+ const [copied, setCopied] = useState<string | null>(null);
48
+
49
+ const copyShareLink = () => {
50
+ if (!token) return;
51
+ const url = `${window.location.origin}/s/${token}`;
52
+ void navigator.clipboard.writeText(url);
53
+ setCopied("link");
54
+ setTimeout(() => setCopied(null), 2000);
55
+ };
56
+
57
+ const copyRawContent = async () => {
58
+ if (state.kind !== "content") return;
59
+ try {
60
+ await navigator.clipboard.writeText(state.content);
61
+ setCopied("raw");
62
+ setTimeout(() => setCopied(null), 2000);
63
+ } catch {
64
+ // silently fail
65
+ }
66
+ };
67
+
68
+ const copyFormattedContent = async () => {
69
+ if (state.kind !== "content") return;
70
+ try {
71
+ const { markdownToHtml } = await import("@/lib/markdown/to-html");
72
+ const html = await markdownToHtml(state.content);
73
+ if ("ClipboardItem" in window && navigator.clipboard.write) {
74
+ await navigator.clipboard.write([
75
+ new ClipboardItem({
76
+ "text/html": new Blob([html], { type: "text/html" }),
77
+ "text/plain": new Blob([state.content], { type: "text/plain" }),
78
+ }),
79
+ ]);
80
+ } else {
81
+ await navigator.clipboard.writeText(state.content);
82
+ }
83
+ setCopied("formatted");
84
+ setTimeout(() => setCopied(null), 2000);
85
+ } catch {
86
+ // silently fail
87
+ }
88
+ };
89
+
90
+ const fetchShare = useCallback(
91
+ async () => {
92
+ if (!token) return;
93
+ setState({ kind: "loading" });
94
+ try {
95
+ const res = await fetch(`/api/share/${token}`);
96
+ const data = await res.json();
97
+
98
+ if (res.ok && data.content !== undefined) {
99
+ useEditorStore.setState({
100
+ currentPath: `shared/${token}/${data.filename ?? "document"}`,
101
+ content: data.content,
102
+ frontmatter: null,
103
+ isLoading: false,
104
+ loadStatus: "ok",
105
+ isDirty: false,
106
+ currentRevision: null,
107
+ saveStatus: "saved",
108
+ });
109
+ setState({
110
+ kind: "content",
111
+ content: data.content,
112
+ filename: data.filename ?? "document",
113
+ viewCount: data.viewCount ?? 0,
114
+ });
115
+ } else if (res.status === 401 && data.protected) {
116
+ setState({ kind: "password", message: data.message ?? "" });
117
+ } else if (res.status === 410) {
118
+ setState({
119
+ kind: "error",
120
+ title: "Link unavailable",
121
+ message: data.message ?? "This share link is no longer available.",
122
+ });
123
+ } else if (res.status === 404) {
124
+ setState({
125
+ kind: "error",
126
+ title: "Not found",
127
+ message: "This share link does not exist.",
128
+ });
129
+ } else {
130
+ setState({
131
+ kind: "error",
132
+ title: "Error",
133
+ message: data.message ?? "Something went wrong. Try again later.",
134
+ });
135
+ }
136
+ } catch {
137
+ setState({
138
+ kind: "error",
139
+ title: "Connection error",
140
+ message: "Could not reach the server. Check your connection.",
141
+ });
142
+ }
143
+ },
144
+ [token],
145
+ );
146
+
147
+ // Resolve token from params
148
+ useEffect(() => {
149
+ void params.then((p) => setToken(p.token));
150
+ }, [params]);
151
+
152
+ // Fetch on token resolve (no password)
153
+ useEffect(() => {
154
+ if (token) void fetchShare();
155
+ }, [token, fetchShare]);
156
+
157
+ const handleSubmitPassword = async (e: React.FormEvent) => {
158
+ e.preventDefault();
159
+ if (!password.trim() || !token) return;
160
+ setVerifying(true);
161
+ setPwdError(false);
162
+ try {
163
+ const res = await fetch(`/api/share/${token}`, {
164
+ method: "POST",
165
+ headers: { "Content-Type": "application/json" },
166
+ body: JSON.stringify({ password: password.trim() }),
167
+ });
168
+ const data = await res.json();
169
+
170
+ if (res.ok && data.content !== undefined) {
171
+ useEditorStore.setState({
172
+ currentPath: `shared/${token}/${data.filename ?? "document"}`,
173
+ content: data.content,
174
+ frontmatter: null,
175
+ isLoading: false,
176
+ loadStatus: "ok",
177
+ isDirty: false,
178
+ currentRevision: null,
179
+ saveStatus: "saved",
180
+ });
181
+ setState({
182
+ kind: "content",
183
+ content: data.content,
184
+ filename: data.filename ?? "document",
185
+ viewCount: data.viewCount ?? 0,
186
+ });
187
+ } else if (res.status === 403) {
188
+ setPwdError(true);
189
+ setState({ kind: "password", message: "Incorrect password" });
190
+ } else if (res.status === 429) {
191
+ setState({ kind: "password", message: "Too many attempts. Try again later." });
192
+ } else {
193
+ setState({ kind: "error", title: "Error", message: data.message ?? "Something went wrong." });
194
+ }
195
+ } catch {
196
+ setState({ kind: "error", title: "Connection error", message: "Could not reach the server." });
197
+ }
198
+ setVerifying(false);
199
+ };
200
+
201
+ return (
202
+ <ThemeProvider>
203
+ <div className="min-h-screen flex flex-col bg-background text-foreground">
204
+ <header className="border-b border-border bg-muted/50">
205
+ <div className="mx-auto flex max-w-4xl items-center gap-2 px-4 py-2">
206
+ {state.kind === "content" ? (
207
+ <>
208
+ <div className="flex items-center gap-2 min-w-0 flex-1">
209
+ <span className="h-2 w-2 rounded-full bg-green-500 shrink-0" />
210
+ <span className="text-sm font-mono truncate" title={state.filename}>
211
+ {state.filename}
212
+ </span>
213
+ </div>
214
+ <div className="flex items-center gap-1 shrink-0">
215
+ <DropdownMenu>
216
+ <DropdownMenuTrigger asChild>
217
+ <Button
218
+ size="sm"
219
+ variant="ghost"
220
+ className="h-7 gap-1.5 px-2 text-xs data-[state=open]:bg-transparent"
221
+ title="Copy link, raw content, or formatted content"
222
+ >
223
+ {copied === "link" ? (
224
+ <Check className="h-3.5 w-3.5 text-green-500" />
225
+ ) : (
226
+ <Copy className="h-3.5 w-3.5" />
227
+ )}
228
+ Copy
229
+ <ChevronDown className="h-3 w-3 opacity-60" />
230
+ </Button>
231
+ </DropdownMenuTrigger>
232
+ <DropdownMenuContent align="end" className="w-48">
233
+ <DropdownMenuItem onClick={copyShareLink}>
234
+ <Link className="mr-2 h-3.5 w-3.5" />
235
+ Copy share link
236
+ </DropdownMenuItem>
237
+ <DropdownMenuSeparator />
238
+ <DropdownMenuItem onClick={copyRawContent}>
239
+ <FileText className="mr-2 h-3.5 w-3.5" />
240
+ Copy raw content
241
+ </DropdownMenuItem>
242
+ <DropdownMenuItem onClick={copyFormattedContent}>
243
+ <FileText className="mr-2 h-3.5 w-3.5" />
244
+ Copy formatted content
245
+ </DropdownMenuItem>
246
+ </DropdownMenuContent>
247
+ </DropdownMenu>
248
+ <ViewWidthToggle />
249
+ <ThemeToggle />
250
+ <span className="text-xs text-muted-foreground ml-2">
251
+ {state.viewCount} view
252
+ {state.viewCount !== 1 ? "s" : ""}
253
+ </span>
254
+ </div>
255
+ </>
256
+ ) : (
257
+ <>
258
+ <Eye className="h-4 w-4 text-muted-foreground" />
259
+ <span className="text-xs font-medium text-muted-foreground">
260
+ Shared document
261
+ </span>
262
+ </>
263
+ )}
264
+ </div>
265
+ </header>
266
+
267
+ {state.kind === "loading" && (
268
+ <div className="flex-1 flex items-center justify-center">
269
+ <Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
270
+ </div>
271
+ )}
272
+
273
+ {state.kind === "password" && (
274
+ <div className="flex-1 flex items-center justify-center px-4">
275
+ <Card className="max-w-sm w-full p-6">
276
+ <div className="flex flex-col items-center gap-4 text-center">
277
+ <div className="rounded-full bg-muted p-3">
278
+ <Lock className="h-6 w-6 text-muted-foreground" />
279
+ </div>
280
+ <div className="space-y-1">
281
+ <h1 className="text-base font-medium">
282
+ Password required
283
+ </h1>
284
+ <p className="text-sm text-muted-foreground">
285
+ {state.message ||
286
+ "This document is password-protected."}
287
+ </p>
288
+ </div>
289
+ <form
290
+ onSubmit={handleSubmitPassword}
291
+ className="w-full space-y-3"
292
+ >
293
+ <Input
294
+ type="password"
295
+ placeholder="Enter password"
296
+ value={password}
297
+ onChange={(e) => {
298
+ setPassword(e.target.value);
299
+ setPwdError(false);
300
+ }}
301
+ autoFocus
302
+ />
303
+ {pwdError && (
304
+ <p className="text-xs text-destructive flex items-center gap-1">
305
+ <AlertCircle className="h-3 w-3" />
306
+ Wrong password. Try again.
307
+ </p>
308
+ )}
309
+ <Button
310
+ type="submit"
311
+ className="w-full"
312
+ disabled={verifying || !password.trim()}
313
+ >
314
+ {verifying ? (
315
+ <Loader2 className="h-4 w-4 animate-spin" />
316
+ ) : (
317
+ "View document"
318
+ )}
319
+ </Button>
320
+ </form>
321
+ </div>
322
+ </Card>
323
+ </div>
324
+ )}
325
+
326
+ {state.kind === "error" && (
327
+ <div className="flex-1 flex flex-col items-center justify-center gap-4 px-4 text-center">
328
+ <div className="rounded-full bg-muted p-3">
329
+ <AlertCircle className="h-6 w-6 text-muted-foreground" />
330
+ </div>
331
+ <div className="space-y-1">
332
+ <h1 className="text-base font-medium">{state.title}</h1>
333
+ <p className="text-sm text-muted-foreground">
334
+ {state.message}
335
+ </p>
336
+ </div>
337
+ </div>
338
+ )}
339
+
340
+ {state.kind === "content" && (
341
+ <KBEditor mode="viewing" />
342
+ )}
343
+
344
+ {state.kind === "content" && (
345
+ <footer className="border-t border-border bg-muted/30">
346
+ <div className="mx-auto flex max-w-4xl items-center gap-2 px-4 py-2">
347
+ <FileText className="h-3 w-3 text-muted-foreground" />
348
+ <span className="text-xs text-muted-foreground">
349
+ {state.filename}
350
+ </span>
351
+ </div>
352
+ </footer>
353
+ )}
354
+ </div>
355
+ </ThemeProvider>
356
+ );
357
+ }
@@ -0,0 +1,307 @@
1
+ "use client";
2
+
3
+ import {
4
+ Copy,
5
+ Check,
6
+ Globe,
7
+ Loader2,
8
+ Lock,
9
+ Trash2,
10
+ Clock,
11
+ } from "lucide-react";
12
+ import { useCallback, useEffect, useState } from "react";
13
+ import { Button } from "@/components/ui/button";
14
+ import { Input } from "@/components/ui/input";
15
+ import { Switch } from "@/components/ui/switch";
16
+ import { Label } from "@/components/ui/label";
17
+ import {
18
+ Dialog,
19
+ DialogContent,
20
+ DialogHeader,
21
+ DialogTitle,
22
+ DialogDescription,
23
+ } from "@/components/ui/dialog";
24
+ import { showSuccess, showError } from "@/lib/toast";
25
+ import { wsFetch } from "@/lib/workspace-client";
26
+
27
+ interface Share {
28
+ id: string;
29
+ token: string;
30
+ url: string;
31
+ hasPassword: boolean;
32
+ expiresAt: string | null;
33
+ createdAt: string;
34
+ viewCount: number;
35
+ isExpired: boolean;
36
+ }
37
+
38
+ interface ShareDialogProps {
39
+ open: boolean;
40
+ onOpenChange: (open: boolean) => void;
41
+ filePath: string;
42
+ }
43
+
44
+ export function ShareDialog({
45
+ open,
46
+ onOpenChange,
47
+ filePath,
48
+ }: ShareDialogProps) {
49
+ const [shares, setShares] = useState<Share[]>([]);
50
+ const [loading, setLoading] = useState(true);
51
+ const [creating, setCreating] = useState(false);
52
+
53
+ // Form fields
54
+ const [password, setPassword] = useState("");
55
+ const [enablePassword, setEnablePassword] = useState(false);
56
+ const [enableExpiry, setEnableExpiry] = useState(false);
57
+ const [expiryDays, setExpiryDays] = useState("7");
58
+
59
+ // Copied state per share token
60
+ const [copiedToken, setCopiedToken] = useState<string | null>(null);
61
+
62
+ const loadShares = useCallback(async () => {
63
+ setLoading(true);
64
+ try {
65
+ const res = await wsFetch(
66
+ `/api/share?path=${encodeURIComponent(filePath)}`,
67
+ );
68
+ if (res.ok) {
69
+ const data = await res.json();
70
+ setShares(data.shares ?? []);
71
+ }
72
+ } catch {
73
+ // silently fail
74
+ }
75
+ setLoading(false);
76
+ }, [filePath]);
77
+
78
+ useEffect(() => {
79
+ if (open) void loadShares();
80
+ }, [open, loadShares]);
81
+
82
+ const handleCreate = async () => {
83
+ setCreating(true);
84
+ try {
85
+ const body: Record<string, unknown> = { path: filePath };
86
+ if (enablePassword && password.trim()) {
87
+ body.password = password.trim();
88
+ }
89
+ if (enableExpiry && expiryDays) {
90
+ const d = new Date();
91
+ d.setDate(d.getDate() + Number(expiryDays));
92
+ body.expiresAt = d.toISOString();
93
+ }
94
+ const res = await wsFetch("/api/share", {
95
+ method: "POST",
96
+ headers: { "Content-Type": "application/json" },
97
+ body: JSON.stringify(body),
98
+ });
99
+ if (!res.ok) {
100
+ const e = await res.json();
101
+ showError(e.error ?? "Failed to create share link");
102
+ return;
103
+ }
104
+ showSuccess("Share link created");
105
+ setPassword("");
106
+ setEnablePassword(false);
107
+ setEnableExpiry(false);
108
+ setExpiryDays("7");
109
+ await loadShares();
110
+ } catch {
111
+ showError("Failed to create share link");
112
+ } finally {
113
+ setCreating(false);
114
+ }
115
+ };
116
+
117
+ const handleRevoke = async (token: string) => {
118
+ try {
119
+ const res = await fetch(`/api/share/${token}`, { method: "DELETE" });
120
+ if (!res.ok) {
121
+ showError("Failed to revoke share link");
122
+ return;
123
+ }
124
+ showSuccess("Share link revoked");
125
+ await loadShares();
126
+ } catch {
127
+ showError("Failed to revoke share link");
128
+ }
129
+ };
130
+
131
+ const copyLink = (url: string, token: string) => {
132
+ const fullUrl = `${window.location.origin}${url}`;
133
+ void navigator.clipboard.writeText(fullUrl);
134
+ setCopiedToken(token);
135
+ setTimeout(() => setCopiedToken(null), 2000);
136
+ };
137
+
138
+ return (
139
+ <Dialog open={open} onOpenChange={onOpenChange}>
140
+ <DialogContent className="sm:max-w-md">
141
+ <DialogHeader>
142
+ <DialogTitle>Share document</DialogTitle>
143
+ <DialogDescription>
144
+ Create a public link to share this document as read-only.
145
+ </DialogDescription>
146
+ </DialogHeader>
147
+
148
+ <div className="space-y-4">
149
+ {/* Create new share */}
150
+ <div className="rounded-sm border border-border p-3 space-y-3">
151
+ <h3 className="text-sm font-medium">New share link</h3>
152
+
153
+ {/* Password toggle */}
154
+ <div className="flex items-center justify-between">
155
+ <Label htmlFor="share-pwd" className="text-xs gap-1.5 flex items-center">
156
+ <Lock className="h-3 w-3 text-muted-foreground" />
157
+ Password protect
158
+ </Label>
159
+ <Switch
160
+ id="share-pwd"
161
+ checked={enablePassword}
162
+ onCheckedChange={setEnablePassword}
163
+ />
164
+ </div>
165
+ {enablePassword && (
166
+ <Input
167
+ type="password"
168
+ placeholder="Set a password"
169
+ value={password}
170
+ onChange={(e) => setPassword(e.target.value)}
171
+ />
172
+ )}
173
+
174
+ {/* Expiry toggle */}
175
+ <div className="flex items-center justify-between">
176
+ <Label htmlFor="share-expiry" className="text-xs gap-1.5 flex items-center">
177
+ <Clock className="h-3 w-3 text-muted-foreground" />
178
+ Set expiration
179
+ </Label>
180
+ <Switch
181
+ id="share-expiry"
182
+ checked={enableExpiry}
183
+ onCheckedChange={setEnableExpiry}
184
+ />
185
+ </div>
186
+ {enableExpiry && (
187
+ <div className="flex items-center gap-2">
188
+ <Input
189
+ type="number"
190
+ min={1}
191
+ max={365}
192
+ value={expiryDays}
193
+ onChange={(e) => setExpiryDays(e.target.value)}
194
+ className="w-20"
195
+ />
196
+ <span className="text-xs text-muted-foreground">days</span>
197
+ </div>
198
+ )}
199
+
200
+ <Button
201
+ size="sm"
202
+ className="w-full gap-1.5"
203
+ onClick={handleCreate}
204
+ disabled={creating}
205
+ >
206
+ {creating ? (
207
+ <Loader2 className="h-3.5 w-3.5 animate-spin" />
208
+ ) : (
209
+ <Globe className="h-3.5 w-3.5" />
210
+ )}
211
+ Create link
212
+ </Button>
213
+ </div>
214
+
215
+ {/* Existing shares */}
216
+ <div className="space-y-2">
217
+ <h3 className="text-xs font-medium text-muted-foreground">
218
+ {shares.length > 0
219
+ ? `Active links (${shares.length})`
220
+ : loading
221
+ ? "Loading..."
222
+ : "No active links"}
223
+ </h3>
224
+ {loading && (
225
+ <div className="flex justify-center py-2">
226
+ <Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
227
+ </div>
228
+ )}
229
+ {shares.map((share) => (
230
+ <div
231
+ key={share.id}
232
+ className="flex items-center gap-2 rounded-sm border border-border p-2"
233
+ >
234
+ <div className="flex-1 min-w-0">
235
+ <div className="flex items-center gap-1.5">
236
+ <span className="text-xs font-mono truncate">
237
+ {window.location.origin}/s/{share.token}
238
+ </span>
239
+ </div>
240
+ <div className="flex items-center gap-2 mt-0.5">
241
+ {share.hasPassword && (
242
+ <span className="flex items-center gap-0.5 text-[10px] text-muted-foreground">
243
+ <Lock className="h-2.5 w-2.5" />
244
+ pwd
245
+ </span>
246
+ )}
247
+ {share.expiresAt && (
248
+ <span className="flex items-center gap-0.5 text-[10px] text-muted-foreground">
249
+ <Clock className="h-2.5 w-2.5" />
250
+ {formatExpiry(share.expiresAt)}
251
+ </span>
252
+ )}
253
+ <span className="text-[10px] text-muted-foreground">
254
+ {share.viewCount} view
255
+ {share.viewCount !== 1 ? "s" : ""}
256
+ </span>
257
+ {share.isExpired && (
258
+ <span className="text-[10px] text-destructive">
259
+ expired
260
+ </span>
261
+ )}
262
+ </div>
263
+ </div>
264
+ <div className="flex items-center gap-1 shrink-0">
265
+ <Button
266
+ size="sm"
267
+ variant="ghost"
268
+ className="h-7 w-7 p-0"
269
+ title="Copy link"
270
+ onClick={() => copyLink(share.url, share.token)}
271
+ >
272
+ {copiedToken === share.token ? (
273
+ <Check className="h-3.5 w-3.5 text-green-500" />
274
+ ) : (
275
+ <Copy className="h-3.5 w-3.5" />
276
+ )}
277
+ </Button>
278
+ <Button
279
+ size="sm"
280
+ variant="ghost"
281
+ className="h-7 w-7 p-0 text-destructive hover:text-destructive"
282
+ title="Revoke link"
283
+ onClick={() => handleRevoke(share.token)}
284
+ >
285
+ <Trash2 className="h-3.5 w-3.5" />
286
+ </Button>
287
+ </div>
288
+ </div>
289
+ ))}
290
+ </div>
291
+ </div>
292
+ </DialogContent>
293
+ </Dialog>
294
+ );
295
+ }
296
+
297
+ function formatExpiry(iso: string): string {
298
+ const d = new Date(iso);
299
+ const now = new Date();
300
+ const ms = d.getTime() - now.getTime();
301
+ if (ms <= 0) return "expired";
302
+ const days = Math.floor(ms / 86400000);
303
+ const hours = Math.floor((ms % 86400000) / 3600000);
304
+ if (days > 0) return `${days}d`;
305
+ if (hours > 0) return `${hours}h`;
306
+ return "<1h";
307
+ }
@@ -12,7 +12,7 @@ function Switch({
12
12
  <SwitchPrimitive.Root
13
13
  data-slot="switch"
14
14
  className={cn(
15
- "peer data-[state=checked]:bg-accent data-[state=unchecked]:bg-input inline-flex h-5 w-9 shrink-0 items-center rounded-sm border-2 border-transparent shadow-e-1 transition-all outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 cursor-pointer",
15
+ "peer data-[state=checked]:bg-[var(--switch-checked)] data-[state=unchecked]:bg-input inline-flex h-5 w-9 shrink-0 items-center rounded-sm border-2 border-transparent shadow-e-1 transition-all outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 cursor-pointer",
16
16
  className,
17
17
  )}
18
18
  {...props}