@jant/core 0.3.36 → 0.3.38

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 (271) 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/url-FWFqPJPb.js +1 -0
  6. package/dist/client/client.css +1 -1
  7. package/dist/client/client.js +4012 -3276
  8. package/dist/index.js +10285 -5809
  9. package/package.json +11 -3
  10. package/src/__tests__/helpers/app.ts +9 -9
  11. package/src/__tests__/helpers/db.ts +91 -93
  12. package/src/app.tsx +157 -27
  13. package/src/auth.ts +20 -2
  14. package/src/client/archive-nav.js +187 -0
  15. package/src/client/audio-player.ts +478 -0
  16. package/src/client/audio-processor.ts +84 -0
  17. package/src/client/avatar-upload.ts +3 -2
  18. package/src/client/components/__tests__/jant-compose-dialog.test.ts +645 -49
  19. package/src/client/components/__tests__/jant-compose-editor.test.ts +208 -16
  20. package/src/client/components/__tests__/jant-post-form.test.ts +19 -9
  21. package/src/client/components/__tests__/jant-settings-avatar.test.ts +2 -2
  22. package/src/client/components/__tests__/jant-settings-general.test.ts +3 -3
  23. package/src/client/components/collection-sidebar-types.ts +7 -9
  24. package/src/client/components/compose-types.ts +101 -4
  25. package/src/client/components/jant-collection-form.ts +43 -7
  26. package/src/client/components/jant-collection-sidebar.ts +88 -84
  27. package/src/client/components/jant-compose-dialog.ts +1655 -219
  28. package/src/client/components/jant-compose-editor.ts +732 -168
  29. package/src/client/components/jant-compose-fullscreen.ts +23 -78
  30. package/src/client/components/jant-media-lightbox.ts +2 -0
  31. package/src/client/components/jant-nav-manager.ts +24 -284
  32. package/src/client/components/jant-post-form.ts +89 -9
  33. package/src/client/components/jant-post-menu.ts +1019 -0
  34. package/src/client/components/jant-settings-avatar.ts +3 -3
  35. package/src/client/components/jant-settings-general.ts +38 -4
  36. package/src/client/components/jant-text-preview.ts +232 -0
  37. package/src/client/components/nav-manager-types.ts +4 -19
  38. package/src/client/components/post-form-template.ts +107 -12
  39. package/src/client/components/post-form-types.ts +11 -4
  40. package/src/client/compose-bridge.ts +410 -109
  41. package/src/client/image-processor.ts +26 -8
  42. package/src/client/media-metadata.ts +247 -0
  43. package/src/client/multipart-upload.ts +160 -0
  44. package/src/client/post-form-bridge.ts +52 -1
  45. package/src/client/settings-bridge.ts +0 -12
  46. package/src/client/thread-context.ts +140 -0
  47. package/src/client/tiptap/create-editor.ts +46 -0
  48. package/src/client/tiptap/extensions.ts +5 -0
  49. package/src/client/tiptap/image-node.ts +2 -8
  50. package/src/client/tiptap/paste-image.ts +2 -13
  51. package/src/client/tiptap/slash-commands.ts +173 -63
  52. package/src/client/toast.ts +101 -3
  53. package/src/client/types/sortablejs.d.ts +15 -0
  54. package/src/client/upload-with-metadata.ts +54 -0
  55. package/src/client/video-processor.ts +207 -0
  56. package/src/client.ts +5 -2
  57. package/src/db/__tests__/migrations.test.ts +118 -0
  58. package/src/db/index.ts +52 -0
  59. package/src/db/migrations/0000_baseline.sql +269 -0
  60. package/src/db/migrations/0001_fts_setup.sql +31 -0
  61. package/src/db/migrations/meta/0000_snapshot.json +703 -119
  62. package/src/db/migrations/meta/0001_snapshot.json +1337 -0
  63. package/src/db/migrations/meta/_journal.json +4 -39
  64. package/src/db/schema.ts +409 -145
  65. package/src/i18n/__tests__/detect.test.ts +115 -0
  66. package/src/i18n/context.tsx +2 -2
  67. package/src/i18n/detect.ts +85 -1
  68. package/src/i18n/i18n.ts +1 -1
  69. package/src/i18n/index.ts +2 -1
  70. package/src/i18n/locales/en.po +487 -1217
  71. package/src/i18n/locales/en.ts +1 -1
  72. package/src/i18n/locales/zh-Hans.po +613 -996
  73. package/src/i18n/locales/zh-Hans.ts +1 -1
  74. package/src/i18n/locales/zh-Hant.po +624 -1007
  75. package/src/i18n/locales/zh-Hant.ts +1 -1
  76. package/src/i18n/middleware.ts +6 -0
  77. package/src/index.ts +5 -7
  78. package/src/lib/__tests__/blurhash-placeholder.test.ts +75 -0
  79. package/src/lib/__tests__/constants.test.ts +0 -1
  80. package/src/lib/__tests__/markdown-to-tiptap.test.ts +358 -0
  81. package/src/lib/__tests__/nanoid.test.ts +26 -0
  82. package/src/lib/__tests__/schemas.test.ts +181 -63
  83. package/src/lib/__tests__/slug.test.ts +126 -0
  84. package/src/lib/__tests__/sse.test.ts +6 -6
  85. package/src/lib/__tests__/summary.test.ts +264 -0
  86. package/src/lib/__tests__/theme.test.ts +1 -1
  87. package/src/lib/__tests__/timeline.test.ts +33 -30
  88. package/src/lib/__tests__/tiptap-to-markdown.test.ts +346 -0
  89. package/src/lib/__tests__/view.test.ts +141 -66
  90. package/src/lib/blurhash-placeholder.ts +102 -0
  91. package/src/lib/constants.ts +3 -1
  92. package/src/lib/emoji-catalog.ts +885 -68
  93. package/src/lib/errors.ts +11 -8
  94. package/src/lib/feed.ts +78 -32
  95. package/src/lib/html.ts +2 -1
  96. package/src/lib/icon-catalog.ts +5033 -1
  97. package/src/lib/icons.ts +3 -2
  98. package/src/lib/index.ts +0 -1
  99. package/src/lib/markdown-to-tiptap.ts +286 -0
  100. package/src/lib/media-helpers.ts +12 -3
  101. package/src/lib/nanoid.ts +29 -0
  102. package/src/lib/navigation.ts +1 -1
  103. package/src/lib/render.tsx +20 -2
  104. package/src/lib/resolve-config.ts +6 -2
  105. package/src/lib/schemas.ts +224 -55
  106. package/src/lib/search-snippet.ts +34 -0
  107. package/src/lib/slug.ts +96 -0
  108. package/src/lib/sse.ts +6 -6
  109. package/src/lib/storage.ts +115 -7
  110. package/src/lib/summary.ts +66 -0
  111. package/src/lib/theme.ts +11 -8
  112. package/src/lib/timeline.ts +74 -34
  113. package/src/lib/tiptap-render.ts +5 -10
  114. package/src/lib/tiptap-to-markdown.ts +305 -0
  115. package/src/lib/upload.ts +190 -29
  116. package/src/lib/url.ts +31 -0
  117. package/src/lib/view.ts +204 -37
  118. package/src/middleware/__tests__/auth.test.ts +191 -11
  119. package/src/middleware/__tests__/onboarding.test.ts +12 -10
  120. package/src/middleware/auth.ts +63 -9
  121. package/src/middleware/onboarding.ts +1 -1
  122. package/src/middleware/secure-headers.ts +40 -0
  123. package/src/preset.css +45 -2
  124. package/src/routes/__tests__/compose.test.ts +17 -24
  125. package/src/routes/api/__tests__/collections.test.ts +109 -61
  126. package/src/routes/api/__tests__/nav-items.test.ts +46 -29
  127. package/src/routes/api/__tests__/posts.test.ts +132 -68
  128. package/src/routes/api/__tests__/search.test.ts +15 -2
  129. package/src/routes/api/__tests__/upload-multipart.test.ts +534 -0
  130. package/src/routes/api/collections.ts +51 -42
  131. package/src/routes/api/custom-urls.ts +80 -0
  132. package/src/routes/api/export.ts +31 -0
  133. package/src/routes/api/nav-items.ts +23 -19
  134. package/src/routes/api/posts.ts +43 -39
  135. package/src/routes/api/search.ts +3 -4
  136. package/src/routes/api/upload-multipart.ts +245 -0
  137. package/src/routes/api/upload.ts +85 -19
  138. package/src/routes/auth/__tests__/setup.test.ts +20 -60
  139. package/src/routes/auth/setup.tsx +26 -33
  140. package/src/routes/auth/signin.tsx +3 -7
  141. package/src/routes/compose.tsx +10 -55
  142. package/src/routes/dash/__tests__/settings-avatar.test.ts +1 -1
  143. package/src/routes/dash/custom-urls.tsx +414 -0
  144. package/src/routes/dash/settings.tsx +304 -232
  145. package/src/routes/feed/__tests__/rss.test.ts +27 -28
  146. package/src/routes/feed/rss.ts +6 -4
  147. package/src/routes/feed/sitemap.ts +2 -12
  148. package/src/routes/pages/__tests__/collections.test.ts +5 -6
  149. package/src/routes/pages/__tests__/featured.test.ts +41 -22
  150. package/src/routes/pages/archive.tsx +175 -39
  151. package/src/routes/pages/collection.tsx +22 -10
  152. package/src/routes/pages/collections.tsx +3 -3
  153. package/src/routes/pages/featured.tsx +28 -4
  154. package/src/routes/pages/home.tsx +16 -15
  155. package/src/routes/pages/latest.tsx +1 -11
  156. package/src/routes/pages/new.tsx +39 -0
  157. package/src/routes/pages/page.tsx +95 -49
  158. package/src/routes/pages/search.tsx +1 -1
  159. package/src/services/__tests__/api-token.test.ts +135 -0
  160. package/src/services/__tests__/collection.test.ts +275 -227
  161. package/src/services/__tests__/custom-url.test.ts +213 -0
  162. package/src/services/__tests__/media.test.ts +162 -22
  163. package/src/services/__tests__/navigation.test.ts +109 -68
  164. package/src/services/__tests__/post-timeline.test.ts +205 -32
  165. package/src/services/__tests__/post.test.ts +713 -234
  166. package/src/services/__tests__/search.test.ts +67 -10
  167. package/src/services/api-token.ts +166 -0
  168. package/src/services/auth.ts +17 -2
  169. package/src/services/collection.ts +397 -131
  170. package/src/services/custom-url.ts +188 -0
  171. package/src/services/export.ts +802 -0
  172. package/src/services/index.ts +26 -19
  173. package/src/services/media.ts +100 -22
  174. package/src/services/navigation.ts +158 -47
  175. package/src/services/path.ts +339 -0
  176. package/src/services/post.ts +687 -154
  177. package/src/services/search.ts +160 -75
  178. package/src/styles/components.css +58 -7
  179. package/src/styles/tokens.css +84 -6
  180. package/src/styles/ui.css +2964 -457
  181. package/src/types/bindings.ts +4 -1
  182. package/src/types/config.ts +12 -4
  183. package/src/types/constants.ts +15 -3
  184. package/src/types/entities.ts +74 -35
  185. package/src/types/operations.ts +11 -24
  186. package/src/types/props.ts +51 -16
  187. package/src/types/views.ts +45 -22
  188. package/src/ui/color-themes.ts +133 -23
  189. package/src/ui/compose/ComposeDialog.tsx +239 -17
  190. package/src/ui/compose/ComposePrompt.tsx +1 -1
  191. package/src/ui/dash/CrudPageHeader.tsx +1 -1
  192. package/src/ui/dash/ListItemRow.tsx +1 -1
  193. package/src/ui/dash/StatusBadge.tsx +3 -1
  194. package/src/ui/dash/appearance/AdvancedContent.tsx +22 -1
  195. package/src/ui/dash/appearance/ColorThemeContent.tsx +22 -2
  196. package/src/ui/dash/appearance/FontThemeContent.tsx +1 -1
  197. package/src/ui/dash/appearance/NavigationContent.tsx +5 -45
  198. package/src/ui/dash/index.ts +0 -3
  199. package/src/ui/dash/settings/AccountContent.tsx +3 -57
  200. package/src/ui/dash/settings/AccountMenuContent.tsx +147 -0
  201. package/src/ui/dash/settings/ApiTokensContent.tsx +232 -0
  202. package/src/ui/dash/settings/AvatarContent.tsx +8 -0
  203. package/src/ui/dash/settings/SessionsContent.tsx +159 -0
  204. package/src/ui/dash/settings/SettingsRootContent.tsx +45 -15
  205. package/src/ui/feed/LinkCard.tsx +89 -40
  206. package/src/ui/feed/NoteCard.tsx +39 -25
  207. package/src/ui/feed/PostStatusBadges.tsx +67 -0
  208. package/src/ui/feed/QuoteCard.tsx +38 -23
  209. package/src/ui/feed/ThreadPreview.tsx +90 -26
  210. package/src/ui/feed/TimelineFeed.tsx +3 -2
  211. package/src/ui/feed/TimelineItem.tsx +15 -6
  212. package/src/ui/feed/__tests__/thread-preview.test.ts +107 -0
  213. package/src/ui/feed/thread-preview-state.ts +61 -0
  214. package/src/ui/font-themes.ts +2 -2
  215. package/src/ui/layouts/BaseLayout.tsx +2 -2
  216. package/src/ui/layouts/SiteLayout.tsx +105 -92
  217. package/src/ui/pages/ArchivePage.tsx +923 -98
  218. package/src/ui/pages/ComposePage.tsx +54 -0
  219. package/src/ui/pages/PostPage.tsx +30 -45
  220. package/src/ui/pages/SearchPage.tsx +181 -37
  221. package/src/ui/shared/AdminBreadcrumb.tsx +29 -0
  222. package/src/ui/shared/CollectionsSidebar.tsx +47 -37
  223. package/src/ui/shared/MediaGallery.tsx +445 -149
  224. package/src/ui/shared/PostFooter.tsx +204 -0
  225. package/src/ui/shared/StarRating.tsx +27 -0
  226. package/src/ui/shared/__tests__/format-chars.test.ts +35 -0
  227. package/src/ui/shared/index.ts +0 -1
  228. package/dist/client/assets/url-8Dj-5CLW.js +0 -1
  229. package/src/client/media-upload.ts +0 -161
  230. package/src/client/page-slug-bridge.ts +0 -42
  231. package/src/db/migrations/0000_square_wallflower.sql +0 -118
  232. package/src/db/migrations/0001_add_search_fts.sql +0 -34
  233. package/src/db/migrations/0002_add_media_attachments.sql +0 -3
  234. package/src/db/migrations/0003_add_navigation_links.sql +0 -8
  235. package/src/db/migrations/0004_add_storage_provider.sql +0 -3
  236. package/src/db/migrations/0005_v2_schema_migration.sql +0 -268
  237. package/src/db/migrations/0006_rename_slug_to_path.sql +0 -5
  238. package/src/db/migrations/0007_post_collections_m2m.sql +0 -94
  239. package/src/db/migrations/0008_add_collection_dividers.sql +0 -8
  240. package/src/db/migrations/0009_drop_collection_show_divider.sql +0 -2
  241. package/src/db/migrations/0010_add_performance_indexes.sql +0 -16
  242. package/src/db/migrations/0011_add_path_registry.sql +0 -23
  243. package/src/db/migrations/0012_add_tiptap_columns.sql +0 -2
  244. package/src/db/migrations/0013_replace_featured_with_visibility.sql +0 -8
  245. package/src/db/migrations/meta/0003_snapshot.json +0 -821
  246. package/src/lib/__tests__/sqid.test.ts +0 -65
  247. package/src/lib/sqid.ts +0 -79
  248. package/src/routes/api/__tests__/pages.test.ts +0 -218
  249. package/src/routes/api/pages.ts +0 -73
  250. package/src/routes/dash/__tests__/pages.test.ts +0 -226
  251. package/src/routes/dash/index.tsx +0 -109
  252. package/src/routes/dash/media.tsx +0 -135
  253. package/src/routes/dash/pages.tsx +0 -245
  254. package/src/routes/dash/posts.tsx +0 -338
  255. package/src/routes/dash/redirects.tsx +0 -263
  256. package/src/routes/pages/post.tsx +0 -59
  257. package/src/services/__tests__/page.test.ts +0 -298
  258. package/src/services/__tests__/path-registry.test.ts +0 -165
  259. package/src/services/__tests__/redirect.test.ts +0 -159
  260. package/src/services/page.ts +0 -216
  261. package/src/services/path-registry.ts +0 -160
  262. package/src/services/redirect.ts +0 -97
  263. package/src/ui/dash/PageForm.tsx +0 -187
  264. package/src/ui/dash/PostList.tsx +0 -95
  265. package/src/ui/dash/media/MediaListContent.tsx +0 -206
  266. package/src/ui/dash/media/ViewMediaContent.tsx +0 -208
  267. package/src/ui/dash/pages/PagesContent.tsx +0 -75
  268. package/src/ui/dash/posts/PostForm.tsx +0 -260
  269. package/src/ui/layouts/DashLayout.tsx +0 -247
  270. package/src/ui/pages/SinglePage.tsx +0 -23
  271. package/src/ui/shared/ThreadView.tsx +0 -136
@@ -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');