@jant/core 0.6.16 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (592) hide show
  1. package/README.md +11 -11
  2. package/bin/commands/assets/upload.js +192 -15
  3. package/bin/commands/export.js +3 -1
  4. package/bin/commands/import-site.js +749 -220
  5. package/bin/commands/reset-password.js +21 -8
  6. package/bin/commands/setup.js +136 -0
  7. package/bin/commands/site/export.js +71 -34
  8. package/bin/commands/site/pull-media.js +2 -6
  9. package/bin/commands/site/snapshot/export.js +19 -61
  10. package/bin/commands/site/snapshot/import.js +23 -24
  11. package/bin/lib/d1-query.js +92 -18
  12. package/bin/lib/hugo-markdown.js +4 -0
  13. package/bin/lib/node-env.js +40 -4
  14. package/bin/lib/site-pull-media.js +21 -28
  15. package/bin/lib/site-selection.js +94 -29
  16. package/bin/lib/site-snapshot.js +338 -3
  17. package/bin/lib/sql-export.js +68 -5
  18. package/bin/lib/wrangler-cli.js +37 -2
  19. package/bin/lib/wrangler-json.js +35 -0
  20. package/bin/lib/zip-archive.js +187 -0
  21. package/dist/{app-C7_4oab9.js → app-ZcaI1kPN.js} +53190 -13529
  22. package/dist/client/.vite/manifest.json +255 -90
  23. package/dist/client/_assets/chunks/confirm-D7GrwsCN.js +45 -0
  24. package/dist/client/_assets/chunks/create-editor-B-m7X7S5.js +261 -0
  25. package/dist/client/_assets/chunks/{native-DpcrFAPh.js → emoji-mart-C4RpRKcU.js} +716 -1
  26. package/dist/client/_assets/chunks/footnote-rail-CmeoVtnU.js +1 -0
  27. package/dist/client/_assets/chunks/heic-to-CuP2Qlsw.js +1 -0
  28. package/dist/client/_assets/chunks/jant-locale-picker-DL6mIOT5.js +69 -0
  29. package/dist/client/_assets/chunks/lit-DW8VmJAT.js +2 -0
  30. package/dist/client/_assets/chunks/mediabunny-DRaCQ1r-.js +31 -0
  31. package/dist/client/_assets/chunks/rolldown-runtime-hePW80VL.js +1 -0
  32. package/dist/client/_assets/chunks/settings-paths-BcdySNx6.js +84 -0
  33. package/dist/client/_assets/chunks/site-header-nav-DzXsFk05.js +1 -0
  34. package/dist/client/_assets/chunks/slug-format-CRXO1AL5.js +1 -0
  35. package/dist/client/_assets/chunks/slugify-373citbs.js +1 -0
  36. package/dist/client/_assets/chunks/sortable-list-BJyd-LXE.js +2 -0
  37. package/dist/client/_assets/chunks/types-D5iF3H1a.js +1 -0
  38. package/dist/client/_assets/chunks/unsafe-html-B5ZEXaxg.js +1 -0
  39. package/dist/client/_assets/chunks/unsafe-svg-BkscJx69.js +2 -0
  40. package/dist/client/_assets/client-DAhoqPdr.css +2 -0
  41. package/dist/client/_assets/client-auth-CAMfTrKW.js +828 -0
  42. package/dist/client/_assets/client-author-DQ8R-8KR.css +2 -0
  43. package/dist/client/_assets/client-compose-D6rExKVK.js +2004 -0
  44. package/dist/client/_assets/client-knSEyUJO.js +295 -0
  45. package/dist/client/_assets/client-manage-sVOkqVbH.js +2170 -0
  46. package/dist/client/_assets/client-settings-CGR_nZ78.js +1112 -0
  47. package/dist/github-sync-Gw4orAHk.js +8398 -0
  48. package/dist/index.js +2 -5
  49. package/dist/node.js +11 -9
  50. package/package.json +15 -5
  51. package/src/__tests__/auth-session-freshness.test.ts +57 -0
  52. package/src/__tests__/basecoat-variants.test.ts +121 -0
  53. package/src/__tests__/bin/assets-upload.test.ts +68 -0
  54. package/src/__tests__/dev-scripts.test.ts +203 -0
  55. package/src/__tests__/export-collection-order.test.ts +276 -0
  56. package/src/__tests__/export-feed-ids.test.ts +184 -0
  57. package/src/__tests__/export-feed-order.test.ts +294 -0
  58. package/src/__tests__/export-hugo-build.test.ts +390 -0
  59. package/src/__tests__/export-import-roundtrip.test.ts +94 -0
  60. package/src/__tests__/export-service.test.ts +842 -28
  61. package/src/__tests__/export-smart-collection.test.ts +329 -0
  62. package/src/__tests__/helpers/component-css.ts +91 -0
  63. package/src/__tests__/helpers/db.ts +33 -0
  64. package/src/__tests__/helpers/export-fixtures.ts +3 -0
  65. package/src/__tests__/helpers/hugo-site.ts +146 -0
  66. package/src/__tests__/import-site-command.test.ts +487 -1
  67. package/src/__tests__/mise-config.test.ts +75 -4
  68. package/src/__tests__/node-dev-tasks.test.ts +264 -0
  69. package/src/__tests__/site-export-canonical-import.test.ts +149 -0
  70. package/src/__tests__/snapshot-canonical-replay.test.ts +179 -0
  71. package/src/__tests__/snapshot-settings.test.ts +97 -0
  72. package/src/__tests__/snapshot-tables.test.ts +219 -0
  73. package/src/__tests__/sql-export.test.ts +173 -0
  74. package/src/__tests__/stylesheet-audience.test.ts +159 -0
  75. package/src/__tests__/stylesheet-breakpoints.test.ts +183 -0
  76. package/src/__tests__/zip-archive.test.ts +106 -0
  77. package/src/app.tsx +86 -22
  78. package/src/auth.ts +18 -1
  79. package/src/client/__tests__/collection-page-actions.test.ts +51 -2
  80. package/src/client/__tests__/compose-bridge-image-upload.test.ts +196 -0
  81. package/src/client/__tests__/compose-bridge-video-poster.test.ts +159 -0
  82. package/src/client/__tests__/compose-bridge.test.ts +272 -0
  83. package/src/client/__tests__/compose-launch.test.ts +62 -1
  84. package/src/client/__tests__/compose-shortcuts.test.ts +38 -9
  85. package/src/client/__tests__/compose-triggers.test.ts +90 -0
  86. package/src/client/__tests__/copy-field.test.ts +162 -0
  87. package/src/client/__tests__/custom-url-menu.test.ts +127 -6
  88. package/src/client/__tests__/image-processor.test.ts +324 -2
  89. package/src/client/__tests__/lazy-entries.test.ts +92 -0
  90. package/src/client/__tests__/media-scroll-hint.test.ts +155 -0
  91. package/src/client/__tests__/runtime-paths.test.ts +84 -0
  92. package/src/client/__tests__/smart-collection-page-actions.test.ts +158 -0
  93. package/src/client/__tests__/toast.test.ts +23 -0
  94. package/src/client/__tests__/video-processor-probe.test.ts +175 -0
  95. package/src/client/__tests__/video-processor.test.ts +181 -0
  96. package/src/client/audio-processor.ts +24 -15
  97. package/src/client/audio-waveform.ts +49 -0
  98. package/src/client/collection-dialog-host.ts +72 -0
  99. package/src/client/collection-navigation.ts +51 -16
  100. package/src/client/collection-page-actions.ts +26 -0
  101. package/src/client/components/__tests__/jant-collection-dialog.test.ts +329 -0
  102. package/src/client/components/__tests__/jant-collection-directory.test.ts +274 -10
  103. package/src/client/components/__tests__/jant-collection-form.test.ts +59 -178
  104. package/src/client/components/__tests__/jant-command-palette.test.ts +28 -0
  105. package/src/client/components/__tests__/jant-compose-dialog-draft-storage.test.ts +340 -0
  106. package/src/client/components/__tests__/jant-compose-dialog.test.ts +1250 -53
  107. package/src/client/components/__tests__/jant-compose-editor.test.ts +544 -40
  108. package/src/client/components/__tests__/jant-compose-fullscreen.test.ts +0 -1
  109. package/src/client/components/__tests__/jant-locale-picker.test.ts +207 -0
  110. package/src/client/components/__tests__/jant-nav-manager.test.ts +234 -15
  111. package/src/client/components/__tests__/jant-post-menu.test.ts +413 -2
  112. package/src/client/components/__tests__/jant-post-picker.test.ts +197 -0
  113. package/src/client/components/__tests__/jant-settings-avatar.test.ts +15 -12
  114. package/src/client/components/__tests__/jant-settings-general.test.ts +561 -172
  115. package/src/client/components/__tests__/jant-settings-language.test.ts +851 -0
  116. package/src/client/components/__tests__/jant-smart-collection-dialog.test.ts +665 -0
  117. package/src/client/components/collection-dialog-types.ts +49 -0
  118. package/src/client/components/collection-manager-types.ts +32 -1
  119. package/src/client/components/collection-types.ts +1 -15
  120. package/src/client/components/compose-types.ts +75 -1
  121. package/src/client/components/jant-collection-dialog.ts +722 -0
  122. package/src/client/components/jant-collection-directory.ts +567 -182
  123. package/src/client/components/jant-collection-form.ts +53 -232
  124. package/src/client/components/jant-command-palette.ts +100 -49
  125. package/src/client/components/jant-compose-dialog.ts +1486 -707
  126. package/src/client/components/jant-compose-editor.ts +673 -336
  127. package/src/client/components/jant-compose-fullscreen.ts +51 -43
  128. package/src/client/components/jant-config-editor.ts +65 -53
  129. package/src/client/components/jant-confirm-dialog.ts +13 -11
  130. package/src/client/components/jant-locale-picker.ts +418 -0
  131. package/src/client/components/jant-media-lightbox.ts +146 -136
  132. package/src/client/components/jant-nav-manager.ts +690 -366
  133. package/src/client/components/jant-post-menu.ts +1086 -282
  134. package/src/client/components/jant-post-picker.ts +324 -0
  135. package/src/client/components/jant-repo-picker-types.ts +6 -1
  136. package/src/client/components/jant-repo-picker.ts +137 -108
  137. package/src/client/components/jant-settings-avatar.ts +31 -27
  138. package/src/client/components/jant-settings-general.ts +622 -543
  139. package/src/client/components/jant-settings-language.ts +1087 -0
  140. package/src/client/components/jant-smart-collection-dialog.ts +1021 -0
  141. package/src/client/components/jant-text-preview.ts +94 -86
  142. package/src/client/components/nav-manager-types.ts +62 -1
  143. package/src/client/components/settings-types.ts +14 -29
  144. package/src/client/components/smart-collection-conditions.ts +285 -0
  145. package/src/client/components/smart-collection-dialog-types.ts +68 -0
  146. package/src/client/compose-bridge.ts +214 -141
  147. package/src/client/compose-launch.ts +76 -2
  148. package/src/client/compose-shortcuts.ts +6 -8
  149. package/src/client/compose-triggers.ts +50 -0
  150. package/src/client/copy-field.ts +108 -0
  151. package/src/client/custom-url-menu.ts +60 -4
  152. package/src/client/icons.ts +14 -0
  153. package/src/client/image-plan.ts +165 -0
  154. package/src/client/image-processor.ts +195 -117
  155. package/src/client/image-worker-client.ts +45 -0
  156. package/src/client/image-worker.ts +135 -0
  157. package/src/client/lazy-entries.ts +95 -0
  158. package/src/client/lazy-slugify.ts +2 -2
  159. package/src/client/media-scroll-hint.ts +43 -2
  160. package/src/client/mediabunny.ts +29 -0
  161. package/src/client/post-picker.ts +41 -0
  162. package/src/client/runtime-paths.ts +74 -1
  163. package/src/client/settings-bridge.ts +4 -10
  164. package/src/client/site-header-nav.js +18 -6
  165. package/src/client/smart-collection-dialog-host.ts +116 -0
  166. package/src/client/smart-collection-page-actions.ts +208 -0
  167. package/src/client/tiptap/__tests__/bubble-menu.test.ts +110 -0
  168. package/src/client/tiptap/__tests__/floating-position.test.ts +136 -1
  169. package/src/client/tiptap/__tests__/inline-image-upload.test.ts +37 -0
  170. package/src/client/tiptap/__tests__/list-editing.test.ts +224 -86
  171. package/src/client/tiptap/__tests__/mark-exit.test.ts +1 -2
  172. package/src/client/tiptap/__tests__/markdown-clipboard.test.ts +26 -0
  173. package/src/client/tiptap/bubble-menu.ts +47 -16
  174. package/src/client/tiptap/extensions.ts +0 -3
  175. package/src/client/tiptap/floating-position.ts +216 -2
  176. package/src/client/tiptap/inline-image-upload.ts +7 -3
  177. package/src/client/tiptap/link-toolbar.ts +22 -9
  178. package/src/client/tiptap/structural-keymap.ts +158 -47
  179. package/src/client/toast.ts +13 -0
  180. package/src/client/types/vite-worker.d.ts +12 -0
  181. package/src/client/upload-with-metadata.ts +3 -13
  182. package/src/client/video-processor.ts +351 -107
  183. package/src/client-auth.ts +14 -31
  184. package/src/client-compose.ts +19 -0
  185. package/src/client-manage.ts +13 -0
  186. package/src/client-settings.ts +14 -0
  187. package/src/client-site.ts +10 -3
  188. package/src/client.ts +4 -0
  189. package/src/db/__tests__/backfill-nav-label-mirrors.test.ts +149 -0
  190. package/src/db/__tests__/d1-query.test.ts +56 -1
  191. package/src/db/__tests__/schema-enum-sources.test.ts +33 -0
  192. package/src/db/__tests__/smart-collection-placement.test.ts +402 -0
  193. package/src/db/backfills/0006_clear_mirrored_page_nav_labels.sql +31 -0
  194. package/src/db/migrations/0032_married_tomas.sql +3 -0
  195. package/src/db/migrations/0033_busy_johnny_storm.sql +198 -0
  196. package/src/db/migrations/0034_cheerful_rumiko_fujikawa.sql +35 -0
  197. package/src/db/migrations/meta/0032_snapshot.json +2582 -0
  198. package/src/db/migrations/meta/0033_snapshot.json +2816 -0
  199. package/src/db/migrations/meta/0034_snapshot.json +2816 -0
  200. package/src/db/migrations/meta/_journal.json +21 -0
  201. package/src/db/migrations/pg/0030_abandoned_nighthawk.sql +3 -0
  202. package/src/db/migrations/pg/0031_strong_ultimatum.sql +128 -0
  203. package/src/db/migrations/pg/0032_furry_multiple_man.sql +6 -0
  204. package/src/db/migrations/pg/meta/0030_snapshot.json +3329 -0
  205. package/src/db/migrations/pg/meta/0031_snapshot.json +3660 -0
  206. package/src/db/migrations/pg/meta/0032_snapshot.json +3660 -0
  207. package/src/db/migrations/pg/meta/_journal.json +21 -0
  208. package/src/db/pg/schema.ts +195 -27
  209. package/src/db/post-visibility.ts +117 -0
  210. package/src/db/schema.ts +222 -27
  211. package/src/i18n/__tests__/detect.test.ts +26 -81
  212. package/src/i18n/__tests__/supported-locales.test.ts +83 -0
  213. package/src/i18n/context.tsx +12 -2
  214. package/src/i18n/detect.ts +7 -66
  215. package/src/i18n/locales/glossary.zh-Hans.yml +44 -4
  216. package/src/i18n/locales/glossary.zh-Hant.yml +44 -4
  217. package/src/i18n/locales/public/en.po +490 -158
  218. package/src/i18n/locales/public/en.ts +1 -1
  219. package/src/i18n/locales/public/zh-Hans.po +487 -155
  220. package/src/i18n/locales/public/zh-Hans.ts +1 -1
  221. package/src/i18n/locales/public/zh-Hant.po +487 -155
  222. package/src/i18n/locales/public/zh-Hant.ts +1 -1
  223. package/src/i18n/locales/settings/en.po +555 -73
  224. package/src/i18n/locales/settings/en.ts +1 -1
  225. package/src/i18n/locales/settings/zh-Hans.po +601 -119
  226. package/src/i18n/locales/settings/zh-Hans.ts +1 -1
  227. package/src/i18n/locales/settings/zh-Hant.po +614 -132
  228. package/src/i18n/locales/settings/zh-Hant.ts +1 -1
  229. package/src/i18n/locales.ts +94 -0
  230. package/src/i18n/middleware.ts +12 -2
  231. package/src/i18n/supported-locales.ts +80 -0
  232. package/src/lib/__tests__/api-settings.test.ts +11 -2
  233. package/src/lib/__tests__/asset-path.test.ts +92 -0
  234. package/src/lib/__tests__/deferred.test.ts +90 -0
  235. package/src/lib/__tests__/discover-ping.test.ts +89 -0
  236. package/src/lib/__tests__/discover.test.ts +410 -0
  237. package/src/lib/__tests__/feed-policy.test.ts +26 -0
  238. package/src/lib/__tests__/feed.test.ts +1526 -15
  239. package/src/lib/__tests__/filter-dimensions.test.ts +341 -0
  240. package/src/lib/__tests__/github-sync-repo-name.test.ts +40 -0
  241. package/src/lib/__tests__/hosted-signin.test.ts +1 -1
  242. package/src/lib/__tests__/http-cache.test.ts +162 -0
  243. package/src/lib/__tests__/image.test.ts +27 -1
  244. package/src/lib/__tests__/jant-docs-dev.test.ts +21 -0
  245. package/src/lib/__tests__/jant-docs.test.ts +23 -0
  246. package/src/lib/__tests__/lang-detect.test.ts +231 -0
  247. package/src/lib/__tests__/markdown-to-tiptap.test.ts +105 -0
  248. package/src/lib/__tests__/markdown.test.ts +10 -0
  249. package/src/lib/__tests__/media-helpers.test.ts +81 -0
  250. package/src/lib/__tests__/navigation.test.ts +135 -1
  251. package/src/lib/__tests__/resolve-config.test.ts +131 -3
  252. package/src/lib/__tests__/schemas.test.ts +69 -5
  253. package/src/lib/__tests__/site-unavailable-page.test.ts +25 -0
  254. package/src/lib/__tests__/slug.test.ts +70 -0
  255. package/src/lib/__tests__/slugify.test.ts +85 -0
  256. package/src/lib/__tests__/storage.test.ts +32 -0
  257. package/src/lib/__tests__/thread-fold.test.ts +113 -0
  258. package/src/lib/__tests__/timeline.test.ts +87 -0
  259. package/src/lib/__tests__/tiptap-to-markdown.test.ts +172 -4
  260. package/src/lib/__tests__/upload-sideload.test.ts +14 -0
  261. package/src/lib/__tests__/url-fetch.test.ts +1 -2
  262. package/src/lib/__tests__/url.test.ts +78 -72
  263. package/src/lib/__tests__/view-language.test.ts +413 -0
  264. package/src/lib/__tests__/worker-response-cache.test.ts +90 -0
  265. package/src/lib/address.ts +57 -0
  266. package/src/lib/api-posts.ts +12 -0
  267. package/src/lib/asset-path.ts +98 -1
  268. package/src/lib/build-env.ts +16 -0
  269. package/src/lib/collection-groups.ts +5 -1
  270. package/src/lib/collection-paths.ts +3 -10
  271. package/src/lib/constants.ts +28 -3
  272. package/src/lib/copy-field.ts +36 -0
  273. package/src/lib/crypto.ts +40 -0
  274. package/src/lib/csp-builder.ts +2 -1
  275. package/src/lib/deferred.ts +79 -0
  276. package/src/lib/discover-ping.ts +141 -0
  277. package/src/lib/discover.ts +439 -0
  278. package/src/lib/env.ts +134 -0
  279. package/src/lib/errors.ts +33 -0
  280. package/src/lib/feed-policy.ts +236 -2
  281. package/src/lib/feed.ts +926 -73
  282. package/src/lib/filter-dimensions.ts +1349 -0
  283. package/src/lib/github-sync-repo-name.ts +45 -0
  284. package/src/lib/github-sync-site-config.ts +3 -0
  285. package/src/lib/hosted-signin.ts +1 -1
  286. package/src/lib/http-cache.ts +148 -0
  287. package/src/lib/hugo-markdown.ts +62 -0
  288. package/src/lib/icons.ts +9 -2
  289. package/src/lib/ids.ts +3 -0
  290. package/src/lib/image.ts +17 -4
  291. package/src/lib/jant-docs.ts +42 -0
  292. package/src/lib/lang-detect.ts +308 -0
  293. package/src/lib/markdown-manager.ts +392 -2
  294. package/src/lib/media-helpers.ts +13 -1
  295. package/src/lib/navigation.ts +78 -11
  296. package/src/lib/pagination.ts +28 -24
  297. package/src/lib/per-language-surfaces.ts +67 -0
  298. package/src/lib/post-body-html.ts +11 -4
  299. package/src/lib/post-meta.ts +19 -0
  300. package/src/lib/render.tsx +55 -7
  301. package/src/lib/resolve-config.ts +111 -6
  302. package/src/lib/schemas.ts +251 -15
  303. package/src/lib/site-header-fragment.tsx +2 -1
  304. package/src/lib/site-unavailable-page.ts +47 -0
  305. package/src/lib/slug.ts +51 -7
  306. package/src/lib/slugify.ts +113 -0
  307. package/src/lib/startup-config.ts +4 -6
  308. package/src/lib/storage.ts +7 -0
  309. package/src/lib/summary.ts +50 -0
  310. package/src/lib/thread-fold.ts +161 -0
  311. package/src/lib/time.ts +32 -0
  312. package/src/lib/timeline.ts +43 -2
  313. package/src/lib/tiptap-render.ts +1 -2
  314. package/src/lib/tiptap-to-markdown.ts +13 -7
  315. package/src/lib/upload.ts +16 -13
  316. package/src/lib/url.ts +159 -86
  317. package/src/lib/version.ts +10 -8
  318. package/src/lib/view-language.ts +436 -0
  319. package/src/lib/view.ts +53 -25
  320. package/src/lib/viewer-context.ts +62 -0
  321. package/src/middleware/__tests__/auth.test.ts +70 -2
  322. package/src/middleware/__tests__/cache-control.test.ts +71 -3
  323. package/src/middleware/__tests__/onboarding.test.ts +76 -5
  324. package/src/middleware/__tests__/secure-headers.test.ts +1 -1
  325. package/src/middleware/__tests__/session.test.ts +181 -33
  326. package/src/middleware/auth.ts +50 -31
  327. package/src/middleware/cache-control.ts +75 -10
  328. package/src/middleware/config.ts +6 -6
  329. package/src/middleware/error-handler.ts +12 -0
  330. package/src/middleware/onboarding.ts +32 -10
  331. package/src/middleware/secure-headers.ts +1 -1
  332. package/src/middleware/session.ts +96 -8
  333. package/src/node/__tests__/cli-migrate.test.ts +21 -19
  334. package/src/node/__tests__/cli-reset-password.test.ts +81 -8
  335. package/src/node/__tests__/cli-runtime-target.test.ts +48 -1
  336. package/src/node/__tests__/cli-setup.test.ts +163 -0
  337. package/src/node/__tests__/cli-site-selection.test.ts +128 -38
  338. package/src/node/__tests__/cli-site-snapshot.test.ts +67 -0
  339. package/src/node/__tests__/cli-snapshot-meta.test.ts +20 -0
  340. package/src/node/__tests__/runtime.test.ts +75 -0
  341. package/src/node/index.ts +3 -0
  342. package/src/node/request-handler.ts +3 -1
  343. package/src/preset.css +76 -22
  344. package/src/routes/__tests__/feed-validator.test.ts +156 -0
  345. package/src/routes/api/__tests__/collections.test.ts +114 -0
  346. package/src/routes/api/__tests__/discover.test.ts +222 -0
  347. package/src/routes/api/__tests__/nav-items.test.ts +212 -2
  348. package/src/routes/api/__tests__/post-translations.test.ts +829 -0
  349. package/src/routes/api/__tests__/posts.test.ts +24 -0
  350. package/src/routes/api/__tests__/settings.test.ts +24 -3
  351. package/src/routes/api/__tests__/telegram.test.ts +6 -5
  352. package/src/routes/api/__tests__/upload.test.ts +34 -0
  353. package/src/routes/api/collections.ts +49 -6
  354. package/src/routes/api/custom-urls.ts +0 -1
  355. package/src/routes/api/discover.ts +95 -0
  356. package/src/routes/api/export.ts +6 -3
  357. package/src/routes/api/internal/__tests__/sites.test.ts +42 -2
  358. package/src/routes/api/internal/sites.ts +0 -1
  359. package/src/routes/api/nav-items.ts +55 -8
  360. package/src/routes/api/posts.ts +161 -0
  361. package/src/routes/api/public/__tests__/archive.test.ts +111 -0
  362. package/src/routes/api/public/archive.ts +77 -81
  363. package/src/routes/api/public/posts.ts +44 -7
  364. package/src/routes/api/smart-collections.ts +132 -0
  365. package/src/routes/api/telegram.ts +2 -40
  366. package/src/routes/api/upload.ts +10 -3
  367. package/src/routes/api/uploads.ts +1 -2
  368. package/src/routes/auth/__tests__/setup-auth.test.ts +137 -0
  369. package/src/routes/auth/__tests__/setup-discover.test.ts +204 -0
  370. package/src/routes/auth/__tests__/setup-flow.test.ts +270 -0
  371. package/src/routes/auth/__tests__/setup-page.test.tsx +329 -0
  372. package/src/routes/auth/__tests__/setup-steps.test.ts +310 -0
  373. package/src/routes/auth/__tests__/setup.test.ts +278 -26
  374. package/src/routes/auth/__tests__/signin.test.ts +135 -0
  375. package/src/routes/auth/setup.tsx +934 -186
  376. package/src/routes/auth/signin.tsx +10 -8
  377. package/src/routes/compose.tsx +9 -0
  378. package/src/routes/dash/__tests__/custom-urls-archive.test.ts +44 -0
  379. package/src/routes/dash/__tests__/custom-urls-page.test.ts +49 -0
  380. package/src/routes/dash/__tests__/delete-account.test.ts +106 -0
  381. package/src/routes/dash/__tests__/github-sync-app.test.ts +365 -0
  382. package/src/routes/dash/__tests__/settings-discover.test.ts +213 -0
  383. package/src/routes/dash/custom-urls.tsx +1 -37
  384. package/src/routes/dash/settings.tsx +714 -111
  385. package/src/routes/discover-announce.ts +96 -0
  386. package/src/routes/feed/__tests__/feed.test.ts +165 -2
  387. package/src/routes/feed/feed.ts +69 -40
  388. package/src/routes/feed/sitemap.ts +95 -11
  389. package/src/routes/pages/__tests__/archive-indexing.test.ts +200 -0
  390. package/src/routes/pages/__tests__/archive-params.test.ts +370 -6
  391. package/src/routes/pages/__tests__/collection-routing.test.ts +16 -0
  392. package/src/routes/pages/__tests__/collections-feed-links.test.ts +72 -0
  393. package/src/routes/pages/__tests__/collections.test.ts +9 -3
  394. package/src/routes/pages/__tests__/custom-archive-url.test.ts +119 -0
  395. package/src/routes/pages/__tests__/feed-autodiscovery.test.ts +148 -0
  396. package/src/routes/pages/__tests__/language-routing.test.ts +679 -0
  397. package/src/routes/pages/__tests__/post-page-round-trips.test.ts +211 -0
  398. package/src/routes/pages/__tests__/post-preview-partial.test.ts +96 -0
  399. package/src/routes/pages/__tests__/smart-collection.test.ts +298 -0
  400. package/src/routes/pages/__tests__/subscribe.test.ts +248 -0
  401. package/src/routes/pages/__tests__/thread-order.test.ts +179 -0
  402. package/src/routes/pages/archive.tsx +487 -379
  403. package/src/routes/pages/collection.tsx +94 -96
  404. package/src/routes/pages/collections.tsx +38 -50
  405. package/src/routes/pages/featured.tsx +43 -18
  406. package/src/routes/pages/home.tsx +25 -6
  407. package/src/routes/pages/language.tsx +113 -0
  408. package/src/routes/pages/latest.tsx +26 -16
  409. package/src/routes/pages/new.tsx +3 -0
  410. package/src/routes/pages/page.tsx +228 -45
  411. package/src/routes/pages/partials.tsx +41 -0
  412. package/src/routes/pages/search.tsx +22 -5
  413. package/src/routes/pages/smart-collection.tsx +340 -0
  414. package/src/routes/pages/subscribe.tsx +182 -0
  415. package/src/runtime/__tests__/index.test.ts +19 -0
  416. package/src/runtime/__tests__/node.test.ts +129 -4
  417. package/src/runtime/__tests__/readiness.test.ts +23 -0
  418. package/src/runtime/cloudflare.ts +21 -2
  419. package/src/runtime/index.ts +27 -1
  420. package/src/runtime/node.ts +67 -1
  421. package/src/runtime/readiness.ts +15 -0
  422. package/src/runtime/site.ts +95 -24
  423. package/src/services/__tests__/auth.test.ts +116 -7
  424. package/src/services/__tests__/bootstrap-setup-instance.test.ts +230 -0
  425. package/src/services/__tests__/collection.test.ts +108 -4
  426. package/src/services/__tests__/custom-url.test.ts +34 -0
  427. package/src/services/__tests__/github-app-installations.test.ts +153 -0
  428. package/src/services/__tests__/github-sync-push.test.ts +46 -0
  429. package/src/services/__tests__/language.test.ts +495 -0
  430. package/src/services/__tests__/media.test.ts +31 -0
  431. package/src/services/__tests__/navigation.test.ts +213 -10
  432. package/src/services/__tests__/path.test.ts +236 -0
  433. package/src/services/__tests__/post-language.test.ts +830 -0
  434. package/src/services/__tests__/post-timeline.test.ts +127 -0
  435. package/src/services/__tests__/post.test.ts +120 -9
  436. package/src/services/__tests__/settings.test.ts +228 -17
  437. package/src/services/__tests__/site-admin.test.ts +5 -5
  438. package/src/services/__tests__/smart-collection.test.ts +651 -0
  439. package/src/services/about-page.ts +22 -1
  440. package/src/services/auth.ts +51 -49
  441. package/src/services/bootstrap.ts +408 -39
  442. package/src/services/collection-directory-position.ts +76 -0
  443. package/src/services/collection.ts +331 -46
  444. package/src/services/custom-url.ts +29 -24
  445. package/src/services/export-theme/assets/client-site.css +1 -1
  446. package/src/services/export-theme/assets/client-site.js +123 -123
  447. package/src/services/export-theme/layouts/_default/alias.html +27 -1
  448. package/src/services/export-theme/layouts/_default/list.html +2 -63
  449. package/src/services/export-theme/layouts/_default/rss.xml +103 -38
  450. package/src/services/export-theme/layouts/collections/list.html +3 -3
  451. package/src/services/export-theme/layouts/featured/list.html +1 -4
  452. package/src/services/export-theme/layouts/index.html +40 -26
  453. package/src/services/export-theme/layouts/partials/collection-members.html +100 -0
  454. package/src/services/export-theme/layouts/partials/collection-threads.html +33 -0
  455. package/src/services/export-theme/layouts/partials/featured-members.html +35 -0
  456. package/src/services/export-theme/layouts/partials/featured-thread.html +1 -1
  457. package/src/services/export-theme/layouts/partials/feed-post-content.xml +105 -2
  458. package/src/services/export-theme/layouts/partials/footer.html +1 -1
  459. package/src/services/export-theme/layouts/partials/head.html +1 -1
  460. package/src/services/export-theme/layouts/partials/header.html +5 -3
  461. package/src/services/export-theme/layouts/partials/jant-data.html +23 -0
  462. package/src/services/export-theme/layouts/partials/latest-members.html +48 -0
  463. package/src/services/export-theme/layouts/partials/media-gallery.html +35 -21
  464. package/src/services/export-theme/layouts/partials/pagination.html +14 -13
  465. package/src/services/export-theme/layouts/partials/post-card.html +8 -4
  466. package/src/services/export-theme/layouts/partials/reply.html +2 -1
  467. package/src/services/export-theme/layouts/partials/smart-collection-members.html +129 -0
  468. package/src/services/export-theme/layouts/partials/thread-preview.html +41 -31
  469. package/src/services/export-theme/layouts/post/list.html +1 -1
  470. package/src/services/export-theme/layouts/smart_collection/list.html +24 -0
  471. package/src/services/export-theme/styles/main.css +13 -2
  472. package/src/services/export-theme/theme.toml +1 -1
  473. package/src/services/export.ts +880 -72
  474. package/src/services/github-app-installations.ts +171 -4
  475. package/src/services/github-sync.ts +69 -15
  476. package/src/services/index.ts +34 -3
  477. package/src/services/language.ts +412 -0
  478. package/src/services/mcp.ts +22 -2
  479. package/src/services/media.ts +22 -7
  480. package/src/services/navigation.ts +429 -67
  481. package/src/services/path.ts +254 -6
  482. package/src/services/post.ts +1234 -190
  483. package/src/services/search.ts +39 -2
  484. package/src/services/settings.ts +238 -43
  485. package/src/services/site-admin.ts +27 -14
  486. package/src/services/site.ts +160 -32
  487. package/src/services/smart-collection.ts +636 -0
  488. package/src/services/telegram.ts +20 -22
  489. package/src/services/upload-session.ts +1 -3
  490. package/src/style-author.css +27 -0
  491. package/src/styles/components-author.css +1622 -0
  492. package/src/styles/components.css +24 -1571
  493. package/src/styles/site-media.css +16 -2
  494. package/src/styles/tokens.css +82 -12
  495. package/src/styles/ui-author.css +7602 -0
  496. package/src/styles/ui.css +1090 -7216
  497. package/src/types/app-context.ts +23 -0
  498. package/src/types/bindings.ts +8 -0
  499. package/src/types/config.ts +94 -15
  500. package/src/types/constants.ts +188 -16
  501. package/src/types/entities.ts +87 -1
  502. package/src/types/operations.ts +74 -2
  503. package/src/types/props.ts +157 -31
  504. package/src/types/views.ts +55 -1
  505. package/src/ui/__tests__/font-themes.test.ts +52 -12
  506. package/src/ui/compose/ComposeDialog.tsx +201 -7
  507. package/src/ui/compose/ComposePrompt.tsx +1 -5
  508. package/src/ui/compose/__tests__/ComposeDialog.test.tsx +125 -0
  509. package/src/ui/dash/appearance/AdvancedContent.tsx +2 -2
  510. package/src/ui/dash/appearance/CodeInjectionContent.tsx +12 -16
  511. package/src/ui/dash/appearance/NavigationContent.tsx +117 -16
  512. package/src/ui/dash/appearance/__tests__/NavigationContent.test.tsx +33 -11
  513. package/src/ui/dash/appearance/__tests__/system-nav-descriptions.test.ts +44 -0
  514. package/src/ui/dash/appearance/system-nav-descriptions.ts +75 -0
  515. package/src/ui/dash/settings/AccountMenuContent.tsx +2 -2
  516. package/src/ui/dash/settings/ApiTokensContent.tsx +2 -1
  517. package/src/ui/dash/settings/ConfigEditorContent.tsx +35 -16
  518. package/src/ui/dash/settings/GeneralContent.tsx +277 -113
  519. package/src/ui/dash/settings/LanguageContent.tsx +409 -0
  520. package/src/ui/dash/settings/SettingsRootContent.tsx +19 -1
  521. package/src/ui/dash/settings/__tests__/GeneralContent.test.tsx +324 -4
  522. package/src/ui/dash/settings/__tests__/LanguageContent.test.tsx +144 -0
  523. package/src/ui/dash/settings/__tests__/discover-copy.test.ts +66 -0
  524. package/src/ui/dash/settings/discover-copy.ts +116 -0
  525. package/src/ui/feed/LinkCard.tsx +55 -45
  526. package/src/ui/feed/NoteCard.tsx +9 -4
  527. package/src/ui/feed/PostStatusBadges.tsx +90 -43
  528. package/src/ui/feed/QuoteCard.tsx +55 -30
  529. package/src/ui/feed/ThreadPreview.tsx +6 -2
  530. package/src/ui/feed/__tests__/thread-preview.test.ts +13 -16
  531. package/src/ui/feed/__tests__/timeline-cards.test.ts +314 -49
  532. package/src/ui/feed/thread-preview-state.ts +20 -6
  533. package/src/ui/font-themes.ts +39 -29
  534. package/src/ui/layouts/BaseLayout.tsx +155 -10
  535. package/src/ui/layouts/SiteLayout.tsx +192 -34
  536. package/src/ui/layouts/__tests__/BaseLayout.test.tsx +196 -17
  537. package/src/ui/layouts/__tests__/SiteLayout.test.tsx +109 -85
  538. package/src/ui/pages/ArchivePage.tsx +282 -289
  539. package/src/ui/pages/CollectionPage.tsx +86 -76
  540. package/src/ui/pages/CollectionsPage.tsx +5 -0
  541. package/src/ui/pages/ComposePage.tsx +8 -0
  542. package/src/ui/pages/PostPage.tsx +47 -0
  543. package/src/ui/pages/SearchPage.tsx +3 -3
  544. package/src/ui/pages/SmartCollectionPage.tsx +434 -0
  545. package/src/ui/pages/SubscribePage.tsx +236 -0
  546. package/src/ui/pages/__tests__/ArchivePage.test.tsx +65 -9
  547. package/src/ui/pages/__tests__/collections-directory-rows.test.tsx +92 -0
  548. package/src/ui/pages/__tests__/collections-view-links.test.tsx +81 -0
  549. package/src/ui/shared/CollectionDirectory.tsx +178 -3
  550. package/src/ui/shared/CollectionsManager.tsx +70 -17
  551. package/src/ui/shared/CopyField.tsx +127 -0
  552. package/src/ui/shared/EmptyPostContent.tsx +23 -0
  553. package/src/ui/shared/MediaGallery.tsx +125 -46
  554. package/src/ui/shared/Pagination.tsx +20 -5
  555. package/src/ui/shared/PostFooter.tsx +20 -11
  556. package/src/ui/shared/__tests__/archive-labels.test.ts +100 -0
  557. package/src/ui/shared/__tests__/media-gallery.test.ts +210 -2
  558. package/src/ui/shared/__tests__/navigation-labels.test.ts +16 -22
  559. package/src/ui/shared/__tests__/pagination.test.ts +38 -24
  560. package/src/ui/shared/__tests__/post-footer.test.ts +32 -0
  561. package/src/ui/shared/archive-labels.ts +98 -0
  562. package/src/ui/shared/collection-management-labels.ts +94 -16
  563. package/src/ui/shared/navigation-labels.ts +45 -71
  564. package/src/ui/shared/post-article-attributes.ts +2 -0
  565. package/src/ui/shared/smart-collection-labels.ts +343 -0
  566. package/dist/app-C75Zc8dD.js +0 -6
  567. package/dist/client/_assets/chunks/heic-to-DUUaO23q.js +0 -1
  568. package/dist/client/_assets/chunks/module-DcsAZQZ_.js +0 -716
  569. package/dist/client/_assets/chunks/url-CU9pEbk5.js +0 -1
  570. package/dist/client/_assets/client-Bq0vre8Y.js +0 -296
  571. package/dist/client/_assets/client-D3VZyG4L.css +0 -2
  572. package/dist/client/_assets/client-auth-F2rb9WfF.js +0 -5571
  573. package/dist/env-BPYViDJJ.js +0 -281
  574. package/dist/export-Dl5KCiEs.js +0 -5562
  575. package/dist/github-api-BNF35Lkx.js +0 -176
  576. package/dist/github-app-DdiD-bC4.js +0 -275
  577. package/dist/github-sync-Bqg62IvV.js +0 -4
  578. package/dist/github-sync-HdK2EgvJ.js +0 -431
  579. package/dist/url-CbLAtlZe.js +0 -900
  580. package/src/client/__tests__/collection-created-notice.test.ts +0 -36
  581. package/src/client/__tests__/collection-form-bridge.test.ts +0 -216
  582. package/src/client/__tests__/post-form-bridge.test.ts +0 -82
  583. package/src/client/collection-created-notice.ts +0 -66
  584. package/src/client/collection-form-bridge.ts +0 -191
  585. package/src/client/components/__tests__/jant-post-form.test.ts +0 -193
  586. package/src/client/components/jant-post-form.ts +0 -422
  587. package/src/client/components/post-form-template.ts +0 -352
  588. package/src/client/components/post-form-types.ts +0 -96
  589. package/src/client/media-metadata.ts +0 -247
  590. package/src/client/post-form-bridge.ts +0 -193
  591. package/src/client/tiptap/exitable-marks.ts +0 -73
  592. package/src/ui/pages/CollectionEditorPage.tsx +0 -175
package/dist/index.js CHANGED
@@ -1,6 +1,3 @@
1
- import { b as url_exports } from "./url-CbLAtlZe.js";
2
- import { C as toPostView, S as toNavItemViews, T as toSearchResultView, _ as createMediaContext, b as toMediaView, d as defaultFeedRenderer, t as createApp, v as toArchiveGroups, w as toPostViews, x as toNavItemView, y as toArchiveGroupsWithMedia } from "./app-C7_4oab9.js";
3
- import { B as NAV_ITEM_TYPES, E as time_exports, F as MAX_MEDIA_ATTACHMENTS, H as STATUSES, I as MAX_PINNED_POSTS, K as TEXT_ATTACHMENT_CONTENT_FORMATS, N as FORMATS, V as SORT_ORDERS, s as markdown_exports, z as MEDIA_KINDS } from "./export-Dl5KCiEs.js";
4
- import "./env-BPYViDJJ.js";
5
- import "./github-sync-HdK2EgvJ.js";
1
+ import { At as MAX_PINNED_POSTS, Ft as NAV_ITEM_TYPES, Ht as SORT_ORDERS, Ln as url_exports, Nt as MEDIA_KINDS, Tt as FORMATS, Ut as STATUSES, kt as MAX_MEDIA_ATTACHMENTS, qt as TEXT_ATTACHMENT_CONTENT_FORMATS, v as markdown_exports, z as time_exports } from "./github-sync-Gw4orAHk.js";
2
+ import { C as toNavItemView, D as toSearchResultView, E as toPostViews, S as toMediaView, T as toPostView, b as toArchiveGroups, n as createApp, v as defaultFeedRenderer, w as toNavItemViews, x as toArchiveGroupsWithMedia, y as createMediaContext } from "./app-ZcaI1kPN.js";
6
3
  export { FORMATS, MAX_MEDIA_ATTACHMENTS, MAX_PINNED_POSTS, MEDIA_KINDS, NAV_ITEM_TYPES, SORT_ORDERS, STATUSES, TEXT_ATTACHMENT_CONTENT_FORMATS, createApp, createMediaContext, defaultFeedRenderer, markdown_exports as markdown, time_exports as time, toArchiveGroups, toArchiveGroupsWithMedia, toMediaView, toNavItemView, toNavItemViews, toPostView, toPostViews, toSearchResultView, url_exports as url };
package/dist/node.js CHANGED
@@ -1,8 +1,5 @@
1
- import "./url-CbLAtlZe.js";
2
- import { A as buildThemeStyle, D as getCjkFontCssVariables, E as BUILTIN_FONT_THEMES, M as getPublicAssetBasePath, N as isAssetPath, O as getFontThemeCssVariables, a as getHostBasedStartupConfigurationIssues, c as getWebhookUrl, f as createStorageDriver, g as schema_exports, h as createNodeDatabase, i as createSiteService, j as BUILTIN_COLOR_THEMES, k as resolveCjkFontProfile, l as setMyCommands, m as sqliteSchemaBundle, n as createNodeCliRuntime, o as resolveDatabaseDialect, p as pgSchemaBundle, r as createNodeRequestRuntime, s as resolveConfig, t as createApp, u as setWebhook } from "./app-C7_4oab9.js";
3
- import { t as createExportService } from "./export-Dl5KCiEs.js";
4
- import { C as shouldTrustProxy, S as getTelegramWebhookSecret, b as getSiteResolutionMode, d as getHostedControlPlaneBaseUrl, i as getConfiguredSingleSitePathPrefix, l as getEnvString, r as getConfiguredSingleSiteOrigin, x as getTelegramBotPool, y as getPort } from "./env-BPYViDJJ.js";
5
- import "./github-sync-HdK2EgvJ.js";
1
+ import { K as getConfiguredStorageDriver, Q as getEnvString, R as now, U as getConfiguredSingleSiteOrigin, W as getConfiguredSingleSitePathPrefix, ct as getPort, dt as getTelegramWebhookSecret, et as getHostedControlPlaneBaseUrl, ft as shouldTrustProxy, lt as getSiteResolutionMode, s as createExportService, ut as getTelegramBotPool } from "./github-sync-Gw4orAHk.js";
2
+ import { A as getFontThemeCssVariables, F as isAssetPath, M as buildThemeStyle, N as BUILTIN_COLOR_THEMES, O as BUILTIN_FONT_THEMES, P as getPublicAssetBasePath, _ as schema_exports, a as setUpNodeInstance, c as resolveDatabaseDialect, d as setMyCommands, f as setWebhook, g as createNodeDatabase, h as sqliteSchemaBundle, i as createNodeRequestRuntime, j as resolveCjkFontProfile, k as getCjkFontCssVariables, l as resolveConfig, m as pgSchemaBundle, n as createApp, o as createSiteService, p as createStorageDriver, r as createNodeCliRuntime, s as getHostBasedStartupConfigurationIssues, u as getWebhookUrl } from "./app-ZcaI1kPN.js";
6
3
  import { drizzle } from "drizzle-orm/better-sqlite3";
7
4
  import { serve } from "@hono/node-server";
8
5
  import Database from "better-sqlite3";
@@ -422,7 +419,8 @@ async function migrate(env = getProcessBindings()) {
422
419
  }
423
420
  const sqlite = createNodeSqlite(env, { createParentDir: true });
424
421
  try {
425
- migrate$1(drizzle(sqlite, { schema: schema_exports }), { migrationsFolder: resolveNodeMigrationsDir(import.meta.url, "sqlite") });
422
+ const db = drizzle(sqlite, { schema: schema_exports });
423
+ migrate$1(db, { migrationsFolder: resolveNodeMigrationsDir(import.meta.url, "sqlite") });
426
424
  } finally {
427
425
  sqlite.close();
428
426
  }
@@ -442,7 +440,11 @@ async function createNodeRequestHandler(options) {
442
440
  const env = options?.env ?? getProcessBindings();
443
441
  const hostBasedStartupIssues = getHostBasedStartupConfigurationIssues(env);
444
442
  if (hostBasedStartupIssues.length > 0) throw new Error(`Host-based startup configuration is invalid:\n- ${hostBasedStartupIssues.map((issue) => issue.message).join("\n- ")}`);
445
- const { bindings, close } = await createNodeBindings(env);
443
+ const { bindings: databaseBindings, close } = await createNodeBindings(env);
444
+ const bindings = {
445
+ ...databaseBindings,
446
+ NODE_STARTED_AT: now()
447
+ };
446
448
  try {
447
449
  await assertNodeSiteResolutionReady(bindings);
448
450
  const assetRoot = options?.assetRoot === void 0 ? resolveNodeAssetRoot() : options.assetRoot;
@@ -529,7 +531,7 @@ async function createNodeRequestHandler(options) {
529
531
  async function start(env = process.env, app) {
530
532
  const handler = await createNodeRequestHandler({
531
533
  env,
532
- app: async () => app ?? (await import("./app-C75Zc8dD.js")).createApp()
534
+ app: async () => app ?? (await import("./app-ZcaI1kPN.js").then((n) => n.t)).createApp()
533
535
  });
534
536
  const hostname = resolveHost(env);
535
537
  const port = resolvePort(env);
@@ -574,4 +576,4 @@ async function start(env = process.env, app) {
574
576
  });
575
577
  }
576
578
  //#endregion
577
- export { BUILTIN_COLOR_THEMES, BUILTIN_FONT_THEMES, buildThemeStyle, createApp, createExportService, createNodeBindings, createNodeCliRuntime, createNodeRequestHandler, createNodeRequestRuntime, createStorageDriver, getCjkFontCssVariables, getFontThemeCssVariables, migrate, resolveCjkFontProfile, resolveConfig, start };
579
+ export { BUILTIN_COLOR_THEMES, BUILTIN_FONT_THEMES, buildThemeStyle, createApp, createExportService, createNodeBindings, createNodeCliRuntime, createNodeRequestHandler, createNodeRequestRuntime, createStorageDriver, getCjkFontCssVariables, getConfiguredStorageDriver, getFontThemeCssVariables, migrate, resolveCjkFontProfile, resolveConfig, setUpNodeInstance, start };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jant/core",
3
- "version": "0.6.16",
3
+ "version": "0.7.1",
4
4
  "description": "A modern, open-source microblogging platform built on Cloudflare Workers",
5
5
  "type": "module",
6
6
  "exports": {
@@ -38,19 +38,26 @@
38
38
  "@lingui/react": "^5.9.3",
39
39
  "@tailwindcss/typography": "^0.5.19",
40
40
  "@tiptap/core": "^3.27.3",
41
+ "@tiptap/extension-bold": "^3.31.3",
41
42
  "@tiptap/extension-code-block": "^3.27.3",
43
+ "@tiptap/extension-hard-break": "^3.31.3",
42
44
  "@tiptap/extension-image": "^3.27.3",
45
+ "@tiptap/extension-italic": "^3.31.3",
43
46
  "@tiptap/extension-link": "^3.27.3",
47
+ "@tiptap/extension-list": "^3.31.3",
48
+ "@tiptap/extension-paragraph": "^3.31.3",
44
49
  "@tiptap/extension-placeholder": "^3.27.3",
50
+ "@tiptap/extension-strike": "^3.31.3",
45
51
  "@tiptap/extension-table": "^3.27.3",
46
52
  "@tiptap/markdown": "^3.27.3",
47
53
  "@tiptap/pm": "^3.27.3",
48
54
  "@tiptap/starter-kit": "^3.27.3",
49
55
  "@tiptap/suggestion": "^3.27.3",
50
56
  "basecoat-css": "^0.3.11",
51
- "better-auth": "^1.5.5",
57
+ "better-auth": "1.6.27",
52
58
  "better-sqlite3": "^12.8.0",
53
59
  "blurhash": "^2.0.5",
60
+ "client-zip": "^2.5.1",
54
61
  "drizzle-orm": "^0.45.1",
55
62
  "emoji-mart": "^5.6.0",
56
63
  "fflate": "^0.8.2",
@@ -73,6 +80,8 @@
73
80
  "unist-util-visit": "^5.1.0",
74
81
  "uqr": "^0.1.3",
75
82
  "yaml": "^2.8.2",
83
+ "yauzl": "^3.4.0",
84
+ "yazl": "^3.3.1",
76
85
  "zod": "^4.3.6"
77
86
  },
78
87
  "peerDependencies": {
@@ -90,18 +99,19 @@
90
99
  "@lingui/conf": "^5.9.3",
91
100
  "@lingui/format-po": "^5.9.3",
92
101
  "@lingui/swc-plugin": "^5.11.0",
93
- "@swc/core": "^1.15.18",
102
+ "@swc/core": "1.15.47",
94
103
  "@tailwindcss/vite": "^4.2.2",
95
104
  "@types/better-sqlite3": "^7.6.13",
96
105
  "@types/node": "^25.5.0",
97
106
  "@types/pg": "^8.20.0",
107
+ "@types/yauzl": "^3.4.0",
108
+ "@types/yazl": "^3.3.1",
98
109
  "cn-font-split": "^7.4.1",
99
110
  "drizzle-kit": "^0.31.10",
100
111
  "glob": "^13.0.6",
101
112
  "happy-dom": "^20.8.4",
102
113
  "sharp": "^0.34.5",
103
114
  "tailwindcss": "^4.2.2",
104
- "tsx": "^4.21.0",
105
115
  "typescript": "^6.0.2",
106
116
  "unplugin-swc": "^1.5.9",
107
117
  "vite": "^8.0.0",
@@ -136,7 +146,7 @@
136
146
  "build:client": "vite build --config vite.config.client.ts",
137
147
  "build:site": "vite build --config vite.config.site.ts",
138
148
  "build:lib": "node -e \"const{rmSync,readdirSync,existsSync}=require('fs');if(existsSync('dist'))readdirSync('dist').filter(f=>f!=='client').forEach(f=>rmSync('dist/'+f,{recursive:true,force:true}))\" && vite build --config vite.config.worker.ts",
139
- "brand:generate": "tsx dev/scripts/generate-brand-assets.ts",
149
+ "brand:generate": "node dev/run-script.mjs dev/scripts/generate-brand-assets.ts",
140
150
  "typecheck": "tsc -b --noEmit",
141
151
  "db:generate": "drizzle-kit generate",
142
152
  "db:generate:pg": "drizzle-kit generate --config drizzle.config.pg.ts",
@@ -0,0 +1,57 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { eq } from "drizzle-orm";
3
+ import { createAuth } from "../auth.js";
4
+ import { createTestDatabase } from "./helpers/db.js";
5
+ import { session as sessionTable } from "../db/schema.js";
6
+
7
+ /**
8
+ * better-auth gates `list-sessions` behind a "fresh session" check whose
9
+ * default window is 24 hours, measured from `session.createdAt` — a value
10
+ * renewal never moves. Jant deliberately runs 90-day rolling sessions, so
11
+ * without `freshAge: 0` the Sessions page answers "Session is not fresh"
12
+ * forever from the second day of a sign-in onwards.
13
+ */
14
+ async function signUpAndGetCookie(auth: ReturnType<typeof createAuth>) {
15
+ const signUp = await auth.api.signUpEmail({
16
+ body: {
17
+ name: "Owner",
18
+ email: "owner@example.com",
19
+ password: "correct-horse-battery",
20
+ },
21
+ returnHeaders: true,
22
+ });
23
+ const token = signUp.headers
24
+ .getSetCookie()
25
+ .find((cookie) => cookie.includes(".session_token="));
26
+ expect(token).toBeDefined();
27
+ // Send only the session token, not the `session_data` cache cookie: a cache
28
+ // hit short-circuits before the database read this test is about.
29
+ return token!.split(";")[0]!;
30
+ }
31
+
32
+ describe("session freshness", () => {
33
+ it("lists sessions that are older than better-auth's default fresh window", async () => {
34
+ const { db } = createTestDatabase();
35
+ const auth = createAuth(db, {
36
+ secret: "test-secret-with-enough-entropy-for-session-cookies",
37
+ baseURL: "https://example.com",
38
+ useSecureCookies: true,
39
+ });
40
+ const cookie = await signUpAndGetCookie(auth);
41
+
42
+ const [row] = await db.select().from(sessionTable);
43
+ expect(row).toBeDefined();
44
+ // Two days old: past the 24-hour default, well inside the 90-day window.
45
+ await db
46
+ .update(sessionTable)
47
+ .set({ createdAt: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000) })
48
+ .where(eq(sessionTable.id, row!.id));
49
+
50
+ const sessions = await auth.api.listSessions({
51
+ headers: new Headers({ cookie }),
52
+ });
53
+
54
+ expect(sessions).toHaveLength(1);
55
+ expect(sessions[0]!.token).toBe(row!.token);
56
+ });
57
+ });
@@ -0,0 +1,121 @@
1
+ /**
2
+ * BaseCoat variant classes are self-contained, and this is what says so out
3
+ * loud.
4
+ *
5
+ * AGENTS.md has carried the rule under Hard Constraints all along and it was
6
+ * broken anyway, more than once, because nothing failed when it was: the markup
7
+ * compiles, every other test passes, and the damage is visible only to an eye
8
+ * looking at the right pixel.
9
+ *
10
+ * What `class="btn btn-outline"` does, exactly: both are single-class
11
+ * selectors, so specificity ties and source order decides. `.btn-outline` is
12
+ * declared later, so its `bg-background` wins the background — but it sets no
13
+ * text colour, so `.btn`'s `text-primary-foreground` survives. A light label on
14
+ * a light fill: the button reads as empty until `:hover`, where
15
+ * `.btn-outline:hover` sets `text-accent-foreground` and the words appear. Each
16
+ * pairing fails for its own reason, which is why the rule is "never combine"
17
+ * rather than a list of bad pairs.
18
+ */
19
+
20
+ import { readdirSync, readFileSync, statSync } from "node:fs";
21
+ import { join } from "node:path";
22
+ import { fileURLToPath } from "node:url";
23
+ import { describe, expect, it } from "vitest";
24
+
25
+ const SRC_DIR = fileURLToPath(new URL("..", import.meta.url));
26
+
27
+ /**
28
+ * The BaseCoat families whose variants replace the base class rather than
29
+ * modify it. Anything of the form `<base>-<x>` is one of `<base>`'s variants.
30
+ */
31
+ const FAMILIES = ["btn", "badge", "alert"];
32
+
33
+ /** Class attributes as authored — JSX `className="…"` and Lit `class="…"` alike. */
34
+ const CLASS_ATTR = /\bclass(?:Name)?="([^"]*)"/g;
35
+
36
+ /**
37
+ * Walk the source tree for authored markup.
38
+ *
39
+ * @param dir - Directory to descend into
40
+ * @returns Absolute paths of every `.ts`/`.tsx` file outside tests
41
+ */
42
+ function collectSourceFiles(dir: string): string[] {
43
+ const found: string[] = [];
44
+ for (const entry of readdirSync(dir)) {
45
+ const path = join(dir, entry);
46
+ if (statSync(path).isDirectory()) {
47
+ if (entry === "__tests__" || entry === "node_modules") continue;
48
+ found.push(...collectSourceFiles(path));
49
+ } else if (entry.endsWith(".ts") || entry.endsWith(".tsx")) {
50
+ found.push(path);
51
+ }
52
+ }
53
+ return found;
54
+ }
55
+
56
+ /**
57
+ * Every class attribute in the repo's own markup, with the file it came from.
58
+ *
59
+ * A `class` built by interpolation is read for its literal words only. That is
60
+ * the point rather than a limitation: the pairing this guards against is
61
+ * written literally, and a regex should not try to evaluate a template.
62
+ *
63
+ * @returns One entry per class attribute found
64
+ */
65
+ function readClassAttributes(): Array<{ file: string; classes: string[] }> {
66
+ const found: Array<{ file: string; classes: string[] }> = [];
67
+
68
+ for (const file of collectSourceFiles(SRC_DIR)) {
69
+ const source = readFileSync(file, "utf8");
70
+ for (const match of source.matchAll(CLASS_ATTR)) {
71
+ found.push({
72
+ file: file.slice(SRC_DIR.length),
73
+ classes: (match[1] ?? "").split(/\s+/).filter(Boolean),
74
+ });
75
+ }
76
+ }
77
+
78
+ return found;
79
+ }
80
+
81
+ describe("BaseCoat variant classes", () => {
82
+ it("are never combined with their base class", () => {
83
+ const offenders: string[] = [];
84
+
85
+ for (const { file, classes } of readClassAttributes()) {
86
+ for (const base of FAMILIES) {
87
+ if (!classes.includes(base)) continue;
88
+ const variant = classes.find(
89
+ (name) => name !== base && name.startsWith(`${base}-`),
90
+ );
91
+ if (variant) {
92
+ offenders.push(`${file}: class="… ${base} ${variant} …"`);
93
+ }
94
+ }
95
+ }
96
+
97
+ expect(
98
+ offenders,
99
+ [
100
+ "A BaseCoat variant replaces the base class, it does not modify it.",
101
+ "Drop the bare base and keep the variant alone:",
102
+ ...offenders,
103
+ ].join("\n"),
104
+ ).toEqual([]);
105
+ });
106
+
107
+ // A guard is worth nothing if the shape it looks for is not the shape the
108
+ // markup writes, so this pins the reader against real files rather than
109
+ // trusting the regex.
110
+ it("reads class attributes out of the real markup", () => {
111
+ const attributes = readClassAttributes();
112
+
113
+ expect(attributes.length).toBeGreaterThan(100);
114
+ expect(attributes.some(({ classes }) => classes.includes("btn"))).toBe(
115
+ true,
116
+ );
117
+ expect(
118
+ attributes.some(({ classes }) => classes.includes("btn-outline")),
119
+ ).toBe(true);
120
+ });
121
+ });
@@ -0,0 +1,68 @@
1
+ import { brotliDecompressSync } from "node:zlib";
2
+ import { describe, expect, it } from "vitest";
3
+ import { compressForUpload } from "../../../bin/commands/assets/upload.js";
4
+
5
+ describe("compressForUpload", () => {
6
+ it("compresses text assets and round-trips them unchanged", () => {
7
+ // Repetitive like real CSS, so brotli has something to work with.
8
+ const body = Buffer.from(
9
+ ".a{color:var(--site-text-primary)}".repeat(200),
10
+ "utf8",
11
+ );
12
+
13
+ const packed = compressForUpload("client.css", body);
14
+
15
+ expect(packed).not.toBeNull();
16
+ expect(packed!.length).toBeLessThan(body.length);
17
+ expect(brotliDecompressSync(packed!).equals(body)).toBe(true);
18
+ });
19
+
20
+ it("leaves already-compressed types alone", () => {
21
+ // Running brotli over a woff2 or a png costs build time and usually grows
22
+ // the file; the CDN would then serve a needless encoding header too.
23
+ const body = Buffer.from("x".repeat(5000), "utf8");
24
+
25
+ for (const name of ["font.woff2", "logo.png", "icon.ico", "photo.jpg"]) {
26
+ expect(compressForUpload(name, body)).toBeNull();
27
+ }
28
+ });
29
+
30
+ it("falls back to the raw body when compression does not shrink it", () => {
31
+ // A few random bytes come back larger once the brotli header is added.
32
+ const body = Buffer.from([0x1f, 0x2e, 0x3d, 0x4c]);
33
+
34
+ expect(compressForUpload("tiny.json", body)).toBeNull();
35
+ });
36
+
37
+ it("matches on the extension case-insensitively", () => {
38
+ const body = Buffer.from("body{margin:0}".repeat(200), "utf8");
39
+
40
+ expect(compressForUpload("STYLE.CSS", body)).not.toBeNull();
41
+ });
42
+ });
43
+
44
+ describe("stale encoding detection", () => {
45
+ // `findStaleEncodingKeys` is not exported — it needs a live S3 client — so
46
+ // these pin the decision it is built on: which files we expect to find
47
+ // stored as brotli, and which correctly have no `Content-Encoding`.
48
+ it("expects compression for the types that carry the reader payload", () => {
49
+ const body = Buffer.from(".x{color:red}".repeat(400), "utf8");
50
+
51
+ // A CJK stylesheet is the case that motivated this: its key never changes,
52
+ // so it was skipped forever and kept being compressed at the CDN's own low
53
+ // quality on every request.
54
+ for (const name of ["client-cjk-B7Z0snDu.css", "client-CDPZMBLo.js"]) {
55
+ expect(compressForUpload(name, body)).not.toBeNull();
56
+ }
57
+ });
58
+
59
+ it("expects no compression where storing raw is the right answer", () => {
60
+ // Anything here would be re-uploaded on every run if a missing
61
+ // `Content-Encoding` counted as stale.
62
+ const dense = Buffer.from("y".repeat(4000), "utf8");
63
+ expect(compressForUpload("subset.woff2", dense)).toBeNull();
64
+
65
+ const tiny = Buffer.from([0x7a, 0x1b, 0x4f, 0x22]);
66
+ expect(compressForUpload("meta.json", tiny)).toBeNull();
67
+ });
68
+ });
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Every TypeScript dev script loads, and loads the way its task runs it.
3
+ *
4
+ * `db-node-rebuild-demo` and `db-node-load-demo` ran their scripts with tsx,
5
+ * which hands Node `src/` untransformed. When `lib/filter-dimensions.ts` began
6
+ * declaring its names with the Lingui macro (539cd1bf), both scripts died on
7
+ * their import lines — and stayed broken for a month, because nothing in CI
8
+ * ever loaded a dev script. The scripts now run through `dev/run-script.mjs`,
9
+ * which compiles `src/` the way the builds do. This file holds both halves:
10
+ * no task goes around the runner, and every script loads through it.
11
+ *
12
+ * Loading is not running. A dev script's work sits behind its default export,
13
+ * so importing one evaluates every module it reaches — where a missing file, an
14
+ * untransformed macro, or an undefined `define` global fails — without
15
+ * resetting a database. That contract is checked here too, before anything is
16
+ * loaded, because a script that broke it would do its work inside this test.
17
+ *
18
+ * What loading cannot see: a named import the module no longer exports. Vite's
19
+ * runner leaves it `undefined` until the script calls it, so a renamed export
20
+ * is a type error, and `tsconfig.dev.json` is what catches it.
21
+ */
22
+
23
+ import { spawnSync } from "node:child_process";
24
+ import {
25
+ mkdtempSync,
26
+ readdirSync,
27
+ readFileSync,
28
+ rmSync,
29
+ writeFileSync,
30
+ } from "node:fs";
31
+ import { tmpdir } from "node:os";
32
+ import { join, resolve } from "node:path";
33
+ import { parse } from "smol-toml";
34
+ import ts from "typescript";
35
+ import { describe, expect, it } from "vitest";
36
+
37
+ const CORE_DIR = resolve(import.meta.dirname, "../..");
38
+ const REPO_ROOT = resolve(CORE_DIR, "../..");
39
+ const RUNNER = "dev/run-script.mjs";
40
+
41
+ /** Every TypeScript dev script, relative to the core package. */
42
+ const SCRIPTS = readdirSync(resolve(CORE_DIR, "dev/scripts"))
43
+ .filter((name) => name.endsWith(".ts"))
44
+ .sort()
45
+ .map((name) => `dev/scripts/${name}`);
46
+
47
+ /** A dev script path as a command names it, with the word before it. */
48
+ const SCRIPT_INVOCATION = /(\S+)\s+(\S*dev\/scripts\/[\w.-]+\.ts)\b/g;
49
+
50
+ interface MiseConfig {
51
+ tasks?: Record<string, { run?: string | string[] }>;
52
+ }
53
+
54
+ /**
55
+ * Every shell command the repo defines: mise tasks and core's package scripts.
56
+ *
57
+ * @returns Each command with the name of the task or script that runs it
58
+ */
59
+ function collectCommands(): { name: string; command: string }[] {
60
+ const mise = parse(
61
+ readFileSync(resolve(REPO_ROOT, "mise.toml"), "utf8"),
62
+ ) as MiseConfig;
63
+ const pkg = JSON.parse(
64
+ readFileSync(resolve(CORE_DIR, "package.json"), "utf8"),
65
+ ) as { scripts?: Record<string, string> };
66
+
67
+ return [
68
+ ...Object.entries(mise.tasks ?? {}).flatMap(([name, task]) =>
69
+ [task.run ?? []].flat().map((command) => ({
70
+ name: `mise task ${name}`,
71
+ command,
72
+ })),
73
+ ),
74
+ ...Object.entries(pkg.scripts ?? {}).map(([name, command]) => ({
75
+ name: `package script ${name}`,
76
+ command,
77
+ })),
78
+ ];
79
+ }
80
+
81
+ /**
82
+ * Top-level statements in a dev script that do work when it is imported.
83
+ *
84
+ * Declarations are allowed, initializers included — resolving a path at module
85
+ * scope is fine. A statement of its own at the top level is not: that is where
86
+ * `await main();` lives.
87
+ *
88
+ * @param script - Script path relative to the core package
89
+ * @returns `path:line` and source text for each offending statement
90
+ */
91
+ function findTopLevelWork(script: string): string[] {
92
+ const source = ts.createSourceFile(
93
+ script,
94
+ readFileSync(resolve(CORE_DIR, script), "utf8"),
95
+ ts.ScriptTarget.Latest,
96
+ true,
97
+ );
98
+
99
+ return source.statements
100
+ .filter(
101
+ (statement) =>
102
+ !ts.isImportDeclaration(statement) &&
103
+ !ts.isExportDeclaration(statement) &&
104
+ !ts.isExportAssignment(statement) &&
105
+ !ts.isFunctionDeclaration(statement) &&
106
+ !ts.isClassDeclaration(statement) &&
107
+ !ts.isVariableStatement(statement) &&
108
+ !ts.isTypeAliasDeclaration(statement) &&
109
+ !ts.isInterfaceDeclaration(statement) &&
110
+ !ts.isEnumDeclaration(statement),
111
+ )
112
+ .map((statement) => {
113
+ const { line } = source.getLineAndCharacterOfPosition(
114
+ statement.getStart(),
115
+ );
116
+ return `${script}:${line + 1}: ${statement.getText()}`;
117
+ });
118
+ }
119
+
120
+ describe("dev scripts", () => {
121
+ it("runs every TypeScript dev script through the runner", () => {
122
+ const invocations = collectCommands().flatMap(({ name, command }) =>
123
+ [...command.matchAll(SCRIPT_INVOCATION)].map(([, runner, script]) => ({
124
+ name,
125
+ runner,
126
+ script,
127
+ })),
128
+ );
129
+
130
+ expect(invocations.map(({ script }) => script)).toEqual(
131
+ expect.arrayContaining([
132
+ "dev/scripts/bootstrap-node-dev.ts",
133
+ "dev/scripts/clean-node-dev.ts",
134
+ "dev/scripts/reset-node-dev.ts",
135
+ "dev/scripts/import-node-demo-site-export.ts",
136
+ ]),
137
+ );
138
+ expect(
139
+ invocations.filter(({ runner }) => !runner.endsWith(RUNNER)),
140
+ ).toEqual([]);
141
+ });
142
+
143
+ it("keeps each script's work behind its default export", () => {
144
+ expect(SCRIPTS.flatMap(findTopLevelWork)).toEqual([]);
145
+ });
146
+
147
+ it(
148
+ "loads every script and everything it imports",
149
+ { timeout: 150_000 },
150
+ () => {
151
+ // Loading evaluates each script. One that works at its top level would
152
+ // do that work here, so it is refused before anything runs.
153
+ expect(SCRIPTS.flatMap(findTopLevelWork)).toEqual([]);
154
+
155
+ // From the repo root, where `brand-export` runs: SWC once resolved its
156
+ // Lingui plugin against the working directory and failed from there.
157
+ const fromRoot = (path: string) => `packages/core/${path}`;
158
+ const result = spawnSync(
159
+ process.execPath,
160
+ [fromRoot(RUNNER), "--check", ...SCRIPTS.map(fromRoot)],
161
+ { cwd: REPO_ROOT, encoding: "utf8", timeout: 120_000 },
162
+ );
163
+
164
+ expect(result.error).toBeUndefined();
165
+ expect(result.status, result.stderr).toBe(0);
166
+ expect(result.stdout.trim().split("\n")).toEqual(
167
+ SCRIPTS.map((script) => `Loaded ${fromRoot(script)}`),
168
+ );
169
+ },
170
+ );
171
+
172
+ it(
173
+ "gives a script the NODE_ENV it was started with",
174
+ { timeout: 150_000 },
175
+ () => {
176
+ // Vite sets NODE_ENV=development when it starts, and a script's child
177
+ // processes inherit it: `db-node-load-demo`'s build produced Lit's
178
+ // development bundle that way.
179
+ const dir = mkdtempSync(join(tmpdir(), "jant-dev-script-"));
180
+ try {
181
+ const script = join(dir, "print-node-env.ts");
182
+ writeFileSync(
183
+ script,
184
+ "export default function main(): void {\n console.log(String(process.env.NODE_ENV));\n}\n",
185
+ );
186
+ const env = { ...process.env };
187
+ delete env.NODE_ENV;
188
+
189
+ const result = spawnSync(process.execPath, [RUNNER, script], {
190
+ cwd: CORE_DIR,
191
+ encoding: "utf8",
192
+ env,
193
+ timeout: 120_000,
194
+ });
195
+
196
+ expect(result.status, result.stderr).toBe(0);
197
+ expect(result.stdout.trim()).toBe("undefined");
198
+ } finally {
199
+ rmSync(dir, { recursive: true, force: true });
200
+ }
201
+ },
202
+ );
203
+ });