@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
@@ -0,0 +1,269 @@
1
+ CREATE TABLE `account` (
2
+ `id` text PRIMARY KEY NOT NULL,
3
+ `account_id` text NOT NULL,
4
+ `provider_id` text NOT NULL,
5
+ `user_id` text NOT NULL,
6
+ `access_token` text,
7
+ `refresh_token` text,
8
+ `id_token` text,
9
+ `access_token_expires_at` integer,
10
+ `refresh_token_expires_at` integer,
11
+ `scope` text,
12
+ `password` text,
13
+ `created_at` integer NOT NULL,
14
+ `updated_at` integer NOT NULL,
15
+ FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE no action
16
+ );
17
+ --> statement-breakpoint
18
+ CREATE TABLE `api_token` (
19
+ `id` text PRIMARY KEY NOT NULL,
20
+ `name` text NOT NULL,
21
+ `token_hash` text NOT NULL,
22
+ `prefix` text NOT NULL,
23
+ `last_used_at` integer,
24
+ `created_at` integer NOT NULL,
25
+ `updated_at` integer NOT NULL
26
+ );
27
+ --> statement-breakpoint
28
+ CREATE UNIQUE INDEX `api_token_token_hash_unique` ON `api_token` (`token_hash`);--> statement-breakpoint
29
+ CREATE TABLE `collection` (
30
+ `id` text PRIMARY KEY NOT NULL,
31
+ `title` text NOT NULL,
32
+ `description` text,
33
+ `icon` text,
34
+ `sort_order` text DEFAULT 'newest' NOT NULL,
35
+ `created_at` integer NOT NULL,
36
+ `updated_at` integer NOT NULL,
37
+ CONSTRAINT "chk_collection_sort_order" CHECK("collection"."sort_order" IN ('newest', 'oldest', 'rating_desc', 'rating_asc'))
38
+ );
39
+ --> statement-breakpoint
40
+ CREATE TABLE `media` (
41
+ `id` text PRIMARY KEY NOT NULL,
42
+ `post_id` text,
43
+ `filename` text NOT NULL,
44
+ `original_name` text NOT NULL,
45
+ `mime_type` text NOT NULL,
46
+ `size` integer NOT NULL,
47
+ `storage_key` text NOT NULL,
48
+ `provider` text DEFAULT 'r2' NOT NULL,
49
+ `width` integer,
50
+ `height` integer,
51
+ `alt` text,
52
+ `position` text DEFAULT 'a0' NOT NULL,
53
+ `blurhash` text,
54
+ `waveform` text,
55
+ `poster_key` text,
56
+ `summary` text,
57
+ `chars` integer,
58
+ `media_kind` text DEFAULT 'document' NOT NULL,
59
+ `created_at` integer NOT NULL,
60
+ `updated_at` integer NOT NULL,
61
+ FOREIGN KEY (`post_id`) REFERENCES `post`(`id`) ON UPDATE no action ON DELETE set null,
62
+ CONSTRAINT "chk_media_provider" CHECK("media"."provider" IN ('r2', 's3')),
63
+ CONSTRAINT "chk_media_media_kind" CHECK("media"."media_kind" IN ('image', 'video', 'audio', 'text', 'document')),
64
+ CONSTRAINT "chk_media_size_positive" CHECK("media"."size" > 0),
65
+ CONSTRAINT "chk_media_position_not_blank" CHECK(trim("media"."position") <> ''),
66
+ CONSTRAINT "chk_media_dimensions_positive" CHECK((
67
+ "media"."width" IS NULL OR "media"."width" > 0
68
+ ) AND (
69
+ "media"."height" IS NULL OR "media"."height" > 0
70
+ )),
71
+ CONSTRAINT "chk_media_chars_nonnegative" CHECK("media"."chars" IS NULL OR "media"."chars" >= 0)
72
+ );
73
+ --> statement-breakpoint
74
+ CREATE INDEX `idx_media_post_id_position` ON `media` (`post_id`,`position`);--> statement-breakpoint
75
+ CREATE UNIQUE INDEX `uq_media_post_position` ON `media` (`post_id`,`position`) WHERE "media"."post_id" IS NOT NULL;--> statement-breakpoint
76
+ CREATE UNIQUE INDEX `uq_media_provider_storage_key` ON `media` (`provider`,`storage_key`);--> statement-breakpoint
77
+ CREATE INDEX `idx_media_media_kind_post_id` ON `media` (`media_kind`,`post_id`);--> statement-breakpoint
78
+ CREATE TABLE `nav_item` (
79
+ `id` text PRIMARY KEY NOT NULL,
80
+ `type` text DEFAULT 'link' NOT NULL,
81
+ `label` text NOT NULL,
82
+ `url` text NOT NULL,
83
+ `position` text DEFAULT 'a0' NOT NULL,
84
+ `created_at` integer NOT NULL,
85
+ `updated_at` integer NOT NULL,
86
+ CONSTRAINT "chk_nav_item_type" CHECK("nav_item"."type" IN ('link', 'system'))
87
+ );
88
+ --> statement-breakpoint
89
+ CREATE UNIQUE INDEX `uq_nav_item_position` ON `nav_item` (`position`);--> statement-breakpoint
90
+ CREATE TABLE `path_registry` (
91
+ `id` text PRIMARY KEY NOT NULL,
92
+ `path` text NOT NULL,
93
+ `kind` text NOT NULL,
94
+ `post_id` text,
95
+ `collection_id` text,
96
+ `redirect_to_path` text,
97
+ `redirect_type` integer,
98
+ `created_at` integer NOT NULL,
99
+ `updated_at` integer NOT NULL,
100
+ FOREIGN KEY (`post_id`) REFERENCES `post`(`id`) ON UPDATE no action ON DELETE cascade,
101
+ FOREIGN KEY (`collection_id`) REFERENCES `collection`(`id`) ON UPDATE no action ON DELETE cascade,
102
+ CONSTRAINT "chk_path_registry_kind" CHECK("path_registry"."kind" IN ('slug', 'alias', 'redirect')),
103
+ CONSTRAINT "chk_path_registry_shape" CHECK((
104
+ "path_registry"."kind" IN ('slug', 'alias')
105
+ AND (
106
+ ("path_registry"."post_id" IS NOT NULL AND "path_registry"."collection_id" IS NULL)
107
+ OR ("path_registry"."post_id" IS NULL AND "path_registry"."collection_id" IS NOT NULL)
108
+ )
109
+ AND "path_registry"."redirect_to_path" IS NULL
110
+ AND "path_registry"."redirect_type" IS NULL
111
+ ) OR (
112
+ "path_registry"."kind" = 'redirect'
113
+ AND "path_registry"."post_id" IS NULL
114
+ AND "path_registry"."collection_id" IS NULL
115
+ AND "path_registry"."redirect_to_path" IS NOT NULL
116
+ AND "path_registry"."redirect_type" IN (301, 302)
117
+ ))
118
+ );
119
+ --> statement-breakpoint
120
+ CREATE UNIQUE INDEX `path_registry_path_unique` ON `path_registry` (`path`);--> statement-breakpoint
121
+ CREATE UNIQUE INDEX `uq_path_registry_post_slug` ON `path_registry` (`post_id`) WHERE "path_registry"."kind" = 'slug' AND "path_registry"."post_id" IS NOT NULL;--> statement-breakpoint
122
+ CREATE UNIQUE INDEX `uq_path_registry_collection_slug` ON `path_registry` (`collection_id`) WHERE "path_registry"."kind" = 'slug' AND "path_registry"."collection_id" IS NOT NULL;--> statement-breakpoint
123
+ CREATE INDEX `idx_path_registry_post_id` ON `path_registry` (`post_id`);--> statement-breakpoint
124
+ CREATE INDEX `idx_path_registry_collection_id` ON `path_registry` (`collection_id`);--> statement-breakpoint
125
+ CREATE TABLE `post_collection` (
126
+ `post_id` text NOT NULL,
127
+ `collection_id` text NOT NULL,
128
+ `created_at` integer NOT NULL,
129
+ PRIMARY KEY(`post_id`, `collection_id`),
130
+ FOREIGN KEY (`post_id`) REFERENCES `post`(`id`) ON UPDATE no action ON DELETE cascade,
131
+ FOREIGN KEY (`collection_id`) REFERENCES `collection`(`id`) ON UPDATE no action ON DELETE cascade
132
+ );
133
+ --> statement-breakpoint
134
+ CREATE INDEX `idx_post_collection_collection_id` ON `post_collection` (`collection_id`);--> statement-breakpoint
135
+ CREATE TABLE `post` (
136
+ `id` text PRIMARY KEY NOT NULL,
137
+ `format` text NOT NULL,
138
+ `status` text DEFAULT 'published' NOT NULL,
139
+ `visibility` text DEFAULT 'public',
140
+ `pinned_at` integer,
141
+ `featured_at` integer,
142
+ `title` text,
143
+ `url` text,
144
+ `body` text,
145
+ `body_html` text,
146
+ `body_text` text,
147
+ `quote_text` text,
148
+ `summary` text,
149
+ `rating` integer,
150
+ `reply_to_id` text,
151
+ `thread_id` text NOT NULL,
152
+ `deleted_at` integer,
153
+ `published_at` integer,
154
+ `last_activity_at` integer,
155
+ `created_at` integer NOT NULL,
156
+ `updated_at` integer NOT NULL,
157
+ FOREIGN KEY (`reply_to_id`) REFERENCES `post`(`id`) ON UPDATE no action ON DELETE no action,
158
+ FOREIGN KEY (`thread_id`) REFERENCES `post`(`id`) ON UPDATE no action ON DELETE no action,
159
+ FOREIGN KEY (`reply_to_id`,`thread_id`) REFERENCES `post`(`id`,`thread_id`) ON UPDATE no action ON DELETE no action,
160
+ CONSTRAINT "chk_post_format" CHECK("post"."format" IN ('note', 'link', 'quote')),
161
+ CONSTRAINT "chk_post_status" CHECK("post"."status" IN ('draft', 'published')),
162
+ CONSTRAINT "chk_post_visibility" CHECK("post"."visibility" IN ('public', 'unlisted', 'private')),
163
+ CONSTRAINT "chk_post_root_visibility_present" CHECK((
164
+ "post"."reply_to_id" IS NULL
165
+ AND "post"."visibility" IS NOT NULL
166
+ ) OR (
167
+ "post"."reply_to_id" IS NOT NULL
168
+ AND "post"."visibility" IS NULL
169
+ )),
170
+ CONSTRAINT "chk_post_reply_to_not_self" CHECK("post"."reply_to_id" IS NULL OR "post"."reply_to_id" <> "post"."id"),
171
+ CONSTRAINT "chk_post_thread_shape" CHECK((
172
+ "post"."reply_to_id" IS NULL
173
+ AND "post"."thread_id" = "post"."id"
174
+ ) OR (
175
+ "post"."reply_to_id" IS NOT NULL
176
+ AND "post"."thread_id" <> "post"."id"
177
+ )),
178
+ CONSTRAINT "chk_post_reply_not_pinned" CHECK("post"."pinned_at" IS NULL OR "post"."reply_to_id" IS NULL),
179
+ CONSTRAINT "chk_post_format_shape" CHECK((
180
+ "post"."format" = 'note'
181
+ AND ("post"."url" IS NULL OR trim("post"."url") = '')
182
+ AND ("post"."quote_text" IS NULL OR trim("post"."quote_text") = '')
183
+ ) OR (
184
+ "post"."format" = 'link'
185
+ AND "post"."url" IS NOT NULL
186
+ AND trim("post"."url") <> ''
187
+ AND ("post"."quote_text" IS NULL OR trim("post"."quote_text") = '')
188
+ ) OR (
189
+ "post"."format" = 'quote'
190
+ AND "post"."quote_text" IS NOT NULL
191
+ AND trim("post"."quote_text") <> ''
192
+ )),
193
+ CONSTRAINT "chk_post_rating_range" CHECK("post"."rating" IS NULL OR "post"."rating" BETWEEN 1 AND 5),
194
+ CONSTRAINT "chk_post_status_published_at" CHECK((
195
+ "post"."status" = 'draft'
196
+ AND "post"."published_at" IS NULL
197
+ ) OR (
198
+ "post"."status" = 'published'
199
+ AND "post"."published_at" IS NOT NULL
200
+ ))
201
+ );
202
+ --> statement-breakpoint
203
+ CREATE UNIQUE INDEX `uq_post_id_thread_id` ON `post` (`id`,`thread_id`);--> statement-breakpoint
204
+ CREATE INDEX `idx_post_thread_id` ON `post` (`thread_id`);--> statement-breakpoint
205
+ CREATE INDEX `idx_post_thread_live_created` ON `post` (`thread_id`,`created_at`,`id`) WHERE "post"."deleted_at" IS NULL;--> statement-breakpoint
206
+ CREATE INDEX `idx_post_status_deleted_published` ON `post` (`status`,`deleted_at`,`published_at`);--> statement-breakpoint
207
+ CREATE INDEX `idx_post_status_deleted_activity` ON `post` (`status`,`deleted_at`,`last_activity_at`);--> statement-breakpoint
208
+ CREATE INDEX `idx_post_root_live_published_activity` ON `post` (`last_activity_at`,`id`) WHERE "post"."deleted_at" IS NULL AND "post"."reply_to_id" IS NULL AND "post"."status" = 'published';--> statement-breakpoint
209
+ CREATE INDEX `idx_post_root_live_draft_updated` ON `post` (`updated_at`,`id`) WHERE "post"."deleted_at" IS NULL AND "post"."reply_to_id" IS NULL AND "post"."status" = 'draft';--> statement-breakpoint
210
+ CREATE INDEX `idx_post_reply_live_thread_created` ON `post` (`thread_id`,`created_at`,`id`) WHERE "post"."deleted_at" IS NULL AND "post"."reply_to_id" IS NOT NULL AND "post"."status" = 'published';--> statement-breakpoint
211
+ CREATE TABLE `session` (
212
+ `id` text PRIMARY KEY NOT NULL,
213
+ `expires_at` integer NOT NULL,
214
+ `token` text NOT NULL,
215
+ `created_at` integer NOT NULL,
216
+ `updated_at` integer NOT NULL,
217
+ `ip_address` text,
218
+ `user_agent` text,
219
+ `user_id` text NOT NULL,
220
+ FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE no action
221
+ );
222
+ --> statement-breakpoint
223
+ CREATE UNIQUE INDEX `session_token_unique` ON `session` (`token`);--> statement-breakpoint
224
+ CREATE INDEX `idx_session_user_id` ON `session` (`user_id`);--> statement-breakpoint
225
+ CREATE TABLE `setting` (
226
+ `key` text PRIMARY KEY NOT NULL,
227
+ `value` text NOT NULL,
228
+ `updated_at` integer NOT NULL
229
+ );
230
+ --> statement-breakpoint
231
+ CREATE TABLE `sidebar_item` (
232
+ `id` text PRIMARY KEY NOT NULL,
233
+ `type` text NOT NULL,
234
+ `collection_id` text,
235
+ `position` text DEFAULT 'a0' NOT NULL,
236
+ `created_at` integer NOT NULL,
237
+ `updated_at` integer NOT NULL,
238
+ FOREIGN KEY (`collection_id`) REFERENCES `collection`(`id`) ON UPDATE no action ON DELETE cascade,
239
+ CONSTRAINT "chk_sidebar_item_type" CHECK("sidebar_item"."type" IN ('collection', 'divider')),
240
+ CONSTRAINT "chk_sidebar_item_shape" CHECK((
241
+ "sidebar_item"."type" = 'collection' AND "sidebar_item"."collection_id" IS NOT NULL
242
+ ) OR (
243
+ "sidebar_item"."type" = 'divider' AND "sidebar_item"."collection_id" IS NULL
244
+ ))
245
+ );
246
+ --> statement-breakpoint
247
+ CREATE INDEX `idx_sidebar_item_collection_id` ON `sidebar_item` (`collection_id`);--> statement-breakpoint
248
+ CREATE UNIQUE INDEX `uq_sidebar_item_position` ON `sidebar_item` (`position`);--> statement-breakpoint
249
+ CREATE UNIQUE INDEX `uq_sidebar_item_collection_once` ON `sidebar_item` (`collection_id`) WHERE "sidebar_item"."type" = 'collection' AND "sidebar_item"."collection_id" IS NOT NULL;--> statement-breakpoint
250
+ CREATE TABLE `user` (
251
+ `id` text PRIMARY KEY NOT NULL,
252
+ `name` text NOT NULL,
253
+ `email` text NOT NULL,
254
+ `email_verified` integer DEFAULT false NOT NULL,
255
+ `image` text,
256
+ `role` text DEFAULT 'member',
257
+ `created_at` integer NOT NULL,
258
+ `updated_at` integer NOT NULL
259
+ );
260
+ --> statement-breakpoint
261
+ CREATE UNIQUE INDEX `user_email_unique` ON `user` (`email`);--> statement-breakpoint
262
+ CREATE TABLE `verification` (
263
+ `id` text PRIMARY KEY NOT NULL,
264
+ `identifier` text NOT NULL,
265
+ `value` text NOT NULL,
266
+ `expires_at` integer NOT NULL,
267
+ `created_at` integer,
268
+ `updated_at` integer
269
+ );
@@ -0,0 +1,31 @@
1
+ -- FTS5 virtual table for full-text search on posts.
2
+ -- Uses trigram tokenizer for partial-match support, including CJK text.
3
+
4
+ CREATE VIRTUAL TABLE post_fts USING fts5(
5
+ title,
6
+ body_text,
7
+ quote_text,
8
+ url,
9
+ content='post',
10
+ content_rowid='rowid',
11
+ tokenize='trigram'
12
+ );
13
+ --> statement-breakpoint
14
+ CREATE TRIGGER post_ai AFTER INSERT ON post BEGIN
15
+ INSERT INTO post_fts(rowid, title, body_text, quote_text, url)
16
+ VALUES (new.rowid, new.title, new.body_text, new.quote_text, new.url);
17
+ END;
18
+ --> statement-breakpoint
19
+ CREATE TRIGGER post_ad AFTER DELETE ON post BEGIN
20
+ INSERT INTO post_fts(post_fts, rowid, title, body_text, quote_text, url)
21
+ VALUES ('delete', old.rowid, old.title, old.body_text, old.quote_text, old.url);
22
+ END;
23
+ --> statement-breakpoint
24
+ CREATE TRIGGER post_au AFTER UPDATE ON post BEGIN
25
+ INSERT INTO post_fts(post_fts, rowid, title, body_text, quote_text, url)
26
+ VALUES ('delete', old.rowid, old.title, old.body_text, old.quote_text, old.url);
27
+ INSERT INTO post_fts(rowid, title, body_text, quote_text, url)
28
+ VALUES (new.rowid, new.title, new.body_text, new.quote_text, new.url);
29
+ END;
30
+ --> statement-breakpoint
31
+ INSERT INTO post_fts(post_fts) VALUES ('rebuild');