docs-i18n 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (249) hide show
  1. package/admin/app/lib/auth-client.ts +21 -0
  2. package/admin/app/lib/auth.server.ts +62 -0
  3. package/admin/app/routeTree.gen.ts +21 -3
  4. package/admin/app/routes/index.tsx +68 -8
  5. package/admin/app/routes/login.tsx +207 -0
  6. package/admin/app/server.ts +23 -0
  7. package/admin/app/styles.css +146 -0
  8. package/admin/app/worker.ts +18 -0
  9. package/admin/dist/client/assets/auth-client-DqJZaFZR.js +3 -0
  10. package/admin/dist/client/assets/login-CQjkiBAF.js +1 -0
  11. package/admin/dist/client/assets/main-bc5tcdGg.js +18 -0
  12. package/admin/dist/client/assets/routes-CTPOG_v1.js +3 -0
  13. package/admin/dist/client/assets/{styles-DJ6QEJmN.css → styles-zS0BbO7e.css} +1 -1
  14. package/admin/dist/client/assets/useNavigate-CEOVvMjz.js +1 -0
  15. package/admin/dist/server/assets/{react-dom-CpO9xk_L.js → __tanstack-start-server-fn-resolver-qK0Yfvti.js} +83 -507
  16. package/admin/dist/server/assets/_tanstack-start-manifest_v-BgMVPPt2.js +21 -0
  17. package/admin/dist/server/assets/adapter-DjXlUL1J.js +2253 -0
  18. package/admin/dist/server/assets/auth-client-CoUpyQIM.js +807 -0
  19. package/admin/dist/server/assets/auth-dSAIPjBw.js +72 -0
  20. package/admin/dist/server/assets/auth.server-BLVDnTCZ.js +31352 -0
  21. package/admin/dist/server/assets/bun-sqlite-dialect-C8OaCWSL-BNNY-FoT.js +154 -0
  22. package/admin/dist/server/assets/compiled-query-CnFG_BVV.js +6967 -0
  23. package/admin/dist/server/assets/d1-sqlite-dialect-sYHNqBte-Bjz-cybU.js +115 -0
  24. package/admin/dist/server/assets/dist-C3-e8E2B.js +215 -0
  25. package/admin/dist/server/assets/dist-CUzFWZag.js +6039 -0
  26. package/admin/dist/server/assets/{init-DJr2glb3.js → dist-DBv71kqn.js} +21 -381
  27. package/admin/dist/server/assets/error-CASJ5tIm.js +457 -0
  28. package/admin/dist/server/assets/error-codes-BhMTGvV6.js +1153 -0
  29. package/admin/dist/server/assets/init-CJJUsPDL.js +49 -0
  30. package/admin/dist/server/assets/job-manager-D9Ab9hgu.js +179 -0
  31. package/admin/dist/server/assets/{jobs-bQfYqSk7.js → jobs-DrEe9YOj.js} +18 -5
  32. package/admin/dist/server/assets/kysely-adapter-YC8RFPyc.js +2 -0
  33. package/admin/dist/server/assets/login-SqzTMYOZ.js +228 -0
  34. package/admin/dist/server/assets/migrator-ZpVZslbq.js +2926 -0
  35. package/admin/dist/server/assets/{misc-DOk3t9vs.js → misc-BSoYldBT.js} +22 -9
  36. package/admin/dist/server/assets/{models-CBb8Owe5.js → models-CoviNHUP.js} +1 -1
  37. package/admin/dist/server/assets/node-sqlite-dialect-BJIaP6lL.js +154 -0
  38. package/admin/dist/server/assets/{router-DlU_fGDK.js → router-D-82slI-.js} +23 -11
  39. package/admin/dist/server/assets/{routes-BcfX6iub.js → routes-B1pNmxF3.js} +43 -29
  40. package/admin/dist/server/assets/{routes-pIM0fgUO.js → routes-C9huiZHw.js} +56 -22
  41. package/admin/dist/server/assets/sqlite-adapter-CL2EidjD.js +69 -0
  42. package/admin/dist/server/assets/{start-BS52hm79.js → start-BiybVoR2.js} +1 -1
  43. package/admin/dist/server/assets/status-B1AGLvHn.js +162 -0
  44. package/admin/dist/server/assets/status-D7PU72hm.js +262 -0
  45. package/admin/dist/server/assets/string-B4XlckmJ.js +6 -0
  46. package/admin/dist/server/assets/useNavigate-0H08s_Q2.js +29 -0
  47. package/admin/dist/server/assets/useRouter-BXJvr8to.js +508 -0
  48. package/admin/dist/server/server.js +70 -90
  49. package/admin/package.json +6 -1
  50. package/admin/server/functions/auth.ts +89 -0
  51. package/admin/server/functions/jobs.ts +30 -2
  52. package/admin/server/functions/misc.ts +25 -5
  53. package/admin/server/functions/status.ts +52 -3
  54. package/admin/server/index.ts +1 -1
  55. package/admin/server/init.ts +21 -9
  56. package/admin/server/services/d1-status.ts +282 -0
  57. package/admin/vite.config.ts +29 -15
  58. package/admin/wrangler.jsonc +16 -0
  59. package/package.json +1 -1
  60. package/template/content/docs-i18n/en/cli.md +9 -5
  61. package/template/content/docs-i18n/en/deployment.md +85 -68
  62. package/template/dist/client/assets/{Doc-CbmLeLjl.js → Doc-BKO69_nz.js} +1 -1
  63. package/template/dist/client/assets/{DocsLayout-ERG7nrAc.js → DocsLayout-BGugXxEQ.js} +1 -1
  64. package/template/dist/client/assets/{FileTabs-CCynw0nL.js → FileTabs-4fZriOj4.js} +1 -1
  65. package/template/dist/client/assets/{Footer-l6Y8-ltB.js → Footer-DYh1AfWA.js} +1 -1
  66. package/template/dist/client/assets/{FrameworkContent-pNf68F7f.js → FrameworkContent-rVvjxASn.js} +1 -1
  67. package/template/dist/client/assets/{MarkdownHeadingContext-6I862CKH.js → MarkdownHeadingContext-CdvUDZFU.js} +4 -4
  68. package/template/dist/client/assets/{PostNotFound-ScC0039d.js → PostNotFound-WoSYGsGu.js} +1 -1
  69. package/template/dist/client/assets/{_basePickBy-B-GcvGxW.js → _basePickBy-Dd7GuR7A.js} +1 -1
  70. package/template/dist/client/assets/{_baseUniq-C1WySGZQ.js → _baseUniq-DMxQLGFI.js} +1 -1
  71. package/template/dist/client/assets/_lang-3AqGszEy.js +1 -0
  72. package/template/dist/client/assets/_lang._project-COkrIqzH.js +1 -0
  73. package/template/dist/client/assets/_lang._project._version-B8vRZczu.js +1 -0
  74. package/template/dist/client/assets/{_lang._project._version.docs-aw08dKvN.js → _lang._project._version.docs-DokNGgvU.js} +1 -1
  75. package/template/dist/client/assets/{_lang._project._version.docs._-B4Vb_S0V.js → _lang._project._version.docs._-CXCNZzOb.js} +1 -1
  76. package/template/dist/client/assets/_lang._project._version.docs._-DR0WSQEb.js +1 -0
  77. package/template/dist/client/assets/_lang._project._version.docs.framework._framework._-C_Grro8r.js +1 -0
  78. package/template/dist/client/assets/{_lang._project._version.docs.framework._framework.index-DInYPTXM.js → _lang._project._version.docs.framework._framework.index-DsYjXRdj.js} +1 -1
  79. package/template/dist/client/assets/{_lang._project._version.docs.framework.index-B7EvJmBI.js → _lang._project._version.docs.framework.index-DQX1lBi3.js} +1 -1
  80. package/template/dist/client/assets/{_lang._project.docs-4oX3ADgu.js → _lang._project.docs-DsYQj9jI.js} +1 -1
  81. package/template/dist/client/assets/_lang._project.docs._-DlM_D6DD.js +1 -0
  82. package/template/dist/client/assets/{_lang._project.docs._-emq0IsQw.js → _lang._project.docs._-l2tTjx80.js} +1 -1
  83. package/template/dist/client/assets/_lang.blog-CEwEtalL.js +1 -0
  84. package/template/dist/client/assets/_lang.blog-D6YGC3tK.js +1 -0
  85. package/template/dist/client/assets/_lang.blog._-DgHu4oLy.js +1 -0
  86. package/template/dist/client/assets/{_lang.blog._-DErizs7q.js → _lang.blog._-Umz18sQE.js} +1 -1
  87. package/template/dist/client/assets/_lang.blog.index-C8LKUFtD.js +1 -0
  88. package/template/dist/client/assets/{_lang.blog.index-DZDuDkQr.js → _lang.blog.index-DzUqpOBE.js} +1 -1
  89. package/template/dist/client/assets/{_lang.docs-CQK0rfqt.js → _lang.docs-CUh3R7DD.js} +1 -1
  90. package/template/dist/client/assets/{_lang.docs._-BiCvgeV1.js → _lang.docs._-DlgTPy3s.js} +1 -1
  91. package/template/dist/client/assets/_lang.docs._-DmaQE7lx.js +1 -0
  92. package/template/dist/client/assets/_lang.docs.framework._framework._-B4C4uDFp.js +1 -0
  93. package/template/dist/client/assets/{_lang.docs.framework._framework.index-Bu5p5Q_r.js → _lang.docs.framework._framework.index-DTg6Xd3p.js} +1 -1
  94. package/template/dist/client/assets/{_lang.docs.framework.index-uTDFLagP.js → _lang.docs.framework.index-BQ2enasl.js} +1 -1
  95. package/template/dist/client/assets/{arc-C16C7aa3.js → arc-DGPgC_QF.js} +1 -1
  96. package/template/dist/client/assets/{architectureDiagram-2XIMDMQ5-DgSSDH9Z.js → architectureDiagram-2XIMDMQ5-yI53_GAi.js} +1 -1
  97. package/template/dist/client/assets/{blockDiagram-WCTKOSBZ-Bs8e58Or.js → blockDiagram-WCTKOSBZ-C3tr24zy.js} +1 -1
  98. package/template/dist/client/assets/{c4Diagram-IC4MRINW-DsGaAPtm.js → c4Diagram-IC4MRINW-DOA-mowm.js} +1 -1
  99. package/template/dist/client/assets/channel-DzZD7dUQ.js +1 -0
  100. package/template/dist/client/assets/{chunk-4BX2VUAB-BQdq93Vq.js → chunk-4BX2VUAB-B6NSnNJJ.js} +1 -1
  101. package/template/dist/client/assets/{chunk-55IACEB6-zjp4uUiZ.js → chunk-55IACEB6-CWYwArBH.js} +1 -1
  102. package/template/dist/client/assets/{chunk-FMBD7UC4-CEdYlBOF.js → chunk-FMBD7UC4-DSyn2wIW.js} +1 -1
  103. package/template/dist/client/assets/{chunk-JSJVCQXG-CVkDw9ls.js → chunk-JSJVCQXG-D83nm5W0.js} +1 -1
  104. package/template/dist/client/assets/{chunk-KX2RTZJC--1vKv-mr.js → chunk-KX2RTZJC-DD7fN9e9.js} +1 -1
  105. package/template/dist/client/assets/{chunk-NQ4KR5QH-Cpo-W18l.js → chunk-NQ4KR5QH-C3YlYiU5.js} +1 -1
  106. package/template/dist/client/assets/{chunk-QZHKN3VN-BizWJuB4.js → chunk-QZHKN3VN-B7wBEuCG.js} +1 -1
  107. package/template/dist/client/assets/{chunk-WL4C6EOR-6lLYa9R1.js → chunk-WL4C6EOR-ByA1FloT.js} +1 -1
  108. package/template/dist/client/assets/classDiagram-VBA2DB6C-CRozKaUD.js +1 -0
  109. package/template/dist/client/assets/classDiagram-v2-RAHNMMFH-CRozKaUD.js +1 -0
  110. package/template/dist/client/assets/clone-CGnOEl4E.js +1 -0
  111. package/template/dist/client/assets/{cose-bilkent-S5V4N54A-CaD0EGPJ.js → cose-bilkent-S5V4N54A-nt_sXfWc.js} +1 -1
  112. package/template/dist/client/assets/{dagre-KLK3FWXG-h4F9WtDQ.js → dagre-KLK3FWXG-DUsyMTPd.js} +1 -1
  113. package/template/dist/client/assets/{diagram-E7M64L7V-CBUSWzH5.js → diagram-E7M64L7V-D5SAypX0.js} +1 -1
  114. package/template/dist/client/assets/{diagram-IFDJBPK2-C5oMubv0.js → diagram-IFDJBPK2-WhP5c8Vz.js} +1 -1
  115. package/template/dist/client/assets/{diagram-P4PSJMXO-DdPwwhHR.js → diagram-P4PSJMXO-AMrwIlhf.js} +1 -1
  116. package/template/dist/client/assets/{erDiagram-INFDFZHY-0U5A-RF0.js → erDiagram-INFDFZHY-BxifSpCV.js} +1 -1
  117. package/template/dist/client/assets/{flowDiagram-PKNHOUZH-CXN3pvSW.js → flowDiagram-PKNHOUZH-BMAowE9I.js} +1 -1
  118. package/template/dist/client/assets/{ganttDiagram-A5KZAMGK-DlovlSO7.js → ganttDiagram-A5KZAMGK-Bay-0iRq.js} +1 -1
  119. package/template/dist/client/assets/{gitGraphDiagram-K3NZZRJ6-Bo-Jjy7v.js → gitGraphDiagram-K3NZZRJ6-Va91W3gw.js} +1 -1
  120. package/template/dist/client/assets/{graph-C0TauvuO.js → graph-CbBYObK_.js} +1 -1
  121. package/template/dist/client/assets/{index-iATq4LEm.js → index-CF6qz2tX.js} +1 -1
  122. package/template/dist/client/assets/{infoDiagram-LFFYTUFH-BbvPzztn.js → infoDiagram-LFFYTUFH-Byd5C-4U.js} +1 -1
  123. package/template/dist/client/assets/{ishikawaDiagram-PHBUUO56-DKCMONMO.js → ishikawaDiagram-PHBUUO56-DxOKnE1v.js} +1 -1
  124. package/template/dist/client/assets/{journeyDiagram-4ABVD52K-D9NP_vvu.js → journeyDiagram-4ABVD52K-IRmt7RI4.js} +1 -1
  125. package/template/dist/client/assets/{kanban-definition-K7BYSVSG-X-u_nWxK.js → kanban-definition-K7BYSVSG-BjTVXn-R.js} +1 -1
  126. package/template/dist/client/assets/{layout-IeRzBrUX.js → layout-Bbx6A0bC.js} +1 -1
  127. package/template/dist/client/assets/{linear-DEzVUeiK.js → linear-Df2eAW4A.js} +1 -1
  128. package/template/dist/client/assets/{main-Csj9i19C.js → main-DqZtiCro.js} +2 -2
  129. package/template/dist/client/assets/{mermaid.core-CCnh2DG0.js → mermaid.core-BIoiBcAA.js} +4 -4
  130. package/template/dist/client/assets/{mindmap-definition-YRQLILUH-DgyN4Ft-.js → mindmap-definition-YRQLILUH-Btzz0iIP.js} +1 -1
  131. package/template/dist/client/assets/ordinal-Cboi1Yqb.js +1 -0
  132. package/template/dist/client/assets/{pieDiagram-SKSYHLDU-DDVqU_2Q.js → pieDiagram-SKSYHLDU-C2amrGtU.js} +1 -1
  133. package/template/dist/client/assets/{quadrantDiagram-337W2JSQ-BeUxMqle.js → quadrantDiagram-337W2JSQ-EVgH9VuN.js} +1 -1
  134. package/template/dist/client/assets/{react-os8EX6z1.js → react-qvbbiZob.js} +1 -1
  135. package/template/dist/client/assets/{requirementDiagram-Z7DCOOCP-CpzdlyEd.js → requirementDiagram-Z7DCOOCP-BkYPbRis.js} +1 -1
  136. package/template/dist/client/assets/{sankeyDiagram-WA2Y5GQK-CmSWF6XU.js → sankeyDiagram-WA2Y5GQK-B5EIaP-h.js} +1 -1
  137. package/template/dist/client/assets/{sequenceDiagram-2WXFIKYE-DarofLka.js → sequenceDiagram-2WXFIKYE-BC33VGOc.js} +1 -1
  138. package/template/dist/client/assets/{stateDiagram-RAJIS63D-CEio2h-7.js → stateDiagram-RAJIS63D-DiKvWUYb.js} +1 -1
  139. package/template/dist/client/assets/stateDiagram-v2-FVOUBMTO-DjKMPYGe.js +1 -0
  140. package/template/dist/client/assets/{timeline-definition-YZTLITO2-By_Wk6uc.js → timeline-definition-YZTLITO2-QiFlgbRA.js} +1 -1
  141. package/template/dist/client/assets/{treemap-KZPCXAKY-mKcaMbv9.js → treemap-KZPCXAKY-BOYbyS9G.js} +1 -1
  142. package/template/dist/client/assets/{vennDiagram-LZ73GAT5-Dx_Fh7nH.js → vennDiagram-LZ73GAT5-CqmW7j4r.js} +1 -1
  143. package/template/dist/client/assets/{xychartDiagram-JWTSCODW-DSAwWbBw.js → xychartDiagram-JWTSCODW-gj6oWX8l.js} +1 -1
  144. package/template/dist/server/assets/{Doc-B8TJBEmx.js → Doc-9tJiX5y6.js} +3 -3
  145. package/template/dist/server/assets/{DocsLayout-CnWgvk8u.js → DocsLayout-BTjhU_W5.js} +2 -2
  146. package/template/dist/server/assets/{Footer-WapWK45U.js → Footer-CefTi2yh.js} +1 -1
  147. package/template/dist/server/assets/{FrameworkContent-gzqT-Q1n.js → FrameworkContent-BkJvuP04.js} +2 -2
  148. package/template/dist/server/assets/{MarkdownHeadingContext-Iyk66Y4x.js → MarkdownHeadingContext-37oQpb36.js} +3 -3
  149. package/template/dist/server/assets/{PostNotFound-GKdNuzsX.js → PostNotFound-BqBZf83v.js} +1 -1
  150. package/template/dist/server/assets/{_basePickBy-DJ9gzwF8.js → _basePickBy-DZ3TPUta.js} +2 -2
  151. package/template/dist/server/assets/{_baseUniq-CezmbvU2.js → _baseUniq-DKicWTQT.js} +1 -1
  152. package/template/dist/server/assets/{_lang._project._version.docs-BOZ34yW7.js → _lang._project._version.docs-U-t4mk5_.js} +3 -3
  153. package/template/dist/server/assets/{_lang._project._version.docs._-5W2jN7Re.js → _lang._project._version.docs._-DMgnElWM.js} +5 -5
  154. package/template/dist/server/assets/{_lang._project._version.docs.framework._framework._-DeN_oA8l.js → _lang._project._version.docs.framework._framework._-kBw_9L-F.js} +5 -5
  155. package/template/dist/server/assets/{_lang._project._version.docs.framework._framework.index-jWKDCQSE.js → _lang._project._version.docs.framework._framework.index-Bsyj0DD5.js} +1 -1
  156. package/template/dist/server/assets/{_lang._project._version.docs.framework.index-DOT4MtjZ.js → _lang._project._version.docs.framework.index-CmLAP_Io.js} +1 -1
  157. package/template/dist/server/assets/{_lang._project.docs-r4V9TXuu.js → _lang._project.docs-Bb4ZZ_jr.js} +3 -3
  158. package/template/dist/server/assets/{_lang._project.docs._-Bge7JaYE.js → _lang._project.docs._-ChrpJ61j.js} +5 -5
  159. package/template/dist/server/assets/{_lang.blog-DJOfiyA8.js → _lang.blog-8j6IvzvQ.js} +2 -2
  160. package/template/dist/server/assets/{_lang.blog._-yJSqbX08.js → _lang.blog._-BPzP97Ac.js} +2 -2
  161. package/template/dist/server/assets/{_lang.blog._-C7iqMj9O.js → _lang.blog._-DNX8UglA.js} +2 -2
  162. package/template/dist/server/assets/{_lang.blog.index-Df_6_IKx.js → _lang.blog.index-CeZnMJBi.js} +1 -1
  163. package/template/dist/server/assets/{_lang.blog.index-CrdyROhK.js → _lang.blog.index-DzVKqoC4.js} +2 -2
  164. package/template/dist/server/assets/{_lang.docs-Jwt4deTW.js → _lang.docs-B4StnHMb.js} +3 -3
  165. package/template/dist/server/assets/{_lang.docs._-D_DdKLAV.js → _lang.docs._--c0In1AT.js} +5 -5
  166. package/template/dist/server/assets/{_lang.docs.framework._framework._-BkQaZ_1f.js → _lang.docs.framework._framework._-Be0U7cDg.js} +5 -5
  167. package/template/dist/server/assets/{_lang.docs.framework._framework.index-BLx8p8IS.js → _lang.docs.framework._framework.index-BZ512aSk.js} +1 -1
  168. package/template/dist/server/assets/{_lang.docs.framework.index-BytQ_q8T.js → _lang.docs.framework.index-U8z3j4kz.js} +1 -1
  169. package/template/dist/server/assets/{_tanstack-start-manifest_v-RX6ItZ5S.js → _tanstack-start-manifest_v-DXpQ8503.js} +1 -1
  170. package/template/dist/server/assets/{arc-BwftnT5H.js → arc-B4h6h_n6.js} +1 -1
  171. package/template/dist/server/assets/{architecture-PBZL5I3N-KbDVC6gM.js → architecture-PBZL5I3N-CUwqLXkR.js} +6 -6
  172. package/template/dist/server/assets/{architectureDiagram-2XIMDMQ5-BoLvWxb3.js → architectureDiagram-2XIMDMQ5-CuCoxdBe.js} +6 -6
  173. package/template/dist/server/assets/{blockDiagram-WCTKOSBZ-GPFcXs-f.js → blockDiagram-WCTKOSBZ-D5PsUOim.js} +6 -6
  174. package/template/dist/server/assets/{c4Diagram-IC4MRINW-EQwQCspo.js → c4Diagram-IC4MRINW-CXy5xO3o.js} +2 -2
  175. package/template/dist/server/assets/{channel-CxvwuPH7.js → channel-D0l-mWaF.js} +1 -1
  176. package/template/dist/server/assets/{chunk-4BX2VUAB-DUgcw5ei.js → chunk-4BX2VUAB-M7FVHMss.js} +1 -1
  177. package/template/dist/server/assets/{chunk-55IACEB6-Cn15uD91.js → chunk-55IACEB6-D_gDAje5.js} +1 -1
  178. package/template/dist/server/assets/{chunk-FMBD7UC4-Ck3iyLPu.js → chunk-FMBD7UC4-B5Bebx-Y.js} +1 -1
  179. package/template/dist/server/assets/{chunk-JSJVCQXG-VAT8yncE.js → chunk-JSJVCQXG-DxBkq-uB.js} +1 -1
  180. package/template/dist/server/assets/{chunk-KX2RTZJC-B1bd2VmA.js → chunk-KX2RTZJC-BMHm1EGi.js} +1 -1
  181. package/template/dist/server/assets/{chunk-NQ4KR5QH-CR67GG9C.js → chunk-NQ4KR5QH-Cp28pTwT.js} +3 -3
  182. package/template/dist/server/assets/{chunk-QZHKN3VN-B9SSazM4.js → chunk-QZHKN3VN-Bq5GZqaR.js} +1 -1
  183. package/template/dist/server/assets/{chunk-WL4C6EOR-DZ4Pjuao.js → chunk-WL4C6EOR-C9Nj5GdW.js} +5 -5
  184. package/template/dist/server/assets/{classDiagram-VBA2DB6C-CA6_4Wb2.js → classDiagram-VBA2DB6C-CUchv9T5.js} +6 -6
  185. package/template/dist/server/assets/{classDiagram-v2-RAHNMMFH-CA6_4Wb2.js → classDiagram-v2-RAHNMMFH-CUchv9T5.js} +6 -6
  186. package/template/dist/server/assets/{clone-DJHP_iVy.js → clone-CJcTi58S.js} +1 -1
  187. package/template/dist/server/assets/{cose-bilkent-S5V4N54A-DtU-cN6W.js → cose-bilkent-S5V4N54A-CxvCMhN_.js} +1 -1
  188. package/template/dist/server/assets/{dagre-KLK3FWXG-yZYrVU4p.js → dagre-KLK3FWXG-B5bQP7FL.js} +6 -6
  189. package/template/dist/server/assets/{diagram-E7M64L7V-8Yyz0aw0.js → diagram-E7M64L7V-NjHca90S.js} +8 -8
  190. package/template/dist/server/assets/{diagram-IFDJBPK2-DcxFYI3M.js → diagram-IFDJBPK2-CoTCfBKd.js} +6 -6
  191. package/template/dist/server/assets/{diagram-P4PSJMXO-CehxUcI0.js → diagram-P4PSJMXO-DHvGgYjH.js} +6 -6
  192. package/template/dist/server/assets/{erDiagram-INFDFZHY-Bu2p1_Pj.js → erDiagram-INFDFZHY-01crajKr.js} +4 -4
  193. package/template/dist/server/assets/{flowDiagram-PKNHOUZH-B_eKR7I0.js → flowDiagram-PKNHOUZH-BkUQ_vxg.js} +6 -6
  194. package/template/dist/server/assets/{ganttDiagram-A5KZAMGK-DP6YEZof.js → ganttDiagram-A5KZAMGK-DvrO-w2P.js} +2 -2
  195. package/template/dist/server/assets/{gitGraph-HDMCJU4V-Bt0qhVL4.js → gitGraph-HDMCJU4V-h9JNaxB7.js} +6 -6
  196. package/template/dist/server/assets/{gitGraphDiagram-K3NZZRJ6-DwvkdYrg.js → gitGraphDiagram-K3NZZRJ6-BoKm6Fm-.js} +7 -7
  197. package/template/dist/server/assets/{graph-BVFNe_k5.js → graph-BoxbfI7Z.js} +2 -2
  198. package/template/dist/server/assets/{index-DvBGSZeA.js → index-Jfzi6SZW.js} +2 -2
  199. package/template/dist/server/assets/{info-3K5VOQVL-CFejRnvB.js → info-3K5VOQVL-DgaSHqkS.js} +6 -6
  200. package/template/dist/server/assets/{infoDiagram-LFFYTUFH-D0v9uyXI.js → infoDiagram-LFFYTUFH-DgV5W8-I.js} +5 -5
  201. package/template/dist/server/assets/{ishikawaDiagram-PHBUUO56-DZumspL4.js → ishikawaDiagram-PHBUUO56-CqlMQ0Fq.js} +1 -1
  202. package/template/dist/server/assets/{journeyDiagram-4ABVD52K-nRp_-qZp.js → journeyDiagram-4ABVD52K-D6ySTub8.js} +4 -4
  203. package/template/dist/server/assets/{kanban-definition-K7BYSVSG-BMKyyzjt.js → kanban-definition-K7BYSVSG-BT8m7Cwk.js} +2 -2
  204. package/template/dist/server/assets/{layout-mpiN5R-5.js → layout-CkYcErfn.js} +4 -4
  205. package/template/dist/server/assets/{linear-CqNYgjEx.js → linear-F_0dWGZL.js} +1 -1
  206. package/template/dist/server/assets/{mermaid-parser.core-B8Uu3QZY.js → mermaid-parser.core-q5MdUJuo.js} +11 -11
  207. package/template/dist/server/assets/{mermaid.core-BI3nMhNO.js → mermaid.core-DOWTODR1.js} +31 -31
  208. package/template/dist/server/assets/{mindmap-definition-YRQLILUH-DCoFqLPh.js → mindmap-definition-YRQLILUH-BQxlQqn-.js} +3 -3
  209. package/template/dist/server/assets/{ordinal-Bcam90FY.js → ordinal-CxptdPJm.js} +1 -1
  210. package/template/dist/server/assets/{packet-RMMSAZCW-djgonfKN.js → packet-RMMSAZCW-D8FkLZuP.js} +6 -6
  211. package/template/dist/server/assets/{pie-UPGHQEXC-Dug2t-PE.js → pie-UPGHQEXC-Diw2fHLk.js} +6 -6
  212. package/template/dist/server/assets/{pieDiagram-SKSYHLDU-CS0_hW4w.js → pieDiagram-SKSYHLDU-B1J4UJZ7.js} +8 -8
  213. package/template/dist/server/assets/{quadrantDiagram-337W2JSQ-BpQNM0zu.js → quadrantDiagram-337W2JSQ-BvjKLapg.js} +2 -2
  214. package/template/dist/server/assets/{radar-KQ55EAFF-3ir2W9Wi.js → radar-KQ55EAFF-CcBdPU3n.js} +6 -6
  215. package/template/dist/server/assets/{requirementDiagram-Z7DCOOCP-D92RyjV4.js → requirementDiagram-Z7DCOOCP-Bgr_wnAs.js} +3 -3
  216. package/template/dist/server/assets/{router-DPPgDicW.js → router-DxwPl-Dc.js} +18 -18
  217. package/template/dist/server/assets/{sankeyDiagram-WA2Y5GQK-DCPRB-xO.js → sankeyDiagram-WA2Y5GQK-B0UwtyW3.js} +2 -2
  218. package/template/dist/server/assets/{sequenceDiagram-2WXFIKYE-C1ab2VvU.js → sequenceDiagram-2WXFIKYE-BbxQJHjO.js} +3 -3
  219. package/template/dist/server/assets/{stateDiagram-RAJIS63D-GhG1G3ff.js → stateDiagram-RAJIS63D-Cg-uJ_UO.js} +8 -8
  220. package/template/dist/server/assets/{stateDiagram-v2-FVOUBMTO-C-KtMadV.js → stateDiagram-v2-FVOUBMTO-BWVPrqfa.js} +4 -4
  221. package/template/dist/server/assets/{timeline-definition-YZTLITO2-DyfAQCd4.js → timeline-definition-YZTLITO2-DCSJT2WT.js} +2 -2
  222. package/template/dist/server/assets/{treemap-KZPCXAKY-Cn0Cw4Cl.js → treemap-KZPCXAKY-a0nhlKgx.js} +6 -6
  223. package/template/dist/server/assets/{vennDiagram-LZ73GAT5-D2Ak5JUa.js → vennDiagram-LZ73GAT5-Bk2HQEQq.js} +1 -1
  224. package/template/dist/server/assets/{xychartDiagram-JWTSCODW-DqoBOs1L.js → xychartDiagram-JWTSCODW-C4svHkt_.js} +3 -3
  225. package/template/dist/server/server.js +5 -5
  226. package/admin/dist/client/assets/main-CSFhgz4p.js +0 -17
  227. package/admin/dist/client/assets/routes-C6bCOSX-.js +0 -3
  228. package/admin/dist/server/assets/_tanstack-start-manifest_v-BE5XHVZ2.js +0 -17
  229. package/admin/dist/server/assets/redirect-DtfSYi2g.js +0 -51
  230. package/admin/dist/server/assets/status-CZz8Rs_7.js +0 -81
  231. package/template/dist/client/assets/_lang-B3tRf7os.js +0 -1
  232. package/template/dist/client/assets/_lang._project-CH0inpmY.js +0 -1
  233. package/template/dist/client/assets/_lang._project._version-CESvrqds.js +0 -1
  234. package/template/dist/client/assets/_lang._project._version.docs._-BexMyJr9.js +0 -1
  235. package/template/dist/client/assets/_lang._project._version.docs.framework._framework._-BbQgUWTH.js +0 -1
  236. package/template/dist/client/assets/_lang._project.docs._-R9bOn492.js +0 -1
  237. package/template/dist/client/assets/_lang.blog-BViCs72M.js +0 -1
  238. package/template/dist/client/assets/_lang.blog-DhVkwYEk.js +0 -1
  239. package/template/dist/client/assets/_lang.blog._-BHdaHDBU.js +0 -1
  240. package/template/dist/client/assets/_lang.blog.index-CELEUrkj.js +0 -1
  241. package/template/dist/client/assets/_lang.docs._-axvS_dfl.js +0 -1
  242. package/template/dist/client/assets/_lang.docs.framework._framework._-D2FAQ0gW.js +0 -1
  243. package/template/dist/client/assets/channel-Clrp6Lr4.js +0 -1
  244. package/template/dist/client/assets/classDiagram-VBA2DB6C-Beq6_jEy.js +0 -1
  245. package/template/dist/client/assets/classDiagram-v2-RAHNMMFH-Beq6_jEy.js +0 -1
  246. package/template/dist/client/assets/clone-BbBu6MzK.js +0 -1
  247. package/template/dist/client/assets/ordinal-BENe2yWM.js +0 -1
  248. package/template/dist/client/assets/stateDiagram-v2-FVOUBMTO-CbfK0_BD.js +0 -1
  249. /package/admin/dist/server/assets/{createServerRpc-DJq9yo-B.js → createServerRpc-Cyyxq9HQ.js} +0 -0
@@ -0,0 +1,21 @@
1
+ import { createAuthClient } from 'better-auth/react';
2
+ import { usernameClient } from 'better-auth/client/plugins';
3
+ import { anonymousClient } from 'better-auth/client/plugins';
4
+ import { adminClient } from 'better-auth/client/plugins';
5
+
6
+ export const authClient = createAuthClient({
7
+ baseURL: typeof window !== 'undefined' ? window.location.origin : 'http://localhost:3456',
8
+ basePath: '/api/auth',
9
+ plugins: [
10
+ usernameClient(),
11
+ anonymousClient(),
12
+ adminClient(),
13
+ ],
14
+ });
15
+
16
+ export const {
17
+ useSession,
18
+ signIn,
19
+ signUp,
20
+ signOut,
21
+ } = authClient;
@@ -0,0 +1,62 @@
1
+ import { betterAuth } from 'better-auth';
2
+ import { username } from 'better-auth/plugins';
3
+ import { anonymous } from 'better-auth/plugins';
4
+ import { admin } from 'better-auth/plugins';
5
+ import Database from 'better-sqlite3';
6
+ import { resolve } from 'node:path';
7
+ import { mkdirSync } from 'node:fs';
8
+
9
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
+ let _auth: any = null;
11
+
12
+ function getDbPath(): string {
13
+ const projectRoot = process.env.DOCS_I18N_PROJECT_ROOT || process.cwd();
14
+ const cacheDir = resolve(projectRoot, '.cache');
15
+ mkdirSync(cacheDir, { recursive: true });
16
+ return resolve(cacheDir, 'auth.db');
17
+ }
18
+
19
+ /**
20
+ * Get or create the better-auth instance (singleton).
21
+ * Uses better-sqlite3 stored at <projectRoot>/.cache/auth.db.
22
+ */
23
+ export function getAuth() {
24
+ if (_auth) return _auth;
25
+
26
+ const dbPath = getDbPath();
27
+ const db = new Database(dbPath);
28
+
29
+ _auth = betterAuth({
30
+ database: db,
31
+ secret: process.env.BETTER_AUTH_SECRET || 'docs-i18n-admin-dev-secret-change-in-production',
32
+ baseURL: process.env.BETTER_AUTH_URL || 'http://localhost:3456',
33
+ basePath: '/api/auth',
34
+ emailAndPassword: {
35
+ enabled: true,
36
+ },
37
+ plugins: [
38
+ username(),
39
+ anonymous(),
40
+ admin({
41
+ defaultRole: 'user',
42
+ }),
43
+ ],
44
+ session: {
45
+ cookieCache: {
46
+ enabled: true,
47
+ maxAge: 5 * 60, // 5 min
48
+ },
49
+ },
50
+ user: {
51
+ additionalFields: {
52
+ displayName: {
53
+ type: 'string',
54
+ required: false,
55
+ defaultValue: '',
56
+ },
57
+ },
58
+ },
59
+ });
60
+
61
+ return _auth;
62
+ }
@@ -9,8 +9,14 @@
9
9
  // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
10
10
 
11
11
  import { Route as rootRouteImport } from './routes/__root'
12
+ import { Route as LoginRouteImport } from './routes/login'
12
13
  import { Route as IndexRouteImport } from './routes/index'
13
14
 
15
+ const LoginRoute = LoginRouteImport.update({
16
+ id: '/login',
17
+ path: '/login',
18
+ getParentRoute: () => rootRouteImport,
19
+ } as any)
14
20
  const IndexRoute = IndexRouteImport.update({
15
21
  id: '/',
16
22
  path: '/',
@@ -19,28 +25,39 @@ const IndexRoute = IndexRouteImport.update({
19
25
 
20
26
  export interface FileRoutesByFullPath {
21
27
  '/': typeof IndexRoute
28
+ '/login': typeof LoginRoute
22
29
  }
23
30
  export interface FileRoutesByTo {
24
31
  '/': typeof IndexRoute
32
+ '/login': typeof LoginRoute
25
33
  }
26
34
  export interface FileRoutesById {
27
35
  __root__: typeof rootRouteImport
28
36
  '/': typeof IndexRoute
37
+ '/login': typeof LoginRoute
29
38
  }
30
39
  export interface FileRouteTypes {
31
40
  fileRoutesByFullPath: FileRoutesByFullPath
32
- fullPaths: '/'
41
+ fullPaths: '/' | '/login'
33
42
  fileRoutesByTo: FileRoutesByTo
34
- to: '/'
35
- id: '__root__' | '/'
43
+ to: '/' | '/login'
44
+ id: '__root__' | '/' | '/login'
36
45
  fileRoutesById: FileRoutesById
37
46
  }
38
47
  export interface RootRouteChildren {
39
48
  IndexRoute: typeof IndexRoute
49
+ LoginRoute: typeof LoginRoute
40
50
  }
41
51
 
42
52
  declare module '@tanstack/react-router' {
43
53
  interface FileRoutesByPath {
54
+ '/login': {
55
+ id: '/login'
56
+ path: '/login'
57
+ fullPath: '/login'
58
+ preLoaderRoute: typeof LoginRouteImport
59
+ parentRoute: typeof rootRouteImport
60
+ }
44
61
  '/': {
45
62
  id: '/'
46
63
  path: '/'
@@ -53,6 +70,7 @@ declare module '@tanstack/react-router' {
53
70
 
54
71
  const rootRouteChildren: RootRouteChildren = {
55
72
  IndexRoute: IndexRoute,
73
+ LoginRoute: LoginRoute,
56
74
  }
57
75
  export const routeTree = rootRouteImport
58
76
  ._addFileChildren(rootRouteChildren)
@@ -1,4 +1,4 @@
1
- import { createFileRoute, useNavigate } from '@tanstack/react-router';
1
+ import { createFileRoute, useNavigate, redirect } from '@tanstack/react-router';
2
2
  import { useQuery } from '@tanstack/react-query';
3
3
  import { useCallback, useEffect, useMemo, useState } from 'react';
4
4
  import { FileList } from '../components/FileList';
@@ -7,6 +7,8 @@ import { JobPanel } from '../components/JobPanel';
7
7
  import { LangGrid } from '../components/LangGrid';
8
8
  import { Preview } from '../components/Preview';
9
9
  import { api } from '../lib/api';
10
+ import { authClient } from '../lib/auth-client';
11
+ import { getSession } from '../../server/functions/auth';
10
12
 
11
13
  type ViewMode = 'split' | 'en' | 'lang';
12
14
  type StatusFilter = 'all' | 'complete' | 'partial' | 'missing';
@@ -51,6 +53,25 @@ function parseProjectVersions(versionKeys: string[]) {
51
53
  };
52
54
  }
53
55
 
56
+ /**
57
+ * Determine user role from session data.
58
+ * Anonymous users are "guest", others check the role field.
59
+ */
60
+ function getUserRole(session: { user: Record<string, unknown> } | null): 'admin' | 'user' | 'guest' {
61
+ if (!session?.user) return 'guest';
62
+ if ((session.user as Record<string, unknown>).isAnonymous) return 'guest';
63
+ const role = (session.user as Record<string, unknown>).role;
64
+ if (role === 'admin') return 'admin';
65
+ return 'user';
66
+ }
67
+
68
+ function getUserDisplayName(session: { user: Record<string, unknown> } | null): string {
69
+ if (!session?.user) return 'Guest';
70
+ const user = session.user as Record<string, unknown>;
71
+ if (user.isAnonymous) return 'Guest';
72
+ return (user.displayName as string) || (user.name as string) || (user.username as string) || (user.email as string) || 'User';
73
+ }
74
+
54
75
  export const Route = createFileRoute('/')({
55
76
  validateSearch: (search: Record<string, unknown>): AdminSearch => ({
56
77
  project: (search.project as string) || undefined,
@@ -64,13 +85,25 @@ export const Route = createFileRoute('/')({
64
85
  status: (search.status as StatusFilter) || undefined,
65
86
  section: (search.section as SectionFilter) || undefined,
66
87
  }),
88
+ beforeLoad: async () => {
89
+ const session = await getSession();
90
+ if (!session) {
91
+ throw redirect({ to: '/login' });
92
+ }
93
+ return { session };
94
+ },
67
95
  component: AdminPage,
68
96
  });
69
97
 
70
98
  function AdminPage() {
71
99
  const search = Route.useSearch();
100
+ const { session } = Route.useRouteContext();
72
101
  const navigate = useNavigate({ from: '/' });
73
102
 
103
+ const userRole = getUserRole(session);
104
+ const userName = getUserDisplayName(session);
105
+ const isAdmin = userRole === 'admin';
106
+
74
107
  const lang = search.lang || null;
75
108
  const file = search.file || null;
76
109
  const showFiles = search.files !== '0';
@@ -261,14 +294,27 @@ function AdminPage() {
261
294
  const handleClear = useCallback(() => setSelected(new Set()), []);
262
295
 
263
296
  const handleTranslateSelected = useCallback(() => {
297
+ if (!isAdmin) {
298
+ setToast('Only admin users can start translation jobs');
299
+ return;
300
+ }
264
301
  setDialogFiles([...selected]);
265
302
  setShowDialog(true);
266
- }, [selected]);
303
+ }, [selected, isAdmin]);
267
304
 
268
305
  const handleNewJob = useCallback(() => {
306
+ if (!isAdmin) {
307
+ setToast('Only admin users can start translation jobs');
308
+ return;
309
+ }
269
310
  setDialogFiles(undefined);
270
311
  setShowDialog(true);
271
- }, []);
312
+ }, [isAdmin]);
313
+
314
+ const handleSignOut = useCallback(async () => {
315
+ await authClient.signOut();
316
+ navigate({ to: '/login' });
317
+ }, [navigate]);
272
318
 
273
319
  if (!statusData) return <div className="loading">Loading...</div>;
274
320
 
@@ -276,14 +322,28 @@ function AdminPage() {
276
322
  <>
277
323
  <nav>
278
324
  <h1>
279
- {'🌐 Translation Admin '}
325
+ {'Translation Admin '}
280
326
  {versionInfo?.version && (
281
327
  <span className="version-badge">v{versionInfo.version}</span>
282
328
  )}
283
329
  </h1>
284
330
  <span className="spacer" />
285
- <button type="button" className="btn" onClick={handleNewJob}>
286
- + New Job
331
+ {isAdmin && (
332
+ <button type="button" className="btn" onClick={handleNewJob}>
333
+ + New Job
334
+ </button>
335
+ )}
336
+ <div className="user-info">
337
+ <span>{userName}</span>
338
+ <span className={`user-role ${userRole}`}>{userRole}</span>
339
+ </div>
340
+ <button
341
+ type="button"
342
+ className="btn-signout"
343
+ onClick={handleSignOut}
344
+ title="Sign out"
345
+ >
346
+ Sign Out
287
347
  </button>
288
348
  <button
289
349
  type="button"
@@ -396,8 +456,8 @@ function AdminPage() {
396
456
  {/* Toast */}
397
457
  {toast && <div className="toast">{toast}</div>}
398
458
 
399
- {/* Job dialog */}
400
- {showDialog && (
459
+ {/* Job dialog — only for admin */}
460
+ {showDialog && isAdmin && (
401
461
  <JobDialog
402
462
  langs={statusData.langs}
403
463
  versions={statusData.versions}
@@ -0,0 +1,207 @@
1
+ import { createFileRoute, useNavigate } from '@tanstack/react-router';
2
+ import { useState } from 'react';
3
+ import { authClient } from '../lib/auth-client';
4
+
5
+ export const Route = createFileRoute('/login')({
6
+ component: LoginPage,
7
+ });
8
+
9
+ function LoginPage() {
10
+ const navigate = useNavigate();
11
+ const [mode, setMode] = useState<'login' | 'register'>('login');
12
+ const [username, setUsername] = useState('');
13
+ const [password, setPassword] = useState('');
14
+ const [email, setEmail] = useState('');
15
+ const [name, setName] = useState('');
16
+ const [error, setError] = useState<string | null>(null);
17
+ const [loading, setLoading] = useState(false);
18
+
19
+ const handleLogin = async (e: React.FormEvent) => {
20
+ e.preventDefault();
21
+ setError(null);
22
+ setLoading(true);
23
+
24
+ try {
25
+ const { error: authError } = await authClient.signIn.username({
26
+ username,
27
+ password,
28
+ });
29
+
30
+ if (authError) {
31
+ setError(authError.message || 'Login failed');
32
+ setLoading(false);
33
+ return;
34
+ }
35
+
36
+ navigate({ to: '/' });
37
+ } catch (err: unknown) {
38
+ setError(err instanceof Error ? err.message : 'Login failed');
39
+ setLoading(false);
40
+ }
41
+ };
42
+
43
+ const handleRegister = async (e: React.FormEvent) => {
44
+ e.preventDefault();
45
+ setError(null);
46
+ setLoading(true);
47
+
48
+ try {
49
+ const { error: authError } = await authClient.signUp.email({
50
+ email,
51
+ password,
52
+ name: name || username,
53
+ username,
54
+ });
55
+
56
+ if (authError) {
57
+ setError(authError.message || 'Registration failed');
58
+ setLoading(false);
59
+ return;
60
+ }
61
+
62
+ navigate({ to: '/' });
63
+ } catch (err: unknown) {
64
+ setError(err instanceof Error ? err.message : 'Registration failed');
65
+ setLoading(false);
66
+ }
67
+ };
68
+
69
+ const handleAnonymousLogin = async () => {
70
+ setError(null);
71
+ setLoading(true);
72
+
73
+ try {
74
+ const { error: authError } = await authClient.signIn.anonymous();
75
+
76
+ if (authError) {
77
+ setError(authError.message || 'Anonymous login failed');
78
+ setLoading(false);
79
+ return;
80
+ }
81
+
82
+ navigate({ to: '/' });
83
+ } catch (err: unknown) {
84
+ setError(err instanceof Error ? err.message : 'Anonymous login failed');
85
+ setLoading(false);
86
+ }
87
+ };
88
+
89
+ return (
90
+ <div className="login-page">
91
+ <div className="login-card">
92
+ <h2>Translation Admin</h2>
93
+ <p className="login-subtitle">Sign in to manage translations</p>
94
+
95
+ {/* Mode toggle */}
96
+ <div className="login-mode-toggle">
97
+ <button
98
+ type="button"
99
+ className={mode === 'login' ? 'active' : ''}
100
+ onClick={() => { setMode('login'); setError(null); }}
101
+ >
102
+ Sign In
103
+ </button>
104
+ <button
105
+ type="button"
106
+ className={mode === 'register' ? 'active' : ''}
107
+ onClick={() => { setMode('register'); setError(null); }}
108
+ >
109
+ Register
110
+ </button>
111
+ </div>
112
+
113
+ {error && <div className="login-error">{error}</div>}
114
+
115
+ {mode === 'login' ? (
116
+ <form onSubmit={handleLogin}>
117
+ <label htmlFor="login-username">Username</label>
118
+ <input
119
+ id="login-username"
120
+ type="text"
121
+ value={username}
122
+ onChange={(e) => setUsername(e.target.value)}
123
+ placeholder="admin"
124
+ required
125
+ autoComplete="username"
126
+ />
127
+ <label htmlFor="login-password">Password</label>
128
+ <input
129
+ id="login-password"
130
+ type="password"
131
+ value={password}
132
+ onChange={(e) => setPassword(e.target.value)}
133
+ placeholder="password"
134
+ required
135
+ autoComplete="current-password"
136
+ />
137
+ <button type="submit" className="btn login-btn" disabled={loading}>
138
+ {loading ? 'Signing in...' : 'Sign In'}
139
+ </button>
140
+ </form>
141
+ ) : (
142
+ <form onSubmit={handleRegister}>
143
+ <label htmlFor="reg-username">Username</label>
144
+ <input
145
+ id="reg-username"
146
+ type="text"
147
+ value={username}
148
+ onChange={(e) => setUsername(e.target.value)}
149
+ placeholder="username"
150
+ required
151
+ autoComplete="username"
152
+ />
153
+ <label htmlFor="reg-name">Display Name</label>
154
+ <input
155
+ id="reg-name"
156
+ type="text"
157
+ value={name}
158
+ onChange={(e) => setName(e.target.value)}
159
+ placeholder="John Doe"
160
+ autoComplete="name"
161
+ />
162
+ <label htmlFor="reg-email">Email</label>
163
+ <input
164
+ id="reg-email"
165
+ type="email"
166
+ value={email}
167
+ onChange={(e) => setEmail(e.target.value)}
168
+ placeholder="user@example.com"
169
+ required
170
+ autoComplete="email"
171
+ />
172
+ <label htmlFor="reg-password">Password</label>
173
+ <input
174
+ id="reg-password"
175
+ type="password"
176
+ value={password}
177
+ onChange={(e) => setPassword(e.target.value)}
178
+ placeholder="password"
179
+ required
180
+ minLength={4}
181
+ autoComplete="new-password"
182
+ />
183
+ <button type="submit" className="btn login-btn" disabled={loading}>
184
+ {loading ? 'Creating account...' : 'Create Account'}
185
+ </button>
186
+ </form>
187
+ )}
188
+
189
+ <div className="login-divider">
190
+ <span>or</span>
191
+ </div>
192
+
193
+ <button
194
+ type="button"
195
+ className="btn btn-outline login-btn"
196
+ onClick={handleAnonymousLogin}
197
+ disabled={loading}
198
+ >
199
+ Continue as Guest
200
+ </button>
201
+ <p className="login-hint">
202
+ Guests can view translations but cannot make changes.
203
+ </p>
204
+ </div>
205
+ </div>
206
+ );
207
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Custom server entry that wraps TanStack Start's default handler
3
+ * to add better-auth API route handling at /api/auth/*.
4
+ */
5
+ import { createStartHandler, defaultStreamHandler } from '@tanstack/react-start/server';
6
+ import { getAuth } from './lib/auth.server';
7
+
8
+ const startHandler = createStartHandler(defaultStreamHandler);
9
+
10
+ export default {
11
+ async fetch(request: Request) {
12
+ const url = new URL(request.url);
13
+
14
+ // Intercept /api/auth/* requests and forward to better-auth
15
+ if (url.pathname.startsWith('/api/auth')) {
16
+ const auth = getAuth();
17
+ return auth.handler(request);
18
+ }
19
+
20
+ // Everything else goes to TanStack Start
21
+ return startHandler(request);
22
+ },
23
+ };
@@ -1140,3 +1140,149 @@ a.preview-filename:hover {
1140
1140
  .log-copy:hover {
1141
1141
  background: var(--hover);
1142
1142
  }
1143
+
1144
+ /* ── Login page ── */
1145
+ .login-page {
1146
+ display: flex;
1147
+ align-items: center;
1148
+ justify-content: center;
1149
+ min-height: 100vh;
1150
+ padding: 2rem;
1151
+ }
1152
+ .login-card {
1153
+ background: var(--card);
1154
+ border: 1px solid var(--border);
1155
+ border-radius: 0.75rem;
1156
+ padding: 2rem;
1157
+ width: 380px;
1158
+ max-width: 100%;
1159
+ }
1160
+ .login-card h2 {
1161
+ font-size: 1.3rem;
1162
+ margin-bottom: 0.25rem;
1163
+ text-align: center;
1164
+ }
1165
+ .login-subtitle {
1166
+ text-align: center;
1167
+ color: var(--fg2);
1168
+ font-size: 0.85rem;
1169
+ margin-bottom: 1.25rem;
1170
+ }
1171
+ .login-mode-toggle {
1172
+ display: flex;
1173
+ gap: 0;
1174
+ margin-bottom: 1rem;
1175
+ border: 1px solid var(--border);
1176
+ border-radius: 0.375rem;
1177
+ overflow: hidden;
1178
+ }
1179
+ .login-mode-toggle button {
1180
+ flex: 1;
1181
+ padding: 0.5rem;
1182
+ border: none;
1183
+ background: transparent;
1184
+ color: var(--fg2);
1185
+ cursor: pointer;
1186
+ font-size: 0.85rem;
1187
+ font-weight: 600;
1188
+ transition: background 0.15s, color 0.15s;
1189
+ }
1190
+ .login-mode-toggle button.active {
1191
+ background: var(--accent);
1192
+ color: var(--btn-fg);
1193
+ }
1194
+ .login-card label {
1195
+ display: block;
1196
+ font-size: 0.8rem;
1197
+ color: var(--fg2);
1198
+ margin: 0.75rem 0 0.25rem;
1199
+ }
1200
+ .login-card input {
1201
+ width: 100%;
1202
+ background: var(--bg);
1203
+ color: var(--fg);
1204
+ border: 1px solid var(--border);
1205
+ padding: 0.55rem 0.75rem;
1206
+ border-radius: 0.375rem;
1207
+ font-size: 0.85rem;
1208
+ outline: none;
1209
+ }
1210
+ .login-card input:focus {
1211
+ border-color: var(--accent);
1212
+ }
1213
+ .login-btn {
1214
+ width: 100%;
1215
+ margin-top: 1rem;
1216
+ padding: 0.6rem;
1217
+ font-size: 0.9rem;
1218
+ }
1219
+ .login-error {
1220
+ background: color-mix(in srgb, var(--red) 10%, transparent);
1221
+ color: var(--red);
1222
+ padding: 0.5rem 0.75rem;
1223
+ border-radius: 0.375rem;
1224
+ font-size: 0.8rem;
1225
+ margin-bottom: 0.75rem;
1226
+ }
1227
+ .login-divider {
1228
+ display: flex;
1229
+ align-items: center;
1230
+ gap: 0.75rem;
1231
+ margin: 1.25rem 0;
1232
+ color: var(--fg2);
1233
+ font-size: 0.8rem;
1234
+ }
1235
+ .login-divider::before,
1236
+ .login-divider::after {
1237
+ content: '';
1238
+ flex: 1;
1239
+ height: 1px;
1240
+ background: var(--border);
1241
+ }
1242
+ .login-hint {
1243
+ text-align: center;
1244
+ color: var(--fg2);
1245
+ font-size: 0.75rem;
1246
+ margin-top: 0.75rem;
1247
+ }
1248
+
1249
+ /* ── User info in nav ── */
1250
+ .user-info {
1251
+ display: flex;
1252
+ align-items: center;
1253
+ gap: 0.5rem;
1254
+ font-size: 0.8rem;
1255
+ color: var(--fg2);
1256
+ }
1257
+ .user-role {
1258
+ font-size: 0.65rem;
1259
+ padding: 0.1rem 0.4rem;
1260
+ border-radius: 0.25rem;
1261
+ font-weight: 600;
1262
+ text-transform: uppercase;
1263
+ }
1264
+ .user-role.admin {
1265
+ background: color-mix(in srgb, var(--accent) 20%, transparent);
1266
+ color: var(--accent);
1267
+ }
1268
+ .user-role.user {
1269
+ background: color-mix(in srgb, var(--green) 20%, transparent);
1270
+ color: var(--green);
1271
+ }
1272
+ .user-role.guest {
1273
+ background: color-mix(in srgb, var(--yellow) 20%, transparent);
1274
+ color: var(--yellow);
1275
+ }
1276
+ .btn-signout {
1277
+ background: transparent;
1278
+ border: 1px solid var(--border);
1279
+ color: var(--fg2);
1280
+ padding: 0.3rem 0.6rem;
1281
+ border-radius: 0.25rem;
1282
+ cursor: pointer;
1283
+ font-size: 0.75rem;
1284
+ }
1285
+ .btn-signout:hover {
1286
+ border-color: var(--red);
1287
+ color: var(--red);
1288
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Cloudflare Workers entry point for the admin dashboard.
3
+ * Re-exports TanStack Start's server entry as a CF Worker fetch handler.
4
+ * Injects D1 binding into globalThis for server-side queries.
5
+ */
6
+ import handler from '@tanstack/react-start/server-entry'
7
+
8
+ export default {
9
+ async fetch(request: Request, env: any, ctx: any) {
10
+ // Expose D1 binding to server-side code via globalThis
11
+ if (env?.DB) {
12
+ ;(globalThis as any).__D1_DB = env.DB
13
+ }
14
+ // Signal that we're running on CF Workers
15
+ ;(globalThis as any).__CF_WORKERS = true
16
+ return handler.fetch(request)
17
+ },
18
+ }