@jant/core 0.3.39 → 1.0.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/README.md +21 -33
- package/bin/commands/assets/upload.js +247 -0
- package/bin/commands/collections.js +268 -0
- package/bin/commands/import-site.js +1169 -343
- package/bin/commands/media.js +302 -0
- package/bin/commands/migrate-text-attachments.js +183 -0
- package/bin/commands/migrate.js +263 -2
- package/bin/commands/posts.js +262 -0
- package/bin/commands/search.js +53 -0
- package/bin/commands/settings.js +93 -0
- package/bin/commands/site/export.js +34 -33
- package/bin/commands/site/{localize-media.js → pull-media.js} +17 -17
- package/bin/lib/d1-query.js +15 -3
- package/bin/lib/http-api.js +223 -0
- package/bin/lib/media-upload.js +206 -0
- package/bin/lib/migration-runner.js +64 -0
- package/bin/lib/runtime-target.js +7 -2
- package/bin/lib/site-media-parser.js +71 -16
- package/bin/lib/site-pull-media.js +698 -0
- package/bin/lib/site-snapshot.js +0 -1
- package/dist/app-B5db9mS0.js +5 -0
- package/dist/{app-BfoG98VD.js → app-CwCepTko.js} +23938 -23014
- package/dist/client/.vite/manifest.json +3485 -0
- package/dist/client/_assets/chunks/02611a045a7fe83a12014e3debc9f731-BqEDtwXC.woff2 +0 -0
- package/dist/client/_assets/chunks/033466ef683afe931f7f520cfb42d928-BluLHEh9.woff2 +0 -0
- package/dist/client/_assets/chunks/04b8bde59cff68eeee74fb1914eb09c7-D5j2CLTt.woff2 +0 -0
- package/dist/client/_assets/chunks/057a6a98bda7fe57105ddaa99ec82015-DY_AoijT.woff2 +0 -0
- package/dist/client/_assets/chunks/05ac821472e235943ed1435e4bb8ecad-CUm8GiH6.woff2 +0 -0
- package/dist/client/_assets/chunks/05da12edb9d52210581dc6ec4541031f-BXAOx2XP.woff2 +0 -0
- package/dist/client/_assets/chunks/074c1f8483d5a4d8c45c8c5f3e4cbb32-CDqdMQm8.woff2 +0 -0
- package/dist/client/_assets/chunks/0968e4861204b51f62a2f8e9f15dd5e0-D5tLgF_8.woff2 +0 -0
- package/dist/client/_assets/chunks/0acd1fe2b2ea1ad1bfee7ae1fa139d27-BKK1m412.woff2 +0 -0
- package/dist/client/_assets/chunks/0c2ab6b295e55f356f8020d4e7747522-CkCQjQw3.woff2 +0 -0
- package/dist/client/_assets/chunks/0c5f9492af03a4fa42c784de94649de1-CQlJqksa.woff2 +0 -0
- package/dist/client/_assets/chunks/0d5dec931dc885f07fe5cd5af8bed675-C74x-U_U.woff2 +0 -0
- package/dist/client/_assets/chunks/0d9a936885a4c39077438effd3779cbd-Bw0fYF4S.woff2 +0 -0
- package/dist/client/_assets/chunks/0e645da524f7cfc0e8c3c03fb2b08428-BVeI_5Th.woff2 +0 -0
- package/dist/client/_assets/chunks/0f5e1a18987dbc84ca05188c129e1936-B6_lZ6fE.woff2 +0 -0
- package/dist/client/_assets/chunks/1076f0f6f66d28d7a2f16427faad4413-ubiXnD1P.woff2 +0 -0
- package/dist/client/_assets/chunks/112743a4ab5fdd1498dfdf2b11336380-B5FzQxTK.woff2 +0 -0
- package/dist/client/_assets/chunks/1211f03d3ff5759a702631445793f60e-DDcSiyCt.woff2 +0 -0
- package/dist/client/_assets/chunks/12ef1ba76bd20b004b865266a1aa70b3-BwmaD87S.woff2 +0 -0
- package/dist/client/_assets/chunks/135e83b403475c5dc9e49b43501a5b84-C5mE_KZS.woff2 +0 -0
- package/dist/client/_assets/chunks/1380210a722ac9aeef54005ad7b015c9-CjA-MP82.woff2 +0 -0
- package/dist/client/_assets/chunks/13b2c53b30e6a3e4de7132dbc18dbdfc-B9WOB7kv.woff2 +0 -0
- package/dist/client/_assets/chunks/147b24c2f08d03bbed30887d4cb3311c-IeeFCJ13.woff2 +0 -0
- package/dist/client/_assets/chunks/152395634a207579552f8cb54db88599-C2y2JyNZ.woff2 +0 -0
- package/dist/client/_assets/chunks/15d95680dc31cc6ce20e0a5464106dc4-CpD8dqRm.woff2 +0 -0
- package/dist/client/_assets/chunks/16663e567f81f4725a1522f37e18f71f-BNoxS9pQ.woff2 +0 -0
- package/dist/client/_assets/chunks/1733f27476507ca68b68a803bc533cc2-DXL-14Ug.woff2 +0 -0
- package/dist/client/_assets/chunks/17c7f5d0a45e92ede0e5dec3a2c77efa-CNj3jQMl.woff2 +0 -0
- package/dist/client/_assets/chunks/1824321da801e6257b902f3d1d09054c-D4dgdyWB.woff2 +0 -0
- package/dist/client/_assets/chunks/188c2db794f3dd7a45889ddbc81da9bb-C9NbUBBO.woff2 +0 -0
- package/dist/client/_assets/chunks/1a08931435f885e707edb85978ea3bb6-BOiP2u7G.woff2 +0 -0
- package/dist/client/_assets/chunks/1a3a92c7c060a71a6c35819b9ebcdbb9-DFfonQfz.woff2 +0 -0
- package/dist/client/_assets/chunks/1be602ad456b0d75902d352116cb35fd-Bc-XQtQh.woff2 +0 -0
- package/dist/client/_assets/chunks/1cf737900dd49c2e88f1b3221a82a602-CfTmnns3.woff2 +0 -0
- package/dist/client/_assets/chunks/1fba7ec0e412e911bf31841de5a8a4e4-18ELMbFF.woff2 +0 -0
- package/dist/client/_assets/chunks/233d3a685ee18276b319363474599d47-BaFdJ0-G.woff2 +0 -0
- package/dist/client/_assets/chunks/2612c60f9dc5459ac42763591240a1d6-CTD69cq1.woff2 +0 -0
- package/dist/client/_assets/chunks/284b53bbefb06924cf236d24c8ed5641-CPDiuOv6.woff2 +0 -0
- package/dist/client/_assets/chunks/28a97af9ab9d38983d20f39ff09840e1-mFqcT3Jw.woff2 +0 -0
- package/dist/client/_assets/chunks/2a56eaf19d1d38a6b57e2a388f733676-CU52qBlE.woff2 +0 -0
- package/dist/client/_assets/chunks/2ab8cf1f23a5ac7939a7876054e711a7-B4T3dK7A.woff2 +0 -0
- package/dist/client/_assets/chunks/2abfbab82b6a7c04426afc054d2464da-D5PIIHde.woff2 +0 -0
- package/dist/client/_assets/chunks/2bfaadaf3479c72286248e6de0be0ec9-DEpU6O74.woff2 +0 -0
- package/dist/client/_assets/chunks/2c8c55e4cec85ce77e95cac9d330f5cf-BCTA96EZ.woff2 +0 -0
- package/dist/client/_assets/chunks/2e6f4bb71ef6b38765d51acc5a79f638-Mbs6PECD.woff2 +0 -0
- package/dist/client/_assets/chunks/2ed9981d2e8983365bd051159b976b6d-D8gg6NWM.woff2 +0 -0
- package/dist/client/_assets/chunks/2f4c633e923ba30c6ba376367379fc91-CIJCFztv.woff2 +0 -0
- package/dist/client/_assets/chunks/31194d303a67561926a544ed0e072aee-w3-eGYAi.woff2 +0 -0
- package/dist/client/_assets/chunks/31a197213ae61d7043c81013f52d10d6-DXZrrkJP.woff2 +0 -0
- package/dist/client/_assets/chunks/349965eee0a9b6c984a319ab96a4ece9-DByAVmXw.woff2 +0 -0
- package/dist/client/_assets/chunks/34e6750e00c3a911ef87dc66b336594d-DNbWesOu.woff2 +0 -0
- package/dist/client/_assets/chunks/3623d96698132c61e861f984ce11cc23-jqV9ErzX.woff2 +0 -0
- package/dist/client/_assets/chunks/36cda3eae13370b934bba4429fab9078-BPDcUlw9.woff2 +0 -0
- package/dist/client/_assets/chunks/36f3df4730cfca4fc77fe52b52e6a126-BwK10NC0.woff2 +0 -0
- package/dist/client/_assets/chunks/37887deb7a9c466cf2af6ee7ff372ea6-BrAerJB1.woff2 +0 -0
- package/dist/client/_assets/chunks/37dbd564820cce2f7b3331e442da0df3-Cql2kzIi.woff2 +0 -0
- package/dist/client/_assets/chunks/37dc8505b20b37a2477a9121b16d44a7-CoXw6XWV.woff2 +0 -0
- package/dist/client/_assets/chunks/39211b02f24c69cbd1b54f6d41b01933-4Xu7vvnq.woff2 +0 -0
- package/dist/client/_assets/chunks/3aa13f1843d7c8fa16109b6395a9a29d-BQFZUc3B.woff2 +0 -0
- package/dist/client/_assets/chunks/3aba89c4d4281553078de4622b498cbb-8QS1zDYk.woff2 +0 -0
- package/dist/client/_assets/chunks/3ac0a07878cacdc98bb889f40f5970d3-C-BaM6-y.woff2 +0 -0
- package/dist/client/_assets/chunks/3d88558097559d775231194d43745ba7-CR2aqGC7.woff2 +0 -0
- package/dist/client/_assets/chunks/3dc3e8c35524cad2d1236f3393104ccf-9sqBsF7B.woff2 +0 -0
- package/dist/client/_assets/chunks/3e24063b19abd2b051af986a6870046d-TlweM3SW.woff2 +0 -0
- package/dist/client/_assets/chunks/3e2c06bdd9dcab29aeaeb0cfb7fa608a-BaqU-dIt.woff2 +0 -0
- package/dist/client/_assets/chunks/424123f9371ba357087363263eeafcda-C8SVfEJi.woff2 +0 -0
- package/dist/client/_assets/chunks/43b3bbf43055c3e65db9cdf2c5b18c1c-CbHx6-Ki.woff2 +0 -0
- package/dist/client/_assets/chunks/4410f876d27c9821839474b6b1059fd7-ClYz91aY.woff2 +0 -0
- package/dist/client/_assets/chunks/44704471b60c18b3ecec5300a88f1102-DDmmy6-m.woff2 +0 -0
- package/dist/client/_assets/chunks/45140742dfa8686b58db2899ce89f89a-D5IMMzDM.woff2 +0 -0
- package/dist/client/_assets/chunks/46604090efbb99c2db1800928af0a239-JX2fpYX_.woff2 +0 -0
- package/dist/client/_assets/chunks/46998df85d31e629c0142f0556f5e7c5-BIkNG9Wh.woff2 +0 -0
- package/dist/client/_assets/chunks/469d2754e315e77270c12fa0ab28026c-D-y-vsfA.woff2 +0 -0
- package/dist/client/_assets/chunks/479329a39a3eb6c0047e6b0981919855-vZKCRx42.woff2 +0 -0
- package/dist/client/_assets/chunks/491bbba374093fff045f55803a22bfef-DSQXiDCd.woff2 +0 -0
- package/dist/client/_assets/chunks/49902f1c41b281f8eb3771abdd4dccb8-DxVxNg2W.woff2 +0 -0
- package/dist/client/_assets/chunks/4c0760284569b87d8f2290c324953973-Bqd-TKHH.woff2 +0 -0
- package/dist/client/_assets/chunks/4cba92c942694bdc479bc54101bb1aa4-BrfsrgrC.woff2 +0 -0
- package/dist/client/_assets/chunks/4d38e56738156625329d93bd5c8cc74a-DONkMP0y.woff2 +0 -0
- package/dist/client/_assets/chunks/4db4f31a16965baa42cb7dad667a8f04-Dt1Cy4gr.woff2 +0 -0
- package/dist/client/_assets/chunks/4e7d263c30bb48604069a3b4404d4eeb-DNPCkvKD.woff2 +0 -0
- package/dist/client/_assets/chunks/5279c7e465d9871edf51fd02e691eee7-CKhyhvVf.woff2 +0 -0
- package/dist/client/_assets/chunks/527ff336279465617aafbafe1a830632-CC3lv4pm.woff2 +0 -0
- package/dist/client/_assets/chunks/54bfdb6f21f9d6191e5100580239e14f-PGlqYvgl.woff2 +0 -0
- package/dist/client/_assets/chunks/56b40518ea0608e62826bd44ee27f5f9-BD9F9Oss.woff2 +0 -0
- package/dist/client/_assets/chunks/56be5e32fd01668fe5ba814d94905839-CSyFA-9l.woff2 +0 -0
- package/dist/client/_assets/chunks/572b9e28f1e6d89b765a16d809db84a1-BIYMjzEa.woff2 +0 -0
- package/dist/client/_assets/chunks/57e9a86651366c1ba299e47aa7e358c2-BHuZXB4W.woff2 +0 -0
- package/dist/client/_assets/chunks/57f89adeae55aa7fe2add3fc1801ce03-Cy3PNrfx.woff2 +0 -0
- package/dist/client/_assets/chunks/5921cef36750ff6092d94b83a802823b-hF-uymTh.woff2 +0 -0
- package/dist/client/_assets/chunks/59e95d8b5332dcdae894a19946ab767d-ClRfsjWZ.woff2 +0 -0
- package/dist/client/_assets/chunks/5acc7f736217259db79a42bf44241c48-FYQUuFOM.woff2 +0 -0
- package/dist/client/_assets/chunks/5c05f8b75c9d7f25b3c04ca711cf43b3-D-YWPkSq.woff2 +0 -0
- package/dist/client/_assets/chunks/5df9ce98c75f8c50fb4fff7f01a23925-DgoCENyW.woff2 +0 -0
- package/dist/client/_assets/chunks/5e0124c7265f1b4cf0fc797b94efbebc-BTBNHsSB.woff2 +0 -0
- package/dist/client/_assets/chunks/5ec349ff62b9ee5fe0c6dae867704dc4-B4dezhrz.woff2 +0 -0
- package/dist/client/_assets/chunks/60020a830d809c26970cf8e48ba1eeda-B6FDTSik.woff2 +0 -0
- package/dist/client/_assets/chunks/601f812e8b1eafecd5ba585a6a6d7962-gIVBlUU9.woff2 +0 -0
- package/dist/client/_assets/chunks/6025ddaf99d86cc8bfd781006b19fbd6-CS-ze337.woff2 +0 -0
- package/dist/client/_assets/chunks/60bcfa3ea7446eb42394aab02d28be40-C-PQfCu3.woff2 +0 -0
- package/dist/client/_assets/chunks/60f6e28b3f0400b0e8fe32c3c7116102-Dag9L2qU.woff2 +0 -0
- package/dist/client/_assets/chunks/615a7e0d63f257109d599b2a1977de68-D6Y93yoG.woff2 +0 -0
- package/dist/client/_assets/chunks/615b38e0b5bb3ea68426f44f47706e6f-B5yzIIer.woff2 +0 -0
- package/dist/client/_assets/chunks/61a2c80d0c924d5a6187c02e8d1d1642-BY3MmHbZ.woff2 +0 -0
- package/dist/client/_assets/chunks/62fc94f8d4c5a750b7f25e7387539910-3ql2_WDK.woff2 +0 -0
- package/dist/client/_assets/chunks/639c7c6b0b0c27c738702741cfa4b8c0-BCD3OGri.woff2 +0 -0
- package/dist/client/_assets/chunks/63fafcb069520613d0ea35ad3e6b1e42-DP0Rrj4o.woff2 +0 -0
- package/dist/client/_assets/chunks/64a404d675f1d726f0891b7a80794595-DU3L0I9s.woff2 +0 -0
- package/dist/client/_assets/chunks/65a60d87c64228d258a123cbe85f5f31-B4kbf-79.woff2 +0 -0
- package/dist/client/_assets/chunks/65e9c4585d71bf48a5c62f367010da16-CvzgzReN.woff2 +0 -0
- package/dist/client/_assets/chunks/68a3a4bf337f8a0722be76676e20b850-Dnaw8EPD.woff2 +0 -0
- package/dist/client/_assets/chunks/6968e889e18891d912809fe484c2e745-Bj1m5e0s.woff2 +0 -0
- package/dist/client/_assets/chunks/6abdd163d2c4b85698db8aa1ce149361-B5FVGJuo.woff2 +0 -0
- package/dist/client/_assets/chunks/6b75213eb0be40ce84241eb2bb438a2e-CqHmF-NR.woff2 +0 -0
- package/dist/client/_assets/chunks/70714891ad3fbfc3d5f10a8669dacc5a-BWk5nLFN.woff2 +0 -0
- package/dist/client/_assets/chunks/7158022889c6c177062ac85036e7af10-B3D4K22n.woff2 +0 -0
- package/dist/client/_assets/chunks/73b794d885b88f7befb7ea8ab1780a15-D0ZehnEI.woff2 +0 -0
- package/dist/client/_assets/chunks/743f290baf027d4626a86e22f3d44600-DDTDQdRC.woff2 +0 -0
- package/dist/client/_assets/chunks/7520ca6ca8c60eb1e62d50e71c8d30f1-CVRaGu2G.woff2 +0 -0
- package/dist/client/_assets/chunks/757019c01c5e2c2b0f54293cea3b5636-BTovUnoH.woff2 +0 -0
- package/dist/client/_assets/chunks/759a647b77791b1e98f99bc0ab5317a7-CrK6FIFz.woff2 +0 -0
- package/dist/client/_assets/chunks/761d84afca8d7f34eebefe538adba827-DRbiVuwX.woff2 +0 -0
- package/dist/client/_assets/chunks/76e07530323418ec723c5d7634c9bcca-DGtVJTTH.woff2 +0 -0
- package/dist/client/_assets/chunks/76e51630143b95b6322ef93ad330da7a-D-kV82C_.woff2 +0 -0
- package/dist/client/_assets/chunks/76f117a3baacda304a71965a17266a13-DFfvsFUm.woff2 +0 -0
- package/dist/client/_assets/chunks/773819b7b9b8fd404a929867c0fd677e-Bu1xCMZb.woff2 +0 -0
- package/dist/client/_assets/chunks/77747f17625a259fb405b7bbdd84ac4b-o_vNfh-6.woff2 +0 -0
- package/dist/client/_assets/chunks/7817dd16805145d8538ad57590f69f5a-DguSUP3O.woff2 +0 -0
- package/dist/client/_assets/chunks/788498548ddfb710d6ef3c7bff79fa97-3ffoQfRd.woff2 +0 -0
- package/dist/client/_assets/chunks/78ea6c40923ce95367e3517dd1e5a849-DvLDRhX9.woff2 +0 -0
- package/dist/client/_assets/chunks/79aa7c8c842c4a27cf57c0a3a1ffca5a-sDoCeoKI.woff2 +0 -0
- package/dist/client/_assets/chunks/7b59f0ec7792b18458dc5a361e37884c-DWvxkKmT.woff2 +0 -0
- package/dist/client/_assets/chunks/7c3945788a689a69356c1a622d69d48b-1JjIpss2.woff2 +0 -0
- package/dist/client/_assets/chunks/7cc72fd2c9105560422b6a67c6162945-Co3AF5_G.woff2 +0 -0
- package/dist/client/_assets/chunks/7d0ea0690e432462f4d05a23d720ec19-Dx7DK4C3.woff2 +0 -0
- package/dist/client/_assets/chunks/7dffa5c1bec57e0903fd62357401ff1a-DuQHmiiN.woff2 +0 -0
- package/dist/client/_assets/chunks/7e38ca789a9e76ac91d9256374e154f0-BtETgGRe.woff2 +0 -0
- package/dist/client/_assets/chunks/7f9a6c9286b68de9c72b0024f7beeb40-JpXdo4FC.woff2 +0 -0
- package/dist/client/_assets/chunks/815a0b797465190f60d8b1a04656c42e-Spzo94nU.woff2 +0 -0
- package/dist/client/_assets/chunks/823d1bb11097331238d103c7f72138dc-CGN6m2VF.woff2 +0 -0
- package/dist/client/_assets/chunks/82f6ccc063960eed1cdfd1d61ada8862-CsmAqx2a.woff2 +0 -0
- package/dist/client/_assets/chunks/835b6505bb9eea9678925a1fa885353d-C6mSBwUc.woff2 +0 -0
- package/dist/client/_assets/chunks/845b4b67564d62cf5cad242f7ac08ea5-DnvzrloJ.woff2 +0 -0
- package/dist/client/_assets/chunks/84c8e7bc0931008ed91f44ed12dfea94-C2Hvhh-b.woff2 +0 -0
- package/dist/client/_assets/chunks/8726558cf297cbda831cc19514897205-gSFV1vW0.woff2 +0 -0
- package/dist/client/_assets/chunks/8855472f3c02f6c7ebb3216617ebe4af-C1JsWVqq.woff2 +0 -0
- package/dist/client/_assets/chunks/887a11290ba78b1e66c6d2f67043005e-L_A1f5Fz.woff2 +0 -0
- package/dist/client/_assets/chunks/888ba53510213d5d1f6a7deb60e569b6-OP8E-ELN.woff2 +0 -0
- package/dist/client/_assets/chunks/88db1d042074fb6e66821ffc10941930-kZ6K3e62.woff2 +0 -0
- package/dist/client/_assets/chunks/892aa49b2529c89bb4076d4aa51fe30f-Bw0_Km2A.woff2 +0 -0
- package/dist/client/_assets/chunks/8b5c9ef81159f31d2ab35f45ca4373e0-Djw95sKC.woff2 +0 -0
- package/dist/client/_assets/chunks/8b91c7c2ed390f1278b9befa3aa87233-B2C3iFbQ.woff2 +0 -0
- package/dist/client/_assets/chunks/8dc18c0cebe6aa4bf4c45dbb831048ab-bUlANLit.woff2 +0 -0
- package/dist/client/_assets/chunks/8e231d707f0c4f8e3cde90a6b52a79aa-CvwbWlul.woff2 +0 -0
- package/dist/client/_assets/chunks/8fb45117a62d92dce44a80f0b729ead5-Djr4-o5-.woff2 +0 -0
- package/dist/client/_assets/chunks/9064c12fd72c7aba235d8c3881755b91-BnguxT-p.woff2 +0 -0
- package/dist/client/_assets/chunks/90b7848e9b1623b77bdcf155e90b839c-CFvPRnoM.woff2 +0 -0
- package/dist/client/_assets/chunks/911b9e53e9814de2998c60bf3115f560-DmPmj635.woff2 +0 -0
- package/dist/client/_assets/chunks/919a879bd2d580d8491a31a449390689-BY2w-8_Y.woff2 +0 -0
- package/dist/client/_assets/chunks/91da6cb174bebfb96976e2f1316be2fe-DztAJb6W.woff2 +0 -0
- package/dist/client/_assets/chunks/92fdc376bce277874e75db666f175b44-DJUnHEIN.woff2 +0 -0
- package/dist/client/_assets/chunks/930a23430f0eb64480d7fe5f82834e21-2VrDPT7E.woff2 +0 -0
- package/dist/client/_assets/chunks/934dfdbed2bb2c4b6129199d699a34fa-CtpHsjRD.woff2 +0 -0
- package/dist/client/_assets/chunks/93bed0e5f2dd5a21cf73304fcfbc149d-DJiaETX7.woff2 +0 -0
- package/dist/client/_assets/chunks/93f3ea6918533d96d9c252378b9a4af0-D-FJaGi-.woff2 +0 -0
- package/dist/client/_assets/chunks/95a0951d2a2722ff773a1a45e8c474d6-DuZg-BpP.woff2 +0 -0
- package/dist/client/_assets/chunks/95ff41191c76ef893ac70a1043e95e44-C08QDbJO.woff2 +0 -0
- package/dist/client/_assets/chunks/96c75862c8cec51a7c05ff025fea86cd-DBnRwCuW.woff2 +0 -0
- package/dist/client/_assets/chunks/97d7a17234f2b5030ae9697ae00aded2-CkUSaB-p.woff2 +0 -0
- package/dist/client/_assets/chunks/982cd1765ca6bbb3e6547e47834d5148-DkIybx1r.woff2 +0 -0
- package/dist/client/_assets/chunks/985d4d41afa0934a4eb2de35473fb9a2-CF7rgJMw.woff2 +0 -0
- package/dist/client/_assets/chunks/995c4fda62d25c3b79dd5987737df6ae-CY5ri8HW.woff2 +0 -0
- package/dist/client/_assets/chunks/9b0c3caac458c7bc9c9133e40405ddea-DhPrYOcz.woff2 +0 -0
- package/dist/client/_assets/chunks/9b21e8244f5930c48ad5073f83777b6c-CuE9-r-r.woff2 +0 -0
- package/dist/client/_assets/chunks/9bb38fd05201de666b88b82d56a386f7-nMl6lB8X.woff2 +0 -0
- package/dist/client/_assets/chunks/9d0afa53dc2f92ba42024f55f11f6779-Bozpx8bL.woff2 +0 -0
- package/dist/client/_assets/chunks/9e13a47242926f1cd7d68c08d9ef8889-DwKQjc8M.woff2 +0 -0
- package/dist/client/_assets/chunks/9eff2ab2a9d2ced47ab761bf6fdb11ec-D86-Zm1H.woff2 +0 -0
- package/dist/client/_assets/chunks/9f1963fe8d4d6878d717d872a8f3fdb5-DxjITUFq.woff2 +0 -0
- package/dist/client/_assets/chunks/9f3bdab4025dc7c5ba1a5871e62e8918-BqxDEFLJ.woff2 +0 -0
- package/dist/client/_assets/chunks/9fce02d1a09f464c36c9fcfb14a354c5-F2tMAB_j.woff2 +0 -0
- package/dist/client/_assets/chunks/a00e94d4f04df6aa659db9c4954c7efe-CRBKCj_3.woff2 +0 -0
- package/dist/client/_assets/chunks/a0a6755c7e3f9e4cf03387027dd9f16c-BAyRqF2w.woff2 +0 -0
- package/dist/client/_assets/chunks/a0d00fe4816c95a8c7dffd445ef00b03-CxcTiRLJ.woff2 +0 -0
- package/dist/client/_assets/chunks/a0f199077fa1a33bc2a1e01c64de7fe6-IdgVJmZD.woff2 +0 -0
- package/dist/client/_assets/chunks/a2b0597837e382aca19919c4b74e58c8-7iVOBjzI.woff2 +0 -0
- package/dist/client/_assets/chunks/a373e85c96aa0dc303092429fb837e51-Dvmw8mbX.woff2 +0 -0
- package/dist/client/_assets/chunks/a379ada89abd750c587ded29f77e731c-CgPBsEsv.woff2 +0 -0
- package/dist/client/_assets/chunks/a4475c442c6b259354c9eda62e64e7df-TZ0c8vK-.woff2 +0 -0
- package/dist/client/_assets/chunks/a48be56ce5d3a99dc8f8331398004412-BR_ixH1W.woff2 +0 -0
- package/dist/client/_assets/chunks/a4a39b5f048671aa37c2b2a9581ab08a-EDfDYsUd.woff2 +0 -0
- package/dist/client/_assets/chunks/a534449d67561ac9b06489f64e57ad98-C355TCrD.woff2 +0 -0
- package/dist/client/_assets/chunks/a6e044424780a57610833cc856c15bf5-x1b8FE4H.woff2 +0 -0
- package/dist/client/_assets/chunks/a7c35e42a659347e490c3cb7983b2e7f-BWpA0-oz.woff2 +0 -0
- package/dist/client/_assets/chunks/a7c58070d68dc1724e9d4e781afb78db-ql27pT-6.woff2 +0 -0
- package/dist/client/_assets/chunks/a806759e72987951d6d08b7cbdf36a1b-TvLDwB_u.woff2 +0 -0
- package/dist/client/_assets/chunks/a88481ec8bc7be11cb66e46781a79bb9-Ck-r_sGx.woff2 +0 -0
- package/dist/client/_assets/chunks/a919a8c6fec6d7e8bb21177965f2e9d7-CC5uWzwd.woff2 +0 -0
- package/dist/client/_assets/chunks/a9a016d4a93409f65278327e8a8bb38d-dylrNwF8.woff2 +0 -0
- package/dist/client/_assets/chunks/aa662092cf249707123ca4d575e2764b-CSxNsTUL.woff2 +0 -0
- package/dist/client/_assets/chunks/aae1eda193285ab817a2d1b408440326-CjyjBoRm.woff2 +0 -0
- package/dist/client/_assets/chunks/ab92d41062a7644faa45f50bf384454a-Cq0X8a9H.woff2 +0 -0
- package/dist/client/_assets/chunks/accc43762ad05edfbff66ba1380d192a-B5jIykaZ.woff2 +0 -0
- package/dist/client/_assets/chunks/ad47bcd6d4663026d648c132d969318d-BYdIbDge.woff2 +0 -0
- package/dist/client/_assets/chunks/ad67113f88b59582991cb0c5d33ea19f-DOH1vcIZ.woff2 +0 -0
- package/dist/client/_assets/chunks/adb6e613fb99c6dd660b727101f554a8-DJDw_ZZK.woff2 +0 -0
- package/dist/client/_assets/chunks/adc4a98a89870ef984ee8f4b57c8a3a5-D30vw26R.woff2 +0 -0
- package/dist/client/_assets/chunks/af57a2e8c72f9ba0efb1af771d32c124-D5Zwq9pS.woff2 +0 -0
- package/dist/client/_assets/chunks/b0ae5f374e43dac992a4a5d334cebc0b-Ccoi4dPt.woff2 +0 -0
- package/dist/client/_assets/chunks/b0cb664cb2e1371efda8943c0b7dcd1c-YzGFnelF.woff2 +0 -0
- package/dist/client/_assets/chunks/b0d1cdced482352cf0d3ae58638aacb9-IunWfc6R.woff2 +0 -0
- package/dist/client/_assets/chunks/b12379ab782468d725519cd07a7d15bc-IjbydKs2.woff2 +0 -0
- package/dist/client/_assets/chunks/b320f5d185b2cff933ac549c184031c5-IYnPrIz4.woff2 +0 -0
- package/dist/client/_assets/chunks/b326a8a9c33b554db570da94f60bc380-B6dzaCQg.woff2 +0 -0
- package/dist/client/_assets/chunks/b55486f8a459c838fe329d4e79a8c211-DW8q7oGV.woff2 +0 -0
- package/dist/client/_assets/chunks/b6117ff2993b11bb1fdc7ea3588a010c-JoMYL5W_.woff2 +0 -0
- package/dist/client/_assets/chunks/b61982951bd51b724143c30dfaaa9fe9-D3KhBKl6.woff2 +0 -0
- package/dist/client/_assets/chunks/b91234c10fd8b8c8abc88e03afe66a1f-BABNh2la.woff2 +0 -0
- package/dist/client/_assets/chunks/b9317198f118a1dfd8ddf2b82ec028f3-CiMecxeH.woff2 +0 -0
- package/dist/client/_assets/chunks/ba825ae79b1a6f7e0cce5215fcb5c96f-B6EWU_D5.woff2 +0 -0
- package/dist/client/_assets/chunks/ba9c59d7dfa4494db1bb764ada81467d-D0yPcC1m.woff2 +0 -0
- package/dist/client/_assets/chunks/bab547459d514f46206e340c4bb2dc88-YnBqlGhw.woff2 +0 -0
- package/dist/client/_assets/chunks/bb0b15492b8cdbbec57c0bcfa0aa9241-BjIFbEsN.woff2 +0 -0
- package/dist/client/_assets/chunks/bc6183ac08f0fac78c46f80c10cf7c92-B81nbRb3.woff2 +0 -0
- package/dist/client/_assets/chunks/bc8ccea5abf6598cf3cfa97eb59804bb-B_7IbluG.woff2 +0 -0
- package/dist/client/_assets/chunks/bc95a792cbca6639214c9b0da13392ff-CHQe0E-D.woff2 +0 -0
- package/dist/client/_assets/chunks/bcc39eda837bb7a7a3d37c8c60fffb81-CGd1Zk6S.woff2 +0 -0
- package/dist/client/_assets/chunks/bcfa62f35731856246c146d3a6932bf3-DMDq6w4v.woff2 +0 -0
- package/dist/client/_assets/chunks/bd73264d7f98776708d5d6f3c9b78fcc-d9QWWMym.woff2 +0 -0
- package/dist/client/_assets/chunks/bed610b217d500f5975cfc9fe6157570-B5t7s1bw.woff2 +0 -0
- package/dist/client/_assets/chunks/bedc74b423b7293b6ad0bdecc61c42cc-4Nnh7peP.woff2 +0 -0
- package/dist/client/_assets/chunks/bf8901f8f11d4f433ea17dabc9370ea6-B8dkfvGn.woff2 +0 -0
- package/dist/client/_assets/chunks/bfb00d4a4c48661bd0be99f300a0faae-OxsWZ7l-.woff2 +0 -0
- package/dist/client/_assets/chunks/c0098958e20db68cab90097b5e62516f-VpjQo3vV.woff2 +0 -0
- package/dist/client/_assets/chunks/c063897793f593eb26d6ff7b7baaba18-BWeJJ1sH.woff2 +0 -0
- package/dist/client/_assets/chunks/c1b0df29ae41d764904df84e9ac83d1e-D1N934vs.woff2 +0 -0
- package/dist/client/_assets/chunks/c4143bb9f2fe77b6ccf20088a8904650-nHfYM24e.woff2 +0 -0
- package/dist/client/_assets/chunks/c42c67070cfe99cf823df92d81c7fa6e-B_a405Ez.woff2 +0 -0
- package/dist/client/_assets/chunks/c4bfaa5e50798246e3770718b7a7c84a-B-r6Y_o0.woff2 +0 -0
- package/dist/client/_assets/chunks/c4d749e45ecd5a5aed5a0bb3ebfd355d-CkqE1fRi.woff2 +0 -0
- package/dist/client/_assets/chunks/c6c2971ad1f3221f6cf84028aa0f477e-D7BZGIcY.woff2 +0 -0
- package/dist/client/_assets/chunks/c7ff3f6bbdcd5f604b7343602ab904df-Bq7UjVrZ.woff2 +0 -0
- package/dist/client/_assets/chunks/c84598999133455503042e06f4ab79cb-DIXndJX3.woff2 +0 -0
- package/dist/client/_assets/chunks/c945c62368357d05a53206620460fb30-82gFEf6n.woff2 +0 -0
- package/dist/client/_assets/chunks/c96d83978add28b356c22c4c84916733-BL4VaPIE.woff2 +0 -0
- package/dist/client/_assets/chunks/c97f41eef722121d86f55d553c056a39-CjejgQO2.woff2 +0 -0
- package/dist/client/_assets/chunks/ca62704509932d3232d62918de97af3f-CKWF-3mX.woff2 +0 -0
- package/dist/client/_assets/chunks/ca9a533988d7019597a60d4e17127e0c-ClZ6ygZM.woff2 +0 -0
- package/dist/client/_assets/chunks/cb7ccd6494256f7a2977b7c2b0225592-Cxp8XObm.woff2 +0 -0
- package/dist/client/_assets/chunks/ce022e18a1377ac509443c3c3790b431-DpH0t6Tn.woff2 +0 -0
- package/dist/client/_assets/chunks/ce41d70ce6a069a498525c9e15c45cf2-DGtgv-_b.woff2 +0 -0
- package/dist/client/_assets/chunks/cf2b28f90f47276f7e2688a65e88a101-LVbNkXHj.woff2 +0 -0
- package/dist/client/_assets/chunks/cf9cffe56636322f62b40d61130fbc5e-DNCBMqAo.woff2 +0 -0
- package/dist/client/_assets/chunks/d1f064825fa5784b5c930652bd831cce-BU6qwjp8.woff2 +0 -0
- package/dist/client/_assets/chunks/d20d8944bc0b85f5b2aae4b24f343516-oY9l-NmC.woff2 +0 -0
- package/dist/client/_assets/chunks/d2faabcedd19f016e7b21bce073c0ec8-Dv6eFCf5.woff2 +0 -0
- package/dist/client/_assets/chunks/d320171e57480510f87dbbc7d5264b0a-CcCfjaFX.woff2 +0 -0
- package/dist/client/_assets/chunks/d36644d6502527e1fff205d0c7eca434-kVBj8zy_.woff2 +0 -0
- package/dist/client/_assets/chunks/d3a72a99d365dddfbca8d017a8011368-Bgdmhl3M.woff2 +0 -0
- package/dist/client/_assets/chunks/d40ab99c7a38026f411c8f112f742b48-D7Nm7fg6.woff2 +0 -0
- package/dist/client/_assets/chunks/d42aafa0f246ad3b4c16fe96d3a3a432-CRxTqZXU.woff2 +0 -0
- package/dist/client/_assets/chunks/d4aaf23c13ae808a4bed617afd13aa07-d_T1SKe9.woff2 +0 -0
- package/dist/client/_assets/chunks/d509ee5c8241bc7c3de2039d75564fa5-BpNFD9JE.woff2 +0 -0
- package/dist/client/_assets/chunks/d675d717cd329bfd4c0524f76ae1579c-Bd5_ctoQ.woff2 +0 -0
- package/dist/client/_assets/chunks/d689b1861d7e4377dd72ad3013482612-jPsVOU3F.woff2 +0 -0
- package/dist/client/_assets/chunks/d6bb686bddfbe8f38a36a68e609a8667-C_QduS-X.woff2 +0 -0
- package/dist/client/_assets/chunks/d9020ff69a83b2a6ee1f42ae480f7db0-DLBUPMCe.woff2 +0 -0
- package/dist/client/_assets/chunks/d9047070d72a816b3dba9d40c2d85e69-LTQ42vEp.woff2 +0 -0
- package/dist/client/_assets/chunks/da04549f3f4ed28076b01b8cd710d313-CDXOeduw.woff2 +0 -0
- package/dist/client/_assets/chunks/da7af303f8c645f9a9dbae0e6e32dd35-DCkS2jqi.woff2 +0 -0
- package/dist/client/_assets/chunks/da90a9012ab2d98f759e3fa0820ef502-D0D9d1zg.woff2 +0 -0
- package/dist/client/_assets/chunks/dc6e234ded795e91f76d6647f628fbf0-IkooXcRh.woff2 +0 -0
- package/dist/client/_assets/chunks/dc8f6256445e68199540be9ade33529f-umb5tWbZ.woff2 +0 -0
- package/dist/client/_assets/chunks/dd0cfdfdac0866e66d587e2b5a9e9961-bl4ozE0c.woff2 +0 -0
- package/dist/client/_assets/chunks/de304c8a02e45ded4f8dcc479d167198-ClRu89-4.woff2 +0 -0
- package/dist/client/_assets/chunks/df10d94bea357a43313e20da5d84bd30-CmAgh2oA.woff2 +0 -0
- package/dist/client/_assets/chunks/df9568257eb29b156449fdd4bec5ec76-BMz6aLRr.woff2 +0 -0
- package/dist/client/_assets/chunks/e067cd0ed76c90cd0a93c9339253f20b-6RxCQ4jy.woff2 +0 -0
- package/dist/client/_assets/chunks/e08b07772e7bed3cec2832d43f7fd339-CQCkeKsr.woff2 +0 -0
- package/dist/client/_assets/chunks/e12150d5a39b30be8f567968c7a527b0-DjdoWzeQ.woff2 +0 -0
- package/dist/client/_assets/chunks/e34b2b141e472dc776c86fdf8eea23b0-Cjk7H-Ev.woff2 +0 -0
- package/dist/client/_assets/chunks/e444fd88f1390636e603d0d681538ac8-Bx7CPOZh.woff2 +0 -0
- package/dist/client/_assets/chunks/e53fcb2381eee345db4f6f973dd95a3e-DmkkCUWz.woff2 +0 -0
- package/dist/client/_assets/chunks/e5bd313ef81f687d398aacb11cec3069-CwBEbcji.woff2 +0 -0
- package/dist/client/_assets/chunks/e79898628283edc27180fc39d0d769c1-By2pplQz.woff2 +0 -0
- package/dist/client/_assets/chunks/e8c15be62faf978d208925e79ea6a10d-Ct5M9lTP.woff2 +0 -0
- package/dist/client/_assets/chunks/e8c364c16daa04835bf32d293d2598db-3v4Tut_d.woff2 +0 -0
- package/dist/client/_assets/chunks/e91c4d941ed9f5c2f3e27f205a3a225e-BwOJ2Lst.woff2 +0 -0
- package/dist/client/_assets/chunks/e9c566be7a5d38a9085225f7372bc82b-BCtnCVML.woff2 +0 -0
- package/dist/client/_assets/chunks/e9ebc567a711eeb29019ddae3e0ce7fe-CnNhV49O.woff2 +0 -0
- package/dist/client/_assets/chunks/eaf332445a40942928e5f5750c1c3116-qZ5LSRrj.woff2 +0 -0
- package/dist/client/_assets/chunks/eb5afb3d952b8593782caec6026514b6-BXugZF2T.woff2 +0 -0
- package/dist/client/_assets/chunks/ec86e23683052da5cfdc3b77641bd15a-BeLcbcRc.woff2 +0 -0
- package/dist/client/_assets/chunks/ecb8875a56c7b038b35432fda41ae128-BVqgNf1o.woff2 +0 -0
- package/dist/client/_assets/chunks/eda1b0cb6d1719dd9bedcf3216a9e8de-BJTfLL5z.woff2 +0 -0
- package/dist/client/_assets/chunks/edd6a4f608d04fc0351d7688cfc321e4-d3V4U40c.woff2 +0 -0
- package/dist/client/_assets/chunks/ee6fce20b420a480714607c66d7f97e5-DEtC-G5G.woff2 +0 -0
- package/dist/client/_assets/chunks/eee3836d6ac17ebb2c450bbcbc9db121-C5a2TZjQ.woff2 +0 -0
- package/dist/client/_assets/chunks/et-book-bold-line-figures-BFJr2_zv.woff +0 -0
- package/dist/client/_assets/chunks/et-book-display-italic-old-style-figures-CoeRJAe8.woff +0 -0
- package/dist/client/_assets/chunks/et-book-roman-line-figures-CaA40oOf.woff +0 -0
- package/dist/client/_assets/chunks/f1661731474b78bdf81114daf10b254f-KnMKX_U3.woff2 +0 -0
- package/dist/client/_assets/chunks/f2c58dee206ba9355046fc23d05491f7-Cm4tCWav.woff2 +0 -0
- package/dist/client/_assets/chunks/f50ac27ea4358d67fdda403c2bb52467-WCfYHde1.woff2 +0 -0
- package/dist/client/_assets/chunks/f55334112f8e8be82d65db29887a663f-vDq1zH8k.woff2 +0 -0
- package/dist/client/_assets/chunks/f5738255e92d8dd34a46d1bcdf4c4074-tpghTzL1.woff2 +0 -0
- package/dist/client/_assets/chunks/f740e93f3c0277ecc616594103bca683-C4BgW_ko.woff2 +0 -0
- package/dist/client/_assets/chunks/f7633b5af033d76ff2fb3c3c266d77c5-BCkrZxwO.woff2 +0 -0
- package/dist/client/_assets/chunks/f7d8468cba2335a83ee414ea68291bab-CVnotkZU.woff2 +0 -0
- package/dist/client/_assets/chunks/f91cd722855f4269256eae1187df64ec-DJlAx1A_.woff2 +0 -0
- package/dist/client/_assets/chunks/f9695c6c4df2bf6bc03045ff79d4f01f-DDaYGYHT.woff2 +0 -0
- package/dist/client/_assets/chunks/fa6e58ce4b52695e7ae19bbea6336ec8-B30jEpze.woff2 +0 -0
- package/dist/client/_assets/chunks/fada6eaa68ff8816afe43d2a36c5423e-DlGAWNPb.woff2 +0 -0
- package/dist/client/_assets/chunks/fbcc4bf5367218951172bdee6f77d7a6-Dax2VSCd.woff2 +0 -0
- package/dist/client/_assets/chunks/fc895f5ce66b656f4a933097bf2a8775-DjjysNdf.woff2 +0 -0
- package/dist/client/_assets/chunks/fc9ae5b600fb711f2d67e93ce768cba4-D1lx7LBz.woff2 +0 -0
- package/dist/client/_assets/chunks/fca6720fd14c467d29a90f18ef3859b9-B3btrwq3.woff2 +0 -0
- package/dist/client/_assets/chunks/fd1bb507bcbf04856eeb7f7fd47ea579-NR1nGJTt.woff2 +0 -0
- package/dist/client/_assets/chunks/fd1bceb55d3e0183ac2454b8532fec7d-D3t-v6nn.woff2 +0 -0
- package/dist/client/_assets/chunks/fd2069e6e8588c70b4f11364093b81f2-BoXhYVgw.woff2 +0 -0
- package/dist/client/_assets/chunks/{url-CG0eolsk.js → url-pLre2DM_.js} +1 -1
- package/dist/client/_assets/client-C_kImWZj.css +2 -0
- package/dist/client/_assets/client-D95FNDg5.js +272 -0
- package/dist/client/_assets/client-auth-BRFl5zQA.js +4547 -0
- package/dist/client/_assets/client-cjk-jp-DZwrTzQC.css +1 -0
- package/dist/client/_assets/client-cjk-kr-_3ZNI2ZP.css +1 -0
- package/dist/env-wCpMcNXs.js +252 -0
- package/dist/github-api-CficQztC.js +176 -0
- package/dist/github-app-F4qZ05xk.js +275 -0
- package/dist/github-sync-zohnA9qv.js +4696 -0
- package/dist/index.js +88 -2
- package/dist/node.js +71 -30
- package/dist/url-FvvgARU9.js +305 -0
- package/package.json +16 -12
- package/src/__tests__/bin/content-cli.test.ts +179 -0
- package/src/__tests__/bin/media-cli.test.ts +192 -0
- package/src/__tests__/export-hugo-build.test.ts +178 -0
- package/src/__tests__/export-import-roundtrip.test.ts +265 -0
- package/src/__tests__/export-service.test.ts +763 -510
- package/src/__tests__/helpers/export-fixtures.ts +108 -0
- package/src/__tests__/import-site-command.test.ts +358 -350
- package/src/__tests__/site-pull-media.test.ts +256 -0
- package/src/app.tsx +65 -13
- package/src/client/__tests__/collection-form-bridge.test.ts +87 -7
- package/src/client/__tests__/collection-page-actions.test.ts +4 -4
- package/src/client/__tests__/collection-picker-order.test.ts +53 -0
- package/src/client/__tests__/collection-sort-menu.test.ts +2 -2
- package/src/client/__tests__/compose-bridge.test.ts +305 -13
- package/src/client/__tests__/compose-launch.test.ts +120 -0
- package/src/client/__tests__/compose-shortcuts.test.ts +141 -0
- package/src/client/__tests__/feed-video-player.test.ts +44 -0
- package/src/client/__tests__/site-header-nav.test.ts +250 -0
- package/src/client/__tests__/sortable-list.test.ts +6 -2
- package/src/client/__tests__/thread-context.test.ts +117 -0
- package/src/client/collection-form-bridge.ts +109 -4
- package/src/client/collection-page-actions.ts +3 -1
- package/src/client/collection-picker-order.ts +104 -0
- package/src/client/components/__tests__/{jant-collection-sidebar.test.ts → jant-collection-directory.test.ts} +145 -8
- package/src/client/components/__tests__/jant-collection-form.test.ts +40 -18
- package/src/client/components/__tests__/jant-compose-dialog.test.ts +1285 -66
- package/src/client/components/__tests__/jant-compose-editor.test.ts +254 -19
- package/src/client/components/__tests__/jant-compose-fullscreen.test.ts +127 -1
- package/src/client/components/__tests__/jant-media-lightbox.test.ts +237 -0
- package/src/client/components/__tests__/jant-nav-manager.test.ts +326 -0
- package/src/client/components/__tests__/jant-post-menu.test.ts +372 -2
- package/src/client/components/__tests__/jant-settings-avatar.test.ts +61 -5
- package/src/client/components/__tests__/jant-settings-general.test.ts +29 -28
- package/src/client/components/__tests__/jant-text-preview.test.ts +206 -0
- package/src/client/components/collection-manager-types.ts +18 -1
- package/src/client/components/compose-types.ts +48 -0
- package/src/client/components/jant-collection-directory.ts +1448 -0
- package/src/client/components/jant-collection-form.ts +65 -15
- package/src/client/components/jant-command-palette.ts +544 -0
- package/src/client/components/jant-compose-dialog.ts +2490 -375
- package/src/client/components/jant-compose-editor.ts +420 -75
- package/src/client/components/jant-compose-fullscreen.ts +59 -8
- package/src/client/components/jant-media-lightbox.ts +373 -18
- package/src/client/components/jant-nav-manager.ts +624 -286
- package/src/client/components/jant-post-menu.ts +451 -126
- package/src/client/components/jant-repo-picker-types.ts +39 -0
- package/src/client/components/jant-repo-picker.ts +799 -0
- package/src/client/components/jant-settings-avatar.ts +16 -2
- package/src/client/components/jant-settings-general.ts +137 -35
- package/src/client/components/jant-text-preview.ts +239 -55
- package/src/client/components/nav-manager-types.ts +25 -9
- package/src/client/components/settings-types.ts +13 -2
- package/src/client/compose-bridge.ts +428 -68
- package/src/client/compose-launch.ts +41 -4
- package/src/client/compose-shortcuts.ts +77 -5
- package/src/client/feed-video-player.ts +374 -0
- package/src/client/image-processor.ts +53 -127
- package/src/client/media-lightbox-events.ts +1 -0
- package/src/client/media-scroll-hint.ts +66 -0
- package/src/client/multipart-upload.ts +4 -1
- package/src/client/palette-shortcuts.ts +35 -0
- package/src/client/search-rank.ts +74 -0
- package/src/client/settings-bridge.ts +7 -0
- package/src/client/site-header-nav.d.ts +1 -0
- package/src/client/site-header-nav.js +139 -51
- package/src/client/sortable-list.ts +2 -0
- package/src/client/thread-context.ts +54 -11
- package/src/client/tiptap/__tests__/block-insertion.test.ts +65 -0
- package/src/client/tiptap/__tests__/footnotes.test.ts +692 -0
- package/src/client/tiptap/__tests__/link-toolbar.test.ts +120 -4
- package/src/client/tiptap/__tests__/markdown-clipboard.test.ts +48 -0
- package/src/client/tiptap/block-insertion.ts +36 -0
- package/src/client/tiptap/bubble-menu.ts +34 -4
- package/src/client/tiptap/create-editor.ts +49 -30
- package/src/client/tiptap/embed-dialog.ts +301 -0
- package/src/client/tiptap/embed-node.ts +373 -0
- package/src/client/tiptap/embed-paste.ts +91 -0
- package/src/client/tiptap/extensions.ts +77 -28
- package/src/client/tiptap/footnotes.ts +718 -0
- package/src/client/tiptap/html-block-node.ts +222 -0
- package/src/client/tiptap/image-node.ts +49 -6
- package/src/client/tiptap/inline-image-upload.ts +200 -40
- package/src/client/tiptap/link-input-rules.ts +50 -16
- package/src/client/tiptap/link-toolbar.ts +156 -133
- package/src/client/tiptap/markdown-clipboard.ts +120 -0
- package/src/client/tiptap/more-break.ts +36 -3
- package/src/client/tiptap/paste-media.ts +6 -0
- package/src/client/tiptap/slash-commands.ts +167 -14
- package/src/client/tiptap/tab-indent.ts +184 -0
- package/src/client/tiptap/toolbar-mode.ts +15 -2
- package/src/client/tiptap/wrapping-input-rules.ts +102 -0
- package/src/client/types/sortablejs.d.ts +9 -1
- package/src/client/upload-session.ts +2 -1
- package/src/client/video-processor.ts +177 -20
- package/src/client-auth.ts +9 -1
- package/src/client-site.ts +15 -0
- package/src/client.ts +2 -0
- package/src/db/__tests__/demo-canonical-snapshot.test.ts +1 -1
- package/src/db/__tests__/migration-rehearsal.test.ts +5 -1
- package/src/db/__tests__/migrations.test.ts +25 -2
- package/src/db/backfills/0001_strip_collection_path_c_prefix.sql +11 -0
- package/src/db/backfills/0002_strip_collection_path_c_prefix_fix.sql +12 -0
- package/src/db/backfills/0003_clear_system_nav_default_labels.sql +15 -0
- package/src/db/dialect.ts +40 -0
- package/src/db/migrations/0005_busy_the_phantom.sql +39 -0
- package/src/db/migrations/0006_adorable_magdalene.sql +3 -0
- package/src/db/migrations/0007_unusual_warstar.sql +1 -0
- package/src/db/migrations/0008_nasty_lockheed.sql +1 -0
- package/src/db/migrations/0009_clear_fixer.sql +31 -0
- package/src/db/migrations/0010_futuristic_preak.sql +31 -0
- package/src/db/migrations/0011_bizarre_smasher.sql +30 -0
- package/src/db/migrations/0012_furry_thena.sql +52 -0
- package/src/db/migrations/0013_mixed_lightspeed.sql +39 -0
- package/src/db/migrations/0014_high_the_santerians.sql +41 -0
- package/src/db/migrations/0015_skinny_shinobi_shaw.sql +1 -0
- package/src/db/migrations/0016_remarkable_nicolaos.sql +17 -0
- package/src/db/migrations/0017_powerful_moonstone.sql +14 -0
- package/src/db/migrations/meta/0005_snapshot.json +1904 -0
- package/src/db/migrations/meta/0006_snapshot.json +1925 -0
- package/src/db/migrations/meta/0007_snapshot.json +1933 -0
- package/src/db/migrations/meta/0008_snapshot.json +1940 -0
- package/src/db/migrations/meta/0009_snapshot.json +1952 -0
- package/src/db/migrations/meta/0010_snapshot.json +1952 -0
- package/src/db/migrations/meta/0011_snapshot.json +1948 -0
- package/src/db/migrations/meta/0012_snapshot.json +1955 -0
- package/src/db/migrations/meta/0013_snapshot.json +1977 -0
- package/src/db/migrations/meta/0014_snapshot.json +1988 -0
- package/src/db/migrations/meta/0015_snapshot.json +1995 -0
- package/src/db/migrations/meta/0016_snapshot.json +2104 -0
- package/src/db/migrations/meta/0017_snapshot.json +2188 -0
- package/src/db/migrations/meta/_journal.json +92 -1
- package/src/db/migrations/pg/0003_motionless_norrin_radd.sql +21 -0
- package/src/db/migrations/pg/0004_nervous_captain_midlands.sql +3 -0
- package/src/db/migrations/pg/0005_romantic_mesmero.sql +1 -0
- package/src/db/migrations/pg/0006_perpetual_bruce_banner.sql +1 -0
- package/src/db/migrations/pg/0007_nav_item_placement.sql +1 -0
- package/src/db/migrations/pg/0008_yielding_frightful_four.sql +3 -0
- package/src/db/migrations/pg/0009_outstanding_ogun.sql +1 -0
- package/src/db/migrations/pg/0010_overjoyed_gertrude_yorkes.sql +28 -0
- package/src/db/migrations/pg/0011_fixed_hulk.sql +19 -0
- package/src/db/migrations/pg/0012_cute_shockwave.sql +2 -0
- package/src/db/migrations/pg/0013_bizarre_obadiah_stane.sql +1 -0
- package/src/db/migrations/pg/0014_tearful_grim_reaper.sql +16 -0
- package/src/db/migrations/pg/0015_daffy_mikhail_rasputin.sql +14 -0
- package/src/db/migrations/pg/meta/0003_snapshot.json +2482 -0
- package/src/db/migrations/pg/meta/0004_snapshot.json +2500 -0
- package/src/db/migrations/pg/meta/0005_snapshot.json +2507 -0
- package/src/db/migrations/pg/meta/0006_snapshot.json +2513 -0
- package/src/db/migrations/pg/meta/0008_snapshot.json +2524 -0
- package/src/db/migrations/pg/meta/0009_snapshot.json +2520 -0
- package/src/db/migrations/pg/meta/0010_snapshot.json +2526 -0
- package/src/db/migrations/pg/meta/0011_snapshot.json +2563 -0
- package/src/db/migrations/pg/meta/0012_snapshot.json +2573 -0
- package/src/db/migrations/pg/meta/0013_snapshot.json +2579 -0
- package/src/db/migrations/pg/meta/0014_snapshot.json +2702 -0
- package/src/db/migrations/pg/meta/0015_snapshot.json +2803 -0
- package/src/db/migrations/pg/meta/_journal.json +92 -1
- package/src/db/pg/__tests__/node.test.ts +38 -0
- package/src/db/pg/node.ts +149 -0
- package/src/db/pg/schema.ts +130 -12
- package/src/db/rehearsal-fixtures/demo-current.sql +47 -3
- package/src/db/schema.ts +139 -12
- package/src/i18n/Trans.tsx +3 -3
- package/src/i18n/__tests__/context.test.tsx +9 -6
- package/src/i18n/__tests__/detect.test.ts +65 -48
- package/src/i18n/__tests__/fallback.test.ts +40 -0
- package/src/i18n/__tests__/message-placeholders.test.ts +43 -0
- package/src/i18n/__tests__/middleware.test.ts +83 -0
- package/src/i18n/context.tsx +9 -44
- package/src/i18n/detect.ts +95 -28
- package/src/i18n/i18n.ts +41 -17
- package/src/i18n/index.ts +7 -5
- package/src/i18n/locales/{en.po → public/en.po} +298 -1151
- package/src/i18n/locales/public/en.ts +1 -0
- package/src/i18n/locales/public/zh-Hans.po +2327 -0
- package/src/i18n/locales/public/zh-Hans.ts +1 -0
- package/src/i18n/locales/public/zh-Hant.po +2327 -0
- package/src/i18n/locales/public/zh-Hant.ts +1 -0
- package/src/i18n/locales/settings/en.po +1622 -0
- package/src/i18n/locales/settings/en.ts +1 -0
- package/src/i18n/locales/settings/zh-Hans.po +1622 -0
- package/src/i18n/locales/settings/zh-Hans.ts +1 -0
- package/src/i18n/locales/settings/zh-Hant.po +1622 -0
- package/src/i18n/locales/settings/zh-Hant.ts +1 -0
- package/src/i18n/middleware.ts +37 -24
- package/src/index.ts +4 -5
- package/src/lib/__tests__/collection-groups.test.ts +80 -0
- package/src/lib/__tests__/constants.test.ts +1 -1
- package/src/lib/__tests__/csp-builder.test.ts +68 -0
- package/src/lib/__tests__/display-text.test.ts +27 -0
- package/src/lib/__tests__/embed-providers.test.ts +104 -0
- package/src/lib/__tests__/embed-render.test.ts +60 -0
- package/src/lib/__tests__/feed.test.ts +125 -63
- package/src/lib/__tests__/hosted-signin.test.ts +11 -2
- package/src/lib/__tests__/markdown-roundtrip-embed.test.ts +88 -0
- package/src/lib/__tests__/markdown-to-tiptap.test.ts +59 -0
- package/src/lib/__tests__/markdown.test.ts +47 -5
- package/src/lib/__tests__/navigation.test.ts +148 -0
- package/src/lib/__tests__/post-display.test.ts +3 -2
- package/src/lib/__tests__/post-meta.test.ts +3 -0
- package/src/lib/__tests__/resolve-config.test.ts +30 -25
- package/src/lib/__tests__/schemas.test.ts +35 -0
- package/src/lib/__tests__/slug-format.test.ts +8 -0
- package/src/lib/__tests__/summary.test.ts +400 -1
- package/src/lib/__tests__/theme.test.ts +41 -2
- package/src/lib/__tests__/timeline.test.ts +114 -26
- package/src/lib/__tests__/tiptap-render.test.ts +224 -0
- package/src/lib/__tests__/tiptap-to-markdown.test.ts +51 -0
- package/src/lib/__tests__/video-playback.test.ts +48 -0
- package/src/lib/__tests__/view.test.ts +115 -8
- package/src/lib/__tests__/worker-response-cache.test.ts +311 -0
- package/src/lib/__tests__/youtube.test.ts +99 -0
- package/src/lib/api-media.ts +55 -0
- package/src/lib/api-posts.ts +99 -0
- package/src/lib/api-search.ts +47 -0
- package/src/lib/api-settings.ts +122 -0
- package/src/lib/asset-path.ts +20 -2
- package/src/lib/collection-groups.ts +70 -0
- package/src/lib/collection-paths.ts +40 -0
- package/src/lib/constants.ts +3 -4
- package/src/lib/csp-builder.ts +99 -0
- package/src/lib/decorative-quote-mark.ts +11 -0
- package/src/lib/display-text.ts +56 -0
- package/src/lib/embed-providers.ts +289 -0
- package/src/lib/embed-render.ts +151 -0
- package/src/lib/env.ts +70 -1
- package/src/lib/excerpt.ts +11 -2
- package/src/lib/feed.ts +89 -66
- package/src/lib/footnotes.ts +146 -0
- package/src/lib/github-api.ts +423 -0
- package/src/lib/github-app-state.ts +135 -0
- package/src/lib/github-app.ts +487 -0
- package/src/lib/github-sync-queue-handler.ts +69 -0
- package/src/lib/github-sync-site-config.ts +57 -0
- package/src/lib/github-sync-trigger.ts +199 -0
- package/src/lib/github-sync-worker.ts +72 -0
- package/src/lib/hosted-signin.ts +1 -1
- package/src/lib/hugo-markdown.ts +255 -0
- package/src/lib/job-queue-cf.ts +18 -0
- package/src/lib/job-queue-db.ts +149 -0
- package/src/lib/job-queue.ts +35 -0
- package/src/lib/markdown-manager.ts +864 -0
- package/src/lib/markdown-to-tiptap.ts +4 -323
- package/src/lib/markdown.ts +16 -24
- package/src/lib/media-helpers.ts +1 -0
- package/src/lib/navigation.ts +40 -8
- package/src/lib/post-display.ts +10 -22
- package/src/lib/public-storage.ts +6 -1
- package/src/lib/render.tsx +5 -2
- package/src/lib/resolve-config.ts +23 -11
- package/src/lib/rich-image.ts +89 -0
- package/src/lib/schemas.ts +186 -12
- package/src/lib/slug-format.ts +8 -0
- package/src/lib/summary.ts +125 -18
- package/src/lib/theme.ts +119 -0
- package/src/lib/timeline.ts +91 -63
- package/src/lib/tiptap-render.ts +265 -126
- package/src/lib/tiptap-to-markdown.ts +6 -329
- package/src/lib/upload.ts +97 -6
- package/src/lib/version.ts +18 -0
- package/src/lib/video-playback.ts +73 -0
- package/src/lib/view.ts +130 -90
- package/src/lib/webhook-signature.ts +65 -0
- package/src/lib/worker-response-cache.ts +220 -0
- package/src/lib/youtube.ts +119 -0
- package/src/middleware/__tests__/onboarding.test.ts +3 -3
- package/src/middleware/__tests__/secure-headers.test.ts +28 -1
- package/src/middleware/config.ts +7 -10
- package/src/middleware/cors.ts +49 -0
- package/src/middleware/secure-headers.ts +45 -55
- package/src/node/__tests__/cli-migrate.test.ts +111 -0
- package/src/node/__tests__/cli-runtime-target.test.ts +1 -1
- package/src/node/__tests__/cli-site-token-env.test.ts +2 -2
- package/src/preset.css +316 -12
- package/src/routes/__tests__/compose.test.ts +3 -1
- package/src/routes/api/__tests__/collections.test.ts +81 -27
- package/src/routes/api/__tests__/mcp.test.ts +389 -0
- package/src/routes/api/__tests__/nav-items.test.ts +163 -2
- package/src/routes/api/__tests__/posts.test.ts +190 -0
- package/src/routes/api/__tests__/settings.test.ts +99 -3
- package/src/routes/api/__tests__/upload-multipart.test.ts +10 -2
- package/src/routes/api/__tests__/upload.test.ts +132 -0
- package/src/routes/api/__tests__/uploads.test.ts +5 -3
- package/src/routes/api/collections.ts +67 -26
- package/src/routes/api/custom-urls.ts +1 -0
- package/src/routes/api/export.ts +8 -4
- package/src/routes/api/github-sync.tsx +445 -0
- package/src/routes/api/internal/__tests__/sites.test.ts +45 -2
- package/src/routes/api/internal/sites.ts +2 -0
- package/src/routes/api/internal/text-attachments.ts +60 -0
- package/src/routes/api/internal/uploads.ts +5 -1
- package/src/routes/api/mcp.ts +30 -0
- package/src/routes/api/nav-items.ts +30 -11
- package/src/routes/api/palette.ts +17 -0
- package/src/routes/api/posts.ts +37 -106
- package/src/routes/api/public/__tests__/posts.test.ts +372 -0
- package/src/routes/api/public/posts.ts +302 -0
- package/src/routes/api/search.ts +1 -47
- package/src/routes/api/settings.ts +44 -58
- package/src/routes/api/upload-multipart.ts +15 -5
- package/src/routes/api/upload.ts +62 -49
- package/src/routes/api/uploads.ts +1 -0
- package/src/routes/auth/__tests__/hosted-sso.test.ts +33 -0
- package/src/routes/auth/__tests__/setup.test.ts +29 -4
- package/src/routes/auth/hosted-sso-expired-page.tsx +89 -0
- package/src/routes/auth/hosted-sso.ts +42 -1
- package/src/routes/auth/reset.tsx +46 -32
- package/src/routes/auth/setup.tsx +53 -43
- package/src/routes/auth/signin.tsx +34 -24
- package/src/routes/compose.tsx +114 -1
- package/src/routes/dash/__tests__/font-theme.test.ts +6 -27
- package/src/routes/dash/__tests__/settings-avatar.test.ts +2 -3
- package/src/routes/dash/custom-urls.tsx +250 -112
- package/src/routes/dash/settings.tsx +1163 -70
- package/src/routes/feed/__tests__/{rss.test.ts → feed.test.ts} +62 -123
- package/src/routes/feed/feed.ts +386 -0
- package/src/routes/feed/manifest.ts +67 -0
- package/src/routes/feed/sitemap.ts +11 -2
- package/src/routes/pages/__tests__/collection-routing.test.ts +176 -0
- package/src/routes/pages/__tests__/collections.test.ts +2 -3
- package/src/routes/pages/__tests__/featured.test.ts +2 -3
- package/src/routes/pages/archive.tsx +523 -127
- package/src/routes/pages/collection.tsx +265 -59
- package/src/routes/pages/collections.tsx +5 -1
- package/src/routes/pages/home.tsx +2 -2
- package/src/routes/pages/latest.tsx +3 -3
- package/src/routes/pages/page.tsx +221 -3
- package/src/routes/pages/partials.tsx +5 -0
- package/src/routes/pages/search.tsx +17 -1
- package/src/routes/pages/theme-sample.tsx +1 -2
- package/src/runtime/__tests__/node.test.ts +1 -1
- package/src/runtime/__tests__/readiness.test.ts +89 -0
- package/src/runtime/readiness.ts +129 -0
- package/src/runtime/site.ts +9 -1
- package/src/services/__tests__/collection.test.ts +181 -53
- package/src/services/__tests__/github-app-installations.test.ts +181 -0
- package/src/services/__tests__/github-sync-classify.test.ts +189 -0
- package/src/services/__tests__/github-sync-push.test.ts +159 -0
- package/src/services/__tests__/media.test.ts +444 -7
- package/src/services/__tests__/navigation.test.ts +271 -14
- package/src/services/__tests__/post-timeline.test.ts +85 -17
- package/src/services/__tests__/post.test.ts +118 -10
- package/src/services/__tests__/settings.test.ts +43 -21
- package/src/services/auth.ts +2 -2
- package/src/services/bootstrap.ts +10 -7
- package/src/services/collection.ts +644 -191
- package/src/services/custom-url.ts +34 -7
- package/src/services/export-theme/assets/client-site.css +2 -0
- package/src/services/export-theme/assets/client-site.js +145 -0
- package/src/services/export-theme/layouts/_default/alias.html +49 -0
- package/src/services/export-theme/layouts/_default/baseof.html +21 -0
- package/src/services/export-theme/layouts/_default/list.html +104 -0
- package/src/services/export-theme/layouts/_default/rss.xml +160 -0
- package/src/services/export-theme/layouts/_default/single.html +15 -0
- package/src/services/export-theme/layouts/archive/list.html +31 -0
- package/src/services/export-theme/layouts/collection/single.html +19 -0
- package/src/services/export-theme/layouts/collections/list.html +111 -0
- package/src/services/export-theme/layouts/featured/list.html +28 -0
- package/src/services/export-theme/layouts/index.html +41 -0
- package/src/services/export-theme/layouts/partials/feed-post-content.xml +107 -0
- package/src/services/export-theme/layouts/partials/footer.html +32 -0
- package/src/services/export-theme/layouts/partials/head.html +52 -0
- package/src/services/export-theme/layouts/partials/header.html +115 -0
- package/src/services/export-theme/layouts/partials/media-gallery.html +246 -0
- package/src/services/export-theme/layouts/partials/pagination.html +55 -0
- package/src/services/export-theme/layouts/partials/post-card.html +127 -0
- package/src/services/export-theme/layouts/partials/reply.html +91 -0
- package/src/services/export-theme/layouts/partials/thread-preview.html +82 -0
- package/src/services/export-theme/layouts/post/list.html +129 -0
- package/src/services/export-theme/styles/main.css +1981 -0
- package/src/services/export-theme/theme.toml +12 -0
- package/src/services/export.ts +1365 -2412
- package/src/services/github-app-installations.ts +302 -0
- package/src/services/github-sync.ts +769 -0
- package/src/services/index.ts +15 -0
- package/src/services/mcp.ts +1324 -0
- package/src/services/media.ts +336 -25
- package/src/services/navigation.ts +115 -23
- package/src/services/path.ts +129 -28
- package/src/services/post.ts +779 -207
- package/src/services/search.ts +3 -0
- package/src/services/settings.ts +29 -15
- package/src/services/site-admin.ts +26 -6
- package/src/services/upload-session.ts +69 -34
- package/src/style-cjk-jp.css +3 -0
- package/src/style-cjk-kr.css +3 -0
- package/src/styles/components.css +160 -59
- package/src/styles/fonts/et-book/et-book-bold-line-figures.woff +0 -0
- package/src/styles/fonts/et-book/et-book-display-italic-old-style-figures.woff +0 -0
- package/src/styles/fonts/et-book/et-book-roman-line-figures.woff +0 -0
- package/src/styles/fonts/et-book.css +31 -0
- package/src/styles/fonts/latin.css +1 -0
- package/src/styles/fonts/noto-serif-jp/400/057a6a98bda7fe57105ddaa99ec82015.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/0acd1fe2b2ea1ad1bfee7ae1fa139d27.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/0c2ab6b295e55f356f8020d4e7747522.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/0c5f9492af03a4fa42c784de94649de1.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/0d9a936885a4c39077438effd3779cbd.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/0e645da524f7cfc0e8c3c03fb2b08428.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/135e83b403475c5dc9e49b43501a5b84.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/13b2c53b30e6a3e4de7132dbc18dbdfc.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/15d95680dc31cc6ce20e0a5464106dc4.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/1733f27476507ca68b68a803bc533cc2.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/188c2db794f3dd7a45889ddbc81da9bb.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/1cf737900dd49c2e88f1b3221a82a602.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/233d3a685ee18276b319363474599d47.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/284b53bbefb06924cf236d24c8ed5641.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/2a56eaf19d1d38a6b57e2a388f733676.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/2abfbab82b6a7c04426afc054d2464da.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/2e6f4bb71ef6b38765d51acc5a79f638.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/31194d303a67561926a544ed0e072aee.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/3623d96698132c61e861f984ce11cc23.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/39211b02f24c69cbd1b54f6d41b01933.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/3e24063b19abd2b051af986a6870046d.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/4410f876d27c9821839474b6b1059fd7.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/479329a39a3eb6c0047e6b0981919855.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/527ff336279465617aafbafe1a830632.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/56b40518ea0608e62826bd44ee27f5f9.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/5acc7f736217259db79a42bf44241c48.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/5c05f8b75c9d7f25b3c04ca711cf43b3.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/5e0124c7265f1b4cf0fc797b94efbebc.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/615a7e0d63f257109d599b2a1977de68.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/61a2c80d0c924d5a6187c02e8d1d1642.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/62fc94f8d4c5a750b7f25e7387539910.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/639c7c6b0b0c27c738702741cfa4b8c0.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/68a3a4bf337f8a0722be76676e20b850.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/6abdd163d2c4b85698db8aa1ce149361.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/73b794d885b88f7befb7ea8ab1780a15.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/743f290baf027d4626a86e22f3d44600.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/757019c01c5e2c2b0f54293cea3b5636.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/76f117a3baacda304a71965a17266a13.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/77747f17625a259fb405b7bbdd84ac4b.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/788498548ddfb710d6ef3c7bff79fa97.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/78ea6c40923ce95367e3517dd1e5a849.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/7f9a6c9286b68de9c72b0024f7beeb40.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/823d1bb11097331238d103c7f72138dc.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/888ba53510213d5d1f6a7deb60e569b6.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/892aa49b2529c89bb4076d4aa51fe30f.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/95ff41191c76ef893ac70a1043e95e44.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/96c75862c8cec51a7c05ff025fea86cd.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/9b21e8244f5930c48ad5073f83777b6c.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/9fce02d1a09f464c36c9fcfb14a354c5.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/a0a6755c7e3f9e4cf03387027dd9f16c.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/a4475c442c6b259354c9eda62e64e7df.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/a4a39b5f048671aa37c2b2a9581ab08a.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/a534449d67561ac9b06489f64e57ad98.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/a919a8c6fec6d7e8bb21177965f2e9d7.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/ad67113f88b59582991cb0c5d33ea19f.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/adb6e613fb99c6dd660b727101f554a8.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/adc4a98a89870ef984ee8f4b57c8a3a5.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/b12379ab782468d725519cd07a7d15bc.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/b55486f8a459c838fe329d4e79a8c211.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/bb0b15492b8cdbbec57c0bcfa0aa9241.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/bedc74b423b7293b6ad0bdecc61c42cc.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/bfb00d4a4c48661bd0be99f300a0faae.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/c1b0df29ae41d764904df84e9ac83d1e.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/c42c67070cfe99cf823df92d81c7fa6e.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/c4d749e45ecd5a5aed5a0bb3ebfd355d.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/c96d83978add28b356c22c4c84916733.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/cb7ccd6494256f7a2977b7c2b0225592.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/ce41d70ce6a069a498525c9e15c45cf2.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/d509ee5c8241bc7c3de2039d75564fa5.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/d675d717cd329bfd4c0524f76ae1579c.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/dc8f6256445e68199540be9ade33529f.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/e8c15be62faf978d208925e79ea6a10d.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/e91c4d941ed9f5c2f3e27f205a3a225e.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/e9c566be7a5d38a9085225f7372bc82b.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/e9ebc567a711eeb29019ddae3e0ce7fe.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/ecb8875a56c7b038b35432fda41ae128.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/f1661731474b78bdf81114daf10b254f.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/f2c58dee206ba9355046fc23d05491f7.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/f50ac27ea4358d67fdda403c2bb52467.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/f55334112f8e8be82d65db29887a663f.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/f740e93f3c0277ecc616594103bca683.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/f7633b5af033d76ff2fb3c3c266d77c5.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/f7d8468cba2335a83ee414ea68291bab.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/fc9ae5b600fb711f2d67e93ce768cba4.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/400/fd1bceb55d3e0183ac2454b8532fec7d.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/02611a045a7fe83a12014e3debc9f731.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/0f5e1a18987dbc84ca05188c129e1936.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/112743a4ab5fdd1498dfdf2b11336380.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/1211f03d3ff5759a702631445793f60e.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/147b24c2f08d03bbed30887d4cb3311c.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/16663e567f81f4725a1522f37e18f71f.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/1824321da801e6257b902f3d1d09054c.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/1a3a92c7c060a71a6c35819b9ebcdbb9.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/1fba7ec0e412e911bf31841de5a8a4e4.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/28a97af9ab9d38983d20f39ff09840e1.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/2bfaadaf3479c72286248e6de0be0ec9.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/2c8c55e4cec85ce77e95cac9d330f5cf.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/2ed9981d2e8983365bd051159b976b6d.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/2f4c633e923ba30c6ba376367379fc91.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/349965eee0a9b6c984a319ab96a4ece9.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/36cda3eae13370b934bba4429fab9078.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/3aa13f1843d7c8fa16109b6395a9a29d.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/3e2c06bdd9dcab29aeaeb0cfb7fa608a.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/424123f9371ba357087363263eeafcda.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/43b3bbf43055c3e65db9cdf2c5b18c1c.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/44704471b60c18b3ecec5300a88f1102.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/46604090efbb99c2db1800928af0a239.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/46998df85d31e629c0142f0556f5e7c5.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/49902f1c41b281f8eb3771abdd4dccb8.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/4db4f31a16965baa42cb7dad667a8f04.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/572b9e28f1e6d89b765a16d809db84a1.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/5921cef36750ff6092d94b83a802823b.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/59e95d8b5332dcdae894a19946ab767d.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/5ec349ff62b9ee5fe0c6dae867704dc4.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/601f812e8b1eafecd5ba585a6a6d7962.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/6025ddaf99d86cc8bfd781006b19fbd6.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/60f6e28b3f0400b0e8fe32c3c7116102.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/64a404d675f1d726f0891b7a80794595.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/7158022889c6c177062ac85036e7af10.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/7e38ca789a9e76ac91d9256374e154f0.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/815a0b797465190f60d8b1a04656c42e.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/8726558cf297cbda831cc19514897205.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/8855472f3c02f6c7ebb3216617ebe4af.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/8e231d707f0c4f8e3cde90a6b52a79aa.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/9064c12fd72c7aba235d8c3881755b91.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/911b9e53e9814de2998c60bf3115f560.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/92fdc376bce277874e75db666f175b44.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/930a23430f0eb64480d7fe5f82834e21.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/93bed0e5f2dd5a21cf73304fcfbc149d.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/93f3ea6918533d96d9c252378b9a4af0.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/95a0951d2a2722ff773a1a45e8c474d6.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/982cd1765ca6bbb3e6547e47834d5148.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/9b0c3caac458c7bc9c9133e40405ddea.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/9f3bdab4025dc7c5ba1a5871e62e8918.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/a00e94d4f04df6aa659db9c4954c7efe.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/a2b0597837e382aca19919c4b74e58c8.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/a373e85c96aa0dc303092429fb837e51.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/a6e044424780a57610833cc856c15bf5.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/a7c58070d68dc1724e9d4e781afb78db.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/accc43762ad05edfbff66ba1380d192a.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/ad47bcd6d4663026d648c132d969318d.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/af57a2e8c72f9ba0efb1af771d32c124.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/b0ae5f374e43dac992a4a5d334cebc0b.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/b91234c10fd8b8c8abc88e03afe66a1f.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/b9317198f118a1dfd8ddf2b82ec028f3.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/ba825ae79b1a6f7e0cce5215fcb5c96f.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/bc6183ac08f0fac78c46f80c10cf7c92.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/bc8ccea5abf6598cf3cfa97eb59804bb.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/bc95a792cbca6639214c9b0da13392ff.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/bcfa62f35731856246c146d3a6932bf3.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/c063897793f593eb26d6ff7b7baaba18.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/c6c2971ad1f3221f6cf84028aa0f477e.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/c97f41eef722121d86f55d553c056a39.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/ca62704509932d3232d62918de97af3f.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/d1f064825fa5784b5c930652bd831cce.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/d2faabcedd19f016e7b21bce073c0ec8.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/d320171e57480510f87dbbc7d5264b0a.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/d3a72a99d365dddfbca8d017a8011368.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/d42aafa0f246ad3b4c16fe96d3a3a432.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/d4aaf23c13ae808a4bed617afd13aa07.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/d6bb686bddfbe8f38a36a68e609a8667.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/d9020ff69a83b2a6ee1f42ae480f7db0.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/da90a9012ab2d98f759e3fa0820ef502.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/df10d94bea357a43313e20da5d84bd30.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/e34b2b141e472dc776c86fdf8eea23b0.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/e444fd88f1390636e603d0d681538ac8.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/e79898628283edc27180fc39d0d769c1.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/eaf332445a40942928e5f5750c1c3116.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/f91cd722855f4269256eae1187df64ec.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/fc895f5ce66b656f4a933097bf2a8775.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/fca6720fd14c467d29a90f18ef3859b9.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/700/fd1bb507bcbf04856eeb7f7fd47ea579.woff2 +0 -0
- package/src/styles/fonts/noto-serif-jp/noto-serif-jp.css +3349 -0
- package/src/styles/fonts/noto-serif-kr/400/033466ef683afe931f7f520cfb42d928.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/05da12edb9d52210581dc6ec4541031f.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/0968e4861204b51f62a2f8e9f15dd5e0.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/0d5dec931dc885f07fe5cd5af8bed675.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/1076f0f6f66d28d7a2f16427faad4413.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/12ef1ba76bd20b004b865266a1aa70b3.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/152395634a207579552f8cb54db88599.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/1a08931435f885e707edb85978ea3bb6.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/31a197213ae61d7043c81013f52d10d6.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/37dbd564820cce2f7b3331e442da0df3.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/37dc8505b20b37a2477a9121b16d44a7.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/3ac0a07878cacdc98bb889f40f5970d3.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/491bbba374093fff045f55803a22bfef.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/4d38e56738156625329d93bd5c8cc74a.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/57e9a86651366c1ba299e47aa7e358c2.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/57f89adeae55aa7fe2add3fc1801ce03.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/5df9ce98c75f8c50fb4fff7f01a23925.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/60020a830d809c26970cf8e48ba1eeda.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/60bcfa3ea7446eb42394aab02d28be40.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/63fafcb069520613d0ea35ad3e6b1e42.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/65a60d87c64228d258a123cbe85f5f31.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/6968e889e18891d912809fe484c2e745.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/70714891ad3fbfc3d5f10a8669dacc5a.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/761d84afca8d7f34eebefe538adba827.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/76e07530323418ec723c5d7634c9bcca.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/773819b7b9b8fd404a929867c0fd677e.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/7817dd16805145d8538ad57590f69f5a.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/7b59f0ec7792b18458dc5a361e37884c.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/7c3945788a689a69356c1a622d69d48b.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/835b6505bb9eea9678925a1fa885353d.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/8b5c9ef81159f31d2ab35f45ca4373e0.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/8b91c7c2ed390f1278b9befa3aa87233.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/8fb45117a62d92dce44a80f0b729ead5.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/90b7848e9b1623b77bdcf155e90b839c.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/985d4d41afa0934a4eb2de35473fb9a2.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/9bb38fd05201de666b88b82d56a386f7.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/9eff2ab2a9d2ced47ab761bf6fdb11ec.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/9f1963fe8d4d6878d717d872a8f3fdb5.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/a0d00fe4816c95a8c7dffd445ef00b03.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/a0f199077fa1a33bc2a1e01c64de7fe6.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/a7c35e42a659347e490c3cb7983b2e7f.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/aa662092cf249707123ca4d575e2764b.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/aae1eda193285ab817a2d1b408440326.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/b0cb664cb2e1371efda8943c0b7dcd1c.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/b0d1cdced482352cf0d3ae58638aacb9.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/b320f5d185b2cff933ac549c184031c5.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/ba9c59d7dfa4494db1bb764ada81467d.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/bab547459d514f46206e340c4bb2dc88.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/bcc39eda837bb7a7a3d37c8c60fffb81.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/bd73264d7f98776708d5d6f3c9b78fcc.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/bed610b217d500f5975cfc9fe6157570.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/bf8901f8f11d4f433ea17dabc9370ea6.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/c4143bb9f2fe77b6ccf20088a8904650.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/c7ff3f6bbdcd5f604b7343602ab904df.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/c945c62368357d05a53206620460fb30.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/ce022e18a1377ac509443c3c3790b431.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/cf9cffe56636322f62b40d61130fbc5e.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/d20d8944bc0b85f5b2aae4b24f343516.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/d36644d6502527e1fff205d0c7eca434.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/d40ab99c7a38026f411c8f112f742b48.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/dc6e234ded795e91f76d6647f628fbf0.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/dd0cfdfdac0866e66d587e2b5a9e9961.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/de304c8a02e45ded4f8dcc479d167198.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/e8c364c16daa04835bf32d293d2598db.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/ec86e23683052da5cfdc3b77641bd15a.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/eda1b0cb6d1719dd9bedcf3216a9e8de.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/ee6fce20b420a480714607c66d7f97e5.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/eee3836d6ac17ebb2c450bbcbc9db121.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/f5738255e92d8dd34a46d1bcdf4c4074.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/fa6e58ce4b52695e7ae19bbea6336ec8.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/400/fd2069e6e8588c70b4f11364093b81f2.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/04b8bde59cff68eeee74fb1914eb09c7.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/05ac821472e235943ed1435e4bb8ecad.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/074c1f8483d5a4d8c45c8c5f3e4cbb32.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/1380210a722ac9aeef54005ad7b015c9.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/17c7f5d0a45e92ede0e5dec3a2c77efa.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/1be602ad456b0d75902d352116cb35fd.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/2612c60f9dc5459ac42763591240a1d6.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/2ab8cf1f23a5ac7939a7876054e711a7.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/34e6750e00c3a911ef87dc66b336594d.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/36f3df4730cfca4fc77fe52b52e6a126.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/37887deb7a9c466cf2af6ee7ff372ea6.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/3aba89c4d4281553078de4622b498cbb.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/3d88558097559d775231194d43745ba7.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/3dc3e8c35524cad2d1236f3393104ccf.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/45140742dfa8686b58db2899ce89f89a.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/469d2754e315e77270c12fa0ab28026c.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/4c0760284569b87d8f2290c324953973.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/4cba92c942694bdc479bc54101bb1aa4.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/4e7d263c30bb48604069a3b4404d4eeb.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/5279c7e465d9871edf51fd02e691eee7.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/54bfdb6f21f9d6191e5100580239e14f.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/56be5e32fd01668fe5ba814d94905839.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/615b38e0b5bb3ea68426f44f47706e6f.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/65e9c4585d71bf48a5c62f367010da16.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/6b75213eb0be40ce84241eb2bb438a2e.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/7520ca6ca8c60eb1e62d50e71c8d30f1.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/759a647b77791b1e98f99bc0ab5317a7.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/76e51630143b95b6322ef93ad330da7a.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/79aa7c8c842c4a27cf57c0a3a1ffca5a.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/7cc72fd2c9105560422b6a67c6162945.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/7d0ea0690e432462f4d05a23d720ec19.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/7dffa5c1bec57e0903fd62357401ff1a.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/82f6ccc063960eed1cdfd1d61ada8862.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/845b4b67564d62cf5cad242f7ac08ea5.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/84c8e7bc0931008ed91f44ed12dfea94.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/887a11290ba78b1e66c6d2f67043005e.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/88db1d042074fb6e66821ffc10941930.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/8dc18c0cebe6aa4bf4c45dbb831048ab.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/919a879bd2d580d8491a31a449390689.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/91da6cb174bebfb96976e2f1316be2fe.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/934dfdbed2bb2c4b6129199d699a34fa.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/97d7a17234f2b5030ae9697ae00aded2.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/995c4fda62d25c3b79dd5987737df6ae.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/9d0afa53dc2f92ba42024f55f11f6779.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/9e13a47242926f1cd7d68c08d9ef8889.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/a379ada89abd750c587ded29f77e731c.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/a48be56ce5d3a99dc8f8331398004412.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/a806759e72987951d6d08b7cbdf36a1b.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/a88481ec8bc7be11cb66e46781a79bb9.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/a9a016d4a93409f65278327e8a8bb38d.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/ab92d41062a7644faa45f50bf384454a.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/b326a8a9c33b554db570da94f60bc380.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/b6117ff2993b11bb1fdc7ea3588a010c.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/b61982951bd51b724143c30dfaaa9fe9.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/c0098958e20db68cab90097b5e62516f.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/c4bfaa5e50798246e3770718b7a7c84a.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/c84598999133455503042e06f4ab79cb.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/ca9a533988d7019597a60d4e17127e0c.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/cf2b28f90f47276f7e2688a65e88a101.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/d689b1861d7e4377dd72ad3013482612.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/d9047070d72a816b3dba9d40c2d85e69.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/da04549f3f4ed28076b01b8cd710d313.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/da7af303f8c645f9a9dbae0e6e32dd35.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/df9568257eb29b156449fdd4bec5ec76.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/e067cd0ed76c90cd0a93c9339253f20b.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/e08b07772e7bed3cec2832d43f7fd339.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/e12150d5a39b30be8f567968c7a527b0.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/e53fcb2381eee345db4f6f973dd95a3e.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/e5bd313ef81f687d398aacb11cec3069.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/eb5afb3d952b8593782caec6026514b6.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/edd6a4f608d04fc0351d7688cfc321e4.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/f9695c6c4df2bf6bc03045ff79d4f01f.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/fada6eaa68ff8816afe43d2a36c5423e.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/700/fbcc4bf5367218951172bdee6f77d7a6.woff2 +0 -0
- package/src/styles/fonts/noto-serif-kr/noto-serif-kr.css +2601 -0
- package/src/styles/site-media.css +823 -0
- package/src/styles/tokens.css +292 -21
- package/src/styles/ui.css +4217 -1869
- package/src/types/bindings.ts +3 -1
- package/src/types/config.ts +139 -9
- package/src/types/constants.ts +46 -11
- package/src/types/entities.ts +24 -8
- package/src/types/operations.ts +80 -1
- package/src/types/props.ts +12 -3
- package/src/types/raw-assets.d.ts +39 -0
- package/src/types/views.ts +28 -7
- package/src/ui/__tests__/color-themes.test.ts +7 -40
- package/src/ui/__tests__/font-themes.test.ts +30 -11
- package/src/ui/color-themes.ts +311 -270
- package/src/ui/compose/ComposeDialog.tsx +712 -394
- package/src/ui/compose/ComposePrompt.tsx +15 -10
- package/src/ui/dash/ActionButtons.tsx +27 -18
- package/src/ui/dash/DangerZone.tsx +15 -10
- package/src/ui/dash/FormatBadge.tsx +21 -8
- package/src/ui/dash/StatusBadge.tsx +33 -22
- package/src/ui/dash/appearance/AdvancedContent.tsx +44 -30
- package/src/ui/dash/appearance/CodeInjectionContent.tsx +164 -0
- package/src/ui/dash/appearance/ColorThemeContent.tsx +127 -160
- package/src/ui/dash/appearance/FontThemeContent.tsx +20 -15
- package/src/ui/dash/appearance/NavigationContent.tsx +368 -225
- package/src/ui/dash/appearance/__tests__/NavigationContent.test.tsx +54 -0
- package/src/ui/dash/settings/AccountContent.tsx +34 -23
- package/src/ui/dash/settings/AccountMenuContent.tsx +226 -137
- package/src/ui/dash/settings/ApiTokensContent.tsx +122 -79
- package/src/ui/dash/settings/AvatarContent.tsx +73 -45
- package/src/ui/dash/settings/DeleteAccountContent.tsx +106 -66
- package/src/ui/dash/settings/GeneralContent.tsx +274 -157
- package/src/ui/dash/settings/GitHubSyncContent.tsx +558 -0
- package/src/ui/dash/settings/SessionsContent.tsx +79 -38
- package/src/ui/dash/settings/SettingsRootContent.tsx +209 -109
- package/src/ui/dash/settings/__tests__/AccountMenuContent.test.tsx +67 -0
- package/src/ui/dash/settings/__tests__/GeneralContent.test.tsx +75 -0
- package/src/ui/feed/CuratedThreadPreview.tsx +24 -14
- package/src/ui/feed/LinkCard.tsx +116 -84
- package/src/ui/feed/LinkPreview.tsx +75 -0
- package/src/ui/feed/NoteCard.tsx +60 -16
- package/src/ui/feed/PostStatusBadges.tsx +15 -0
- package/src/ui/feed/QuoteCard.tsx +10 -3
- package/src/ui/feed/ThreadPreview.tsx +62 -36
- package/src/ui/feed/TimelineFeed.tsx +2 -1
- package/src/ui/feed/__tests__/thread-preview.test.ts +220 -11
- package/src/ui/feed/__tests__/timeline-cards.test.ts +186 -5
- package/src/ui/feed/thread-preview-state.ts +23 -10
- package/src/ui/font-themes.ts +57 -97
- package/src/ui/layouts/BaseLayout.tsx +221 -136
- package/src/ui/layouts/SiteLayout.tsx +431 -143
- package/src/ui/layouts/__tests__/BaseLayout.test.tsx +76 -6
- package/src/ui/layouts/__tests__/SiteLayout.test.tsx +76 -0
- package/src/ui/pages/ArchivePage.tsx +320 -207
- package/src/ui/pages/BrandPage.tsx +499 -341
- package/src/ui/pages/CollectionEditorPage.tsx +50 -30
- package/src/ui/pages/CollectionPage.tsx +201 -61
- package/src/ui/pages/CollectionsPage.tsx +27 -18
- package/src/ui/pages/ComposePage.tsx +15 -10
- package/src/ui/pages/FeaturedPage.tsx +16 -11
- package/src/ui/pages/HomePage.tsx +15 -10
- package/src/ui/pages/PostPage.tsx +5 -1
- package/src/ui/pages/SearchPage.tsx +93 -43
- package/src/ui/pages/ThemeSamplePage.tsx +758 -520
- package/src/ui/pages/__tests__/ArchivePage.test.tsx +72 -0
- package/src/ui/shared/CollectionDirectory.tsx +232 -37
- package/src/ui/shared/CollectionsManager.tsx +155 -75
- package/src/ui/shared/DecorativeQuoteMark.tsx +12 -9
- package/src/ui/shared/MediaGallery.tsx +350 -256
- package/src/ui/shared/Pagination.tsx +36 -25
- package/src/ui/shared/PostFooter.tsx +139 -96
- package/src/ui/shared/__tests__/media-gallery.test.ts +27 -0
- package/src/ui/shared/__tests__/navigation-labels.test.ts +79 -28
- package/src/ui/shared/__tests__/post-footer.test.ts +42 -17
- package/src/ui/shared/collection-management-labels.ts +109 -33
- package/src/ui/shared/navigation-labels.ts +78 -8
- package/bin/lib/site-localize-media.js +0 -427
- package/dist/client/_assets/client-auth.js +0 -3251
- package/dist/client/_assets/client.css +0 -2
- package/dist/client/_assets/client.js +0 -380
- package/src/__tests__/site-localize-media.test.ts +0 -150
- package/src/client/components/jant-collection-sidebar.ts +0 -803
- package/src/i18n/locales/en.ts +0 -1
- package/src/i18n/locales/zh-Hans.po +0 -3183
- package/src/i18n/locales/zh-Hans.ts +0 -1
- package/src/i18n/locales/zh-Hant.po +0 -3183
- package/src/i18n/locales/zh-Hant.ts +0 -1
- package/src/routes/feed/rss.ts +0 -216
- package/src/types/lingui-react-macro.d.ts +0 -34
- /package/dist/client/_assets/chunks/{heic-to-XcUDQvtx.js → heic-to-DUUaO23q.js} +0 -0
- /package/dist/client/_assets/chunks/{module-ChVQstFd.js → module-DcsAZQZ_.js} +0 -0
- /package/dist/client/_assets/chunks/{native-CR5HLOyf.js → native-DpcrFAPh.js} +0 -0
- /package/dist/client/_assets/{client-cjk.css → client-cjk-B7Z0snDu.css} +0 -0
- /package/dist/client/_assets/{client-cjk-tc.css → client-cjk-tc-BesJYrb2.css} +0 -0
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { Hono, type Context } from "hono";
|
|
10
|
+
import { getCookie, setCookie } from "hono/cookie";
|
|
10
11
|
import { msg } from "@lingui/core/macro";
|
|
11
12
|
import { z } from "zod";
|
|
12
13
|
import type { Bindings } from "../../types.js";
|
|
@@ -36,8 +37,13 @@ import { NavigationContent } from "../../ui/dash/appearance/NavigationContent.js
|
|
|
36
37
|
import { ColorThemeContent } from "../../ui/dash/appearance/ColorThemeContent.js";
|
|
37
38
|
import { FontThemeContent } from "../../ui/dash/appearance/FontThemeContent.js";
|
|
38
39
|
import { AdvancedContent } from "../../ui/dash/appearance/AdvancedContent.js";
|
|
40
|
+
import { CodeInjectionContent } from "../../ui/dash/appearance/CodeInjectionContent.js";
|
|
39
41
|
import { ApiTokensContent } from "../../ui/dash/settings/ApiTokensContent.js";
|
|
40
42
|
import { DeleteAccountContent } from "../../ui/dash/settings/DeleteAccountContent.js";
|
|
43
|
+
import {
|
|
44
|
+
GitHubSyncContent,
|
|
45
|
+
type GitHubSyncStatus,
|
|
46
|
+
} from "../../ui/dash/settings/GitHubSyncContent.js";
|
|
41
47
|
import { toAbsoluteSiteUrl, toPublicPath } from "../../lib/url.js";
|
|
42
48
|
import { parseValidated, UpdateSiteSettingsSchema } from "../../lib/schemas.js";
|
|
43
49
|
import {
|
|
@@ -47,6 +53,27 @@ import {
|
|
|
47
53
|
getHostedControlPlaneSiteDeleteUrl,
|
|
48
54
|
} from "../../lib/hosted-signin.js";
|
|
49
55
|
import { syncHostedControlPlaneSiteAvatar } from "../../lib/hosted-control-plane-sync.js";
|
|
56
|
+
import {
|
|
57
|
+
getGitHubAppConfig,
|
|
58
|
+
getHostedControlPlaneSsoSecret,
|
|
59
|
+
} from "../../lib/env.js";
|
|
60
|
+
import {
|
|
61
|
+
buildInstallUrl,
|
|
62
|
+
getInstallation,
|
|
63
|
+
listInstallationReposPage,
|
|
64
|
+
searchInstallationRepos,
|
|
65
|
+
} from "../../lib/github-app.js";
|
|
66
|
+
import {
|
|
67
|
+
isSyncPending,
|
|
68
|
+
markSyncPending,
|
|
69
|
+
runBackgroundSync,
|
|
70
|
+
} from "../../lib/github-sync-trigger.js";
|
|
71
|
+
import { buildSyncSiteConfig } from "../../lib/github-sync-site-config.js";
|
|
72
|
+
import {
|
|
73
|
+
generateInstallNonce,
|
|
74
|
+
signInstallState,
|
|
75
|
+
verifyInstallState,
|
|
76
|
+
} from "../../lib/github-app-state.js";
|
|
50
77
|
|
|
51
78
|
type Env = { Bindings: Bindings; Variables: AppVariables };
|
|
52
79
|
|
|
@@ -54,6 +81,7 @@ export const settingsRoutes = new Hono<Env>();
|
|
|
54
81
|
|
|
55
82
|
const UpdateLocaleSettingsSchema = z.object({
|
|
56
83
|
siteLanguage: z.string(),
|
|
84
|
+
cjkSerifFont: z.string(),
|
|
57
85
|
timeZone: z.string(),
|
|
58
86
|
});
|
|
59
87
|
|
|
@@ -73,6 +101,100 @@ function publicPath(c: Context<Env>, path: string): string {
|
|
|
73
101
|
return toPublicPath(path, c.var.appConfig.sitePathPrefix);
|
|
74
102
|
}
|
|
75
103
|
|
|
104
|
+
/**
|
|
105
|
+
* Breadcrumb labels for admin settings pages.
|
|
106
|
+
*
|
|
107
|
+
* These duplicate labels defined in the corresponding UI components (e.g.
|
|
108
|
+
* `SettingsRootContent`, `AccountMenuContent`) on purpose: Lingui hashes are
|
|
109
|
+
* computed from `message` alone, so identical text produces the same catalog
|
|
110
|
+
* entry and shares the translation. Keep the text in sync with the UI source
|
|
111
|
+
* of truth.
|
|
112
|
+
*/
|
|
113
|
+
function breadcrumbLabel(
|
|
114
|
+
c: Context<Env>,
|
|
115
|
+
key:
|
|
116
|
+
| "settings"
|
|
117
|
+
| "general"
|
|
118
|
+
| "avatar"
|
|
119
|
+
| "navigation"
|
|
120
|
+
| "colorTheme"
|
|
121
|
+
| "fontTheme"
|
|
122
|
+
| "customCss"
|
|
123
|
+
| "codeInjection"
|
|
124
|
+
| "account"
|
|
125
|
+
| "sessions"
|
|
126
|
+
| "password"
|
|
127
|
+
| "deleteAccount"
|
|
128
|
+
| "apiTokens"
|
|
129
|
+
| "githubSync",
|
|
130
|
+
): string {
|
|
131
|
+
const i18n = getI18n(c);
|
|
132
|
+
switch (key) {
|
|
133
|
+
case "settings":
|
|
134
|
+
return i18n._(
|
|
135
|
+
msg({ message: "Settings", comment: "@context: Breadcrumb label" }),
|
|
136
|
+
);
|
|
137
|
+
case "general":
|
|
138
|
+
return i18n._(
|
|
139
|
+
msg({ message: "General", comment: "@context: Breadcrumb label" }),
|
|
140
|
+
);
|
|
141
|
+
case "avatar":
|
|
142
|
+
return i18n._(
|
|
143
|
+
msg({ message: "Avatar", comment: "@context: Breadcrumb label" }),
|
|
144
|
+
);
|
|
145
|
+
case "navigation":
|
|
146
|
+
return i18n._(
|
|
147
|
+
msg({ message: "Navigation", comment: "@context: Breadcrumb label" }),
|
|
148
|
+
);
|
|
149
|
+
case "colorTheme":
|
|
150
|
+
return i18n._(
|
|
151
|
+
msg({ message: "Color Theme", comment: "@context: Breadcrumb label" }),
|
|
152
|
+
);
|
|
153
|
+
case "fontTheme":
|
|
154
|
+
return i18n._(
|
|
155
|
+
msg({ message: "Font Theme", comment: "@context: Breadcrumb label" }),
|
|
156
|
+
);
|
|
157
|
+
case "customCss":
|
|
158
|
+
return i18n._(
|
|
159
|
+
msg({ message: "Custom CSS", comment: "@context: Breadcrumb label" }),
|
|
160
|
+
);
|
|
161
|
+
case "codeInjection":
|
|
162
|
+
return i18n._(
|
|
163
|
+
msg({
|
|
164
|
+
message: "Code Injection",
|
|
165
|
+
comment: "@context: Breadcrumb label",
|
|
166
|
+
}),
|
|
167
|
+
);
|
|
168
|
+
case "account":
|
|
169
|
+
return i18n._(
|
|
170
|
+
msg({ message: "Account", comment: "@context: Breadcrumb label" }),
|
|
171
|
+
);
|
|
172
|
+
case "sessions":
|
|
173
|
+
return i18n._(
|
|
174
|
+
msg({ message: "Sessions", comment: "@context: Breadcrumb label" }),
|
|
175
|
+
);
|
|
176
|
+
case "password":
|
|
177
|
+
return i18n._(
|
|
178
|
+
msg({ message: "Password", comment: "@context: Breadcrumb label" }),
|
|
179
|
+
);
|
|
180
|
+
case "deleteAccount":
|
|
181
|
+
return i18n._(
|
|
182
|
+
msg({
|
|
183
|
+
message: "Delete Account",
|
|
184
|
+
comment: "@context: Breadcrumb label",
|
|
185
|
+
}),
|
|
186
|
+
);
|
|
187
|
+
case "apiTokens":
|
|
188
|
+
return i18n._(
|
|
189
|
+
msg({ message: "API Tokens", comment: "@context: Breadcrumb label" }),
|
|
190
|
+
);
|
|
191
|
+
case "githubSync":
|
|
192
|
+
return i18n._(
|
|
193
|
+
msg({ message: "GitHub Sync", comment: "@context: Breadcrumb label" }),
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
76
198
|
type DemoRestriction = "sessions" | "password" | "accountDeletion";
|
|
77
199
|
|
|
78
200
|
function getDemoRestrictionMessage(
|
|
@@ -163,14 +285,15 @@ settingsRoutes.get("/general", async (c) => {
|
|
|
163
285
|
content: (
|
|
164
286
|
<>
|
|
165
287
|
<AdminBreadcrumb
|
|
166
|
-
parent="
|
|
288
|
+
parent={breadcrumbLabel(c, "settings")}
|
|
167
289
|
parentHref={publicPath(c, "/settings")}
|
|
168
|
-
current="
|
|
290
|
+
current={breadcrumbLabel(c, "general")}
|
|
169
291
|
/>
|
|
170
292
|
<GeneralContent
|
|
171
293
|
siteName={dbSiteName || ""}
|
|
172
294
|
siteDescription={dbSiteDescription || ""}
|
|
173
295
|
siteLanguage={appConfig.siteLanguage}
|
|
296
|
+
cjkSerifFont={appConfig.cjkSerifFont}
|
|
174
297
|
siteNameFallback={appConfig.fallbacks.siteName}
|
|
175
298
|
siteDescriptionFallback={appConfig.fallbacks.siteDescription}
|
|
176
299
|
mainRssFeed={appConfig.mainRssFeed}
|
|
@@ -277,7 +400,8 @@ settingsRoutes.post("/general/language-time", async (c) => {
|
|
|
277
400
|
);
|
|
278
401
|
const { languageChanged } =
|
|
279
402
|
await c.var.services.settings.updateLocaleSettings(body, {
|
|
280
|
-
oldLanguage: c.var.
|
|
403
|
+
oldLanguage: c.var.appConfig.siteLanguage,
|
|
404
|
+
oldCjkSerifFont: c.var.appConfig.cjkSerifFont,
|
|
281
405
|
});
|
|
282
406
|
|
|
283
407
|
const wantsJson = c.req.header("accept")?.includes("application/json");
|
|
@@ -386,9 +510,9 @@ settingsRoutes.get("/avatar", async (c) => {
|
|
|
386
510
|
content: (
|
|
387
511
|
<>
|
|
388
512
|
<AdminBreadcrumb
|
|
389
|
-
parent="
|
|
513
|
+
parent={breadcrumbLabel(c, "settings")}
|
|
390
514
|
parentHref={publicPath(c, "/settings")}
|
|
391
|
-
current="
|
|
515
|
+
current={breadcrumbLabel(c, "avatar")}
|
|
392
516
|
/>
|
|
393
517
|
<AvatarContent
|
|
394
518
|
siteAvatarUrl={c.var.appConfig.siteAvatarUrl}
|
|
@@ -576,9 +700,10 @@ settingsRoutes.post("/avatar/display", async (c) => {
|
|
|
576
700
|
// ===========================================================================
|
|
577
701
|
|
|
578
702
|
settingsRoutes.get("/navigation", async (c) => {
|
|
579
|
-
const navItems = await
|
|
580
|
-
|
|
581
|
-
|
|
703
|
+
const [navItems, directoryData] = await Promise.all([
|
|
704
|
+
c.var.services.navItems.list(),
|
|
705
|
+
c.var.services.collections.listDirectoryData(),
|
|
706
|
+
]);
|
|
582
707
|
const navData = await getNavigationData(c);
|
|
583
708
|
|
|
584
709
|
return renderPublicPage(c, {
|
|
@@ -587,14 +712,13 @@ settingsRoutes.get("/navigation", async (c) => {
|
|
|
587
712
|
content: (
|
|
588
713
|
<>
|
|
589
714
|
<AdminBreadcrumb
|
|
590
|
-
parent="
|
|
715
|
+
parent={breadcrumbLabel(c, "settings")}
|
|
591
716
|
parentHref={publicPath(c, "/settings")}
|
|
592
|
-
current="
|
|
717
|
+
current={breadcrumbLabel(c, "navigation")}
|
|
593
718
|
/>
|
|
594
719
|
<NavigationContent
|
|
595
720
|
navItems={navItems}
|
|
596
|
-
|
|
597
|
-
homeDefaultView={homeDefaultView}
|
|
721
|
+
directoryData={directoryData}
|
|
598
722
|
mainRssFeed={c.var.appConfig.mainRssFeed}
|
|
599
723
|
siteName={navData.siteName}
|
|
600
724
|
sitePathPrefix={c.var.appConfig.sitePathPrefix}
|
|
@@ -604,41 +728,12 @@ settingsRoutes.get("/navigation", async (c) => {
|
|
|
604
728
|
});
|
|
605
729
|
});
|
|
606
730
|
|
|
607
|
-
settingsRoutes.post("/navigation/nav-max-visible", async (c) => {
|
|
608
|
-
const body = await c.req.json<{ value: number }>();
|
|
609
|
-
const { settings } = c.var.services;
|
|
610
|
-
|
|
611
|
-
const navMax = Math.max(0, Math.min(5, body.value ?? 3));
|
|
612
|
-
if (navMax !== 3) {
|
|
613
|
-
await settings.set("HEADER_NAV_MAX_VISIBLE", String(navMax));
|
|
614
|
-
} else {
|
|
615
|
-
await settings.remove("HEADER_NAV_MAX_VISIBLE");
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
return c.json({ ok: true });
|
|
619
|
-
});
|
|
620
|
-
|
|
621
|
-
settingsRoutes.post("/navigation/home-default-view", async (c) => {
|
|
622
|
-
const body = await c.req.json<{ value: string }>();
|
|
623
|
-
const { settings } = c.var.services;
|
|
624
|
-
|
|
625
|
-
if (body.value === "featured") {
|
|
626
|
-
await settings.set("HOME_DEFAULT_VIEW", "featured");
|
|
627
|
-
} else {
|
|
628
|
-
await settings.remove("HOME_DEFAULT_VIEW");
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
return c.json({ ok: true });
|
|
632
|
-
});
|
|
633
|
-
|
|
634
731
|
// ===========================================================================
|
|
635
732
|
// Color Theme (moved from appearance routes)
|
|
636
733
|
// ===========================================================================
|
|
637
734
|
|
|
638
735
|
settingsRoutes.get("/color-theme", async (c) => {
|
|
639
|
-
const
|
|
640
|
-
const currentThemeId =
|
|
641
|
-
c.var.allSettings[SETTINGS_KEYS.THEME] ?? defaultThemeId;
|
|
736
|
+
const currentThemeId = c.var.appConfig.themeId;
|
|
642
737
|
const currentThemeMode = c.var.appConfig.themeMode;
|
|
643
738
|
const themes = getAvailableThemes();
|
|
644
739
|
const saved = c.req.query("saved") !== undefined;
|
|
@@ -651,9 +746,9 @@ settingsRoutes.get("/color-theme", async (c) => {
|
|
|
651
746
|
content: (
|
|
652
747
|
<>
|
|
653
748
|
<AdminBreadcrumb
|
|
654
|
-
parent="
|
|
749
|
+
parent={breadcrumbLabel(c, "settings")}
|
|
655
750
|
parentHref={publicPath(c, "/settings")}
|
|
656
|
-
current=
|
|
751
|
+
current={breadcrumbLabel(c, "colorTheme")}
|
|
657
752
|
/>
|
|
658
753
|
<ColorThemeContent
|
|
659
754
|
themes={themes}
|
|
@@ -685,12 +780,7 @@ settingsRoutes.post("/color-theme", async (c) => {
|
|
|
685
780
|
);
|
|
686
781
|
}
|
|
687
782
|
|
|
688
|
-
|
|
689
|
-
if (validTheme.id === defaultThemeId) {
|
|
690
|
-
await settings.remove(SETTINGS_KEYS.THEME);
|
|
691
|
-
} else {
|
|
692
|
-
await settings.set(SETTINGS_KEYS.THEME, validTheme.id);
|
|
693
|
-
}
|
|
783
|
+
await settings.set(SETTINGS_KEYS.THEME, validTheme.id);
|
|
694
784
|
|
|
695
785
|
const themeMode: ThemeMode = THEME_MODES.includes(body.themeMode as ThemeMode)
|
|
696
786
|
? (body.themeMode as ThemeMode)
|
|
@@ -710,7 +800,7 @@ settingsRoutes.post("/color-theme", async (c) => {
|
|
|
710
800
|
// ===========================================================================
|
|
711
801
|
|
|
712
802
|
settingsRoutes.get("/font-theme", async (c) => {
|
|
713
|
-
const currentFontThemeId = c.var.
|
|
803
|
+
const currentFontThemeId = c.var.appConfig.fontThemeId;
|
|
714
804
|
const saved = c.req.query("saved") !== undefined;
|
|
715
805
|
const navData = await getNavigationData(c);
|
|
716
806
|
|
|
@@ -721,9 +811,9 @@ settingsRoutes.get("/font-theme", async (c) => {
|
|
|
721
811
|
content: (
|
|
722
812
|
<>
|
|
723
813
|
<AdminBreadcrumb
|
|
724
|
-
parent="
|
|
814
|
+
parent={breadcrumbLabel(c, "settings")}
|
|
725
815
|
parentHref={publicPath(c, "/settings")}
|
|
726
|
-
current=
|
|
816
|
+
current={breadcrumbLabel(c, "fontTheme")}
|
|
727
817
|
/>
|
|
728
818
|
<FontThemeContent
|
|
729
819
|
fontThemes={BUILTIN_FONT_THEMES}
|
|
@@ -754,11 +844,7 @@ settingsRoutes.post("/font-theme", async (c) => {
|
|
|
754
844
|
);
|
|
755
845
|
}
|
|
756
846
|
|
|
757
|
-
|
|
758
|
-
await settings.remove("FONT_THEME");
|
|
759
|
-
} else {
|
|
760
|
-
await settings.set("FONT_THEME", validFont.id);
|
|
761
|
-
}
|
|
847
|
+
await settings.set("FONT_THEME", validFont.id);
|
|
762
848
|
|
|
763
849
|
return dsRedirect(publicPath(c, "/settings/font-theme?saved"));
|
|
764
850
|
});
|
|
@@ -777,9 +863,9 @@ settingsRoutes.get("/custom-css", async (c) => {
|
|
|
777
863
|
content: (
|
|
778
864
|
<>
|
|
779
865
|
<AdminBreadcrumb
|
|
780
|
-
parent="
|
|
866
|
+
parent={breadcrumbLabel(c, "settings")}
|
|
781
867
|
parentHref={publicPath(c, "/settings")}
|
|
782
|
-
current=
|
|
868
|
+
current={breadcrumbLabel(c, "customCss")}
|
|
783
869
|
/>
|
|
784
870
|
<AdvancedContent
|
|
785
871
|
customCSS={customCSS}
|
|
@@ -813,6 +899,70 @@ settingsRoutes.post("/custom-css", async (c) => {
|
|
|
813
899
|
);
|
|
814
900
|
});
|
|
815
901
|
|
|
902
|
+
// ===========================================================================
|
|
903
|
+
// Code Injection — site-wide HTML in <head> and at end of <body>.
|
|
904
|
+
// ===========================================================================
|
|
905
|
+
|
|
906
|
+
settingsRoutes.get("/code-injection", async (c) => {
|
|
907
|
+
const customHeadHtml =
|
|
908
|
+
c.var.allSettings[SETTINGS_KEYS.CUSTOM_HEAD_HTML] ?? "";
|
|
909
|
+
const customBodyEndHtml =
|
|
910
|
+
c.var.allSettings[SETTINGS_KEYS.CUSTOM_BODY_END_HTML] ?? "";
|
|
911
|
+
const navData = await getNavigationData(c);
|
|
912
|
+
|
|
913
|
+
return renderPublicPage(c, {
|
|
914
|
+
title: buildPageTitle("Code Injection", navData.siteName),
|
|
915
|
+
navData,
|
|
916
|
+
content: (
|
|
917
|
+
<>
|
|
918
|
+
<AdminBreadcrumb
|
|
919
|
+
parent={breadcrumbLabel(c, "settings")}
|
|
920
|
+
parentHref={publicPath(c, "/settings")}
|
|
921
|
+
current={breadcrumbLabel(c, "codeInjection")}
|
|
922
|
+
/>
|
|
923
|
+
<CodeInjectionContent
|
|
924
|
+
customHeadHtml={customHeadHtml}
|
|
925
|
+
customBodyEndHtml={customBodyEndHtml}
|
|
926
|
+
sitePathPrefix={c.var.appConfig.sitePathPrefix}
|
|
927
|
+
/>
|
|
928
|
+
</>
|
|
929
|
+
),
|
|
930
|
+
});
|
|
931
|
+
});
|
|
932
|
+
|
|
933
|
+
settingsRoutes.post("/code-injection", async (c) => {
|
|
934
|
+
const i18n = getI18n(c);
|
|
935
|
+
const body = await c.req.json<{
|
|
936
|
+
customHeadHtml?: string;
|
|
937
|
+
customBodyEndHtml?: string;
|
|
938
|
+
}>();
|
|
939
|
+
const { settings } = c.var.services;
|
|
940
|
+
|
|
941
|
+
const headHtml = body.customHeadHtml?.trim() ?? "";
|
|
942
|
+
const bodyEndHtml = body.customBodyEndHtml?.trim() ?? "";
|
|
943
|
+
|
|
944
|
+
if (headHtml) {
|
|
945
|
+
await settings.set(SETTINGS_KEYS.CUSTOM_HEAD_HTML, headHtml);
|
|
946
|
+
} else {
|
|
947
|
+
await settings.remove(SETTINGS_KEYS.CUSTOM_HEAD_HTML);
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
if (bodyEndHtml) {
|
|
951
|
+
await settings.set(SETTINGS_KEYS.CUSTOM_BODY_END_HTML, bodyEndHtml);
|
|
952
|
+
} else {
|
|
953
|
+
await settings.remove(SETTINGS_KEYS.CUSTOM_BODY_END_HTML);
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
return dsToast(
|
|
957
|
+
i18n._(
|
|
958
|
+
msg({
|
|
959
|
+
message: "Code injection updated.",
|
|
960
|
+
comment: "@context: Toast after saving Code Injection settings",
|
|
961
|
+
}),
|
|
962
|
+
),
|
|
963
|
+
);
|
|
964
|
+
});
|
|
965
|
+
|
|
816
966
|
// ===========================================================================
|
|
817
967
|
// Account sub-menu
|
|
818
968
|
// ===========================================================================
|
|
@@ -834,9 +984,9 @@ settingsRoutes.get("/account", async (c) => {
|
|
|
834
984
|
content: (
|
|
835
985
|
<>
|
|
836
986
|
<AdminBreadcrumb
|
|
837
|
-
parent="
|
|
987
|
+
parent={breadcrumbLabel(c, "settings")}
|
|
838
988
|
parentHref={publicPath(c, "/settings")}
|
|
839
|
-
current="
|
|
989
|
+
current={breadcrumbLabel(c, "account")}
|
|
840
990
|
/>
|
|
841
991
|
<AccountMenuContent
|
|
842
992
|
sitePathPrefix={c.var.appConfig.sitePathPrefix}
|
|
@@ -900,9 +1050,9 @@ settingsRoutes.get("/account/sessions", async (c) => {
|
|
|
900
1050
|
content: (
|
|
901
1051
|
<>
|
|
902
1052
|
<AdminBreadcrumb
|
|
903
|
-
parent="
|
|
1053
|
+
parent={breadcrumbLabel(c, "account")}
|
|
904
1054
|
parentHref={publicPath(c, "/settings/account")}
|
|
905
|
-
current="
|
|
1055
|
+
current={breadcrumbLabel(c, "sessions")}
|
|
906
1056
|
/>
|
|
907
1057
|
<SessionsContent
|
|
908
1058
|
sessions={sessions}
|
|
@@ -955,9 +1105,9 @@ settingsRoutes.get("/account/password", async (c) => {
|
|
|
955
1105
|
content: (
|
|
956
1106
|
<>
|
|
957
1107
|
<AdminBreadcrumb
|
|
958
|
-
parent="
|
|
1108
|
+
parent={breadcrumbLabel(c, "account")}
|
|
959
1109
|
parentHref={publicPath(c, "/settings/account")}
|
|
960
|
-
current="
|
|
1110
|
+
current={breadcrumbLabel(c, "password")}
|
|
961
1111
|
/>
|
|
962
1112
|
<AccountContent sitePathPrefix={c.var.appConfig.sitePathPrefix} />
|
|
963
1113
|
</>
|
|
@@ -1066,9 +1216,9 @@ settingsRoutes.get("/account/delete-account", async (c) => {
|
|
|
1066
1216
|
content: (
|
|
1067
1217
|
<>
|
|
1068
1218
|
<AdminBreadcrumb
|
|
1069
|
-
parent="
|
|
1219
|
+
parent={breadcrumbLabel(c, "account")}
|
|
1070
1220
|
parentHref={publicPath(c, "/settings/account")}
|
|
1071
|
-
current=
|
|
1221
|
+
current={breadcrumbLabel(c, "deleteAccount")}
|
|
1072
1222
|
/>
|
|
1073
1223
|
<DeleteAccountContent
|
|
1074
1224
|
siteName={navData.siteName}
|
|
@@ -1152,9 +1302,9 @@ settingsRoutes.get("/api-tokens", async (c) => {
|
|
|
1152
1302
|
content: (
|
|
1153
1303
|
<>
|
|
1154
1304
|
<AdminBreadcrumb
|
|
1155
|
-
parent="
|
|
1305
|
+
parent={breadcrumbLabel(c, "settings")}
|
|
1156
1306
|
parentHref={publicPath(c, "/settings")}
|
|
1157
|
-
current=
|
|
1307
|
+
current={breadcrumbLabel(c, "apiTokens")}
|
|
1158
1308
|
/>
|
|
1159
1309
|
<ApiTokensContent
|
|
1160
1310
|
tokens={tokens}
|
|
@@ -1190,3 +1340,946 @@ settingsRoutes.post("/api-tokens/:id/delete", async (c) => {
|
|
|
1190
1340
|
|
|
1191
1341
|
return dsRedirect(publicPath(c, "/settings/api-tokens"));
|
|
1192
1342
|
});
|
|
1343
|
+
|
|
1344
|
+
// ===========================================================================
|
|
1345
|
+
// GitHub Sync
|
|
1346
|
+
// ===========================================================================
|
|
1347
|
+
|
|
1348
|
+
settingsRoutes.post("/github-sync/connect", async (c) => {
|
|
1349
|
+
// When a GitHub App is configured on this deployment, PAT connect is
|
|
1350
|
+
// disabled — users must go through the App install flow so we don't end
|
|
1351
|
+
// up with a mix of auth modes per site (harder to audit, easier to leak
|
|
1352
|
+
// a long-lived token by accident). The UI hides the PAT form too.
|
|
1353
|
+
if (getGitHubAppConfig(c.env)) {
|
|
1354
|
+
return dsToast(
|
|
1355
|
+
"This deployment uses GitHub App authentication. Use Install GitHub App instead.",
|
|
1356
|
+
"error",
|
|
1357
|
+
);
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
const body = await c.req.json<{ token: string; repo: string }>();
|
|
1361
|
+
|
|
1362
|
+
if (!body.token?.trim() || !body.repo?.trim()) {
|
|
1363
|
+
return dsToast("Token and repository are required.", "error");
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
const { parseRepoSlug, createGitHubClient } =
|
|
1367
|
+
await import("../../lib/github-api.js");
|
|
1368
|
+
const parsed = parseRepoSlug(body.repo);
|
|
1369
|
+
if (!parsed) {
|
|
1370
|
+
return dsToast("Invalid repository format. Use owner/repo.", "error");
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
// Validate token
|
|
1374
|
+
const client = createGitHubClient(body.token);
|
|
1375
|
+
try {
|
|
1376
|
+
await client.getRepo(parsed.owner, parsed.repo);
|
|
1377
|
+
} catch (err) {
|
|
1378
|
+
const detail = err instanceof Error ? err.message : JSON.stringify(err);
|
|
1379
|
+
process.stderr.write(
|
|
1380
|
+
`[Jant] GitHub Sync connect failed for ${body.repo}: ${detail}\n`,
|
|
1381
|
+
);
|
|
1382
|
+
return dsToast(`Could not access the repository: ${detail}`, "error");
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
// Check if this repo already has a Jant webhook
|
|
1386
|
+
try {
|
|
1387
|
+
const hooks = await client.listWebhooks(parsed.owner, parsed.repo);
|
|
1388
|
+
const existingJantHook = hooks.find((h) =>
|
|
1389
|
+
h.config.url?.includes("/api/github-sync/webhook"),
|
|
1390
|
+
);
|
|
1391
|
+
if (existingJantHook) {
|
|
1392
|
+
return dsToast(
|
|
1393
|
+
"This repository is already connected to a Jant site. Disconnect it first before connecting to a new site.",
|
|
1394
|
+
"error",
|
|
1395
|
+
);
|
|
1396
|
+
}
|
|
1397
|
+
} catch {
|
|
1398
|
+
// If listing webhooks fails (permissions), skip the check and continue
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
// Save config
|
|
1402
|
+
await c.var.services.settings.set("GITHUB_SYNC_TOKEN", body.token);
|
|
1403
|
+
await c.var.services.settings.set("GITHUB_SYNC_REPO", body.repo);
|
|
1404
|
+
await c.var.services.settings.set("GITHUB_SYNC_AUTH_MODE", "pat");
|
|
1405
|
+
await c.var.services.settings.set("GITHUB_SYNC_APP_INSTALLATION_ID", "");
|
|
1406
|
+
await c.var.services.settings.set("GITHUB_SYNC_ENABLED", "true");
|
|
1407
|
+
|
|
1408
|
+
// Create webhook
|
|
1409
|
+
const { createGitHubSyncService } =
|
|
1410
|
+
await import("../../services/github-sync.js");
|
|
1411
|
+
const syncService = createGitHubSyncService(
|
|
1412
|
+
c.var.services,
|
|
1413
|
+
c.var.currentSite.id,
|
|
1414
|
+
await buildSyncSiteConfig(c),
|
|
1415
|
+
{ storage: c.var.storage, githubApp: getGitHubAppConfig(c.env) },
|
|
1416
|
+
);
|
|
1417
|
+
const siteUrl = c.var.appConfig.siteUrl.replace(/\/+$/, "");
|
|
1418
|
+
try {
|
|
1419
|
+
await syncService.setupWebhook(`${siteUrl}/api/github-sync/webhook`);
|
|
1420
|
+
} catch {
|
|
1421
|
+
return dsToast(
|
|
1422
|
+
"Connected, but webhook creation failed. You may need to create it manually.",
|
|
1423
|
+
"error",
|
|
1424
|
+
);
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
// Kick off an initial background push so "Last sync" doesn't sit on
|
|
1428
|
+
// "Not synced yet" until the user's next edit. See the App flow's
|
|
1429
|
+
// equivalent block below for why we bypass the queue.
|
|
1430
|
+
await markSyncPending(c.var.services.settings);
|
|
1431
|
+
const initialSync = runBackgroundSync(c.var.services.settings, syncService);
|
|
1432
|
+
try {
|
|
1433
|
+
c.executionCtx?.waitUntil(initialSync);
|
|
1434
|
+
} catch {
|
|
1435
|
+
// executionCtx unavailable (tests / Node).
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
return dsRedirect(publicPath(c, "/settings/github-sync"));
|
|
1439
|
+
});
|
|
1440
|
+
|
|
1441
|
+
settingsRoutes.post("/github-sync/push", async (c) => {
|
|
1442
|
+
const { createGitHubSyncService } =
|
|
1443
|
+
await import("../../services/github-sync.js");
|
|
1444
|
+
const syncService = createGitHubSyncService(
|
|
1445
|
+
c.var.services,
|
|
1446
|
+
c.var.currentSite.id,
|
|
1447
|
+
await buildSyncSiteConfig(c),
|
|
1448
|
+
{ storage: c.var.storage, githubApp: getGitHubAppConfig(c.env) },
|
|
1449
|
+
);
|
|
1450
|
+
|
|
1451
|
+
const config = await syncService.getConfig();
|
|
1452
|
+
if (!config) {
|
|
1453
|
+
return dsToast("GitHub Sync is not configured.", "error");
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
// Run the push in the background so the status card's live "Syncing…"
|
|
1457
|
+
// indicator drives the UX instead of the button's own spinner. The
|
|
1458
|
+
// button returns a toast immediately; the page polls for completion.
|
|
1459
|
+
await markSyncPending(c.var.services.settings);
|
|
1460
|
+
const push = runBackgroundSync(c.var.services.settings, syncService);
|
|
1461
|
+
try {
|
|
1462
|
+
c.executionCtx?.waitUntil(push);
|
|
1463
|
+
} catch {
|
|
1464
|
+
// executionCtx unavailable (tests / Node).
|
|
1465
|
+
}
|
|
1466
|
+
return dsToast("Syncing to GitHub…");
|
|
1467
|
+
});
|
|
1468
|
+
|
|
1469
|
+
settingsRoutes.post("/github-sync/disconnect", async (c) => {
|
|
1470
|
+
const { createGitHubSyncService } =
|
|
1471
|
+
await import("../../services/github-sync.js");
|
|
1472
|
+
const syncService = createGitHubSyncService(
|
|
1473
|
+
c.var.services,
|
|
1474
|
+
c.var.currentSite.id,
|
|
1475
|
+
await buildSyncSiteConfig(c),
|
|
1476
|
+
{ githubApp: getGitHubAppConfig(c.env) },
|
|
1477
|
+
);
|
|
1478
|
+
await syncService.teardownWebhook();
|
|
1479
|
+
|
|
1480
|
+
return dsRedirect(publicPath(c, "/settings/github-sync"));
|
|
1481
|
+
});
|
|
1482
|
+
|
|
1483
|
+
// ---------------------------------------------------------------------------
|
|
1484
|
+
// GitHub App install flow
|
|
1485
|
+
// ---------------------------------------------------------------------------
|
|
1486
|
+
|
|
1487
|
+
/**
|
|
1488
|
+
* Redirect the user to GitHub to install the App on their account/org.
|
|
1489
|
+
*
|
|
1490
|
+
* Only available when GitHub App env vars are configured. Uses a signed
|
|
1491
|
+
* state cookie for CSRF protection.
|
|
1492
|
+
*/
|
|
1493
|
+
settingsRoutes.get("/github-sync/app/install", async (c) => {
|
|
1494
|
+
const app = getGitHubAppConfig(c.env);
|
|
1495
|
+
if (!app) {
|
|
1496
|
+
return c.text("GitHub App is not configured on this deployment.", 404);
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
// Reinstall-same-account predicate (§5): when this site already has at
|
|
1500
|
+
// least one authorized installation, skip the GitHub round-trip and
|
|
1501
|
+
// render the picker directly. The GitHub redirect is a dead end when
|
|
1502
|
+
// the App is already installed on the chosen account — GitHub shows
|
|
1503
|
+
// its Configure page and never comes back with installation_id.
|
|
1504
|
+
//
|
|
1505
|
+
// `?force=new` bypasses the predicate so the picker's "Install on
|
|
1506
|
+
// another account" action can still reach GitHub to add a fresh
|
|
1507
|
+
// install.
|
|
1508
|
+
const forceNew = c.req.query("force") === "new";
|
|
1509
|
+
if (!forceNew) {
|
|
1510
|
+
const existing =
|
|
1511
|
+
await c.var.services.githubAppInstallations.listInstallationsForSite(
|
|
1512
|
+
c.var.currentSite.id,
|
|
1513
|
+
);
|
|
1514
|
+
if (existing.length > 0) {
|
|
1515
|
+
const navData = await getNavigationData(c);
|
|
1516
|
+
const base = publicPath(c, "/settings/github-sync");
|
|
1517
|
+
const labels = buildRepoPickerLabels(c);
|
|
1518
|
+
const suggestedRepoName = buildSuggestedRepoName(c);
|
|
1519
|
+
return renderPublicPage(c, {
|
|
1520
|
+
title: buildPageTitle(
|
|
1521
|
+
"GitHub Sync — Pick Repository",
|
|
1522
|
+
navData.siteName,
|
|
1523
|
+
),
|
|
1524
|
+
navData,
|
|
1525
|
+
content: (
|
|
1526
|
+
<>
|
|
1527
|
+
<AdminBreadcrumb
|
|
1528
|
+
parent={breadcrumbLabel(c, "settings")}
|
|
1529
|
+
parentHref={publicPath(c, "/settings")}
|
|
1530
|
+
current={breadcrumbLabel(c, "githubSync")}
|
|
1531
|
+
/>
|
|
1532
|
+
<jant-repo-picker
|
|
1533
|
+
labels={labels}
|
|
1534
|
+
api-base={`${base}/app`}
|
|
1535
|
+
connect-url={`${base}/app/connect`}
|
|
1536
|
+
install-url={`${base}/app/install?force=new`}
|
|
1537
|
+
cancel-url={publicPath(c, "/settings")}
|
|
1538
|
+
create-repo-name-hint={suggestedRepoName}
|
|
1539
|
+
>
|
|
1540
|
+
<div class="flex flex-col gap-6 max-w-lg">
|
|
1541
|
+
<div>
|
|
1542
|
+
<h2 class="text-lg font-medium mb-1">Pick a repository</h2>
|
|
1543
|
+
<p class="text-sm text-muted-foreground">
|
|
1544
|
+
Loading repositories…
|
|
1545
|
+
</p>
|
|
1546
|
+
</div>
|
|
1547
|
+
</div>
|
|
1548
|
+
</jant-repo-picker>
|
|
1549
|
+
</>
|
|
1550
|
+
),
|
|
1551
|
+
});
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
// Build the state token. When running behind a hosted control plane we
|
|
1556
|
+
// sign host+nonce with the shared SSO secret so the control plane can
|
|
1557
|
+
// verify and route the callback back to the correct site host. In
|
|
1558
|
+
// self-hosted single-site mode the secret is absent and a plain nonce
|
|
1559
|
+
// suffices (the App's Callback URL points directly at this site).
|
|
1560
|
+
const nonce = generateInstallNonce();
|
|
1561
|
+
const ssoSecret = getHostedControlPlaneSsoSecret(c.env);
|
|
1562
|
+
const host = new URL(c.var.appConfig.siteUrl).host;
|
|
1563
|
+
const state = ssoSecret
|
|
1564
|
+
? await signInstallState(host, nonce, ssoSecret)
|
|
1565
|
+
: nonce;
|
|
1566
|
+
|
|
1567
|
+
// Cookie is pinned to this host; compared byte-for-byte on the callback
|
|
1568
|
+
// to defeat CSRF regardless of whether the state is signed.
|
|
1569
|
+
setCookie(c, "jant_gh_app_state", state, {
|
|
1570
|
+
httpOnly: true,
|
|
1571
|
+
sameSite: "Lax",
|
|
1572
|
+
path: "/",
|
|
1573
|
+
maxAge: 600,
|
|
1574
|
+
});
|
|
1575
|
+
|
|
1576
|
+
return c.redirect(buildInstallUrl(app.slug, state));
|
|
1577
|
+
});
|
|
1578
|
+
|
|
1579
|
+
/**
|
|
1580
|
+
* Landing page after the user installs the GitHub App.
|
|
1581
|
+
*
|
|
1582
|
+
* GitHub redirects here with `installation_id`, `setup_action`, and the
|
|
1583
|
+
* `state` we sent. We verify the state, list the installation's repos, and
|
|
1584
|
+
* render a repo picker that POSTs back to `/github-sync/app/connect`.
|
|
1585
|
+
*/
|
|
1586
|
+
settingsRoutes.get("/github-sync/app/callback", async (c) => {
|
|
1587
|
+
const app = getGitHubAppConfig(c.env);
|
|
1588
|
+
if (!app) {
|
|
1589
|
+
return c.text("GitHub App is not configured on this deployment.", 404);
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
const installationId = c.req.query("installation_id");
|
|
1593
|
+
const state = c.req.query("state");
|
|
1594
|
+
if (!installationId) {
|
|
1595
|
+
return c.text("Missing installation_id.", 400);
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
const expected = getCookie(c, "jant_gh_app_state");
|
|
1599
|
+
if (!state || !expected || expected !== state) {
|
|
1600
|
+
return c.text("Invalid or expired state.", 400);
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
// Defense in depth: when an SSO secret is present the state should also
|
|
1604
|
+
// HMAC-verify and its embedded host must match the host serving this
|
|
1605
|
+
// request. This blocks a rogue control plane from redirecting a victim
|
|
1606
|
+
// to the wrong site with a replayed token.
|
|
1607
|
+
const ssoSecret = getHostedControlPlaneSsoSecret(c.env);
|
|
1608
|
+
if (ssoSecret) {
|
|
1609
|
+
const payload = await verifyInstallState(state, ssoSecret);
|
|
1610
|
+
const currentHost = new URL(c.var.appConfig.siteUrl).host;
|
|
1611
|
+
if (!payload || payload.host !== currentHost) {
|
|
1612
|
+
return c.text("State signature invalid for this host.", 400);
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
// One-shot: clear the cookie so it can't be replayed.
|
|
1617
|
+
setCookie(c, "jant_gh_app_state", "", {
|
|
1618
|
+
httpOnly: true,
|
|
1619
|
+
sameSite: "Lax",
|
|
1620
|
+
path: "/",
|
|
1621
|
+
maxAge: 0,
|
|
1622
|
+
});
|
|
1623
|
+
|
|
1624
|
+
// Fetch the account info for this installation and remember it. The
|
|
1625
|
+
// picker's owner dropdown reads the stored list, so subsequent visits
|
|
1626
|
+
// can switch between accounts without re-running the install flow.
|
|
1627
|
+
// Failures are non-fatal: this callback must still render the picker
|
|
1628
|
+
// so the user isn't locked out right after a successful install.
|
|
1629
|
+
try {
|
|
1630
|
+
const installation = await getInstallation(app, installationId);
|
|
1631
|
+
await c.var.services.githubAppInstallations.upsertInstallation(
|
|
1632
|
+
installationId,
|
|
1633
|
+
c.var.currentSite.id,
|
|
1634
|
+
installation.account,
|
|
1635
|
+
);
|
|
1636
|
+
} catch {
|
|
1637
|
+
// Swallow — the legacy inline picker still works with just the
|
|
1638
|
+
// installation_id from the URL, just without the owner list.
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
const navData = await getNavigationData(c);
|
|
1642
|
+
const base = publicPath(c, "/settings/github-sync");
|
|
1643
|
+
const labels = buildRepoPickerLabels(c);
|
|
1644
|
+
const suggestedRepoName = buildSuggestedRepoName(c);
|
|
1645
|
+
|
|
1646
|
+
return renderPublicPage(c, {
|
|
1647
|
+
title: buildPageTitle("GitHub Sync — Pick Repository", navData.siteName),
|
|
1648
|
+
navData,
|
|
1649
|
+
content: (
|
|
1650
|
+
<>
|
|
1651
|
+
<AdminBreadcrumb
|
|
1652
|
+
parent={breadcrumbLabel(c, "settings")}
|
|
1653
|
+
parentHref={publicPath(c, "/settings")}
|
|
1654
|
+
current={breadcrumbLabel(c, "githubSync")}
|
|
1655
|
+
/>
|
|
1656
|
+
<jant-repo-picker
|
|
1657
|
+
labels={labels}
|
|
1658
|
+
api-base={`${base}/app`}
|
|
1659
|
+
connect-url={`${base}/app/connect`}
|
|
1660
|
+
install-url={`${base}/app/install`}
|
|
1661
|
+
cancel-url={publicPath(c, "/settings")}
|
|
1662
|
+
create-repo-name-hint={suggestedRepoName}
|
|
1663
|
+
>
|
|
1664
|
+
{/* SSR fallback while the Lit component upgrades. */}
|
|
1665
|
+
<div class="flex flex-col gap-6 max-w-lg">
|
|
1666
|
+
<div>
|
|
1667
|
+
<h2 class="text-lg font-medium mb-1">Pick a repository</h2>
|
|
1668
|
+
<p class="text-sm text-muted-foreground">Loading repositories…</p>
|
|
1669
|
+
</div>
|
|
1670
|
+
</div>
|
|
1671
|
+
</jant-repo-picker>
|
|
1672
|
+
</>
|
|
1673
|
+
),
|
|
1674
|
+
});
|
|
1675
|
+
});
|
|
1676
|
+
|
|
1677
|
+
/**
|
|
1678
|
+
* Derive a default repository name to prefill on github.com/new.
|
|
1679
|
+
*
|
|
1680
|
+
* Uses the site's host — the first DNS label is a stable, URL-safe
|
|
1681
|
+
* identifier tied to this specific Jant instance. Fallback to
|
|
1682
|
+
* "jant-site-sync" when the host parse fails so we never hand GitHub an
|
|
1683
|
+
* empty `name=`. The `-jant-sync` suffix disambiguates the sync mirror
|
|
1684
|
+
* from a user's own `{slug}-jant` source repo.
|
|
1685
|
+
*/
|
|
1686
|
+
function buildSuggestedRepoName(c: Context<Env>): string {
|
|
1687
|
+
let firstLabel = "";
|
|
1688
|
+
try {
|
|
1689
|
+
firstLabel = new URL(c.var.appConfig.siteUrl).host.split(".")[0] ?? "";
|
|
1690
|
+
} catch {
|
|
1691
|
+
/* fall through */
|
|
1692
|
+
}
|
|
1693
|
+
const slug = firstLabel
|
|
1694
|
+
.toLowerCase()
|
|
1695
|
+
.replace(/[^a-z0-9-_]+/g, "-")
|
|
1696
|
+
.replace(/^-+|-+$/g, "");
|
|
1697
|
+
return slug ? `${slug}-jant-sync` : "jant-site-sync";
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
function buildRepoPickerLabels(c: Context<Env>): string {
|
|
1701
|
+
const i18n = getI18n(c);
|
|
1702
|
+
return JSON.stringify({
|
|
1703
|
+
pageTitle: i18n._(
|
|
1704
|
+
msg({
|
|
1705
|
+
message: "Pick a repository",
|
|
1706
|
+
comment: "@context: GitHub sync picker — page heading",
|
|
1707
|
+
}),
|
|
1708
|
+
),
|
|
1709
|
+
pageSubtitle: i18n._(
|
|
1710
|
+
msg({
|
|
1711
|
+
message:
|
|
1712
|
+
"Choose the GitHub account and repository to sync with this site.",
|
|
1713
|
+
comment: "@context: GitHub sync picker — page subtitle",
|
|
1714
|
+
}),
|
|
1715
|
+
),
|
|
1716
|
+
ownerLabel: i18n._(
|
|
1717
|
+
msg({
|
|
1718
|
+
message: "Account",
|
|
1719
|
+
comment: "@context: GitHub sync picker — owner dropdown label",
|
|
1720
|
+
}),
|
|
1721
|
+
),
|
|
1722
|
+
ownerPlaceholder: i18n._(
|
|
1723
|
+
msg({
|
|
1724
|
+
message: "Select an account",
|
|
1725
|
+
comment:
|
|
1726
|
+
"@context: GitHub sync picker — owner dropdown placeholder when nothing is selected",
|
|
1727
|
+
}),
|
|
1728
|
+
),
|
|
1729
|
+
ownerEmpty: i18n._(
|
|
1730
|
+
msg({
|
|
1731
|
+
message: "No accounts authorized yet",
|
|
1732
|
+
comment:
|
|
1733
|
+
"@context: GitHub sync picker — shown when the owner list is empty",
|
|
1734
|
+
}),
|
|
1735
|
+
),
|
|
1736
|
+
installAnother: i18n._(
|
|
1737
|
+
msg({
|
|
1738
|
+
message: "+ Install on another account",
|
|
1739
|
+
comment:
|
|
1740
|
+
"@context: GitHub sync picker — entry at the bottom of the owner dropdown that starts a new install flow",
|
|
1741
|
+
}),
|
|
1742
|
+
),
|
|
1743
|
+
repositoryLabel: i18n._(
|
|
1744
|
+
msg({
|
|
1745
|
+
message: "Repository",
|
|
1746
|
+
comment: "@context: GitHub sync picker — repo dropdown label",
|
|
1747
|
+
}),
|
|
1748
|
+
),
|
|
1749
|
+
repoPlaceholderNoOwner: i18n._(
|
|
1750
|
+
msg({
|
|
1751
|
+
message: "Pick an account first",
|
|
1752
|
+
comment:
|
|
1753
|
+
"@context: GitHub sync picker — repo dropdown placeholder before an owner is chosen",
|
|
1754
|
+
}),
|
|
1755
|
+
),
|
|
1756
|
+
repoPlaceholder: i18n._(
|
|
1757
|
+
msg({
|
|
1758
|
+
message: "Select a repository",
|
|
1759
|
+
comment: "@context: GitHub sync picker — repo dropdown placeholder",
|
|
1760
|
+
}),
|
|
1761
|
+
),
|
|
1762
|
+
repoSearchPlaceholder: i18n._(
|
|
1763
|
+
msg({
|
|
1764
|
+
message: "Search repositories",
|
|
1765
|
+
comment: "@context: GitHub sync picker — search input placeholder",
|
|
1766
|
+
}),
|
|
1767
|
+
),
|
|
1768
|
+
repoEmpty: i18n._(
|
|
1769
|
+
msg({
|
|
1770
|
+
message: "No repositories match.",
|
|
1771
|
+
comment:
|
|
1772
|
+
"@context: GitHub sync picker — empty state when search returns nothing",
|
|
1773
|
+
}),
|
|
1774
|
+
),
|
|
1775
|
+
repoLoading: i18n._(
|
|
1776
|
+
msg({
|
|
1777
|
+
message: "Loading…",
|
|
1778
|
+
comment: "@context: GitHub sync picker — loading state",
|
|
1779
|
+
}),
|
|
1780
|
+
),
|
|
1781
|
+
repoShowingOf: i18n._(
|
|
1782
|
+
msg({
|
|
1783
|
+
message: "Showing {shown} of {total}",
|
|
1784
|
+
comment:
|
|
1785
|
+
"@context: GitHub sync picker — paginated repo count hint. Placeholders {shown} and {total} are integers.",
|
|
1786
|
+
}),
|
|
1787
|
+
),
|
|
1788
|
+
repoSearchHint: i18n._(
|
|
1789
|
+
msg({
|
|
1790
|
+
message: "type to search all",
|
|
1791
|
+
comment:
|
|
1792
|
+
"@context: GitHub sync picker — hint telling the user typing will search the full list",
|
|
1793
|
+
}),
|
|
1794
|
+
),
|
|
1795
|
+
refreshRepos: i18n._(
|
|
1796
|
+
msg({
|
|
1797
|
+
message: "Refresh repository list",
|
|
1798
|
+
comment:
|
|
1799
|
+
"@context: GitHub sync picker — tooltip for the refresh button next to the search input",
|
|
1800
|
+
}),
|
|
1801
|
+
),
|
|
1802
|
+
createOnGitHub: i18n._(
|
|
1803
|
+
msg({
|
|
1804
|
+
message: "Create a new repository on GitHub",
|
|
1805
|
+
comment:
|
|
1806
|
+
"@context: GitHub sync picker — entry that opens github.com/new in a new tab",
|
|
1807
|
+
}),
|
|
1808
|
+
),
|
|
1809
|
+
createOnGitHubHint: i18n._(
|
|
1810
|
+
msg({
|
|
1811
|
+
message: "We'll prefill the name {name}. The list refreshes on return.",
|
|
1812
|
+
comment:
|
|
1813
|
+
"@context: GitHub sync picker — hint under the create-on-github entry. Placeholder {name} is the suggested repo name.",
|
|
1814
|
+
}),
|
|
1815
|
+
),
|
|
1816
|
+
classifyLoading: i18n._(
|
|
1817
|
+
msg({
|
|
1818
|
+
message: "Checking repository…",
|
|
1819
|
+
comment:
|
|
1820
|
+
"@context: GitHub sync picker — status text while classifying the picked repo",
|
|
1821
|
+
}),
|
|
1822
|
+
),
|
|
1823
|
+
classificationEmpty: i18n._(
|
|
1824
|
+
msg({
|
|
1825
|
+
message: "Empty repository. Ready to connect.",
|
|
1826
|
+
comment:
|
|
1827
|
+
"@context: GitHub sync picker — shown when the selected repo has no commits",
|
|
1828
|
+
}),
|
|
1829
|
+
),
|
|
1830
|
+
classificationOwned: i18n._(
|
|
1831
|
+
msg({
|
|
1832
|
+
message: "This repository is already backing up this site.",
|
|
1833
|
+
comment:
|
|
1834
|
+
"@context: GitHub sync picker — shown when the selected repo's marker matches this site",
|
|
1835
|
+
}),
|
|
1836
|
+
),
|
|
1837
|
+
classificationOwnedByOther: i18n._(
|
|
1838
|
+
msg({
|
|
1839
|
+
message:
|
|
1840
|
+
"This repository is already backing up another Jant site ({host}). Pick a different repository.",
|
|
1841
|
+
comment:
|
|
1842
|
+
"@context: GitHub sync picker — blocking message when marker belongs to another site. Placeholder {host} is the other site's host.",
|
|
1843
|
+
}),
|
|
1844
|
+
),
|
|
1845
|
+
classificationForeign: i18n._(
|
|
1846
|
+
msg({
|
|
1847
|
+
message: "This repository has existing content.",
|
|
1848
|
+
comment:
|
|
1849
|
+
"@context: GitHub sync picker — heading above the foreign-repo confirmation",
|
|
1850
|
+
}),
|
|
1851
|
+
),
|
|
1852
|
+
confirmHeading: i18n._(
|
|
1853
|
+
msg({
|
|
1854
|
+
message: "This repository already has commits",
|
|
1855
|
+
comment:
|
|
1856
|
+
"@context: GitHub sync picker — confirmation card heading for foreign repos",
|
|
1857
|
+
}),
|
|
1858
|
+
),
|
|
1859
|
+
confirmBody: i18n._(
|
|
1860
|
+
msg({
|
|
1861
|
+
message:
|
|
1862
|
+
"Connecting will sync your site onto {repo}'s default branch on top of its existing history. Existing files outside Jant's managed paths are kept. This can't be undone.",
|
|
1863
|
+
comment:
|
|
1864
|
+
"@context: GitHub sync picker — explanatory body for foreign-repo confirmation. Placeholder {repo} is the owner/repo slug.",
|
|
1865
|
+
}),
|
|
1866
|
+
),
|
|
1867
|
+
confirmInputLabel: i18n._(
|
|
1868
|
+
msg({
|
|
1869
|
+
message: "Type {repo} to confirm",
|
|
1870
|
+
comment:
|
|
1871
|
+
"@context: GitHub sync picker — label above the typed-confirmation input",
|
|
1872
|
+
}),
|
|
1873
|
+
),
|
|
1874
|
+
confirmInputPlaceholder: i18n._(
|
|
1875
|
+
msg({
|
|
1876
|
+
message: "owner/repo",
|
|
1877
|
+
comment:
|
|
1878
|
+
"@context: GitHub sync picker — placeholder text showing the expected input shape",
|
|
1879
|
+
}),
|
|
1880
|
+
),
|
|
1881
|
+
cancel: i18n._(
|
|
1882
|
+
msg({
|
|
1883
|
+
message: "Cancel",
|
|
1884
|
+
comment: "@context: GitHub sync picker — cancel action",
|
|
1885
|
+
}),
|
|
1886
|
+
),
|
|
1887
|
+
connect: i18n._(
|
|
1888
|
+
msg({
|
|
1889
|
+
message: "Connect",
|
|
1890
|
+
comment: "@context: GitHub sync picker — primary action button",
|
|
1891
|
+
}),
|
|
1892
|
+
),
|
|
1893
|
+
connecting: i18n._(
|
|
1894
|
+
msg({
|
|
1895
|
+
message: "Connecting…",
|
|
1896
|
+
comment:
|
|
1897
|
+
"@context: GitHub sync picker — primary action button while a request is in flight",
|
|
1898
|
+
}),
|
|
1899
|
+
),
|
|
1900
|
+
privateBadge: i18n._(
|
|
1901
|
+
msg({
|
|
1902
|
+
message: "Private",
|
|
1903
|
+
comment: "@context: GitHub sync picker — badge next to private repos",
|
|
1904
|
+
}),
|
|
1905
|
+
),
|
|
1906
|
+
connectionFailed: i18n._(
|
|
1907
|
+
msg({
|
|
1908
|
+
message: "Couldn't connect. Check the error and try again.",
|
|
1909
|
+
comment:
|
|
1910
|
+
"@context: GitHub sync picker — generic failure message for Connect",
|
|
1911
|
+
}),
|
|
1912
|
+
),
|
|
1913
|
+
retry: i18n._(
|
|
1914
|
+
msg({
|
|
1915
|
+
message: "Try again",
|
|
1916
|
+
comment: "@context: GitHub sync picker — retry button",
|
|
1917
|
+
}),
|
|
1918
|
+
),
|
|
1919
|
+
}).replace(/</g, "\\u003c");
|
|
1920
|
+
}
|
|
1921
|
+
|
|
1922
|
+
/**
|
|
1923
|
+
* Finalize the App connection: validate access, classify the target repo
|
|
1924
|
+
* to gate foreign/conflicting choices behind explicit user confirmation,
|
|
1925
|
+
* then persist the installation id and chosen repo and register the webhook.
|
|
1926
|
+
*
|
|
1927
|
+
* Accepts both classic form submits (redirects on success) and JSON
|
|
1928
|
+
* requests (returns JSON). Phase 3's picker component uses the JSON path.
|
|
1929
|
+
*/
|
|
1930
|
+
settingsRoutes.post("/github-sync/app/connect", async (c) => {
|
|
1931
|
+
const app = getGitHubAppConfig(c.env);
|
|
1932
|
+
if (!app) {
|
|
1933
|
+
return c.text("GitHub App is not configured on this deployment.", 404);
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
const wantsJson = c.req.header("content-type")?.includes("application/json");
|
|
1937
|
+
const body = wantsJson
|
|
1938
|
+
? ((await c.req.json().catch(() => ({}))) as Record<string, unknown>)
|
|
1939
|
+
: await c.req.parseBody();
|
|
1940
|
+
|
|
1941
|
+
const installationId = String(body.installationId ?? "").trim();
|
|
1942
|
+
const repo = String(body.repo ?? "").trim();
|
|
1943
|
+
const confirmForeign =
|
|
1944
|
+
body.confirmForeign === true || body.confirmForeign === "true";
|
|
1945
|
+
if (!installationId || !repo) {
|
|
1946
|
+
return wantsJson
|
|
1947
|
+
? c.json({ error: "Missing installationId or repo." }, 400)
|
|
1948
|
+
: c.text("Missing installationId or repo.", 400);
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1951
|
+
const { parseRepoSlug, createGitHubClient } =
|
|
1952
|
+
await import("../../lib/github-api.js");
|
|
1953
|
+
const parsed = parseRepoSlug(repo);
|
|
1954
|
+
if (!parsed) {
|
|
1955
|
+
return wantsJson
|
|
1956
|
+
? c.json({ error: "Invalid repository format." }, 400)
|
|
1957
|
+
: c.text("Invalid repository format.", 400);
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1960
|
+
// Classify the repo before we commit any state: empty and already-owned
|
|
1961
|
+
// targets proceed immediately; foreign or other-site targets require an
|
|
1962
|
+
// explicit `confirmForeign` flag from the caller (a typed confirmation
|
|
1963
|
+
// in the UI) to avoid silently pushing onto unrelated histories.
|
|
1964
|
+
const { classifyRepoForSync } = await import("../../services/github-sync.js");
|
|
1965
|
+
const ghClient = createGitHubClient(() =>
|
|
1966
|
+
getInstallationTokenFromApp(app, installationId),
|
|
1967
|
+
);
|
|
1968
|
+
let classification;
|
|
1969
|
+
try {
|
|
1970
|
+
classification = await classifyRepoForSync(
|
|
1971
|
+
ghClient,
|
|
1972
|
+
parsed.owner,
|
|
1973
|
+
parsed.repo,
|
|
1974
|
+
c.var.currentSite.id,
|
|
1975
|
+
);
|
|
1976
|
+
} catch (err) {
|
|
1977
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
1978
|
+
return wantsJson
|
|
1979
|
+
? c.json({ error: `Could not read repository: ${detail}` }, 500)
|
|
1980
|
+
: c.text(`Could not read repository: ${detail}`, 500);
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
if (classification.kind === "owned-by-other-site") {
|
|
1984
|
+
const msg = `This repository is already backing up another Jant site (${classification.marker.site_host}). Pick a different repository.`;
|
|
1985
|
+
return wantsJson
|
|
1986
|
+
? c.json(
|
|
1987
|
+
{
|
|
1988
|
+
error: msg,
|
|
1989
|
+
classification: "owned-by-other-site",
|
|
1990
|
+
marker: classification.marker,
|
|
1991
|
+
},
|
|
1992
|
+
409,
|
|
1993
|
+
)
|
|
1994
|
+
: c.text(msg, 409);
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
if (classification.kind === "foreign" && !confirmForeign) {
|
|
1998
|
+
const msg = `${repo} already has commits but isn't managed by Jant. Re-submit with confirmation to push on top of its history.`;
|
|
1999
|
+
return wantsJson
|
|
2000
|
+
? c.json(
|
|
2001
|
+
{
|
|
2002
|
+
error: msg,
|
|
2003
|
+
classification: "foreign",
|
|
2004
|
+
defaultBranch: classification.defaultBranch,
|
|
2005
|
+
},
|
|
2006
|
+
409,
|
|
2007
|
+
)
|
|
2008
|
+
: c.text(msg, 409);
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
// Persist config before creating webhook so the sync service can load it.
|
|
2012
|
+
await c.var.services.settings.set("GITHUB_SYNC_AUTH_MODE", "app");
|
|
2013
|
+
await c.var.services.settings.set(
|
|
2014
|
+
"GITHUB_SYNC_APP_INSTALLATION_ID",
|
|
2015
|
+
installationId,
|
|
2016
|
+
);
|
|
2017
|
+
await c.var.services.settings.set("GITHUB_SYNC_REPO", repo);
|
|
2018
|
+
await c.var.services.settings.set("GITHUB_SYNC_TOKEN", "");
|
|
2019
|
+
await c.var.services.settings.set("GITHUB_SYNC_ENABLED", "true");
|
|
2020
|
+
|
|
2021
|
+
const { createGitHubSyncService } =
|
|
2022
|
+
await import("../../services/github-sync.js");
|
|
2023
|
+
const syncService = createGitHubSyncService(
|
|
2024
|
+
c.var.services,
|
|
2025
|
+
c.var.currentSite.id,
|
|
2026
|
+
await buildSyncSiteConfig(c),
|
|
2027
|
+
{ storage: c.var.storage, githubApp: app },
|
|
2028
|
+
);
|
|
2029
|
+
const siteUrl = c.var.appConfig.siteUrl.replace(/\/+$/, "");
|
|
2030
|
+
try {
|
|
2031
|
+
await syncService.setupWebhook(`${siteUrl}/api/github-sync/webhook`);
|
|
2032
|
+
} catch (err) {
|
|
2033
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
2034
|
+
const msg = `Connected, but webhook creation failed: ${detail}. You may need to create it manually.`;
|
|
2035
|
+
return wantsJson ? c.json({ error: msg }, 500) : c.text(msg, 500);
|
|
2036
|
+
}
|
|
2037
|
+
|
|
2038
|
+
// Kick off an initial push so the user's content lands in the repo
|
|
2039
|
+
// immediately. We can't use the queue path: CF Queue isn't wired up
|
|
2040
|
+
// for most self-hosted deployments, and the noop fallback would
|
|
2041
|
+
// silently drop the job. Instead, set PENDING and run the sync in
|
|
2042
|
+
// the background via waitUntil. The status page reads PENDING and
|
|
2043
|
+
// polls until it clears, so the user sees "Syncing…" right away.
|
|
2044
|
+
await markSyncPending(c.var.services.settings);
|
|
2045
|
+
const initialSync = runBackgroundSync(c.var.services.settings, syncService);
|
|
2046
|
+
try {
|
|
2047
|
+
c.executionCtx?.waitUntil(initialSync);
|
|
2048
|
+
} catch {
|
|
2049
|
+
// executionCtx unavailable (tests / Node) — let the promise resolve
|
|
2050
|
+
// on its own; response still returns immediately.
|
|
2051
|
+
}
|
|
2052
|
+
|
|
2053
|
+
const redirect = publicPath(c, "/settings/github-sync");
|
|
2054
|
+
return wantsJson ? c.json({ ok: true, redirect }) : c.redirect(redirect);
|
|
2055
|
+
});
|
|
2056
|
+
|
|
2057
|
+
// ---------------------------------------------------------------------------
|
|
2058
|
+
// GitHub App picker JSON API (consumed by the jant-repo-picker component)
|
|
2059
|
+
// ---------------------------------------------------------------------------
|
|
2060
|
+
|
|
2061
|
+
/**
|
|
2062
|
+
* Helper: load the GitHub App config or short-circuit with a 404 JSON error.
|
|
2063
|
+
*/
|
|
2064
|
+
type RequireAppResult =
|
|
2065
|
+
| { app: import("../../lib/env.js").GitHubAppEnvConfig; response: null }
|
|
2066
|
+
| { app: null; response: Response };
|
|
2067
|
+
|
|
2068
|
+
function requireGitHubApp(c: Context<Env>): RequireAppResult {
|
|
2069
|
+
const app = getGitHubAppConfig(c.env);
|
|
2070
|
+
if (!app) {
|
|
2071
|
+
return {
|
|
2072
|
+
app: null,
|
|
2073
|
+
response: c.json(
|
|
2074
|
+
{ error: "GitHub App is not configured on this deployment." },
|
|
2075
|
+
404,
|
|
2076
|
+
),
|
|
2077
|
+
};
|
|
2078
|
+
}
|
|
2079
|
+
return { app, response: null };
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
/**
|
|
2083
|
+
* Dynamic import shim for `getInstallationToken`. Used by `/connect` to
|
|
2084
|
+
* build a client for classification without adding the helper to the
|
|
2085
|
+
* top-level imports (the module already lazy-imports github-api).
|
|
2086
|
+
*/
|
|
2087
|
+
async function getInstallationTokenFromApp(
|
|
2088
|
+
app: import("../../lib/env.js").GitHubAppEnvConfig,
|
|
2089
|
+
installationId: string,
|
|
2090
|
+
): Promise<string> {
|
|
2091
|
+
const { getInstallationToken } = await import("../../lib/github-app.js");
|
|
2092
|
+
return getInstallationToken(app, installationId);
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
/** List GitHub App installations authorized for this site. */
|
|
2096
|
+
settingsRoutes.get("/github-sync/app/installations", async (c) => {
|
|
2097
|
+
const installations =
|
|
2098
|
+
await c.var.services.githubAppInstallations.listInstallationsForSite(
|
|
2099
|
+
c.var.currentSite.id,
|
|
2100
|
+
);
|
|
2101
|
+
return c.json({
|
|
2102
|
+
installations: installations.map((entry) => ({
|
|
2103
|
+
installationId: entry.installationId,
|
|
2104
|
+
account: entry.account,
|
|
2105
|
+
addedAt: entry.addedAt,
|
|
2106
|
+
})),
|
|
2107
|
+
});
|
|
2108
|
+
});
|
|
2109
|
+
|
|
2110
|
+
/**
|
|
2111
|
+
* List (or search) repositories accessible via an installation.
|
|
2112
|
+
*
|
|
2113
|
+
* Query params:
|
|
2114
|
+
* - installationId (required)
|
|
2115
|
+
* - page (default 1) — only used when `q` is empty
|
|
2116
|
+
* - q (optional) — when non-empty switches to GitHub search API
|
|
2117
|
+
*
|
|
2118
|
+
* 401 from GitHub indicates the installation was removed; we lazy-clean
|
|
2119
|
+
* the stored entry and return a 410 so the UI can refresh its list.
|
|
2120
|
+
*/
|
|
2121
|
+
settingsRoutes.get("/github-sync/app/repos", async (c) => {
|
|
2122
|
+
const { app, response } = requireGitHubApp(c);
|
|
2123
|
+
if (!app) return response;
|
|
2124
|
+
|
|
2125
|
+
const installationId = c.req.query("installationId")?.trim();
|
|
2126
|
+
if (!installationId) {
|
|
2127
|
+
return c.json({ error: "Missing installationId." }, 400);
|
|
2128
|
+
}
|
|
2129
|
+
const q = c.req.query("q")?.trim() ?? "";
|
|
2130
|
+
const pageParam = Number(c.req.query("page") ?? "1");
|
|
2131
|
+
const page =
|
|
2132
|
+
Number.isFinite(pageParam) && pageParam > 0 ? Math.floor(pageParam) : 1;
|
|
2133
|
+
|
|
2134
|
+
try {
|
|
2135
|
+
if (q) {
|
|
2136
|
+
const installations =
|
|
2137
|
+
await c.var.services.githubAppInstallations.listInstallationsForSite(
|
|
2138
|
+
c.var.currentSite.id,
|
|
2139
|
+
);
|
|
2140
|
+
const installation = installations.find(
|
|
2141
|
+
(i) => i.installationId === installationId,
|
|
2142
|
+
);
|
|
2143
|
+
if (!installation) {
|
|
2144
|
+
return c.json({ error: "Unknown installation." }, 404);
|
|
2145
|
+
}
|
|
2146
|
+
const result = await searchInstallationRepos(
|
|
2147
|
+
app,
|
|
2148
|
+
installationId,
|
|
2149
|
+
installation.account.login,
|
|
2150
|
+
q,
|
|
2151
|
+
);
|
|
2152
|
+
return c.json({
|
|
2153
|
+
repos: result.repos,
|
|
2154
|
+
totalCount: result.totalCount,
|
|
2155
|
+
hasMore: false, // search API doesn't page for us here
|
|
2156
|
+
nextPage: null,
|
|
2157
|
+
mode: "search",
|
|
2158
|
+
});
|
|
2159
|
+
}
|
|
2160
|
+
|
|
2161
|
+
const result = await listInstallationReposPage(app, installationId, page);
|
|
2162
|
+
return c.json({
|
|
2163
|
+
repos: result.repos,
|
|
2164
|
+
totalCount: result.totalCount,
|
|
2165
|
+
hasMore: result.hasMore,
|
|
2166
|
+
nextPage: result.nextPage,
|
|
2167
|
+
mode: "list",
|
|
2168
|
+
});
|
|
2169
|
+
} catch (err) {
|
|
2170
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
2171
|
+
// GitHub returns 401 when an installation was uninstalled on their
|
|
2172
|
+
// side. Clean up our cached entry so the UI stops showing a dead owner.
|
|
2173
|
+
if (/\b401\b/.test(detail) || /\b404\b/.test(detail)) {
|
|
2174
|
+
await c.var.services.githubAppInstallations.removeInstallation(
|
|
2175
|
+
installationId,
|
|
2176
|
+
c.var.currentSite.id,
|
|
2177
|
+
);
|
|
2178
|
+
return c.json(
|
|
2179
|
+
{ error: "Installation is no longer accessible.", removed: true },
|
|
2180
|
+
410,
|
|
2181
|
+
);
|
|
2182
|
+
}
|
|
2183
|
+
return c.json({ error: detail }, 500);
|
|
2184
|
+
}
|
|
2185
|
+
});
|
|
2186
|
+
|
|
2187
|
+
/**
|
|
2188
|
+
* Classify a repo: empty / owned / owned-by-other-site / foreign.
|
|
2189
|
+
*
|
|
2190
|
+
* The picker calls this when the user picks a repo so it can show an
|
|
2191
|
+
* appropriate confirmation UI before submitting `/connect`.
|
|
2192
|
+
*/
|
|
2193
|
+
settingsRoutes.post("/github-sync/app/classify", async (c) => {
|
|
2194
|
+
const { app, response } = requireGitHubApp(c);
|
|
2195
|
+
if (!app) return response;
|
|
2196
|
+
|
|
2197
|
+
const body = (await c.req.json().catch(() => ({}))) as Record<
|
|
2198
|
+
string,
|
|
2199
|
+
unknown
|
|
2200
|
+
>;
|
|
2201
|
+
const installationId = String(body.installationId ?? "").trim();
|
|
2202
|
+
const repo = String(body.repo ?? "").trim();
|
|
2203
|
+
if (!installationId || !repo) {
|
|
2204
|
+
return c.json({ error: "Missing installationId or repo." }, 400);
|
|
2205
|
+
}
|
|
2206
|
+
|
|
2207
|
+
const { parseRepoSlug, createGitHubClient } =
|
|
2208
|
+
await import("../../lib/github-api.js");
|
|
2209
|
+
const parsed = parseRepoSlug(repo);
|
|
2210
|
+
if (!parsed) {
|
|
2211
|
+
return c.json({ error: "Invalid repository format." }, 400);
|
|
2212
|
+
}
|
|
2213
|
+
|
|
2214
|
+
const { classifyRepoForSync } = await import("../../services/github-sync.js");
|
|
2215
|
+
const client = createGitHubClient(() =>
|
|
2216
|
+
getInstallationTokenFromApp(app, installationId),
|
|
2217
|
+
);
|
|
2218
|
+
try {
|
|
2219
|
+
const classification = await classifyRepoForSync(
|
|
2220
|
+
client,
|
|
2221
|
+
parsed.owner,
|
|
2222
|
+
parsed.repo,
|
|
2223
|
+
c.var.currentSite.id,
|
|
2224
|
+
);
|
|
2225
|
+
return c.json({ classification });
|
|
2226
|
+
} catch (err) {
|
|
2227
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
2228
|
+
return c.json({ error: detail }, 500);
|
|
2229
|
+
}
|
|
2230
|
+
});
|
|
2231
|
+
|
|
2232
|
+
settingsRoutes.get("/github-sync", async (c) => {
|
|
2233
|
+
const [
|
|
2234
|
+
enabled,
|
|
2235
|
+
repo,
|
|
2236
|
+
lastPushSha,
|
|
2237
|
+
webhookId,
|
|
2238
|
+
lastPushAt,
|
|
2239
|
+
authMode,
|
|
2240
|
+
lastError,
|
|
2241
|
+
] = await Promise.all([
|
|
2242
|
+
c.var.services.settings.get("GITHUB_SYNC_ENABLED"),
|
|
2243
|
+
c.var.services.settings.get("GITHUB_SYNC_REPO"),
|
|
2244
|
+
c.var.services.settings.get("GITHUB_SYNC_LAST_PUSH_SHA"),
|
|
2245
|
+
c.var.services.settings.get("GITHUB_SYNC_WEBHOOK_ID"),
|
|
2246
|
+
c.var.services.settings.get("GITHUB_SYNC_LAST_PUSH_AT"),
|
|
2247
|
+
c.var.services.settings.get("GITHUB_SYNC_AUTH_MODE"),
|
|
2248
|
+
c.var.services.settings.get("GITHUB_SYNC_LAST_ERROR"),
|
|
2249
|
+
]);
|
|
2250
|
+
// Use isSyncPending (not raw flag) so a worker that died mid-push
|
|
2251
|
+
// doesn't leave the UI stuck on "Syncing…" forever.
|
|
2252
|
+
const pending = await isSyncPending(c.var.services.settings);
|
|
2253
|
+
|
|
2254
|
+
const status: GitHubSyncStatus = {
|
|
2255
|
+
enabled: enabled === "true",
|
|
2256
|
+
repo: repo ?? null,
|
|
2257
|
+
lastPushSha: lastPushSha ?? null,
|
|
2258
|
+
webhookId: webhookId ?? null,
|
|
2259
|
+
lastPushAt: lastPushAt ? Number(lastPushAt) : null,
|
|
2260
|
+
authMode: authMode === "app" ? "app" : "pat",
|
|
2261
|
+
appConfigured: getGitHubAppConfig(c.env) !== null,
|
|
2262
|
+
pending,
|
|
2263
|
+
lastError: lastError || null,
|
|
2264
|
+
};
|
|
2265
|
+
|
|
2266
|
+
const navData = await getNavigationData(c);
|
|
2267
|
+
|
|
2268
|
+
return renderPublicPage(c, {
|
|
2269
|
+
title: buildPageTitle("GitHub Sync", navData.siteName),
|
|
2270
|
+
navData,
|
|
2271
|
+
content: (
|
|
2272
|
+
<>
|
|
2273
|
+
<AdminBreadcrumb
|
|
2274
|
+
parent={breadcrumbLabel(c, "settings")}
|
|
2275
|
+
parentHref={publicPath(c, "/settings")}
|
|
2276
|
+
current={breadcrumbLabel(c, "githubSync")}
|
|
2277
|
+
/>
|
|
2278
|
+
<GitHubSyncContent
|
|
2279
|
+
status={status}
|
|
2280
|
+
sitePathPrefix={c.var.appConfig.sitePathPrefix}
|
|
2281
|
+
/>
|
|
2282
|
+
</>
|
|
2283
|
+
),
|
|
2284
|
+
});
|
|
2285
|
+
});
|