docs-i18n 0.9.2 → 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.
- package/admin/app/lib/auth-client.ts +21 -0
- package/admin/app/lib/auth.server.ts +62 -0
- package/admin/app/routeTree.gen.ts +21 -3
- package/admin/app/routes/index.tsx +68 -8
- package/admin/app/routes/login.tsx +207 -0
- package/admin/app/server.ts +23 -0
- package/admin/app/styles.css +146 -0
- package/admin/app/worker.ts +18 -0
- package/admin/dist/client/assets/auth-client-DqJZaFZR.js +3 -0
- package/admin/dist/client/assets/login-CQjkiBAF.js +1 -0
- package/admin/dist/client/assets/main-bc5tcdGg.js +18 -0
- package/admin/dist/client/assets/routes-CTPOG_v1.js +3 -0
- package/admin/dist/client/assets/{styles-DJ6QEJmN.css → styles-zS0BbO7e.css} +1 -1
- package/admin/dist/client/assets/useNavigate-CEOVvMjz.js +1 -0
- package/admin/dist/server/assets/{react-dom-CpO9xk_L.js → __tanstack-start-server-fn-resolver-qK0Yfvti.js} +83 -507
- package/admin/dist/server/assets/_tanstack-start-manifest_v-BgMVPPt2.js +21 -0
- package/admin/dist/server/assets/adapter-DjXlUL1J.js +2253 -0
- package/admin/dist/server/assets/auth-client-CoUpyQIM.js +807 -0
- package/admin/dist/server/assets/auth-dSAIPjBw.js +72 -0
- package/admin/dist/server/assets/auth.server-BLVDnTCZ.js +31352 -0
- package/admin/dist/server/assets/bun-sqlite-dialect-C8OaCWSL-BNNY-FoT.js +154 -0
- package/admin/dist/server/assets/compiled-query-CnFG_BVV.js +6967 -0
- package/admin/dist/server/assets/d1-sqlite-dialect-sYHNqBte-Bjz-cybU.js +115 -0
- package/admin/dist/server/assets/dist-C3-e8E2B.js +215 -0
- package/admin/dist/server/assets/dist-CUzFWZag.js +6039 -0
- package/admin/dist/server/assets/{init-DJr2glb3.js → dist-DBv71kqn.js} +21 -381
- package/admin/dist/server/assets/error-CASJ5tIm.js +457 -0
- package/admin/dist/server/assets/error-codes-BhMTGvV6.js +1153 -0
- package/admin/dist/server/assets/init-CJJUsPDL.js +49 -0
- package/admin/dist/server/assets/job-manager-D9Ab9hgu.js +179 -0
- package/admin/dist/server/assets/{jobs-bQfYqSk7.js → jobs-DrEe9YOj.js} +18 -5
- package/admin/dist/server/assets/kysely-adapter-YC8RFPyc.js +2 -0
- package/admin/dist/server/assets/login-SqzTMYOZ.js +228 -0
- package/admin/dist/server/assets/migrator-ZpVZslbq.js +2926 -0
- package/admin/dist/server/assets/{misc-DOk3t9vs.js → misc-BSoYldBT.js} +22 -9
- package/admin/dist/server/assets/{models-CBb8Owe5.js → models-CoviNHUP.js} +1 -1
- package/admin/dist/server/assets/node-sqlite-dialect-BJIaP6lL.js +154 -0
- package/admin/dist/server/assets/{router-DlU_fGDK.js → router-D-82slI-.js} +23 -11
- package/admin/dist/server/assets/{routes-BcfX6iub.js → routes-B1pNmxF3.js} +43 -29
- package/admin/dist/server/assets/{routes-pIM0fgUO.js → routes-C9huiZHw.js} +56 -22
- package/admin/dist/server/assets/sqlite-adapter-CL2EidjD.js +69 -0
- package/admin/dist/server/assets/{start-BS52hm79.js → start-BiybVoR2.js} +1 -1
- package/admin/dist/server/assets/status-B1AGLvHn.js +162 -0
- package/admin/dist/server/assets/status-D7PU72hm.js +262 -0
- package/admin/dist/server/assets/string-B4XlckmJ.js +6 -0
- package/admin/dist/server/assets/useNavigate-0H08s_Q2.js +29 -0
- package/admin/dist/server/assets/useRouter-BXJvr8to.js +508 -0
- package/admin/dist/server/server.js +70 -90
- package/admin/package.json +6 -1
- package/admin/server/functions/auth.ts +89 -0
- package/admin/server/functions/jobs.ts +30 -2
- package/admin/server/functions/misc.ts +25 -5
- package/admin/server/functions/status.ts +52 -3
- package/admin/server/index.ts +1 -1
- package/admin/server/init.ts +21 -9
- package/admin/server/services/d1-status.ts +282 -0
- package/admin/vite.config.ts +29 -15
- package/admin/wrangler.jsonc +16 -0
- package/package.json +1 -1
- package/template/app/components/markdown/Markdown.tsx +7 -1
- package/template/app/utils/docs.server.ts +37 -4
- package/template/app/worker.ts +16 -0
- package/template/content/docs-i18n/en/cli.md +9 -5
- package/template/content/docs-i18n/en/deployment.md +85 -68
- package/template/dist/client/assets/{Doc-CGhUfH9r.js → Doc-BKO69_nz.js} +1 -1
- package/template/dist/client/assets/{DocsLayout-CoPL9BM9.js → DocsLayout-BGugXxEQ.js} +1 -1
- package/template/dist/client/assets/{FileTabs-DsPkEUu7.js → FileTabs-4fZriOj4.js} +1 -1
- package/template/dist/client/assets/{Footer-4faHyha8.js → Footer-DYh1AfWA.js} +1 -1
- package/template/dist/client/assets/{FrameworkContent-Cxg_X_EP.js → FrameworkContent-rVvjxASn.js} +1 -1
- package/template/dist/client/assets/{MarkdownHeadingContext-CwDqQdSh.js → MarkdownHeadingContext-CdvUDZFU.js} +4 -4
- package/template/dist/client/assets/{PostNotFound-1ZaWdycM.js → PostNotFound-WoSYGsGu.js} +1 -1
- package/template/dist/client/assets/{_basePickBy-FbrKkfHa.js → _basePickBy-Dd7GuR7A.js} +1 -1
- package/template/dist/client/assets/{_baseUniq-g6ljCkn8.js → _baseUniq-DMxQLGFI.js} +1 -1
- package/template/dist/client/assets/_lang-3AqGszEy.js +1 -0
- package/template/dist/client/assets/_lang._project-COkrIqzH.js +1 -0
- package/template/dist/client/assets/_lang._project._version-B8vRZczu.js +1 -0
- package/template/dist/client/assets/{_lang._project._version.docs-DjZ_USgK.js → _lang._project._version.docs-DokNGgvU.js} +1 -1
- package/template/dist/client/assets/{_lang._project._version.docs._-CNb1EMFX.js → _lang._project._version.docs._-CXCNZzOb.js} +1 -1
- package/template/dist/client/assets/_lang._project._version.docs._-DR0WSQEb.js +1 -0
- package/template/dist/client/assets/_lang._project._version.docs.framework._framework._-C_Grro8r.js +1 -0
- package/template/dist/client/assets/{_lang._project._version.docs.framework._framework.index-CqyVy6eq.js → _lang._project._version.docs.framework._framework.index-DsYjXRdj.js} +1 -1
- package/template/dist/client/assets/{_lang._project._version.docs.framework.index-S3Frbfn4.js → _lang._project._version.docs.framework.index-DQX1lBi3.js} +1 -1
- package/template/dist/client/assets/{_lang._project.docs-CkmM5v1V.js → _lang._project.docs-DsYQj9jI.js} +1 -1
- package/template/dist/client/assets/_lang._project.docs._-DlM_D6DD.js +1 -0
- package/template/dist/client/assets/{_lang._project.docs._-BHYKQj_2.js → _lang._project.docs._-l2tTjx80.js} +1 -1
- package/template/dist/client/assets/_lang.blog-CEwEtalL.js +1 -0
- package/template/dist/client/assets/_lang.blog-D6YGC3tK.js +1 -0
- package/template/dist/client/assets/_lang.blog._-DgHu4oLy.js +1 -0
- package/template/dist/client/assets/{_lang.blog._-bXJwKw9E.js → _lang.blog._-Umz18sQE.js} +1 -1
- package/template/dist/client/assets/_lang.blog.index-C8LKUFtD.js +1 -0
- package/template/dist/client/assets/{_lang.blog.index-CdR5PZOo.js → _lang.blog.index-DzUqpOBE.js} +1 -1
- package/template/dist/client/assets/{_lang.docs-Cp3wmc9k.js → _lang.docs-CUh3R7DD.js} +1 -1
- package/template/dist/client/assets/{_lang.docs._-0bwIpeOn.js → _lang.docs._-DlgTPy3s.js} +1 -1
- package/template/dist/client/assets/_lang.docs._-DmaQE7lx.js +1 -0
- package/template/dist/client/assets/_lang.docs.framework._framework._-B4C4uDFp.js +1 -0
- package/template/dist/client/assets/{_lang.docs.framework._framework.index-BLgwIvQA.js → _lang.docs.framework._framework.index-DTg6Xd3p.js} +1 -1
- package/template/dist/client/assets/{_lang.docs.framework.index-CzW7Dul3.js → _lang.docs.framework.index-BQ2enasl.js} +1 -1
- package/template/dist/client/assets/{arc-B4lRpBfi.js → arc-DGPgC_QF.js} +1 -1
- package/template/dist/client/assets/{architectureDiagram-2XIMDMQ5-Coq1Gceq.js → architectureDiagram-2XIMDMQ5-yI53_GAi.js} +1 -1
- package/template/dist/client/assets/{blockDiagram-WCTKOSBZ-C7BGTzDN.js → blockDiagram-WCTKOSBZ-C3tr24zy.js} +1 -1
- package/template/dist/client/assets/{c4Diagram-IC4MRINW-xTBVTs0q.js → c4Diagram-IC4MRINW-DOA-mowm.js} +1 -1
- package/template/dist/client/assets/channel-DzZD7dUQ.js +1 -0
- package/template/dist/client/assets/{chunk-4BX2VUAB-DUUHBu75.js → chunk-4BX2VUAB-B6NSnNJJ.js} +1 -1
- package/template/dist/client/assets/{chunk-55IACEB6-MUxF_n9_.js → chunk-55IACEB6-CWYwArBH.js} +1 -1
- package/template/dist/client/assets/{chunk-FMBD7UC4-BWh6wvYo.js → chunk-FMBD7UC4-DSyn2wIW.js} +1 -1
- package/template/dist/client/assets/{chunk-JSJVCQXG-CLUdUV5u.js → chunk-JSJVCQXG-D83nm5W0.js} +1 -1
- package/template/dist/client/assets/{chunk-KX2RTZJC-CAlz_cXA.js → chunk-KX2RTZJC-DD7fN9e9.js} +1 -1
- package/template/dist/client/assets/{chunk-NQ4KR5QH-BaYKfUVy.js → chunk-NQ4KR5QH-C3YlYiU5.js} +1 -1
- package/template/dist/client/assets/{chunk-QZHKN3VN-NxDloxi5.js → chunk-QZHKN3VN-B7wBEuCG.js} +1 -1
- package/template/dist/client/assets/{chunk-WL4C6EOR-C2Ncbi5S.js → chunk-WL4C6EOR-ByA1FloT.js} +1 -1
- package/template/dist/client/assets/classDiagram-VBA2DB6C-CRozKaUD.js +1 -0
- package/template/dist/client/assets/classDiagram-v2-RAHNMMFH-CRozKaUD.js +1 -0
- package/template/dist/client/assets/clone-CGnOEl4E.js +1 -0
- package/template/dist/client/assets/{cose-bilkent-S5V4N54A-Ct9-ZJcv.js → cose-bilkent-S5V4N54A-nt_sXfWc.js} +1 -1
- package/template/dist/client/assets/{dagre-KLK3FWXG-u9dz8dcq.js → dagre-KLK3FWXG-DUsyMTPd.js} +1 -1
- package/template/dist/client/assets/{diagram-E7M64L7V-BXmcaktT.js → diagram-E7M64L7V-D5SAypX0.js} +1 -1
- package/template/dist/client/assets/{diagram-IFDJBPK2-CRlP5SeV.js → diagram-IFDJBPK2-WhP5c8Vz.js} +1 -1
- package/template/dist/client/assets/{diagram-P4PSJMXO-B9rJcj_H.js → diagram-P4PSJMXO-AMrwIlhf.js} +1 -1
- package/template/dist/client/assets/{erDiagram-INFDFZHY-DX-vee6w.js → erDiagram-INFDFZHY-BxifSpCV.js} +1 -1
- package/template/dist/client/assets/{flowDiagram-PKNHOUZH-CoBCSOFc.js → flowDiagram-PKNHOUZH-BMAowE9I.js} +1 -1
- package/template/dist/client/assets/{ganttDiagram-A5KZAMGK-BlqU_ghi.js → ganttDiagram-A5KZAMGK-Bay-0iRq.js} +1 -1
- package/template/dist/client/assets/{gitGraphDiagram-K3NZZRJ6-CntCsuti.js → gitGraphDiagram-K3NZZRJ6-Va91W3gw.js} +1 -1
- package/template/dist/client/assets/{graph-CZaxZzO8.js → graph-CbBYObK_.js} +1 -1
- package/template/dist/client/assets/{index-XelhTkgl.js → index-CF6qz2tX.js} +1 -1
- package/template/dist/client/assets/{infoDiagram-LFFYTUFH-_jCC8Jtt.js → infoDiagram-LFFYTUFH-Byd5C-4U.js} +1 -1
- package/template/dist/client/assets/{ishikawaDiagram-PHBUUO56-D3m_r2ig.js → ishikawaDiagram-PHBUUO56-DxOKnE1v.js} +1 -1
- package/template/dist/client/assets/{journeyDiagram-4ABVD52K-CvRNm03C.js → journeyDiagram-4ABVD52K-IRmt7RI4.js} +1 -1
- package/template/dist/client/assets/{kanban-definition-K7BYSVSG-nQcLuNSy.js → kanban-definition-K7BYSVSG-BjTVXn-R.js} +1 -1
- package/template/dist/client/assets/{layout-DZIdDq97.js → layout-Bbx6A0bC.js} +1 -1
- package/template/dist/client/assets/{linear-C2JcF5ss.js → linear-Df2eAW4A.js} +1 -1
- package/template/dist/client/assets/{main-C8MldI1o.js → main-DqZtiCro.js} +2 -2
- package/template/dist/client/assets/{mermaid.core-DlB0QBo2.js → mermaid.core-BIoiBcAA.js} +4 -4
- package/template/dist/client/assets/{mindmap-definition-YRQLILUH-D9OjtrBW.js → mindmap-definition-YRQLILUH-Btzz0iIP.js} +1 -1
- package/template/dist/client/assets/ordinal-Cboi1Yqb.js +1 -0
- package/template/dist/client/assets/{pieDiagram-SKSYHLDU-DoYJZfNJ.js → pieDiagram-SKSYHLDU-C2amrGtU.js} +1 -1
- package/template/dist/client/assets/{quadrantDiagram-337W2JSQ-Bs71YHJr.js → quadrantDiagram-337W2JSQ-EVgH9VuN.js} +1 -1
- package/template/dist/client/assets/{react-C0klD_r9.js → react-qvbbiZob.js} +1 -1
- package/template/dist/client/assets/{requirementDiagram-Z7DCOOCP-BWvQcALn.js → requirementDiagram-Z7DCOOCP-BkYPbRis.js} +1 -1
- package/template/dist/client/assets/{sankeyDiagram-WA2Y5GQK-CiGy1SQP.js → sankeyDiagram-WA2Y5GQK-B5EIaP-h.js} +1 -1
- package/template/dist/client/assets/{sequenceDiagram-2WXFIKYE-DRZim8vR.js → sequenceDiagram-2WXFIKYE-BC33VGOc.js} +1 -1
- package/template/dist/client/assets/{stateDiagram-RAJIS63D-BoqzJeL7.js → stateDiagram-RAJIS63D-DiKvWUYb.js} +1 -1
- package/template/dist/client/assets/stateDiagram-v2-FVOUBMTO-DjKMPYGe.js +1 -0
- package/template/dist/client/assets/{timeline-definition-YZTLITO2-CyvR95Wz.js → timeline-definition-YZTLITO2-QiFlgbRA.js} +1 -1
- package/template/dist/client/assets/{treemap-KZPCXAKY-DkXgGvs_.js → treemap-KZPCXAKY-BOYbyS9G.js} +1 -1
- package/template/dist/client/assets/{vennDiagram-LZ73GAT5-CVpGZu6p.js → vennDiagram-LZ73GAT5-CqmW7j4r.js} +1 -1
- package/template/dist/client/assets/{xychartDiagram-JWTSCODW-Cjqbi_DU.js → xychartDiagram-JWTSCODW-gj6oWX8l.js} +1 -1
- package/template/dist/server/assets/{Doc-DKBxQduk.js → Doc-9tJiX5y6.js} +3 -3
- package/template/dist/server/assets/{DocsLayout-CQfCTal3.js → DocsLayout-BTjhU_W5.js} +2 -2
- package/template/dist/server/assets/{Footer-Dcw5XVqX.js → Footer-CefTi2yh.js} +1 -1
- package/template/dist/server/assets/{FrameworkContent-OJfvCBHi.js → FrameworkContent-BkJvuP04.js} +2 -2
- package/template/dist/server/assets/{MarkdownHeadingContext-h4SfZq-C.js → MarkdownHeadingContext-37oQpb36.js} +8 -4
- package/template/dist/server/assets/{PostNotFound-DRJpnWrj.js → PostNotFound-BqBZf83v.js} +1 -1
- package/template/dist/server/assets/{_basePickBy-DJ9gzwF8.js → _basePickBy-DZ3TPUta.js} +2 -2
- package/template/dist/server/assets/{_baseUniq-CezmbvU2.js → _baseUniq-DKicWTQT.js} +1 -1
- package/template/dist/server/assets/{_lang._project._version.docs-CE_Z2zvG.js → _lang._project._version.docs-DOTNQiDb.js} +1 -1
- package/template/dist/server/assets/{_lang._project._version.docs-sJvASz_e.js → _lang._project._version.docs-U-t4mk5_.js} +3 -3
- package/template/dist/server/assets/{_lang._project._version.docs._-B2vf_QGY.js → _lang._project._version.docs._-DMgnElWM.js} +5 -5
- package/template/dist/server/assets/{_lang._project._version.docs._-CQcamDns.js → _lang._project._version.docs._-DSg82-Ug.js} +1 -1
- package/template/dist/server/assets/{_lang._project._version.docs.framework._framework._-54LEIllb.js → _lang._project._version.docs.framework._framework._-DbeN6toN.js} +1 -1
- package/template/dist/server/assets/{_lang._project._version.docs.framework._framework._-Dmn8xCf0.js → _lang._project._version.docs.framework._framework._-kBw_9L-F.js} +5 -5
- package/template/dist/server/assets/{_lang._project._version.docs.framework._framework.index-COKb9ffR.js → _lang._project._version.docs.framework._framework.index-Bsyj0DD5.js} +1 -1
- package/template/dist/server/assets/{_lang._project._version.docs.framework.index-DoEddI6Z.js → _lang._project._version.docs.framework.index-CmLAP_Io.js} +1 -1
- package/template/dist/server/assets/{_lang._project.docs-BjOhmwp6.js → _lang._project.docs-Bb4ZZ_jr.js} +3 -3
- package/template/dist/server/assets/{_lang._project.docs-dl8MxaGg.js → _lang._project.docs-BsnkRf-R.js} +1 -1
- package/template/dist/server/assets/{_lang._project.docs._-hSRVM-U7.js → _lang._project.docs._-ChrpJ61j.js} +5 -5
- package/template/dist/server/assets/{_lang._project.docs._-Bq0ajlaH.js → _lang._project.docs._-axRfm8vS.js} +1 -1
- package/template/dist/server/assets/{_lang.blog-Dk36D6Ol.js → _lang.blog-8j6IvzvQ.js} +2 -2
- package/template/dist/server/assets/{_lang.blog._-Cm8zXsPs.js → _lang.blog._-BPzP97Ac.js} +2 -2
- package/template/dist/server/assets/{_lang.blog._-D4CEjSkM.js → _lang.blog._-CjgFipz7.js} +1 -1
- package/template/dist/server/assets/{_lang.blog.index-orWcAgbi.js → _lang.blog._-DNX8UglA.js} +2 -2
- package/template/dist/server/assets/{_lang.blog.index-ZhMds6Jp.js → _lang.blog.index-CeZnMJBi.js} +1 -1
- package/template/dist/server/assets/{_lang.blog.index-Dfy48Gbt.js → _lang.blog.index-Dk5fYp4Q.js} +1 -1
- package/template/dist/server/assets/{_lang.blog._-A8h17fpC.js → _lang.blog.index-DzVKqoC4.js} +2 -2
- package/template/dist/server/assets/{_lang.docs-CAEkhcnT.js → _lang.docs-B4StnHMb.js} +3 -3
- package/template/dist/server/assets/{_lang.docs-CB1sGjRO.js → _lang.docs-DSB3iI6a.js} +1 -1
- package/template/dist/server/assets/{_lang.docs._-Zbv8OwJU.js → _lang.docs._--c0In1AT.js} +5 -5
- package/template/dist/server/assets/{_lang.docs._-DEX6FutM.js → _lang.docs._-S-y4-3Qn.js} +1 -1
- package/template/dist/server/assets/{_lang.docs.framework._framework._-BnpTV3KM.js → _lang.docs.framework._framework._-BFWLyU2h.js} +1 -1
- package/template/dist/server/assets/{_lang.docs.framework._framework._-4s4-ZCYh.js → _lang.docs.framework._framework._-Be0U7cDg.js} +5 -5
- package/template/dist/server/assets/{_lang.docs.framework._framework.index-BLryfsl2.js → _lang.docs.framework._framework.index-BZ512aSk.js} +1 -1
- package/template/dist/server/assets/{_lang.docs.framework.index-DGxWQH6q.js → _lang.docs.framework.index-U8z3j4kz.js} +1 -1
- package/template/dist/server/assets/{_tanstack-start-manifest_v-CURwM8Tc.js → _tanstack-start-manifest_v-DXpQ8503.js} +1 -1
- package/template/dist/server/assets/{arc-BwftnT5H.js → arc-B4h6h_n6.js} +1 -1
- package/template/dist/server/assets/{architecture-PBZL5I3N-KbDVC6gM.js → architecture-PBZL5I3N-CUwqLXkR.js} +6 -6
- package/template/dist/server/assets/{architectureDiagram-2XIMDMQ5-BoLvWxb3.js → architectureDiagram-2XIMDMQ5-CuCoxdBe.js} +6 -6
- package/template/dist/server/assets/{blockDiagram-WCTKOSBZ-GPFcXs-f.js → blockDiagram-WCTKOSBZ-D5PsUOim.js} +6 -6
- package/template/dist/server/assets/{blog.server-Bbk2Ifog.js → blog.server-WqzZ00iA.js} +1 -1
- package/template/dist/server/assets/{c4Diagram-IC4MRINW-EQwQCspo.js → c4Diagram-IC4MRINW-CXy5xO3o.js} +2 -2
- package/template/dist/server/assets/{channel-CxvwuPH7.js → channel-D0l-mWaF.js} +1 -1
- package/template/dist/server/assets/{chunk-4BX2VUAB-DUgcw5ei.js → chunk-4BX2VUAB-M7FVHMss.js} +1 -1
- package/template/dist/server/assets/{chunk-55IACEB6-Cn15uD91.js → chunk-55IACEB6-D_gDAje5.js} +1 -1
- package/template/dist/server/assets/{chunk-FMBD7UC4-Ck3iyLPu.js → chunk-FMBD7UC4-B5Bebx-Y.js} +1 -1
- package/template/dist/server/assets/{chunk-JSJVCQXG-VAT8yncE.js → chunk-JSJVCQXG-DxBkq-uB.js} +1 -1
- package/template/dist/server/assets/{chunk-KX2RTZJC-B1bd2VmA.js → chunk-KX2RTZJC-BMHm1EGi.js} +1 -1
- package/template/dist/server/assets/{chunk-NQ4KR5QH-CR67GG9C.js → chunk-NQ4KR5QH-Cp28pTwT.js} +3 -3
- package/template/dist/server/assets/{chunk-QZHKN3VN-B9SSazM4.js → chunk-QZHKN3VN-Bq5GZqaR.js} +1 -1
- package/template/dist/server/assets/{chunk-WL4C6EOR-DZ4Pjuao.js → chunk-WL4C6EOR-C9Nj5GdW.js} +5 -5
- package/template/dist/server/assets/{classDiagram-VBA2DB6C-CA6_4Wb2.js → classDiagram-VBA2DB6C-CUchv9T5.js} +6 -6
- package/template/dist/server/assets/{classDiagram-v2-RAHNMMFH-CA6_4Wb2.js → classDiagram-v2-RAHNMMFH-CUchv9T5.js} +6 -6
- package/template/dist/server/assets/{clone-DJHP_iVy.js → clone-CJcTi58S.js} +1 -1
- package/template/dist/server/assets/{cose-bilkent-S5V4N54A-DtU-cN6W.js → cose-bilkent-S5V4N54A-CxvCMhN_.js} +1 -1
- package/template/dist/server/assets/{dagre-KLK3FWXG-yZYrVU4p.js → dagre-KLK3FWXG-B5bQP7FL.js} +6 -6
- package/template/dist/server/assets/{diagram-E7M64L7V-8Yyz0aw0.js → diagram-E7M64L7V-NjHca90S.js} +8 -8
- package/template/dist/server/assets/{diagram-IFDJBPK2-DcxFYI3M.js → diagram-IFDJBPK2-CoTCfBKd.js} +6 -6
- package/template/dist/server/assets/{diagram-P4PSJMXO-CehxUcI0.js → diagram-P4PSJMXO-DHvGgYjH.js} +6 -6
- package/template/dist/server/assets/{docs.server-7EUAkSBN.js → docs.server-BSH7IvIU.js} +3884 -444
- package/template/dist/server/assets/{erDiagram-INFDFZHY-Bu2p1_Pj.js → erDiagram-INFDFZHY-01crajKr.js} +4 -4
- package/template/dist/server/assets/{flowDiagram-PKNHOUZH-B_eKR7I0.js → flowDiagram-PKNHOUZH-BkUQ_vxg.js} +6 -6
- package/template/dist/server/assets/{ganttDiagram-A5KZAMGK-DP6YEZof.js → ganttDiagram-A5KZAMGK-DvrO-w2P.js} +2 -2
- package/template/dist/server/assets/{gitGraph-HDMCJU4V-Bt0qhVL4.js → gitGraph-HDMCJU4V-h9JNaxB7.js} +6 -6
- package/template/dist/server/assets/{gitGraphDiagram-K3NZZRJ6-DwvkdYrg.js → gitGraphDiagram-K3NZZRJ6-BoKm6Fm-.js} +7 -7
- package/template/dist/server/assets/{graph-BVFNe_k5.js → graph-BoxbfI7Z.js} +2 -2
- package/template/dist/server/assets/{index-BvagF3L5.js → index-Jfzi6SZW.js} +2 -2
- package/template/dist/server/assets/{info-3K5VOQVL-CFejRnvB.js → info-3K5VOQVL-DgaSHqkS.js} +6 -6
- package/template/dist/server/assets/{infoDiagram-LFFYTUFH-D0v9uyXI.js → infoDiagram-LFFYTUFH-DgV5W8-I.js} +5 -5
- package/template/dist/server/assets/{ishikawaDiagram-PHBUUO56-DZumspL4.js → ishikawaDiagram-PHBUUO56-CqlMQ0Fq.js} +1 -1
- package/template/dist/server/assets/{journeyDiagram-4ABVD52K-nRp_-qZp.js → journeyDiagram-4ABVD52K-D6ySTub8.js} +4 -4
- package/template/dist/server/assets/{kanban-definition-K7BYSVSG-BMKyyzjt.js → kanban-definition-K7BYSVSG-BT8m7Cwk.js} +2 -2
- package/template/dist/server/assets/{layout-mpiN5R-5.js → layout-CkYcErfn.js} +4 -4
- package/template/dist/server/assets/{linear-CqNYgjEx.js → linear-F_0dWGZL.js} +1 -1
- package/template/dist/server/assets/{mermaid-parser.core-B8Uu3QZY.js → mermaid-parser.core-q5MdUJuo.js} +11 -11
- package/template/dist/server/assets/{mermaid.core-BI3nMhNO.js → mermaid.core-DOWTODR1.js} +31 -31
- package/template/dist/server/assets/{mindmap-definition-YRQLILUH-DCoFqLPh.js → mindmap-definition-YRQLILUH-BQxlQqn-.js} +3 -3
- package/template/dist/server/assets/{ordinal-Bcam90FY.js → ordinal-CxptdPJm.js} +1 -1
- package/template/dist/server/assets/{packet-RMMSAZCW-djgonfKN.js → packet-RMMSAZCW-D8FkLZuP.js} +6 -6
- package/template/dist/server/assets/{pie-UPGHQEXC-Dug2t-PE.js → pie-UPGHQEXC-Diw2fHLk.js} +6 -6
- package/template/dist/server/assets/{pieDiagram-SKSYHLDU-CS0_hW4w.js → pieDiagram-SKSYHLDU-B1J4UJZ7.js} +8 -8
- package/template/dist/server/assets/{quadrantDiagram-337W2JSQ-BpQNM0zu.js → quadrantDiagram-337W2JSQ-BvjKLapg.js} +2 -2
- package/template/dist/server/assets/{radar-KQ55EAFF-3ir2W9Wi.js → radar-KQ55EAFF-CcBdPU3n.js} +6 -6
- package/template/dist/server/assets/{requirementDiagram-Z7DCOOCP-D92RyjV4.js → requirementDiagram-Z7DCOOCP-Bgr_wnAs.js} +3 -3
- package/template/dist/server/assets/{router-DK1vpPhv.js → router-DxwPl-Dc.js} +18 -18
- package/template/dist/server/assets/{sankeyDiagram-WA2Y5GQK-DCPRB-xO.js → sankeyDiagram-WA2Y5GQK-B0UwtyW3.js} +2 -2
- package/template/dist/server/assets/{sequenceDiagram-2WXFIKYE-C1ab2VvU.js → sequenceDiagram-2WXFIKYE-BbxQJHjO.js} +3 -3
- package/template/dist/server/assets/{stateDiagram-RAJIS63D-GhG1G3ff.js → stateDiagram-RAJIS63D-Cg-uJ_UO.js} +8 -8
- package/template/dist/server/assets/{stateDiagram-v2-FVOUBMTO-C-KtMadV.js → stateDiagram-v2-FVOUBMTO-BWVPrqfa.js} +4 -4
- package/template/dist/server/assets/{timeline-definition-YZTLITO2-DyfAQCd4.js → timeline-definition-YZTLITO2-DCSJT2WT.js} +2 -2
- package/template/dist/server/assets/{treemap-KZPCXAKY-Cn0Cw4Cl.js → treemap-KZPCXAKY-a0nhlKgx.js} +6 -6
- package/template/dist/server/assets/{vennDiagram-LZ73GAT5-D2Ak5JUa.js → vennDiagram-LZ73GAT5-Bk2HQEQq.js} +1 -1
- package/template/dist/server/assets/{xychartDiagram-JWTSCODW-DqoBOs1L.js → xychartDiagram-JWTSCODW-C4svHkt_.js} +3 -3
- package/template/dist/server/server.js +16 -16
- package/template/package.json +2 -0
- package/template/vite.config.ts +33 -18
- package/template/wrangler.jsonc +2 -2
- package/admin/dist/client/assets/main-CSFhgz4p.js +0 -17
- package/admin/dist/client/assets/routes-C6bCOSX-.js +0 -3
- package/admin/dist/server/assets/_tanstack-start-manifest_v-BE5XHVZ2.js +0 -17
- package/admin/dist/server/assets/redirect-DtfSYi2g.js +0 -51
- package/admin/dist/server/assets/status-CZz8Rs_7.js +0 -81
- package/template/dist/client/assets/_lang-Cpuy5xmU.js +0 -1
- package/template/dist/client/assets/_lang._project-DBdR04In.js +0 -1
- package/template/dist/client/assets/_lang._project._version-CtCLMJs2.js +0 -1
- package/template/dist/client/assets/_lang._project._version.docs._-CxgRZ17Q.js +0 -1
- package/template/dist/client/assets/_lang._project._version.docs.framework._framework._-Qph6wahA.js +0 -1
- package/template/dist/client/assets/_lang._project.docs._-C_ZfXEJ7.js +0 -1
- package/template/dist/client/assets/_lang.blog-BcRmhv23.js +0 -1
- package/template/dist/client/assets/_lang.blog-C5Aa7k5r.js +0 -1
- package/template/dist/client/assets/_lang.blog._-BVw4vhtF.js +0 -1
- package/template/dist/client/assets/_lang.blog.index-Y35iFzkp.js +0 -1
- package/template/dist/client/assets/_lang.docs._-B9hwwoTY.js +0 -1
- package/template/dist/client/assets/_lang.docs.framework._framework._-BENbKZIu.js +0 -1
- package/template/dist/client/assets/channel-C_1F7tzH.js +0 -1
- package/template/dist/client/assets/classDiagram-VBA2DB6C-CqViWWFw.js +0 -1
- package/template/dist/client/assets/classDiagram-v2-RAHNMMFH-CqViWWFw.js +0 -1
- package/template/dist/client/assets/clone-EeiNAO_N.js +0 -1
- package/template/dist/client/assets/ordinal-BENe2yWM.js +0 -1
- package/template/dist/client/assets/stateDiagram-v2-FVOUBMTO-CJYWvllO.js +0 -1
- /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
|
-
{'
|
|
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
|
-
|
|
286
|
-
|
|
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
|
+
};
|
package/admin/app/styles.css
CHANGED
|
@@ -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
|
+
}
|