@jant/core 0.3.35 → 0.3.37

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 (307) hide show
  1. package/bin/commands/export.js +1 -1
  2. package/bin/commands/import-site.js +529 -0
  3. package/bin/commands/reset-password.js +3 -2
  4. package/dist/client/assets/heic-to-DIRPI3VF.js +1 -0
  5. package/dist/client/assets/module-RjUF93sV.js +716 -0
  6. package/dist/client/assets/native-48B9X9Wg.js +1 -0
  7. package/dist/client/assets/url-FWFqPJPb.js +1 -0
  8. package/dist/client/client.css +1 -1
  9. package/dist/client/client.js +4564 -3013
  10. package/dist/index.js +12885 -8161
  11. package/package.json +23 -6
  12. package/src/__tests__/helpers/app.ts +10 -10
  13. package/src/__tests__/helpers/db.ts +91 -87
  14. package/src/app.tsx +157 -31
  15. package/src/auth.ts +20 -2
  16. package/src/client/archive-nav.js +187 -0
  17. package/src/client/audio-player.ts +478 -0
  18. package/src/client/audio-processor.ts +84 -0
  19. package/src/{lib → client}/avatar-upload.ts +4 -3
  20. package/src/{lib → client}/collection-form-bridge.ts +2 -2
  21. package/src/{ui → client}/components/__tests__/jant-collection-form.test.ts +26 -9
  22. package/src/client/components/__tests__/jant-compose-dialog.test.ts +1140 -0
  23. package/src/client/components/__tests__/jant-compose-editor.test.ts +504 -0
  24. package/src/{ui → client}/components/__tests__/jant-post-form.test.ts +37 -17
  25. package/src/{ui → client}/components/__tests__/jant-settings-avatar.test.ts +2 -2
  26. package/src/{ui → client}/components/__tests__/jant-settings-general.test.ts +3 -3
  27. package/src/client/components/collection-sidebar-types.ts +43 -0
  28. package/src/{ui → client}/components/collection-types.ts +3 -4
  29. package/src/client/components/compose-types.ts +174 -0
  30. package/src/client/components/jant-collection-form.ts +667 -0
  31. package/src/client/components/jant-collection-sidebar.ts +805 -0
  32. package/src/client/components/jant-compose-dialog.ts +2161 -0
  33. package/src/client/components/jant-compose-editor.ts +1813 -0
  34. package/src/client/components/jant-compose-fullscreen.ts +283 -0
  35. package/src/client/components/jant-media-lightbox.ts +259 -0
  36. package/src/{ui → client}/components/jant-nav-manager.ts +97 -298
  37. package/src/{ui → client}/components/jant-post-form.ts +141 -12
  38. package/src/client/components/jant-post-menu.ts +1019 -0
  39. package/src/{ui → client}/components/jant-settings-avatar.ts +3 -3
  40. package/src/{ui → client}/components/jant-settings-general.ts +38 -4
  41. package/src/client/components/jant-text-preview.ts +232 -0
  42. package/src/{ui → client}/components/nav-manager-types.ts +6 -18
  43. package/src/{ui → client}/components/post-form-template.ts +137 -38
  44. package/src/{ui → client}/components/post-form-types.ts +15 -4
  45. package/src/client/compose-bridge.ts +583 -0
  46. package/src/{lib → client}/image-processor.ts +26 -8
  47. package/src/client/lazy-slugify.ts +51 -0
  48. package/src/client/media-metadata.ts +247 -0
  49. package/src/client/multipart-upload.ts +160 -0
  50. package/src/{lib → client}/nav-manager-bridge.ts +1 -1
  51. package/src/{lib → client}/post-form-bridge.ts +53 -2
  52. package/src/{lib → client}/settings-bridge.ts +3 -15
  53. package/src/client/thread-context.ts +140 -0
  54. package/src/client/tiptap/bubble-menu.ts +205 -0
  55. package/src/client/tiptap/create-editor.ts +86 -0
  56. package/src/client/tiptap/exitable-marks.ts +73 -0
  57. package/src/client/tiptap/extensions.ts +65 -0
  58. package/src/client/tiptap/image-node.ts +482 -0
  59. package/src/client/tiptap/link-toolbar.ts +371 -0
  60. package/src/client/tiptap/more-break.ts +50 -0
  61. package/src/client/tiptap/paste-image.ts +129 -0
  62. package/src/client/tiptap/slash-commands.ts +438 -0
  63. package/src/{lib → client}/toast.ts +101 -3
  64. package/src/client/types/sortablejs.d.ts +44 -0
  65. package/src/client/upload-with-metadata.ts +54 -0
  66. package/src/client/video-processor.ts +207 -0
  67. package/src/client.ts +27 -17
  68. package/src/db/__tests__/migrations.test.ts +118 -0
  69. package/src/db/index.ts +52 -0
  70. package/src/db/migrations/0000_baseline.sql +269 -0
  71. package/src/db/migrations/0001_fts_setup.sql +31 -0
  72. package/src/db/migrations/meta/0000_snapshot.json +703 -119
  73. package/src/db/migrations/meta/0001_snapshot.json +1337 -0
  74. package/src/db/migrations/meta/_journal.json +4 -39
  75. package/src/db/schema.ts +409 -140
  76. package/src/i18n/__tests__/detect.test.ts +115 -0
  77. package/src/i18n/context.tsx +2 -2
  78. package/src/i18n/detect.ts +85 -1
  79. package/src/i18n/i18n.ts +1 -1
  80. package/src/i18n/index.ts +2 -1
  81. package/src/i18n/locales/en.po +783 -1087
  82. package/src/i18n/locales/en.ts +1 -1
  83. package/src/i18n/locales/zh-Hans.po +867 -812
  84. package/src/i18n/locales/zh-Hans.ts +1 -1
  85. package/src/i18n/locales/zh-Hant.po +878 -823
  86. package/src/i18n/locales/zh-Hant.ts +1 -1
  87. package/src/i18n/middleware.ts +6 -0
  88. package/src/index.ts +5 -7
  89. package/src/lib/__tests__/blurhash-placeholder.test.ts +75 -0
  90. package/src/lib/__tests__/constants.test.ts +0 -1
  91. package/src/lib/__tests__/markdown-to-tiptap.test.ts +358 -0
  92. package/src/lib/__tests__/nanoid.test.ts +26 -0
  93. package/src/lib/__tests__/resolve-config.test.ts +2 -2
  94. package/src/lib/__tests__/schemas.test.ts +186 -65
  95. package/src/lib/__tests__/slug.test.ts +126 -0
  96. package/src/lib/__tests__/sse.test.ts +6 -6
  97. package/src/lib/__tests__/summary.test.ts +264 -0
  98. package/src/lib/__tests__/theme.test.ts +1 -1
  99. package/src/lib/__tests__/timeline.test.ts +33 -30
  100. package/src/lib/__tests__/tiptap-to-markdown.test.ts +346 -0
  101. package/src/lib/__tests__/url.test.ts +2 -2
  102. package/src/lib/__tests__/view.test.ts +140 -65
  103. package/src/lib/blurhash-placeholder.ts +102 -0
  104. package/src/lib/constants.ts +3 -1
  105. package/src/lib/emoji-catalog.ts +963 -0
  106. package/src/lib/errors.ts +11 -8
  107. package/src/lib/feed.ts +77 -31
  108. package/src/lib/html.ts +2 -1
  109. package/src/lib/icon-catalog.ts +5033 -1
  110. package/src/lib/icons.ts +3 -2
  111. package/src/lib/index.ts +0 -1
  112. package/src/lib/markdown-to-tiptap.ts +286 -0
  113. package/src/lib/media-helpers.ts +22 -12
  114. package/src/lib/nanoid.ts +29 -0
  115. package/src/lib/navigation.ts +1 -1
  116. package/src/lib/render.tsx +24 -5
  117. package/src/lib/resolve-config.ts +13 -2
  118. package/src/lib/schemas.ts +226 -58
  119. package/src/lib/search-snippet.ts +34 -0
  120. package/src/lib/slug.ts +96 -0
  121. package/src/lib/sse.ts +6 -6
  122. package/src/lib/storage.ts +115 -7
  123. package/src/lib/summary.ts +158 -0
  124. package/src/lib/theme.ts +11 -8
  125. package/src/lib/timeline.ts +76 -34
  126. package/src/lib/tiptap-render.ts +191 -0
  127. package/src/lib/tiptap-to-markdown.ts +305 -0
  128. package/src/lib/upload.ts +263 -14
  129. package/src/lib/url.ts +37 -22
  130. package/src/lib/view.ts +236 -55
  131. package/src/middleware/__tests__/auth.test.ts +191 -11
  132. package/src/middleware/__tests__/onboarding.test.ts +12 -10
  133. package/src/middleware/auth.ts +63 -9
  134. package/src/middleware/error-handler.ts +3 -3
  135. package/src/middleware/onboarding.ts +1 -1
  136. package/src/middleware/secure-headers.ts +40 -0
  137. package/src/preset.css +83 -2
  138. package/src/routes/__tests__/compose.test.ts +17 -24
  139. package/src/routes/api/__tests__/collections.test.ts +109 -61
  140. package/src/routes/api/__tests__/nav-items.test.ts +46 -29
  141. package/src/routes/api/__tests__/posts.test.ts +132 -68
  142. package/src/routes/api/__tests__/search.test.ts +15 -2
  143. package/src/routes/api/__tests__/upload-multipart.test.ts +534 -0
  144. package/src/routes/api/collections.ts +57 -31
  145. package/src/routes/api/custom-urls.ts +80 -0
  146. package/src/routes/api/export.ts +31 -0
  147. package/src/routes/api/nav-items.ts +23 -19
  148. package/src/routes/api/posts.ts +81 -62
  149. package/src/routes/api/search.ts +3 -4
  150. package/src/routes/api/upload-multipart.ts +245 -0
  151. package/src/routes/api/upload.ts +92 -24
  152. package/src/routes/auth/__tests__/setup.test.ts +20 -60
  153. package/src/routes/auth/reset.tsx +5 -4
  154. package/src/routes/auth/setup.tsx +39 -31
  155. package/src/routes/auth/signin.tsx +13 -14
  156. package/src/routes/compose.tsx +27 -63
  157. package/src/routes/dash/__tests__/settings-avatar.test.ts +44 -9
  158. package/src/routes/dash/custom-urls.tsx +414 -0
  159. package/src/routes/dash/settings.tsx +475 -99
  160. package/src/routes/feed/__tests__/rss.test.ts +22 -23
  161. package/src/routes/feed/rss.ts +6 -2
  162. package/src/routes/feed/sitemap.ts +2 -12
  163. package/src/routes/pages/__tests__/collections.test.ts +5 -6
  164. package/src/routes/pages/__tests__/featured.test.ts +36 -18
  165. package/src/routes/pages/archive.tsx +177 -37
  166. package/src/routes/pages/collection.tsx +43 -14
  167. package/src/routes/pages/collections.tsx +11 -2
  168. package/src/routes/pages/featured.tsx +27 -3
  169. package/src/routes/pages/home.tsx +15 -14
  170. package/src/routes/pages/latest.tsx +1 -11
  171. package/src/routes/pages/new.tsx +39 -0
  172. package/src/routes/pages/page.tsx +95 -49
  173. package/src/routes/pages/search.tsx +1 -1
  174. package/src/services/__tests__/api-token.test.ts +135 -0
  175. package/src/services/__tests__/collection.test.ts +275 -227
  176. package/src/services/__tests__/custom-url.test.ts +213 -0
  177. package/src/services/__tests__/media.test.ts +162 -22
  178. package/src/services/__tests__/navigation.test.ts +109 -68
  179. package/src/services/__tests__/post-timeline.test.ts +205 -32
  180. package/src/services/__tests__/post.test.ts +800 -230
  181. package/src/services/__tests__/search.test.ts +67 -10
  182. package/src/services/__tests__/settings.test.ts +3 -3
  183. package/src/services/api-token.ts +166 -0
  184. package/src/services/auth.ts +17 -2
  185. package/src/services/collection.ts +397 -131
  186. package/src/services/custom-url.ts +188 -0
  187. package/src/services/export.ts +802 -0
  188. package/src/services/index.ts +26 -19
  189. package/src/services/media.ts +100 -22
  190. package/src/services/navigation.ts +158 -47
  191. package/src/services/path.ts +339 -0
  192. package/src/services/post.ts +764 -172
  193. package/src/services/search.ts +161 -74
  194. package/src/services/settings.ts +6 -2
  195. package/src/styles/components.css +293 -62
  196. package/src/styles/tokens.css +93 -5
  197. package/src/styles/ui.css +4349 -766
  198. package/src/types/bindings.ts +8 -0
  199. package/src/types/config.ts +34 -4
  200. package/src/types/constants.ts +17 -2
  201. package/src/types/entities.ts +83 -37
  202. package/src/types/operations.ts +20 -27
  203. package/src/types/props.ts +52 -17
  204. package/src/types/views.ts +48 -24
  205. package/src/ui/color-themes.ts +133 -23
  206. package/src/ui/compose/ComposeDialog.tsx +255 -16
  207. package/src/ui/compose/ComposePrompt.tsx +1 -1
  208. package/src/ui/dash/CrudPageHeader.tsx +1 -1
  209. package/src/ui/dash/ListItemRow.tsx +1 -1
  210. package/src/ui/dash/StatusBadge.tsx +12 -2
  211. package/src/ui/dash/appearance/AdvancedContent.tsx +71 -59
  212. package/src/ui/dash/appearance/ColorThemeContent.tsx +48 -33
  213. package/src/ui/dash/appearance/FontThemeContent.tsx +65 -73
  214. package/src/ui/dash/appearance/NavigationContent.tsx +106 -135
  215. package/src/ui/dash/index.ts +0 -3
  216. package/src/ui/dash/settings/AccountContent.tsx +87 -146
  217. package/src/ui/dash/settings/AccountMenuContent.tsx +147 -0
  218. package/src/ui/dash/settings/ApiTokensContent.tsx +232 -0
  219. package/src/ui/dash/settings/AvatarContent.tsx +78 -0
  220. package/src/ui/dash/settings/GeneralContent.tsx +3 -62
  221. package/src/ui/dash/settings/SessionsContent.tsx +159 -0
  222. package/src/ui/dash/settings/SettingsRootContent.tsx +266 -0
  223. package/src/ui/feed/LinkCard.tsx +89 -40
  224. package/src/ui/feed/NoteCard.tsx +39 -25
  225. package/src/ui/feed/PostStatusBadges.tsx +67 -0
  226. package/src/ui/feed/QuoteCard.tsx +38 -23
  227. package/src/ui/feed/ThreadPreview.tsx +90 -26
  228. package/src/ui/feed/TimelineFeed.tsx +3 -2
  229. package/src/ui/feed/TimelineItem.tsx +15 -6
  230. package/src/ui/feed/__tests__/thread-preview.test.ts +107 -0
  231. package/src/ui/feed/thread-preview-state.ts +61 -0
  232. package/src/ui/font-themes.ts +2 -2
  233. package/src/ui/layouts/BaseLayout.tsx +2 -2
  234. package/src/ui/layouts/SiteLayout.tsx +116 -103
  235. package/src/ui/pages/ArchivePage.tsx +923 -95
  236. package/src/ui/pages/CollectionPage.tsx +6 -35
  237. package/src/ui/pages/CollectionsPage.tsx +2 -1
  238. package/src/ui/pages/ComposePage.tsx +54 -0
  239. package/src/ui/pages/FeaturedPage.tsx +2 -1
  240. package/src/ui/pages/HomePage.tsx +1 -1
  241. package/src/ui/pages/PostPage.tsx +30 -45
  242. package/src/ui/pages/SearchPage.tsx +182 -38
  243. package/src/ui/shared/AdminBreadcrumb.tsx +29 -0
  244. package/src/ui/shared/CollectionsSidebar.tsx +239 -4
  245. package/src/ui/shared/MediaGallery.tsx +475 -41
  246. package/src/ui/shared/PostFooter.tsx +204 -0
  247. package/src/ui/shared/StarRating.tsx +27 -0
  248. package/src/ui/shared/__tests__/format-chars.test.ts +35 -0
  249. package/src/ui/shared/index.ts +0 -1
  250. package/src/db/migrations/0000_square_wallflower.sql +0 -118
  251. package/src/db/migrations/0001_add_search_fts.sql +0 -34
  252. package/src/db/migrations/0002_add_media_attachments.sql +0 -3
  253. package/src/db/migrations/0003_add_navigation_links.sql +0 -8
  254. package/src/db/migrations/0004_add_storage_provider.sql +0 -3
  255. package/src/db/migrations/0005_v2_schema_migration.sql +0 -268
  256. package/src/db/migrations/0006_rename_slug_to_path.sql +0 -5
  257. package/src/db/migrations/0007_post_collections_m2m.sql +0 -94
  258. package/src/db/migrations/0008_add_collection_dividers.sql +0 -8
  259. package/src/db/migrations/0009_drop_collection_show_divider.sql +0 -2
  260. package/src/db/migrations/0010_add_performance_indexes.sql +0 -16
  261. package/src/db/migrations/0011_add_path_registry.sql +0 -23
  262. package/src/db/migrations/meta/0003_snapshot.json +0 -821
  263. package/src/lib/__tests__/sqid.test.ts +0 -65
  264. package/src/lib/collections-reorder.ts +0 -28
  265. package/src/lib/compose-bridge.ts +0 -280
  266. package/src/lib/media-upload.ts +0 -148
  267. package/src/lib/sqid.ts +0 -79
  268. package/src/routes/api/__tests__/pages.test.ts +0 -218
  269. package/src/routes/api/pages.ts +0 -73
  270. package/src/routes/dash/__tests__/pages.test.ts +0 -226
  271. package/src/routes/dash/appearance.tsx +0 -240
  272. package/src/routes/dash/collections.tsx +0 -211
  273. package/src/routes/dash/index.tsx +0 -103
  274. package/src/routes/dash/media.tsx +0 -132
  275. package/src/routes/dash/pages.tsx +0 -239
  276. package/src/routes/dash/posts.tsx +0 -334
  277. package/src/routes/dash/redirects.tsx +0 -257
  278. package/src/routes/pages/post.tsx +0 -59
  279. package/src/services/__tests__/page.test.ts +0 -298
  280. package/src/services/__tests__/path-registry.test.ts +0 -165
  281. package/src/services/__tests__/redirect.test.ts +0 -159
  282. package/src/services/page.ts +0 -203
  283. package/src/services/path-registry.ts +0 -160
  284. package/src/services/redirect.ts +0 -97
  285. package/src/types/sortablejs.d.ts +0 -29
  286. package/src/ui/components/__tests__/jant-compose-dialog.test.ts +0 -512
  287. package/src/ui/components/__tests__/jant-compose-editor.test.ts +0 -272
  288. package/src/ui/components/compose-types.ts +0 -75
  289. package/src/ui/components/jant-collection-form.ts +0 -512
  290. package/src/ui/components/jant-compose-dialog.ts +0 -495
  291. package/src/ui/components/jant-compose-editor.ts +0 -814
  292. package/src/ui/dash/PageForm.tsx +0 -185
  293. package/src/ui/dash/PostList.tsx +0 -95
  294. package/src/ui/dash/appearance/AppearanceNav.tsx +0 -60
  295. package/src/ui/dash/collections/CollectionForm.tsx +0 -166
  296. package/src/ui/dash/collections/CollectionsListContent.tsx +0 -146
  297. package/src/ui/dash/collections/IconPickerGrid.tsx +0 -50
  298. package/src/ui/dash/collections/ViewCollectionContent.tsx +0 -103
  299. package/src/ui/dash/media/MediaListContent.tsx +0 -201
  300. package/src/ui/dash/media/ViewMediaContent.tsx +0 -208
  301. package/src/ui/dash/pages/PagesContent.tsx +0 -74
  302. package/src/ui/dash/posts/PostForm.tsx +0 -248
  303. package/src/ui/dash/settings/SettingsNav.tsx +0 -52
  304. package/src/ui/layouts/DashLayout.tsx +0 -165
  305. package/src/ui/pages/SinglePage.tsx +0 -23
  306. package/src/ui/shared/ThreadView.tsx +0 -136
  307. /package/src/{ui → client}/components/settings-types.ts +0 -0
@@ -12,6 +12,7 @@ export interface Bindings {
12
12
  IMAGE_TRANSFORM_URL?: string;
13
13
  DEMO_EMAIL?: string;
14
14
  DEMO_PASSWORD?: string;
15
+ DEV_API_TOKEN?: string;
15
16
  // Timeline
16
17
  PAGE_SIZE?: string;
17
18
  // Site configuration (optional - can be overridden in DB)
@@ -27,6 +28,13 @@ export interface Bindings {
27
28
  S3_SECRET_ACCESS_KEY?: string;
28
29
  S3_REGION?: string;
29
30
  S3_PUBLIC_URL?: string;
31
+ // Upload
32
+ UPLOAD_MAX_FILE_SIZE_MB?: string;
33
+ // Summary extraction
34
+ SUMMARY_MAX_PARAGRAPHS?: string;
35
+ SUMMARY_MAX_CHARS?: string;
36
+ // Slug generation
37
+ SLUG_ID_LENGTH?: string;
30
38
  // RSS feed
31
39
  RSS_FEED_LIMIT?: string;
32
40
  }
@@ -15,7 +15,7 @@
15
15
  * - envOnly: true -> Environment-only (ENV > Default)
16
16
  */
17
17
  export const CONFIG_FIELDS = {
18
- // User-configurable (can be modified in dashboard)
18
+ // User-configurable (can be modified in settings)
19
19
  SITE_NAME: {
20
20
  defaultValue: "Jant",
21
21
  envOnly: false,
@@ -33,7 +33,7 @@ export const CONFIG_FIELDS = {
33
33
  envOnly: false,
34
34
  },
35
35
  HEADER_NAV_MAX_VISIBLE: {
36
- defaultValue: "3",
36
+ defaultValue: "2",
37
37
  envOnly: false,
38
38
  },
39
39
 
@@ -98,8 +98,24 @@ export const CONFIG_FIELDS = {
98
98
  defaultValue: "",
99
99
  envOnly: true,
100
100
  },
101
+ UPLOAD_MAX_FILE_SIZE_MB: {
102
+ defaultValue: "500",
103
+ envOnly: true,
104
+ },
105
+ SUMMARY_MAX_PARAGRAPHS: {
106
+ defaultValue: "5",
107
+ envOnly: true,
108
+ },
109
+ SUMMARY_MAX_CHARS: {
110
+ defaultValue: "500",
111
+ envOnly: true,
112
+ },
113
+ SLUG_ID_LENGTH: {
114
+ defaultValue: "5",
115
+ envOnly: true,
116
+ },
101
117
 
102
- // Internal settings (DB-only, not configurable via env or dashboard)
118
+ // Internal settings (DB-only, not configurable via env or settings UI)
103
119
  THEME: {
104
120
  defaultValue: "",
105
121
  envOnly: false,
@@ -195,10 +211,24 @@ export interface AppConfig {
195
211
  s3PublicUrl: string;
196
212
  imageTransformUrl: string;
197
213
 
214
+ // Upload (ENV only, parsed to number)
215
+ /** Max upload file size in MB. Defaults to 500. */
216
+ uploadMaxFileSize: number;
217
+
218
+ // Summary extraction (ENV only)
219
+ /** Max paragraphs to include in auto-extracted summary. Defaults to 5. */
220
+ summaryMaxParagraphs: number;
221
+ /** Max characters to include in auto-extracted summary. Defaults to 500. */
222
+ summaryMaxChars: number;
223
+
198
224
  // Pagination/Feed (ENV only, parsed to number)
199
225
  pageSize: number;
200
226
  rssFeedLimit: number;
201
227
 
228
+ // Slug (ENV only)
229
+ /** Length of random IDs used in auto-generated slugs. Defaults to 5. */
230
+ slugIdLength: number;
231
+
202
232
  // Demo (ENV only)
203
233
  demoEmail: string;
204
234
  demoPassword: string;
@@ -216,7 +246,7 @@ export interface AppConfig {
216
246
  siteAvatarUrl: string;
217
247
  faviconVersion: string;
218
248
 
219
- // Dashboard form placeholders (ENV > Default, without DB)
249
+ // Settings form placeholders (ENV > Default, without DB)
220
250
  fallbacks: {
221
251
  siteName: string;
222
252
  siteDescription: string;
@@ -8,6 +8,9 @@ export type Format = (typeof FORMATS)[number];
8
8
  export const STATUSES = ["draft", "published"] as const;
9
9
  export type Status = (typeof STATUSES)[number];
10
10
 
11
+ export const VISIBILITIES = ["public", "unlisted", "private"] as const;
12
+ export type Visibility = (typeof VISIBILITIES)[number];
13
+
11
14
  export const SORT_ORDERS = [
12
15
  "newest",
13
16
  "oldest",
@@ -16,12 +19,12 @@ export const SORT_ORDERS = [
16
19
  ] as const;
17
20
  export type SortOrder = (typeof SORT_ORDERS)[number];
18
21
 
19
- export const NAV_ITEM_TYPES = ["page", "link", "system"] as const;
22
+ export const NAV_ITEM_TYPES = ["link", "system"] as const;
20
23
  export type NavItemType = (typeof NAV_ITEM_TYPES)[number];
21
24
 
22
25
  export const SYSTEM_NAV_KEYS = {
23
26
  rss: { defaultLabel: "RSS", url: "/feed" },
24
- dashboard: { defaultLabel: "Dashboard", url: "/dash" },
27
+ settings: { defaultLabel: "Settings", url: "/settings" },
25
28
  collections: { defaultLabel: "Collections", url: "/c" },
26
29
  archive: { defaultLabel: "Archive", url: "/archive" },
27
30
  } as const;
@@ -30,5 +33,17 @@ export type SystemNavKey = keyof typeof SYSTEM_NAV_KEYS;
30
33
  export const MAX_MEDIA_ATTACHMENTS = 20;
31
34
  export const MAX_PINNED_POSTS = 3;
32
35
 
36
+ export const MEDIA_KINDS = [
37
+ "image",
38
+ "video",
39
+ "audio",
40
+ "text",
41
+ "document",
42
+ ] as const;
43
+ export type MediaKind = (typeof MEDIA_KINDS)[number];
44
+
33
45
  export const STORAGE_DRIVERS = ["r2", "s3"] as const;
34
46
  export type StorageDriver = (typeof STORAGE_DRIVERS)[number];
47
+
48
+ export const PATH_KINDS = ["slug", "alias", "redirect"] as const;
49
+ export type PathKind = (typeof PATH_KINDS)[number];
@@ -2,43 +2,44 @@
2
2
  * Entity Types (database-level models)
3
3
  */
4
4
 
5
- import type { Format, Status, SortOrder, NavItemType } from "./constants.js";
5
+ import type {
6
+ Format,
7
+ Status,
8
+ Visibility,
9
+ SortOrder,
10
+ NavItemType,
11
+ MediaKind,
12
+ PathKind,
13
+ } from "./constants.js";
6
14
 
7
15
  export interface Post {
8
- id: number;
16
+ id: string;
9
17
  format: Format;
10
18
  status: Status;
11
- featured: number; // 0 | 1
12
- pinned: number; // 0 | 1
13
- path: string | null;
19
+ visibility: Visibility;
20
+ pinnedAt: number | null;
21
+ featuredAt: number | null;
22
+ slug: string;
14
23
  title: string | null;
15
24
  url: string | null;
16
25
  body: string | null;
17
26
  bodyHtml: string | null;
27
+ bodyText: string | null;
18
28
  quoteText: string | null;
29
+ summary: string | null;
19
30
  rating: number | null;
20
- replyToId: number | null;
21
- threadId: number | null;
31
+ replyToId: string | null;
32
+ threadId: string;
22
33
  deletedAt: number | null;
23
- publishedAt: number;
24
- createdAt: number;
25
- updatedAt: number;
26
- }
27
-
28
- export interface Page {
29
- id: number;
30
- slug: string;
31
- title: string | null;
32
- body: string | null;
33
- bodyHtml: string | null;
34
- status: Status;
34
+ publishedAt: number | null;
35
+ lastActivityAt: number;
35
36
  createdAt: number;
36
37
  updatedAt: number;
37
38
  }
38
39
 
39
40
  export interface Media {
40
41
  id: string; // UUIDv7
41
- postId: number | null;
42
+ postId: string | null;
42
43
  filename: string;
43
44
  originalName: string;
44
45
  mimeType: string;
@@ -48,9 +49,15 @@ export interface Media {
48
49
  width: number | null;
49
50
  height: number | null;
50
51
  alt: string | null;
51
- position: number;
52
+ position: string;
52
53
  blurhash: string | null;
54
+ waveform: string | null;
55
+ posterKey: string | null;
56
+ summary: string | null;
57
+ chars: number | null;
58
+ mediaKind: MediaKind;
53
59
  createdAt: number;
60
+ updatedAt: number;
54
61
  }
55
62
 
56
63
  export interface MediaAttachment {
@@ -59,10 +66,16 @@ export interface MediaAttachment {
59
66
  previewUrl: string;
60
67
  alt: string | null;
61
68
  blurhash: string | null;
69
+ waveform: string | null;
70
+ posterUrl: string | null;
62
71
  width: number | null;
63
72
  height: number | null;
64
- position: number;
73
+ position: string;
65
74
  mimeType: string;
75
+ originalName: string;
76
+ size: number;
77
+ summary: string | null;
78
+ chars: number | null;
66
79
  }
67
80
 
68
81
  export interface PostWithMedia extends Post {
@@ -70,46 +83,62 @@ export interface PostWithMedia extends Post {
70
83
  }
71
84
 
72
85
  export interface Collection {
73
- id: number;
86
+ id: string;
74
87
  slug: string;
75
88
  title: string;
76
89
  description: string | null;
77
90
  icon: string | null;
78
91
  sortOrder: SortOrder;
79
- position: number;
80
92
  createdAt: number;
81
93
  updatedAt: number;
82
94
  }
83
95
 
84
- export interface CollectionDivider {
85
- id: number;
86
- position: number;
96
+ export type SidebarItemType = "collection" | "divider";
97
+
98
+ export interface SidebarItem {
99
+ id: string;
100
+ type: SidebarItemType;
101
+ collectionId: string | null;
102
+ position: string;
87
103
  createdAt: number;
88
104
  updatedAt: number;
89
105
  }
90
106
 
91
107
  export interface PostCollection {
92
- postId: number;
93
- collectionId: number;
108
+ postId: string;
109
+ collectionId: string;
94
110
  }
95
111
 
96
112
  export interface NavItem {
97
- id: number;
113
+ id: string;
98
114
  type: NavItemType;
99
115
  label: string;
100
116
  url: string;
101
- pageId: number | null;
102
- position: number;
117
+ position: string;
103
118
  createdAt: number;
104
119
  updatedAt: number;
105
120
  }
106
121
 
107
- export interface Redirect {
108
- id: number;
109
- fromPath: string;
110
- toPath: string;
111
- type: 301 | 302;
122
+ export interface CustomUrl {
123
+ id: string;
124
+ path: string;
125
+ targetType: "post" | "collection" | "redirect";
126
+ targetId: string | null;
127
+ toPath: string | null;
128
+ redirectType: 301 | 302 | null;
129
+ createdAt: number;
130
+ }
131
+
132
+ export interface PathRecord {
133
+ id: string;
134
+ path: string;
135
+ kind: PathKind;
136
+ postId: string | null;
137
+ collectionId: string | null;
138
+ redirectToPath: string | null;
139
+ redirectType: 301 | 302 | null;
112
140
  createdAt: number;
141
+ updatedAt: number;
113
142
  }
114
143
 
115
144
  export interface Setting {
@@ -117,3 +146,20 @@ export interface Setting {
117
146
  value: string;
118
147
  updatedAt: number;
119
148
  }
149
+
150
+ export interface ApiToken {
151
+ id: string;
152
+ name: string;
153
+ prefix: string;
154
+ lastUsedAt: number | null;
155
+ createdAt: number;
156
+ updatedAt: number;
157
+ }
158
+
159
+ /** Latest-reply context for a thread root, used in timeline display */
160
+ export interface ThreadTimelineContext {
161
+ latestReply: Post;
162
+ /** Parent of latestReply, only if it's not the root */
163
+ parentReply: Post | null;
164
+ totalReplyCount: number;
165
+ }
@@ -2,21 +2,30 @@
2
2
  * Operation Types (create/update DTOs)
3
3
  */
4
4
 
5
- import type { Format, Status, SortOrder, NavItemType } from "./constants.js";
5
+ import type {
6
+ Format,
7
+ Status,
8
+ Visibility,
9
+ SortOrder,
10
+ NavItemType,
11
+ } from "./constants.js";
6
12
 
7
13
  export interface CreatePost {
8
14
  format: Format;
9
15
  status?: Status;
10
- featured?: boolean;
16
+ visibility?: Visibility;
11
17
  pinned?: boolean;
18
+ featured?: boolean;
19
+ slug?: string;
12
20
  path?: string;
13
21
  title?: string;
14
22
  url?: string;
15
23
  body?: string;
24
+ bodyMarkdown?: string;
16
25
  quoteText?: string;
17
26
  rating?: number;
18
- collectionIds?: number[];
19
- replyToId?: number;
27
+ collectionIds?: string[];
28
+ replyToId?: string;
20
29
  publishedAt?: number;
21
30
  mediaIds?: string[];
22
31
  }
@@ -24,47 +33,33 @@ export interface CreatePost {
24
33
  export interface UpdatePost {
25
34
  format?: Format;
26
35
  status?: Status;
27
- featured?: boolean;
36
+ visibility?: Visibility;
28
37
  pinned?: boolean;
29
- path?: string | null;
38
+ featured?: boolean;
39
+ slug?: string;
30
40
  title?: string | null;
31
41
  url?: string | null;
32
42
  body?: string | null;
43
+ bodyMarkdown?: string | null;
33
44
  quoteText?: string | null;
34
45
  rating?: number | null;
35
- collectionIds?: number[];
46
+ collectionIds?: string[];
36
47
  publishedAt?: number;
37
48
  mediaIds?: string[];
38
49
  }
39
50
 
40
- export interface CreatePage {
41
- slug: string;
42
- title?: string;
43
- body?: string;
44
- status?: Status;
45
- }
46
-
47
- export interface UpdatePage {
48
- slug?: string;
49
- title?: string | null;
50
- body?: string | null;
51
- status?: Status;
52
- }
53
-
54
51
  export interface CreateNavItem {
55
52
  type: NavItemType;
56
53
  label: string;
57
54
  url: string;
58
- pageId?: number;
59
- position?: number;
55
+ position?: string;
60
56
  }
61
57
 
62
58
  export interface UpdateNavItem {
63
59
  type?: NavItemType;
64
60
  label?: string;
65
61
  url?: string;
66
- pageId?: number | null;
67
- position?: number;
62
+ position?: string;
68
63
  }
69
64
 
70
65
  export interface CreateCollection {
@@ -73,7 +68,6 @@ export interface CreateCollection {
73
68
  description?: string;
74
69
  icon?: string;
75
70
  sortOrder?: SortOrder;
76
- position?: number;
77
71
  }
78
72
 
79
73
  export interface UpdateCollection {
@@ -82,5 +76,4 @@ export interface UpdateCollection {
82
76
  description?: string | null;
83
77
  icon?: string | null;
84
78
  sortOrder?: SortOrder;
85
- position?: number;
86
79
  }
@@ -2,11 +2,10 @@
2
2
  * Page-Level Props & Feed Data Types
3
3
  */
4
4
 
5
- import type { Format } from "./constants.js";
5
+ import type { Format, MediaKind } from "./constants.js";
6
6
  import type { Collection } from "./entities.js";
7
7
  import type {
8
8
  PostView,
9
- PageView,
10
9
  TimelineItemView,
11
10
  SearchResultView,
12
11
  ArchiveGroup,
@@ -19,7 +18,6 @@ import type {
19
18
  /** Props for the home page component */
20
19
  export interface HomePageProps {
21
20
  items: TimelineItemView[];
22
- pinnedItems: PostView[];
23
21
  currentPage: number;
24
22
  totalPages: number;
25
23
  }
@@ -27,11 +25,7 @@ export interface HomePageProps {
27
25
  /** Props for the single post page component */
28
26
  export interface PostPageProps {
29
27
  post: PostView;
30
- }
31
-
32
- /** Props for the custom page component */
33
- export interface SinglePageProps {
34
- page: PageView;
28
+ threadPosts?: PostView[];
35
29
  }
36
30
 
37
31
  /** Props for the featured page component */
@@ -39,13 +33,35 @@ export interface FeaturedPageProps {
39
33
  items: TimelineItemView[];
40
34
  }
41
35
 
36
+ /** Visibility filter values for the archive page (includes "featured" as a virtual value). */
37
+ export type ArchiveVisibility = "public" | "unlisted" | "private" | "featured";
38
+
39
+ /** View mode for the archive page. */
40
+ export type ArchiveView = "grid" | "list";
41
+
42
+ /** Filters currently active on the archive page */
43
+ export interface ArchiveFilters {
44
+ year?: number;
45
+ collectionSlug?: string;
46
+ collectionTitle?: string;
47
+ collectionIcon?: string | null;
48
+ format?: Format;
49
+ mediaKinds?: MediaKind[];
50
+ hasMedia?: boolean;
51
+ hasTitle?: boolean;
52
+ visibility?: ArchiveVisibility;
53
+ view?: ArchiveView;
54
+ }
55
+
42
56
  /** Props for the archive page component */
43
57
  export interface ArchivePageProps {
44
58
  groups: ArchiveGroup[];
45
- hasMore: boolean;
46
- nextCursor?: number;
47
- format?: Format;
48
- featured?: boolean;
59
+ currentPage: number;
60
+ totalPages: number;
61
+ filters: ArchiveFilters;
62
+ availableYears: number[];
63
+ availableCollections: { slug: string; title: string; icon: string | null }[];
64
+ isAuthenticated: boolean;
49
65
  }
50
66
 
51
67
  /** Props for the search page component */
@@ -60,9 +76,9 @@ export interface SearchPageProps {
60
76
  /** Props for the single collection page component */
61
77
  export interface CollectionPageProps {
62
78
  collection: Collection;
63
- posts: PostView[];
79
+ items: TimelineItemView[];
64
80
  hasMore: boolean;
65
- nextCursor?: number;
81
+ nextCursor?: string;
66
82
  }
67
83
 
68
84
  /** Props for the collections list page component */
@@ -87,23 +103,42 @@ export interface FeedData {
87
103
  export interface SitemapData {
88
104
  siteUrl: string;
89
105
  posts: PostView[];
90
- pages: PageView[];
91
106
  }
92
107
 
93
108
  // =============================================================================
94
109
  // Timeline Types
95
110
  // =============================================================================
96
111
 
112
+ /**
113
+ * Display mode for timeline cards.
114
+ * - `compact` — condensed view for constrained contexts
115
+ * - `feed` — standard timeline card (default)
116
+ * - `detail` — full single-post page view
117
+ */
118
+ export type CardMode = "compact" | "feed" | "detail";
119
+
120
+ export interface PostFooterDisplayOptions {
121
+ hideActions?: boolean;
122
+ }
123
+
124
+ export interface TimelineCardDisplayOptions {
125
+ hideStatusBadges?: boolean;
126
+ hideRating?: boolean;
127
+ footer?: PostFooterDisplayOptions;
128
+ }
129
+
97
130
  /** Props for per-type timeline cards */
98
131
  export interface TimelineCardProps {
99
132
  post: PostView;
100
- compact?: boolean;
133
+ mode?: CardMode;
134
+ display?: TimelineCardDisplayOptions;
101
135
  }
102
136
 
103
137
  /** Props for thread inline preview */
104
138
  export interface ThreadPreviewProps {
105
139
  rootPost: PostView;
106
- previewReplies: PostView[];
140
+ latestReply: PostView;
141
+ parentReply?: PostView;
107
142
  totalReplyCount: number;
108
143
  }
109
144