@jant/core 0.6.16 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (508) hide show
  1. package/README.md +11 -11
  2. package/bin/commands/assets/upload.js +192 -15
  3. package/bin/commands/import-site.js +60 -4
  4. package/bin/commands/reset-password.js +21 -8
  5. package/bin/commands/site/snapshot/export.js +1 -1
  6. package/bin/commands/site/snapshot/import.js +1 -1
  7. package/bin/lib/d1-query.js +5 -16
  8. package/bin/lib/node-env.js +40 -4
  9. package/bin/lib/site-selection.js +85 -29
  10. package/bin/lib/wrangler-cli.js +28 -2
  11. package/bin/lib/wrangler-json.js +35 -0
  12. package/dist/{app-C7_4oab9.js → app-K_Aa1MMn.js} +52476 -13330
  13. package/dist/client/.vite/manifest.json +255 -90
  14. package/dist/client/_assets/chunks/confirm-D7GrwsCN.js +45 -0
  15. package/dist/client/_assets/chunks/create-editor-CD3FhrOB.js +257 -0
  16. package/dist/client/_assets/chunks/{native-DpcrFAPh.js → emoji-mart-C4RpRKcU.js} +716 -1
  17. package/dist/client/_assets/chunks/footnote-rail-CmeoVtnU.js +1 -0
  18. package/dist/client/_assets/chunks/heic-to-CuP2Qlsw.js +1 -0
  19. package/dist/client/_assets/chunks/jant-locale-picker-DL6mIOT5.js +69 -0
  20. package/dist/client/_assets/chunks/lit-DW8VmJAT.js +2 -0
  21. package/dist/client/_assets/chunks/mediabunny-DRaCQ1r-.js +31 -0
  22. package/dist/client/_assets/chunks/rolldown-runtime-hePW80VL.js +1 -0
  23. package/dist/client/_assets/chunks/settings-paths-BcdySNx6.js +84 -0
  24. package/dist/client/_assets/chunks/site-header-nav-DzXsFk05.js +1 -0
  25. package/dist/client/_assets/chunks/slug-format-CRXO1AL5.js +1 -0
  26. package/dist/client/_assets/chunks/slugify-373citbs.js +1 -0
  27. package/dist/client/_assets/chunks/sortable-list-CgaL2jCs.js +2 -0
  28. package/dist/client/_assets/chunks/types-D5iF3H1a.js +1 -0
  29. package/dist/client/_assets/chunks/unsafe-html-B5ZEXaxg.js +1 -0
  30. package/dist/client/_assets/chunks/unsafe-svg-0QCkP0vZ.js +2 -0
  31. package/dist/client/_assets/client-GiYENVw8.css +2 -0
  32. package/dist/client/_assets/client-VnFxJN7G.js +295 -0
  33. package/dist/client/_assets/client-auth-k8gJ6QJj.js +828 -0
  34. package/dist/client/_assets/client-author-DQ8R-8KR.css +2 -0
  35. package/dist/client/_assets/client-compose-B_kDtWkW.js +2004 -0
  36. package/dist/client/_assets/client-manage-M90aSTOk.js +2170 -0
  37. package/dist/client/_assets/client-settings-DfYs9n1F.js +1112 -0
  38. package/dist/{export-Dl5KCiEs.js → github-sync-BPAvT999.js} +2254 -107
  39. package/dist/index.js +2 -5
  40. package/dist/node.js +5 -7
  41. package/package.json +3 -3
  42. package/src/__tests__/auth-session-freshness.test.ts +57 -0
  43. package/src/__tests__/basecoat-variants.test.ts +121 -0
  44. package/src/__tests__/bin/assets-upload.test.ts +68 -0
  45. package/src/__tests__/export-hugo-build.test.ts +260 -0
  46. package/src/__tests__/export-service.test.ts +231 -0
  47. package/src/__tests__/helpers/component-css.ts +91 -0
  48. package/src/__tests__/helpers/db.ts +33 -0
  49. package/src/__tests__/helpers/export-fixtures.ts +3 -0
  50. package/src/__tests__/stylesheet-audience.test.ts +159 -0
  51. package/src/__tests__/stylesheet-breakpoints.test.ts +183 -0
  52. package/src/app.tsx +71 -16
  53. package/src/auth.ts +18 -1
  54. package/src/client/__tests__/collection-page-actions.test.ts +51 -2
  55. package/src/client/__tests__/compose-bridge-image-upload.test.ts +196 -0
  56. package/src/client/__tests__/compose-bridge-video-poster.test.ts +159 -0
  57. package/src/client/__tests__/compose-bridge.test.ts +272 -0
  58. package/src/client/__tests__/compose-launch.test.ts +62 -1
  59. package/src/client/__tests__/compose-shortcuts.test.ts +38 -9
  60. package/src/client/__tests__/compose-triggers.test.ts +90 -0
  61. package/src/client/__tests__/copy-field.test.ts +162 -0
  62. package/src/client/__tests__/custom-url-menu.test.ts +127 -6
  63. package/src/client/__tests__/image-processor.test.ts +324 -2
  64. package/src/client/__tests__/lazy-entries.test.ts +92 -0
  65. package/src/client/__tests__/media-scroll-hint.test.ts +155 -0
  66. package/src/client/__tests__/runtime-paths.test.ts +84 -0
  67. package/src/client/__tests__/smart-collection-page-actions.test.ts +158 -0
  68. package/src/client/__tests__/toast.test.ts +23 -0
  69. package/src/client/__tests__/video-processor-probe.test.ts +175 -0
  70. package/src/client/__tests__/video-processor.test.ts +181 -0
  71. package/src/client/audio-processor.ts +24 -15
  72. package/src/client/audio-waveform.ts +49 -0
  73. package/src/client/collection-dialog-host.ts +72 -0
  74. package/src/client/collection-navigation.ts +51 -16
  75. package/src/client/collection-page-actions.ts +26 -0
  76. package/src/client/components/__tests__/jant-collection-dialog.test.ts +329 -0
  77. package/src/client/components/__tests__/jant-collection-directory.test.ts +274 -10
  78. package/src/client/components/__tests__/jant-collection-form.test.ts +59 -178
  79. package/src/client/components/__tests__/jant-command-palette.test.ts +28 -0
  80. package/src/client/components/__tests__/jant-compose-dialog-draft-storage.test.ts +340 -0
  81. package/src/client/components/__tests__/jant-compose-dialog.test.ts +1250 -53
  82. package/src/client/components/__tests__/jant-compose-editor.test.ts +544 -40
  83. package/src/client/components/__tests__/jant-compose-fullscreen.test.ts +0 -1
  84. package/src/client/components/__tests__/jant-locale-picker.test.ts +207 -0
  85. package/src/client/components/__tests__/jant-nav-manager.test.ts +234 -15
  86. package/src/client/components/__tests__/jant-post-menu.test.ts +413 -2
  87. package/src/client/components/__tests__/jant-post-picker.test.ts +197 -0
  88. package/src/client/components/__tests__/jant-settings-avatar.test.ts +15 -12
  89. package/src/client/components/__tests__/jant-settings-general.test.ts +541 -172
  90. package/src/client/components/__tests__/jant-settings-language.test.ts +851 -0
  91. package/src/client/components/__tests__/jant-smart-collection-dialog.test.ts +665 -0
  92. package/src/client/components/collection-dialog-types.ts +49 -0
  93. package/src/client/components/collection-manager-types.ts +32 -1
  94. package/src/client/components/collection-types.ts +1 -15
  95. package/src/client/components/compose-types.ts +75 -1
  96. package/src/client/components/jant-collection-dialog.ts +722 -0
  97. package/src/client/components/jant-collection-directory.ts +567 -182
  98. package/src/client/components/jant-collection-form.ts +53 -232
  99. package/src/client/components/jant-command-palette.ts +100 -49
  100. package/src/client/components/jant-compose-dialog.ts +1486 -707
  101. package/src/client/components/jant-compose-editor.ts +673 -336
  102. package/src/client/components/jant-compose-fullscreen.ts +51 -43
  103. package/src/client/components/jant-config-editor.ts +65 -53
  104. package/src/client/components/jant-confirm-dialog.ts +13 -11
  105. package/src/client/components/jant-locale-picker.ts +418 -0
  106. package/src/client/components/jant-media-lightbox.ts +146 -136
  107. package/src/client/components/jant-nav-manager.ts +690 -366
  108. package/src/client/components/jant-post-menu.ts +1086 -282
  109. package/src/client/components/jant-post-picker.ts +324 -0
  110. package/src/client/components/jant-repo-picker.ts +138 -106
  111. package/src/client/components/jant-settings-avatar.ts +31 -27
  112. package/src/client/components/jant-settings-general.ts +617 -543
  113. package/src/client/components/jant-settings-language.ts +1087 -0
  114. package/src/client/components/jant-smart-collection-dialog.ts +1021 -0
  115. package/src/client/components/jant-text-preview.ts +94 -86
  116. package/src/client/components/nav-manager-types.ts +62 -1
  117. package/src/client/components/settings-types.ts +14 -29
  118. package/src/client/components/smart-collection-conditions.ts +285 -0
  119. package/src/client/components/smart-collection-dialog-types.ts +68 -0
  120. package/src/client/compose-bridge.ts +214 -141
  121. package/src/client/compose-launch.ts +76 -2
  122. package/src/client/compose-shortcuts.ts +6 -8
  123. package/src/client/compose-triggers.ts +50 -0
  124. package/src/client/copy-field.ts +108 -0
  125. package/src/client/custom-url-menu.ts +60 -4
  126. package/src/client/icons.ts +14 -0
  127. package/src/client/image-plan.ts +165 -0
  128. package/src/client/image-processor.ts +195 -117
  129. package/src/client/image-worker-client.ts +45 -0
  130. package/src/client/image-worker.ts +135 -0
  131. package/src/client/lazy-entries.ts +95 -0
  132. package/src/client/lazy-slugify.ts +2 -2
  133. package/src/client/media-scroll-hint.ts +43 -2
  134. package/src/client/mediabunny.ts +29 -0
  135. package/src/client/post-picker.ts +41 -0
  136. package/src/client/runtime-paths.ts +74 -1
  137. package/src/client/settings-bridge.ts +4 -10
  138. package/src/client/site-header-nav.js +18 -6
  139. package/src/client/smart-collection-dialog-host.ts +116 -0
  140. package/src/client/smart-collection-page-actions.ts +208 -0
  141. package/src/client/tiptap/__tests__/bubble-menu.test.ts +110 -0
  142. package/src/client/tiptap/__tests__/floating-position.test.ts +136 -1
  143. package/src/client/tiptap/__tests__/inline-image-upload.test.ts +37 -0
  144. package/src/client/tiptap/bubble-menu.ts +47 -16
  145. package/src/client/tiptap/floating-position.ts +216 -2
  146. package/src/client/tiptap/inline-image-upload.ts +7 -3
  147. package/src/client/tiptap/link-toolbar.ts +22 -9
  148. package/src/client/toast.ts +13 -0
  149. package/src/client/types/vite-worker.d.ts +12 -0
  150. package/src/client/upload-with-metadata.ts +3 -13
  151. package/src/client/video-processor.ts +351 -107
  152. package/src/client-auth.ts +14 -31
  153. package/src/client-compose.ts +19 -0
  154. package/src/client-manage.ts +13 -0
  155. package/src/client-settings.ts +14 -0
  156. package/src/client-site.ts +10 -3
  157. package/src/client.ts +4 -0
  158. package/src/db/__tests__/backfill-nav-label-mirrors.test.ts +149 -0
  159. package/src/db/__tests__/schema-enum-sources.test.ts +33 -0
  160. package/src/db/__tests__/smart-collection-placement.test.ts +402 -0
  161. package/src/db/backfills/0006_clear_mirrored_page_nav_labels.sql +31 -0
  162. package/src/db/migrations/0032_married_tomas.sql +3 -0
  163. package/src/db/migrations/0033_busy_johnny_storm.sql +198 -0
  164. package/src/db/migrations/0034_cheerful_rumiko_fujikawa.sql +35 -0
  165. package/src/db/migrations/meta/0032_snapshot.json +2582 -0
  166. package/src/db/migrations/meta/0033_snapshot.json +2816 -0
  167. package/src/db/migrations/meta/0034_snapshot.json +2816 -0
  168. package/src/db/migrations/meta/_journal.json +21 -0
  169. package/src/db/migrations/pg/0030_abandoned_nighthawk.sql +3 -0
  170. package/src/db/migrations/pg/0031_strong_ultimatum.sql +128 -0
  171. package/src/db/migrations/pg/0032_furry_multiple_man.sql +6 -0
  172. package/src/db/migrations/pg/meta/0030_snapshot.json +3329 -0
  173. package/src/db/migrations/pg/meta/0031_snapshot.json +3660 -0
  174. package/src/db/migrations/pg/meta/0032_snapshot.json +3660 -0
  175. package/src/db/migrations/pg/meta/_journal.json +21 -0
  176. package/src/db/pg/schema.ts +195 -27
  177. package/src/db/post-visibility.ts +117 -0
  178. package/src/db/schema.ts +222 -27
  179. package/src/i18n/__tests__/detect.test.ts +26 -81
  180. package/src/i18n/__tests__/supported-locales.test.ts +83 -0
  181. package/src/i18n/context.tsx +12 -2
  182. package/src/i18n/detect.ts +7 -66
  183. package/src/i18n/locales/glossary.zh-Hans.yml +44 -4
  184. package/src/i18n/locales/glossary.zh-Hant.yml +44 -4
  185. package/src/i18n/locales/public/en.po +490 -158
  186. package/src/i18n/locales/public/en.ts +1 -1
  187. package/src/i18n/locales/public/zh-Hans.po +487 -155
  188. package/src/i18n/locales/public/zh-Hans.ts +1 -1
  189. package/src/i18n/locales/public/zh-Hant.po +487 -155
  190. package/src/i18n/locales/public/zh-Hant.ts +1 -1
  191. package/src/i18n/locales/settings/en.po +551 -69
  192. package/src/i18n/locales/settings/en.ts +1 -1
  193. package/src/i18n/locales/settings/zh-Hans.po +597 -115
  194. package/src/i18n/locales/settings/zh-Hans.ts +1 -1
  195. package/src/i18n/locales/settings/zh-Hant.po +610 -128
  196. package/src/i18n/locales/settings/zh-Hant.ts +1 -1
  197. package/src/i18n/locales.ts +94 -0
  198. package/src/i18n/middleware.ts +12 -2
  199. package/src/i18n/supported-locales.ts +80 -0
  200. package/src/lib/__tests__/api-settings.test.ts +11 -2
  201. package/src/lib/__tests__/asset-path.test.ts +92 -0
  202. package/src/lib/__tests__/deferred.test.ts +90 -0
  203. package/src/lib/__tests__/discover-ping.test.ts +89 -0
  204. package/src/lib/__tests__/discover.test.ts +410 -0
  205. package/src/lib/__tests__/feed-policy.test.ts +26 -0
  206. package/src/lib/__tests__/feed.test.ts +1526 -15
  207. package/src/lib/__tests__/filter-dimensions.test.ts +341 -0
  208. package/src/lib/__tests__/hosted-signin.test.ts +1 -1
  209. package/src/lib/__tests__/http-cache.test.ts +162 -0
  210. package/src/lib/__tests__/jant-docs-dev.test.ts +21 -0
  211. package/src/lib/__tests__/jant-docs.test.ts +23 -0
  212. package/src/lib/__tests__/lang-detect.test.ts +231 -0
  213. package/src/lib/__tests__/media-helpers.test.ts +81 -0
  214. package/src/lib/__tests__/navigation.test.ts +135 -1
  215. package/src/lib/__tests__/resolve-config.test.ts +64 -3
  216. package/src/lib/__tests__/schemas.test.ts +42 -4
  217. package/src/lib/__tests__/site-unavailable-page.test.ts +25 -0
  218. package/src/lib/__tests__/slug.test.ts +70 -0
  219. package/src/lib/__tests__/slugify.test.ts +85 -0
  220. package/src/lib/__tests__/storage.test.ts +32 -0
  221. package/src/lib/__tests__/thread-fold.test.ts +113 -0
  222. package/src/lib/__tests__/upload-sideload.test.ts +14 -0
  223. package/src/lib/__tests__/url-fetch.test.ts +1 -2
  224. package/src/lib/__tests__/url.test.ts +78 -72
  225. package/src/lib/__tests__/view-language.test.ts +413 -0
  226. package/src/lib/__tests__/worker-response-cache.test.ts +90 -0
  227. package/src/lib/address.ts +57 -0
  228. package/src/lib/api-posts.ts +12 -0
  229. package/src/lib/asset-path.ts +98 -1
  230. package/src/lib/build-env.ts +16 -0
  231. package/src/lib/collection-groups.ts +5 -1
  232. package/src/lib/collection-paths.ts +3 -10
  233. package/src/lib/constants.ts +28 -3
  234. package/src/lib/copy-field.ts +36 -0
  235. package/src/lib/crypto.ts +40 -0
  236. package/src/lib/csp-builder.ts +2 -1
  237. package/src/lib/deferred.ts +79 -0
  238. package/src/lib/discover-ping.ts +141 -0
  239. package/src/lib/discover.ts +437 -0
  240. package/src/lib/env.ts +134 -0
  241. package/src/lib/errors.ts +33 -0
  242. package/src/lib/feed-policy.ts +236 -2
  243. package/src/lib/feed.ts +926 -73
  244. package/src/lib/filter-dimensions.ts +1349 -0
  245. package/src/lib/github-sync-site-config.ts +3 -0
  246. package/src/lib/hosted-signin.ts +1 -1
  247. package/src/lib/http-cache.ts +148 -0
  248. package/src/lib/hugo-markdown.ts +16 -0
  249. package/src/lib/icons.ts +9 -2
  250. package/src/lib/ids.ts +3 -0
  251. package/src/lib/jant-docs.ts +42 -0
  252. package/src/lib/lang-detect.ts +308 -0
  253. package/src/lib/media-helpers.ts +13 -1
  254. package/src/lib/navigation.ts +78 -11
  255. package/src/lib/pagination.ts +28 -24
  256. package/src/lib/per-language-surfaces.ts +67 -0
  257. package/src/lib/post-meta.ts +19 -0
  258. package/src/lib/render.tsx +55 -7
  259. package/src/lib/resolve-config.ts +53 -5
  260. package/src/lib/schemas.ts +201 -10
  261. package/src/lib/site-header-fragment.tsx +2 -1
  262. package/src/lib/site-unavailable-page.ts +47 -0
  263. package/src/lib/slug.ts +51 -7
  264. package/src/lib/slugify.ts +113 -0
  265. package/src/lib/startup-config.ts +4 -6
  266. package/src/lib/storage.ts +7 -0
  267. package/src/lib/summary.ts +50 -0
  268. package/src/lib/thread-fold.ts +161 -0
  269. package/src/lib/time.ts +32 -0
  270. package/src/lib/timeline.ts +42 -1
  271. package/src/lib/tiptap-render.ts +1 -2
  272. package/src/lib/upload.ts +16 -13
  273. package/src/lib/url.ts +139 -86
  274. package/src/lib/version.ts +10 -8
  275. package/src/lib/view-language.ts +436 -0
  276. package/src/lib/view.ts +51 -23
  277. package/src/lib/viewer-context.ts +62 -0
  278. package/src/middleware/__tests__/auth.test.ts +70 -2
  279. package/src/middleware/__tests__/cache-control.test.ts +71 -3
  280. package/src/middleware/__tests__/onboarding.test.ts +76 -5
  281. package/src/middleware/__tests__/secure-headers.test.ts +1 -1
  282. package/src/middleware/__tests__/session.test.ts +181 -33
  283. package/src/middleware/auth.ts +50 -31
  284. package/src/middleware/cache-control.ts +75 -10
  285. package/src/middleware/config.ts +6 -6
  286. package/src/middleware/error-handler.ts +12 -0
  287. package/src/middleware/onboarding.ts +32 -10
  288. package/src/middleware/secure-headers.ts +1 -1
  289. package/src/middleware/session.ts +96 -8
  290. package/src/node/__tests__/cli-migrate.test.ts +21 -19
  291. package/src/node/__tests__/cli-reset-password.test.ts +81 -8
  292. package/src/node/__tests__/cli-runtime-target.test.ts +48 -1
  293. package/src/node/__tests__/cli-site-selection.test.ts +128 -38
  294. package/src/node/__tests__/runtime.test.ts +37 -0
  295. package/src/node/index.ts +1 -0
  296. package/src/preset.css +76 -22
  297. package/src/routes/__tests__/feed-validator.test.ts +156 -0
  298. package/src/routes/api/__tests__/collections.test.ts +114 -0
  299. package/src/routes/api/__tests__/discover.test.ts +222 -0
  300. package/src/routes/api/__tests__/nav-items.test.ts +212 -2
  301. package/src/routes/api/__tests__/post-translations.test.ts +829 -0
  302. package/src/routes/api/__tests__/settings.test.ts +24 -3
  303. package/src/routes/api/__tests__/telegram.test.ts +6 -5
  304. package/src/routes/api/collections.ts +49 -6
  305. package/src/routes/api/custom-urls.ts +0 -1
  306. package/src/routes/api/discover.ts +95 -0
  307. package/src/routes/api/export.ts +3 -0
  308. package/src/routes/api/internal/__tests__/sites.test.ts +42 -2
  309. package/src/routes/api/nav-items.ts +55 -8
  310. package/src/routes/api/posts.ts +159 -0
  311. package/src/routes/api/public/__tests__/archive.test.ts +111 -0
  312. package/src/routes/api/public/archive.ts +77 -81
  313. package/src/routes/api/public/posts.ts +23 -6
  314. package/src/routes/api/smart-collections.ts +132 -0
  315. package/src/routes/api/telegram.ts +2 -40
  316. package/src/routes/api/uploads.ts +1 -2
  317. package/src/routes/auth/__tests__/setup-auth.test.ts +137 -0
  318. package/src/routes/auth/__tests__/setup-discover.test.ts +204 -0
  319. package/src/routes/auth/__tests__/setup-flow.test.ts +270 -0
  320. package/src/routes/auth/__tests__/setup-page.test.tsx +329 -0
  321. package/src/routes/auth/__tests__/setup-steps.test.ts +310 -0
  322. package/src/routes/auth/__tests__/setup.test.ts +278 -26
  323. package/src/routes/auth/__tests__/signin.test.ts +135 -0
  324. package/src/routes/auth/setup.tsx +934 -186
  325. package/src/routes/auth/signin.tsx +10 -8
  326. package/src/routes/compose.tsx +5 -0
  327. package/src/routes/dash/__tests__/custom-urls-archive.test.ts +44 -0
  328. package/src/routes/dash/__tests__/custom-urls-page.test.ts +49 -0
  329. package/src/routes/dash/__tests__/delete-account.test.ts +106 -0
  330. package/src/routes/dash/__tests__/settings-discover.test.ts +213 -0
  331. package/src/routes/dash/custom-urls.tsx +1 -37
  332. package/src/routes/dash/settings.tsx +502 -41
  333. package/src/routes/discover-announce.ts +96 -0
  334. package/src/routes/feed/__tests__/feed.test.ts +165 -2
  335. package/src/routes/feed/feed.ts +69 -40
  336. package/src/routes/feed/sitemap.ts +95 -11
  337. package/src/routes/pages/__tests__/archive-indexing.test.ts +200 -0
  338. package/src/routes/pages/__tests__/archive-params.test.ts +370 -6
  339. package/src/routes/pages/__tests__/collection-routing.test.ts +16 -0
  340. package/src/routes/pages/__tests__/collections-feed-links.test.ts +72 -0
  341. package/src/routes/pages/__tests__/collections.test.ts +9 -3
  342. package/src/routes/pages/__tests__/custom-archive-url.test.ts +119 -0
  343. package/src/routes/pages/__tests__/feed-autodiscovery.test.ts +148 -0
  344. package/src/routes/pages/__tests__/language-routing.test.ts +679 -0
  345. package/src/routes/pages/__tests__/post-preview-partial.test.ts +96 -0
  346. package/src/routes/pages/__tests__/smart-collection.test.ts +298 -0
  347. package/src/routes/pages/__tests__/subscribe.test.ts +248 -0
  348. package/src/routes/pages/archive.tsx +471 -369
  349. package/src/routes/pages/collection.tsx +94 -96
  350. package/src/routes/pages/collections.tsx +38 -50
  351. package/src/routes/pages/featured.tsx +32 -13
  352. package/src/routes/pages/home.tsx +25 -6
  353. package/src/routes/pages/language.tsx +113 -0
  354. package/src/routes/pages/latest.tsx +26 -16
  355. package/src/routes/pages/new.tsx +3 -0
  356. package/src/routes/pages/page.tsx +178 -17
  357. package/src/routes/pages/partials.tsx +41 -0
  358. package/src/routes/pages/search.tsx +18 -3
  359. package/src/routes/pages/smart-collection.tsx +340 -0
  360. package/src/routes/pages/subscribe.tsx +182 -0
  361. package/src/runtime/__tests__/index.test.ts +19 -0
  362. package/src/runtime/__tests__/node.test.ts +129 -4
  363. package/src/runtime/cloudflare.ts +21 -2
  364. package/src/runtime/index.ts +27 -1
  365. package/src/runtime/node.ts +18 -1
  366. package/src/runtime/site.ts +95 -24
  367. package/src/services/__tests__/auth.test.ts +116 -7
  368. package/src/services/__tests__/collection.test.ts +108 -4
  369. package/src/services/__tests__/language.test.ts +495 -0
  370. package/src/services/__tests__/navigation.test.ts +213 -10
  371. package/src/services/__tests__/path.test.ts +180 -0
  372. package/src/services/__tests__/post-language.test.ts +830 -0
  373. package/src/services/__tests__/post.test.ts +46 -9
  374. package/src/services/__tests__/settings.test.ts +228 -17
  375. package/src/services/__tests__/site-admin.test.ts +5 -5
  376. package/src/services/__tests__/smart-collection.test.ts +651 -0
  377. package/src/services/about-page.ts +22 -1
  378. package/src/services/auth.ts +51 -49
  379. package/src/services/bootstrap.ts +188 -38
  380. package/src/services/collection-directory-position.ts +76 -0
  381. package/src/services/collection.ts +331 -46
  382. package/src/services/custom-url.ts +27 -22
  383. package/src/services/export-theme/assets/client-site.css +1 -1
  384. package/src/services/export-theme/assets/client-site.js +123 -123
  385. package/src/services/export-theme/layouts/_default/rss.xml +77 -1
  386. package/src/services/export-theme/layouts/partials/feed-post-content.xml +105 -2
  387. package/src/services/export-theme/layouts/partials/media-gallery.html +35 -21
  388. package/src/services/export-theme/layouts/partials/pagination.html +14 -13
  389. package/src/services/export-theme/layouts/partials/post-card.html +8 -4
  390. package/src/services/export-theme/layouts/partials/reply.html +2 -1
  391. package/src/services/export-theme/layouts/partials/thread-preview.html +40 -30
  392. package/src/services/export-theme/styles/main.css +13 -1
  393. package/src/services/export.ts +278 -19
  394. package/src/services/index.ts +34 -3
  395. package/src/services/language.ts +412 -0
  396. package/src/services/mcp.ts +3 -1
  397. package/src/services/media.ts +14 -6
  398. package/src/services/navigation.ts +429 -67
  399. package/src/services/path.ts +221 -6
  400. package/src/services/post.ts +1021 -152
  401. package/src/services/search.ts +39 -2
  402. package/src/services/settings.ts +238 -43
  403. package/src/services/site-admin.ts +24 -7
  404. package/src/services/site.ts +77 -1
  405. package/src/services/smart-collection.ts +636 -0
  406. package/src/services/telegram.ts +20 -22
  407. package/src/services/upload-session.ts +1 -3
  408. package/src/style-author.css +27 -0
  409. package/src/styles/components-author.css +1622 -0
  410. package/src/styles/components.css +24 -1571
  411. package/src/styles/site-media.css +16 -2
  412. package/src/styles/tokens.css +82 -12
  413. package/src/styles/ui-author.css +7602 -0
  414. package/src/styles/ui.css +1087 -7219
  415. package/src/types/app-context.ts +7 -0
  416. package/src/types/bindings.ts +3 -0
  417. package/src/types/config.ts +94 -15
  418. package/src/types/constants.ts +188 -16
  419. package/src/types/entities.ts +87 -1
  420. package/src/types/operations.ts +64 -2
  421. package/src/types/props.ts +157 -31
  422. package/src/types/views.ts +55 -1
  423. package/src/ui/__tests__/font-themes.test.ts +52 -12
  424. package/src/ui/compose/ComposeDialog.tsx +201 -7
  425. package/src/ui/compose/ComposePrompt.tsx +1 -5
  426. package/src/ui/compose/__tests__/ComposeDialog.test.tsx +125 -0
  427. package/src/ui/dash/appearance/AdvancedContent.tsx +2 -2
  428. package/src/ui/dash/appearance/CodeInjectionContent.tsx +12 -16
  429. package/src/ui/dash/appearance/NavigationContent.tsx +117 -16
  430. package/src/ui/dash/appearance/__tests__/NavigationContent.test.tsx +33 -11
  431. package/src/ui/dash/appearance/__tests__/system-nav-descriptions.test.ts +44 -0
  432. package/src/ui/dash/appearance/system-nav-descriptions.ts +75 -0
  433. package/src/ui/dash/settings/AccountMenuContent.tsx +2 -2
  434. package/src/ui/dash/settings/ApiTokensContent.tsx +2 -1
  435. package/src/ui/dash/settings/ConfigEditorContent.tsx +35 -16
  436. package/src/ui/dash/settings/GeneralContent.tsx +275 -113
  437. package/src/ui/dash/settings/LanguageContent.tsx +409 -0
  438. package/src/ui/dash/settings/SettingsRootContent.tsx +19 -1
  439. package/src/ui/dash/settings/__tests__/GeneralContent.test.tsx +324 -4
  440. package/src/ui/dash/settings/__tests__/LanguageContent.test.tsx +144 -0
  441. package/src/ui/dash/settings/__tests__/discover-copy.test.ts +66 -0
  442. package/src/ui/dash/settings/discover-copy.ts +116 -0
  443. package/src/ui/feed/LinkCard.tsx +55 -45
  444. package/src/ui/feed/NoteCard.tsx +9 -4
  445. package/src/ui/feed/PostStatusBadges.tsx +90 -43
  446. package/src/ui/feed/QuoteCard.tsx +55 -30
  447. package/src/ui/feed/ThreadPreview.tsx +6 -2
  448. package/src/ui/feed/__tests__/thread-preview.test.ts +13 -16
  449. package/src/ui/feed/__tests__/timeline-cards.test.ts +314 -49
  450. package/src/ui/feed/thread-preview-state.ts +20 -6
  451. package/src/ui/font-themes.ts +39 -29
  452. package/src/ui/layouts/BaseLayout.tsx +155 -10
  453. package/src/ui/layouts/SiteLayout.tsx +192 -34
  454. package/src/ui/layouts/__tests__/BaseLayout.test.tsx +196 -17
  455. package/src/ui/layouts/__tests__/SiteLayout.test.tsx +109 -85
  456. package/src/ui/pages/ArchivePage.tsx +282 -289
  457. package/src/ui/pages/CollectionPage.tsx +86 -76
  458. package/src/ui/pages/CollectionsPage.tsx +5 -0
  459. package/src/ui/pages/ComposePage.tsx +8 -0
  460. package/src/ui/pages/PostPage.tsx +47 -0
  461. package/src/ui/pages/SearchPage.tsx +3 -3
  462. package/src/ui/pages/SmartCollectionPage.tsx +434 -0
  463. package/src/ui/pages/SubscribePage.tsx +236 -0
  464. package/src/ui/pages/__tests__/ArchivePage.test.tsx +65 -9
  465. package/src/ui/pages/__tests__/collections-directory-rows.test.tsx +92 -0
  466. package/src/ui/pages/__tests__/collections-view-links.test.tsx +81 -0
  467. package/src/ui/shared/CollectionDirectory.tsx +178 -3
  468. package/src/ui/shared/CollectionsManager.tsx +70 -17
  469. package/src/ui/shared/CopyField.tsx +127 -0
  470. package/src/ui/shared/EmptyPostContent.tsx +23 -0
  471. package/src/ui/shared/MediaGallery.tsx +125 -46
  472. package/src/ui/shared/Pagination.tsx +20 -5
  473. package/src/ui/shared/PostFooter.tsx +20 -11
  474. package/src/ui/shared/__tests__/archive-labels.test.ts +100 -0
  475. package/src/ui/shared/__tests__/media-gallery.test.ts +210 -2
  476. package/src/ui/shared/__tests__/navigation-labels.test.ts +16 -22
  477. package/src/ui/shared/__tests__/pagination.test.ts +38 -24
  478. package/src/ui/shared/__tests__/post-footer.test.ts +32 -0
  479. package/src/ui/shared/archive-labels.ts +98 -0
  480. package/src/ui/shared/collection-management-labels.ts +94 -16
  481. package/src/ui/shared/navigation-labels.ts +45 -71
  482. package/src/ui/shared/post-article-attributes.ts +2 -0
  483. package/src/ui/shared/smart-collection-labels.ts +343 -0
  484. package/dist/app-C75Zc8dD.js +0 -6
  485. package/dist/client/_assets/chunks/heic-to-DUUaO23q.js +0 -1
  486. package/dist/client/_assets/chunks/module-DcsAZQZ_.js +0 -716
  487. package/dist/client/_assets/chunks/url-CU9pEbk5.js +0 -1
  488. package/dist/client/_assets/client-Bq0vre8Y.js +0 -296
  489. package/dist/client/_assets/client-D3VZyG4L.css +0 -2
  490. package/dist/client/_assets/client-auth-F2rb9WfF.js +0 -5571
  491. package/dist/env-BPYViDJJ.js +0 -281
  492. package/dist/github-api-BNF35Lkx.js +0 -176
  493. package/dist/github-app-DdiD-bC4.js +0 -275
  494. package/dist/github-sync-Bqg62IvV.js +0 -4
  495. package/dist/github-sync-HdK2EgvJ.js +0 -431
  496. package/dist/url-CbLAtlZe.js +0 -900
  497. package/src/client/__tests__/collection-created-notice.test.ts +0 -36
  498. package/src/client/__tests__/collection-form-bridge.test.ts +0 -216
  499. package/src/client/__tests__/post-form-bridge.test.ts +0 -82
  500. package/src/client/collection-created-notice.ts +0 -66
  501. package/src/client/collection-form-bridge.ts +0 -191
  502. package/src/client/components/__tests__/jant-post-form.test.ts +0 -193
  503. package/src/client/components/jant-post-form.ts +0 -422
  504. package/src/client/components/post-form-template.ts +0 -352
  505. package/src/client/components/post-form-types.ts +0 -96
  506. package/src/client/media-metadata.ts +0 -247
  507. package/src/client/post-form-bridge.ts +0 -193
  508. package/src/ui/pages/CollectionEditorPage.tsx +0 -175
@@ -1,431 +0,0 @@
1
- import { r as parseFrontMatter, t as createExportService, u as parseMarkdownDocument } from "./export-Dl5KCiEs.js";
2
- import { r as getInstallationToken } from "./github-app-DdiD-bC4.js";
3
- import { r as parseRepoSlug, t as createGitHubClient } from "./github-api-BNF35Lkx.js";
4
- //#region src/lib/markdown-to-tiptap.ts
5
- /**
6
- * Markdown → TipTap JSON Conversion
7
- *
8
- * Converts Markdown strings to TipTap JSON documents using the official
9
- * Tiptap MarkdownManager and the same extension schema used elsewhere in Jant.
10
- */
11
- /**
12
- * Converts a Markdown string to a TipTap JSON document string.
13
- *
14
- * @param markdown - Markdown source text
15
- * @returns Stringified TipTap JSON document
16
- *
17
- * @example
18
- * ```ts
19
- * const json = markdownToTiptapJson("Hello **world**");
20
- * // '{"type":"doc","content":[{"type":"paragraph","content":[...]}]}'
21
- * ```
22
- */ function markdownToTiptapJson(markdown) {
23
- return JSON.stringify(parseMarkdownDocument(markdown));
24
- }
25
- //#endregion
26
- //#region src/services/github-sync.ts
27
- /**
28
- * GitHub Sync Service
29
- *
30
- * Handles bidirectional content synchronization between Jant and a GitHub repo.
31
- * Posts are serialized as Hugo-format Markdown bundles (reusing the export
32
- * format): each post is a branch bundle at `content/{slug}/_index.md` with
33
- * reply leaves at `content/{root-slug}/{reply-slug}/index.md`.
34
- *
35
- * Push (Jant → GitHub):
36
- * - Always full sync: regenerate Jant-managed files in a single atomic commit
37
- * - Uses base_tree so untracked files in the repo (READMEs, CI, etc.) are preserved
38
- * - Debounced: multiple rapid changes collapse into one sync
39
- *
40
- * Pull (GitHub → Jant):
41
- * - Webhook-triggered: match modified files to existing posts by slug and update
42
- * - Unknown files are skipped; new posts cannot be created from GitHub
43
- * - File deletions are intentionally ignored to avoid catastrophic data loss
44
- * (e.g. user deletes the repo → site wiped). Deletes must go through Jant's UI.
45
- *
46
- * Anti-loop: all commits from Jant include `[jant-sync]` in the message.
47
- * Incoming webhooks with this marker are skipped.
48
- */
49
- /** Marker included in commit messages to prevent webhook loops. */ var SYNC_COMMIT_MARKER = "[jant-sync]";
50
- /**
51
- * Path of the ownership marker file written at the repo root.
52
- *
53
- * Presence of this file (with a matching `site_id`) identifies the repo
54
- * as actively managed by a Jant site. Used to distinguish three states
55
- * during connect: empty repo, Jant-owned repo, foreign repo with existing
56
- * content. Also serves as the initialization file for empty repos so we
57
- * don't need a separate throwaway placeholder.
58
- */ var JANT_SYNC_MARKER_PATH = ".jant-sync";
59
- /**
60
- * Hard list of paths Jant fully owns and always overwrites on push.
61
- * Anything outside this set is user territory and preserved via base_tree.
62
- * Files inside this set that Jant no longer generates are deleted on the
63
- * next push (see `computeManagedDeletions`).
64
- *
65
- * - `content/**` — posts, collections, sections (rendered by Hugo)
66
- * - `data/jant.toml` — nav, branding, collections directory (the rest of
67
- * `data/` is user territory so Hugo's `data/menu.toml` convention, etc.,
68
- * can be used freely)
69
- * - `themes/jant/**` — the packaged Jant theme (layouts + static assets)
70
- * - `hugo.toml` — site config, including `theme = "jant"`
71
- * - `.gitignore`, `README.md` — scaffolded once, then kept in sync
72
- * - `.jant-sync` — ownership marker; written by this service, not by export
73
- *
74
- * The list is also stored in the marker itself (`managed_globs`) so future
75
- * schema bumps can diff the old and new sets to decide what needs cleanup.
76
- */ var JANT_MANAGED_GLOBS = [
77
- "content/**",
78
- "data/jant.toml",
79
- "themes/jant/**",
80
- "hugo.toml",
81
- ".gitignore",
82
- "README.md",
83
- ".jant-sync"
84
- ];
85
- /**
86
- * Match a repo-relative path against a single glob from
87
- * `JANT_MANAGED_GLOBS`. Only two forms are supported because those are
88
- * the only two shapes the constant uses:
89
- *
90
- * - Exact path (`"hugo.toml"`, `"data/jant.toml"`)
91
- * - Directory prefix + `/**` (`"content/**"`, `"themes/jant/**"`)
92
- *
93
- * Exported for testing.
94
- */ function pathMatchesManagedGlob(path, glob) {
95
- if (glob.endsWith("/**")) {
96
- const prefix = glob.slice(0, -3);
97
- return path === prefix || path.startsWith(prefix + "/");
98
- }
99
- return path === glob;
100
- }
101
- /**
102
- * True when `path` falls inside one of Jant's managed globs.
103
- *
104
- * Exported for testing.
105
- */ function isManagedPath(path) {
106
- return JANT_MANAGED_GLOBS.some((g) => pathMatchesManagedGlob(path, g));
107
- }
108
- /**
109
- * Compute the tree items that should null-out files on the remote HEAD
110
- * which Jant claims ownership of (matches `JANT_MANAGED_GLOBS`) but is
111
- * not writing in the current push (not in `writtenPaths`).
112
- *
113
- * Returns a list of `{ sha: null }` tree entries suitable for appending
114
- * to the payload of `createTree`. Exported for testing.
115
- */ function computeManagedDeletions(headTreeItems, writtenPaths) {
116
- const items = [];
117
- for (const item of headTreeItems) {
118
- if (item.type !== "blob") continue;
119
- if (!isManagedPath(item.path)) continue;
120
- if (writtenPaths.has(item.path)) continue;
121
- items.push({
122
- path: item.path,
123
- mode: "100644",
124
- type: "blob",
125
- sha: null
126
- });
127
- }
128
- return items;
129
- }
130
- function parseMarker(text) {
131
- try {
132
- const parsed = JSON.parse(text);
133
- if (typeof parsed.site_id === "string" && typeof parsed.site_host === "string" && typeof parsed.created_at === "number" && typeof parsed.schema_version === "number") return parsed;
134
- } catch {}
135
- return null;
136
- }
137
- function decodeMarkerContent(file) {
138
- if (file.encoding === "base64") try {
139
- const cleaned = file.content.replace(/\s+/g, "");
140
- const binary = atob(cleaned);
141
- const bytes = Uint8Array.from(binary, (ch) => ch.charCodeAt(0));
142
- return new TextDecoder("utf-8").decode(bytes);
143
- } catch {
144
- return "";
145
- }
146
- return file.content;
147
- }
148
- function formatMarker(marker) {
149
- return `${JSON.stringify(marker, null, 2)}\n`;
150
- }
151
- function safeHost(siteUrl) {
152
- try {
153
- return new URL(siteUrl).host;
154
- } catch {
155
- return "";
156
- }
157
- }
158
- /**
159
- * Classify a repository to decide how to proceed with a sync connection.
160
- *
161
- * - `empty`: repo has no commits on the default branch (or repo is brand new).
162
- * - `owned`: `.jant-sync` marker present with matching `site_id`.
163
- * - `owned-by-other-site`: `.jant-sync` present but `site_id` differs —
164
- * another Jant site already backs up here, blocking the connect.
165
- * - `foreign`: non-empty repo without a marker — requires explicit
166
- * user confirmation before connect.
167
- */ async function classifyRepoForSync(client, owner, repo, siteId) {
168
- const defaultBranch = (await client.getRepo(owner, repo)).default_branch;
169
- try {
170
- await client.getRef(owner, repo, `heads/${defaultBranch}`);
171
- } catch {
172
- return { kind: "empty" };
173
- }
174
- const markerFile = await client.getFileContent(owner, repo, JANT_SYNC_MARKER_PATH);
175
- if (!markerFile) return {
176
- kind: "foreign",
177
- defaultBranch
178
- };
179
- const marker = parseMarker(decodeMarkerContent(markerFile));
180
- if (!marker) return {
181
- kind: "foreign",
182
- defaultBranch
183
- };
184
- if (marker.site_id === siteId) return {
185
- kind: "owned",
186
- marker
187
- };
188
- return {
189
- kind: "owned-by-other-site",
190
- marker
191
- };
192
- }
193
- function createGitHubSyncService(services, siteId, siteConfig, deps = {}) {
194
- /**
195
- * Build the ownership marker for this push. Preserves `created_at`
196
- * from an existing marker (when readable) so the timestamp reflects
197
- * when this repo was first bound to this site, not the latest push.
198
- */ function buildMarker(existingContent, now) {
199
- const existing = existingContent ? parseMarker(existingContent) : null;
200
- const preservedCreatedAt = existing && existing.site_id === siteId ? existing.created_at : now;
201
- return {
202
- schema_version: 3,
203
- site_id: siteId,
204
- site_host: safeHost(siteConfig.siteUrl),
205
- created_at: preservedCreatedAt,
206
- managed_globs: [...JANT_MANAGED_GLOBS]
207
- };
208
- }
209
- async function loadConfig() {
210
- const [repo, enabled, authModeRaw] = await Promise.all([
211
- services.settings.get("GITHUB_SYNC_REPO"),
212
- services.settings.get("GITHUB_SYNC_ENABLED"),
213
- services.settings.get("GITHUB_SYNC_AUTH_MODE")
214
- ]);
215
- if (!repo || enabled !== "true") return null;
216
- const authMode = authModeRaw === "app" ? "app" : "pat";
217
- const [token, installationId, webhookId, webhookSecret, lastPushSha] = await Promise.all([
218
- services.settings.get("GITHUB_SYNC_TOKEN"),
219
- services.settings.get("GITHUB_SYNC_APP_INSTALLATION_ID"),
220
- services.settings.get("GITHUB_SYNC_WEBHOOK_ID"),
221
- services.settings.get("GITHUB_SYNC_WEBHOOK_SECRET"),
222
- services.settings.get("GITHUB_SYNC_LAST_PUSH_SHA")
223
- ]);
224
- if (authMode === "pat" && !token) return null;
225
- if (authMode === "app" && !installationId) return null;
226
- return {
227
- authMode,
228
- token: token ?? void 0,
229
- installationId: installationId ?? void 0,
230
- repo,
231
- enabled: true,
232
- webhookId: webhookId ?? void 0,
233
- webhookSecret: webhookSecret ?? void 0,
234
- lastPushSha: lastPushSha ?? void 0
235
- };
236
- }
237
- function createClient(config) {
238
- const parsed = parseRepoSlug(config.repo);
239
- if (!parsed) throw new Error(`Invalid repo slug: ${config.repo}`);
240
- let client;
241
- if (config.authMode === "app") {
242
- if (!deps.githubApp) throw new Error("GitHub App is not configured on this deployment. Set GITHUB_APP_ID, GITHUB_APP_PRIVATE_KEY, and GITHUB_APP_SLUG to use App auth.");
243
- if (!config.installationId) throw new Error("GitHub App installation id is missing.");
244
- const app = deps.githubApp;
245
- const installationId = config.installationId;
246
- client = createGitHubClient(() => getInstallationToken(app, installationId));
247
- } else {
248
- if (!config.token) throw new Error("GitHub sync PAT is missing.");
249
- client = createGitHubClient(config.token);
250
- }
251
- return {
252
- client,
253
- owner: parsed.owner,
254
- repo: parsed.repo
255
- };
256
- }
257
- /**
258
- * Get the HEAD SHA, initializing an empty repo if needed.
259
- * GitHub's Git Trees API requires at least one commit to exist.
260
- */ async function getOrInitHead(client, owner, repo, defaultBranch, seedMarker) {
261
- try {
262
- return { sha: (await client.getRef(owner, repo, `heads/${defaultBranch}`)).sha };
263
- } catch {
264
- await client.createOrUpdateFile(owner, repo, JANT_SYNC_MARKER_PATH, {
265
- content: formatMarker(seedMarker),
266
- message: `Initialize Jant sync ${SYNC_COMMIT_MARKER}`
267
- });
268
- return { sha: (await client.getRef(owner, repo, `heads/${defaultBranch}`)).sha };
269
- }
270
- }
271
- return {
272
- getConfig: loadConfig,
273
- async pushFullSync() {
274
- const config = await loadConfig();
275
- if (!config) throw new Error("GitHub Sync is not configured");
276
- const { client, owner, repo } = createClient(config);
277
- const exportFiles = await createExportService(services, siteConfig, {
278
- storage: deps.storage,
279
- bundleMedia: false
280
- }).generateHugoFiles();
281
- const defaultBranch = (await client.getRepo(owner, repo)).default_branch;
282
- const now = Math.floor(Date.now() / 1e3);
283
- const existingMarkerBeforeInit = await client.getFileContent(owner, repo, JANT_SYNC_MARKER_PATH).catch(() => null);
284
- const marker = buildMarker(existingMarkerBeforeInit ? decodeMarkerContent(existingMarkerBeforeInit) : null, now);
285
- const { sha: headSha } = await getOrInitHead(client, owner, repo, defaultBranch, marker);
286
- const treeItems = [{
287
- path: JANT_SYNC_MARKER_PATH,
288
- mode: "100644",
289
- type: "blob",
290
- content: formatMarker(marker)
291
- }];
292
- for (const file of exportFiles) if (typeof file.content === "string") treeItems.push({
293
- path: file.path,
294
- mode: "100644",
295
- type: "blob",
296
- content: file.content
297
- });
298
- else {
299
- const blob = await client.createBlob(owner, repo, uint8ArrayToBase64(file.content), "base64");
300
- treeItems.push({
301
- path: file.path,
302
- mode: "100644",
303
- type: "blob",
304
- sha: blob.sha
305
- });
306
- }
307
- const headCommit = await client.getCommit(owner, repo, headSha);
308
- const headTree = await client.getTree(owner, repo, headCommit.treeSha, { recursive: true });
309
- if (headTree.truncated) throw new Error("GitHub tree exceeds API limits (>100k entries or >7MB); incremental deletion cannot run safely against this repo.");
310
- const writtenPaths = new Set(treeItems.map((item) => item.path));
311
- treeItems.push(...computeManagedDeletions(headTree.tree, writtenPaths));
312
- const tree = await client.createTree(owner, repo, treeItems, headCommit.treeSha);
313
- const commit = await client.createCommit(owner, repo, {
314
- message: `Sync site ${SYNC_COMMIT_MARKER}`,
315
- tree: tree.sha,
316
- parents: [headSha]
317
- });
318
- await client.updateRef(owner, repo, `heads/${defaultBranch}`, commit.sha);
319
- await services.settings.set("GITHUB_SYNC_LAST_PUSH_SHA", commit.sha);
320
- await services.settings.set("GITHUB_SYNC_LAST_PUSH_AT", String(Math.floor(Date.now() / 1e3)));
321
- return { commitSha: commit.sha };
322
- },
323
- async handleWebhookPush(payload) {
324
- if (payload.commits.some((c) => c.message.includes("[jant-sync]")) && payload.commits.length === 1) return;
325
- const modified = /* @__PURE__ */ new Set();
326
- for (const commit of payload.commits) {
327
- if (commit.message.includes("[jant-sync]")) continue;
328
- for (const file of [...commit.modified, ...commit.added]) if (classifyBundlePath(file)) modified.add(file);
329
- }
330
- if (modified.size === 0) return;
331
- const config = await loadConfig();
332
- if (!config) return;
333
- const { client, owner, repo } = createClient(config);
334
- for (const filePath of modified) {
335
- const classification = classifyBundlePath(filePath);
336
- if (!classification) continue;
337
- const fileContent = await client.getFileContent(owner, repo, filePath, payload.after);
338
- if (!fileContent) continue;
339
- const { frontMatter, body } = await parseFrontMatter(decodeBase64Content(fileContent.content));
340
- const slug = typeof frontMatter.slug === "string" && frontMatter.slug.trim() ? frontMatter.slug.trim() : classification.slug;
341
- if (!slug) continue;
342
- const pathRecord = await services.paths.getByPath(slug);
343
- if (!pathRecord?.postId) continue;
344
- const existingPost = await services.posts.getById(pathRecord.postId);
345
- if (!existingPost) continue;
346
- if (classification.kind === "reply") {
347
- const rootPath = await services.paths.getByPath(classification.rootSlug);
348
- if (!rootPath?.postId) continue;
349
- if (existingPost.threadId !== rootPath.postId) continue;
350
- }
351
- const trimmedBody = body.trim();
352
- const tiptapBody = trimmedBody ? markdownToTiptapJson(trimmedBody) : null;
353
- const updateData = {};
354
- if (tiptapBody !== null) updateData.body = tiptapBody;
355
- if (frontMatter.title !== void 0) updateData.title = frontMatter.title;
356
- if (frontMatter.link_url !== void 0) updateData.url = frontMatter.link_url;
357
- if (frontMatter.source_name !== void 0) updateData.sourceName = frontMatter.source_name;
358
- if (frontMatter.source_url !== void 0) updateData.sourceUrl = frontMatter.source_url;
359
- if (frontMatter.quote_text !== void 0) updateData.quoteText = frontMatter.quote_text;
360
- if (frontMatter.rating !== void 0) updateData.rating = frontMatter.rating;
361
- if (Object.keys(updateData).length > 0) await services.posts.update(existingPost.id, updateData);
362
- }
363
- },
364
- async setupWebhook(callbackUrl) {
365
- const config = await loadConfig();
366
- if (!config) throw new Error("GitHub Sync is not configured");
367
- const { client, owner, repo } = createClient(config);
368
- const secretBytes = new Uint8Array(32);
369
- crypto.getRandomValues(secretBytes);
370
- const secret = Array.from(secretBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
371
- const webhook = await client.createWebhook(owner, repo, {
372
- url: callbackUrl,
373
- secret,
374
- events: ["push"]
375
- });
376
- await services.settings.set("GITHUB_SYNC_WEBHOOK_SECRET", secret);
377
- await services.settings.set("GITHUB_SYNC_WEBHOOK_ID", String(webhook.id));
378
- return { webhookId: webhook.id };
379
- },
380
- async teardownWebhook() {
381
- const config = await loadConfig();
382
- if (!config) return;
383
- if (config.webhookId) try {
384
- const { client, owner, repo } = createClient(config);
385
- await client.deleteWebhook(owner, repo, parseInt(config.webhookId));
386
- } catch {}
387
- await services.settings.set("GITHUB_SYNC_ENABLED", "false");
388
- await services.settings.set("GITHUB_SYNC_TOKEN", "");
389
- await services.settings.set("GITHUB_SYNC_REPO", "");
390
- await services.settings.set("GITHUB_SYNC_WEBHOOK_SECRET", "");
391
- await services.settings.set("GITHUB_SYNC_WEBHOOK_ID", "");
392
- await services.settings.set("GITHUB_SYNC_LAST_PUSH_SHA", "");
393
- await services.settings.set("GITHUB_SYNC_AUTH_MODE", "pat");
394
- await services.settings.set("GITHUB_SYNC_APP_INSTALLATION_ID", "");
395
- }
396
- };
397
- }
398
- function decodeBase64Content(content) {
399
- const cleaned = content.replace(/\n/g, "");
400
- return decodeURIComponent(escape(atob(cleaned)));
401
- }
402
- function classifyBundlePath(path) {
403
- if (!path.startsWith("content/")) return null;
404
- const segments = path.slice(8).split("/");
405
- if (segments.length === 2 && segments[1] === "_index.md") {
406
- const slug = segments[0];
407
- if (!slug) return null;
408
- return {
409
- kind: "root",
410
- slug
411
- };
412
- }
413
- if (segments.length === 3 && segments[2] === "index.md") {
414
- const rootSlug = segments[0];
415
- const slug = segments[1];
416
- if (!rootSlug || !slug) return null;
417
- return {
418
- kind: "reply",
419
- rootSlug,
420
- slug
421
- };
422
- }
423
- return null;
424
- }
425
- function uint8ArrayToBase64(bytes) {
426
- let binary = "";
427
- for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
428
- return btoa(binary);
429
- }
430
- //#endregion
431
- export { computeManagedDeletions as a, pathMatchesManagedGlob as c, classifyRepoForSync as i, markdownToTiptapJson as l, JANT_SYNC_MARKER_PATH as n, createGitHubSyncService as o, SYNC_COMMIT_MARKER as r, isManagedPath as s, JANT_MANAGED_GLOBS as t };