@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.
- package/bin/commands/export.js +1 -1
- package/bin/commands/import-site.js +529 -0
- package/bin/commands/reset-password.js +3 -2
- package/dist/client/assets/heic-to-DIRPI3VF.js +1 -0
- package/dist/client/assets/url-FWFqPJPb.js +1 -0
- package/dist/client/client.css +1 -1
- package/dist/client/client.js +4012 -3276
- package/dist/index.js +10285 -5809
- package/package.json +11 -3
- package/src/__tests__/helpers/app.ts +9 -9
- package/src/__tests__/helpers/db.ts +91 -93
- package/src/app.tsx +157 -27
- package/src/auth.ts +20 -2
- package/src/client/archive-nav.js +187 -0
- package/src/client/audio-player.ts +478 -0
- package/src/client/audio-processor.ts +84 -0
- package/src/client/avatar-upload.ts +3 -2
- package/src/client/components/__tests__/jant-compose-dialog.test.ts +645 -49
- package/src/client/components/__tests__/jant-compose-editor.test.ts +208 -16
- package/src/client/components/__tests__/jant-post-form.test.ts +19 -9
- package/src/client/components/__tests__/jant-settings-avatar.test.ts +2 -2
- package/src/client/components/__tests__/jant-settings-general.test.ts +3 -3
- package/src/client/components/collection-sidebar-types.ts +7 -9
- package/src/client/components/compose-types.ts +101 -4
- package/src/client/components/jant-collection-form.ts +43 -7
- package/src/client/components/jant-collection-sidebar.ts +88 -84
- package/src/client/components/jant-compose-dialog.ts +1655 -219
- package/src/client/components/jant-compose-editor.ts +732 -168
- package/src/client/components/jant-compose-fullscreen.ts +23 -78
- package/src/client/components/jant-media-lightbox.ts +2 -0
- package/src/client/components/jant-nav-manager.ts +24 -284
- package/src/client/components/jant-post-form.ts +89 -9
- package/src/client/components/jant-post-menu.ts +1019 -0
- package/src/client/components/jant-settings-avatar.ts +3 -3
- package/src/client/components/jant-settings-general.ts +38 -4
- package/src/client/components/jant-text-preview.ts +232 -0
- package/src/client/components/nav-manager-types.ts +4 -19
- package/src/client/components/post-form-template.ts +107 -12
- package/src/client/components/post-form-types.ts +11 -4
- package/src/client/compose-bridge.ts +410 -109
- package/src/client/image-processor.ts +26 -8
- package/src/client/media-metadata.ts +247 -0
- package/src/client/multipart-upload.ts +160 -0
- package/src/client/post-form-bridge.ts +52 -1
- package/src/client/settings-bridge.ts +0 -12
- package/src/client/thread-context.ts +140 -0
- package/src/client/tiptap/create-editor.ts +46 -0
- package/src/client/tiptap/extensions.ts +5 -0
- package/src/client/tiptap/image-node.ts +2 -8
- package/src/client/tiptap/paste-image.ts +2 -13
- package/src/client/tiptap/slash-commands.ts +173 -63
- package/src/client/toast.ts +101 -3
- package/src/client/types/sortablejs.d.ts +15 -0
- package/src/client/upload-with-metadata.ts +54 -0
- package/src/client/video-processor.ts +207 -0
- package/src/client.ts +5 -2
- package/src/db/__tests__/migrations.test.ts +118 -0
- package/src/db/index.ts +52 -0
- package/src/db/migrations/0000_baseline.sql +269 -0
- package/src/db/migrations/0001_fts_setup.sql +31 -0
- package/src/db/migrations/meta/0000_snapshot.json +703 -119
- package/src/db/migrations/meta/0001_snapshot.json +1337 -0
- package/src/db/migrations/meta/_journal.json +4 -39
- package/src/db/schema.ts +409 -145
- package/src/i18n/__tests__/detect.test.ts +115 -0
- package/src/i18n/context.tsx +2 -2
- package/src/i18n/detect.ts +85 -1
- package/src/i18n/i18n.ts +1 -1
- package/src/i18n/index.ts +2 -1
- package/src/i18n/locales/en.po +487 -1217
- package/src/i18n/locales/en.ts +1 -1
- package/src/i18n/locales/zh-Hans.po +613 -996
- package/src/i18n/locales/zh-Hans.ts +1 -1
- package/src/i18n/locales/zh-Hant.po +624 -1007
- package/src/i18n/locales/zh-Hant.ts +1 -1
- package/src/i18n/middleware.ts +6 -0
- package/src/index.ts +5 -7
- package/src/lib/__tests__/blurhash-placeholder.test.ts +75 -0
- package/src/lib/__tests__/constants.test.ts +0 -1
- package/src/lib/__tests__/markdown-to-tiptap.test.ts +358 -0
- package/src/lib/__tests__/nanoid.test.ts +26 -0
- package/src/lib/__tests__/schemas.test.ts +181 -63
- package/src/lib/__tests__/slug.test.ts +126 -0
- package/src/lib/__tests__/sse.test.ts +6 -6
- package/src/lib/__tests__/summary.test.ts +264 -0
- package/src/lib/__tests__/theme.test.ts +1 -1
- package/src/lib/__tests__/timeline.test.ts +33 -30
- package/src/lib/__tests__/tiptap-to-markdown.test.ts +346 -0
- package/src/lib/__tests__/view.test.ts +141 -66
- package/src/lib/blurhash-placeholder.ts +102 -0
- package/src/lib/constants.ts +3 -1
- package/src/lib/emoji-catalog.ts +885 -68
- package/src/lib/errors.ts +11 -8
- package/src/lib/feed.ts +78 -32
- package/src/lib/html.ts +2 -1
- package/src/lib/icon-catalog.ts +5033 -1
- package/src/lib/icons.ts +3 -2
- package/src/lib/index.ts +0 -1
- package/src/lib/markdown-to-tiptap.ts +286 -0
- package/src/lib/media-helpers.ts +12 -3
- package/src/lib/nanoid.ts +29 -0
- package/src/lib/navigation.ts +1 -1
- package/src/lib/render.tsx +20 -2
- package/src/lib/resolve-config.ts +6 -2
- package/src/lib/schemas.ts +224 -55
- package/src/lib/search-snippet.ts +34 -0
- package/src/lib/slug.ts +96 -0
- package/src/lib/sse.ts +6 -6
- package/src/lib/storage.ts +115 -7
- package/src/lib/summary.ts +66 -0
- package/src/lib/theme.ts +11 -8
- package/src/lib/timeline.ts +74 -34
- package/src/lib/tiptap-render.ts +5 -10
- package/src/lib/tiptap-to-markdown.ts +305 -0
- package/src/lib/upload.ts +190 -29
- package/src/lib/url.ts +31 -0
- package/src/lib/view.ts +204 -37
- package/src/middleware/__tests__/auth.test.ts +191 -11
- package/src/middleware/__tests__/onboarding.test.ts +12 -10
- package/src/middleware/auth.ts +63 -9
- package/src/middleware/onboarding.ts +1 -1
- package/src/middleware/secure-headers.ts +40 -0
- package/src/preset.css +45 -2
- package/src/routes/__tests__/compose.test.ts +17 -24
- package/src/routes/api/__tests__/collections.test.ts +109 -61
- package/src/routes/api/__tests__/nav-items.test.ts +46 -29
- package/src/routes/api/__tests__/posts.test.ts +132 -68
- package/src/routes/api/__tests__/search.test.ts +15 -2
- package/src/routes/api/__tests__/upload-multipart.test.ts +534 -0
- package/src/routes/api/collections.ts +51 -42
- package/src/routes/api/custom-urls.ts +80 -0
- package/src/routes/api/export.ts +31 -0
- package/src/routes/api/nav-items.ts +23 -19
- package/src/routes/api/posts.ts +43 -39
- package/src/routes/api/search.ts +3 -4
- package/src/routes/api/upload-multipart.ts +245 -0
- package/src/routes/api/upload.ts +85 -19
- package/src/routes/auth/__tests__/setup.test.ts +20 -60
- package/src/routes/auth/setup.tsx +26 -33
- package/src/routes/auth/signin.tsx +3 -7
- package/src/routes/compose.tsx +10 -55
- package/src/routes/dash/__tests__/settings-avatar.test.ts +1 -1
- package/src/routes/dash/custom-urls.tsx +414 -0
- package/src/routes/dash/settings.tsx +304 -232
- package/src/routes/feed/__tests__/rss.test.ts +27 -28
- package/src/routes/feed/rss.ts +6 -4
- package/src/routes/feed/sitemap.ts +2 -12
- package/src/routes/pages/__tests__/collections.test.ts +5 -6
- package/src/routes/pages/__tests__/featured.test.ts +41 -22
- package/src/routes/pages/archive.tsx +175 -39
- package/src/routes/pages/collection.tsx +22 -10
- package/src/routes/pages/collections.tsx +3 -3
- package/src/routes/pages/featured.tsx +28 -4
- package/src/routes/pages/home.tsx +16 -15
- package/src/routes/pages/latest.tsx +1 -11
- package/src/routes/pages/new.tsx +39 -0
- package/src/routes/pages/page.tsx +95 -49
- package/src/routes/pages/search.tsx +1 -1
- package/src/services/__tests__/api-token.test.ts +135 -0
- package/src/services/__tests__/collection.test.ts +275 -227
- package/src/services/__tests__/custom-url.test.ts +213 -0
- package/src/services/__tests__/media.test.ts +162 -22
- package/src/services/__tests__/navigation.test.ts +109 -68
- package/src/services/__tests__/post-timeline.test.ts +205 -32
- package/src/services/__tests__/post.test.ts +713 -234
- package/src/services/__tests__/search.test.ts +67 -10
- package/src/services/api-token.ts +166 -0
- package/src/services/auth.ts +17 -2
- package/src/services/collection.ts +397 -131
- package/src/services/custom-url.ts +188 -0
- package/src/services/export.ts +802 -0
- package/src/services/index.ts +26 -19
- package/src/services/media.ts +100 -22
- package/src/services/navigation.ts +158 -47
- package/src/services/path.ts +339 -0
- package/src/services/post.ts +687 -154
- package/src/services/search.ts +160 -75
- package/src/styles/components.css +58 -7
- package/src/styles/tokens.css +84 -6
- package/src/styles/ui.css +2964 -457
- package/src/types/bindings.ts +4 -1
- package/src/types/config.ts +12 -4
- package/src/types/constants.ts +15 -3
- package/src/types/entities.ts +74 -35
- package/src/types/operations.ts +11 -24
- package/src/types/props.ts +51 -16
- package/src/types/views.ts +45 -22
- package/src/ui/color-themes.ts +133 -23
- package/src/ui/compose/ComposeDialog.tsx +239 -17
- package/src/ui/compose/ComposePrompt.tsx +1 -1
- package/src/ui/dash/CrudPageHeader.tsx +1 -1
- package/src/ui/dash/ListItemRow.tsx +1 -1
- package/src/ui/dash/StatusBadge.tsx +3 -1
- package/src/ui/dash/appearance/AdvancedContent.tsx +22 -1
- package/src/ui/dash/appearance/ColorThemeContent.tsx +22 -2
- package/src/ui/dash/appearance/FontThemeContent.tsx +1 -1
- package/src/ui/dash/appearance/NavigationContent.tsx +5 -45
- package/src/ui/dash/index.ts +0 -3
- package/src/ui/dash/settings/AccountContent.tsx +3 -57
- package/src/ui/dash/settings/AccountMenuContent.tsx +147 -0
- package/src/ui/dash/settings/ApiTokensContent.tsx +232 -0
- package/src/ui/dash/settings/AvatarContent.tsx +8 -0
- package/src/ui/dash/settings/SessionsContent.tsx +159 -0
- package/src/ui/dash/settings/SettingsRootContent.tsx +45 -15
- package/src/ui/feed/LinkCard.tsx +89 -40
- package/src/ui/feed/NoteCard.tsx +39 -25
- package/src/ui/feed/PostStatusBadges.tsx +67 -0
- package/src/ui/feed/QuoteCard.tsx +38 -23
- package/src/ui/feed/ThreadPreview.tsx +90 -26
- package/src/ui/feed/TimelineFeed.tsx +3 -2
- package/src/ui/feed/TimelineItem.tsx +15 -6
- package/src/ui/feed/__tests__/thread-preview.test.ts +107 -0
- package/src/ui/feed/thread-preview-state.ts +61 -0
- package/src/ui/font-themes.ts +2 -2
- package/src/ui/layouts/BaseLayout.tsx +2 -2
- package/src/ui/layouts/SiteLayout.tsx +105 -92
- package/src/ui/pages/ArchivePage.tsx +923 -98
- package/src/ui/pages/ComposePage.tsx +54 -0
- package/src/ui/pages/PostPage.tsx +30 -45
- package/src/ui/pages/SearchPage.tsx +181 -37
- package/src/ui/shared/AdminBreadcrumb.tsx +29 -0
- package/src/ui/shared/CollectionsSidebar.tsx +47 -37
- package/src/ui/shared/MediaGallery.tsx +445 -149
- package/src/ui/shared/PostFooter.tsx +204 -0
- package/src/ui/shared/StarRating.tsx +27 -0
- package/src/ui/shared/__tests__/format-chars.test.ts +35 -0
- package/src/ui/shared/index.ts +0 -1
- package/dist/client/assets/url-8Dj-5CLW.js +0 -1
- package/src/client/media-upload.ts +0 -161
- package/src/client/page-slug-bridge.ts +0 -42
- package/src/db/migrations/0000_square_wallflower.sql +0 -118
- package/src/db/migrations/0001_add_search_fts.sql +0 -34
- package/src/db/migrations/0002_add_media_attachments.sql +0 -3
- package/src/db/migrations/0003_add_navigation_links.sql +0 -8
- package/src/db/migrations/0004_add_storage_provider.sql +0 -3
- package/src/db/migrations/0005_v2_schema_migration.sql +0 -268
- package/src/db/migrations/0006_rename_slug_to_path.sql +0 -5
- package/src/db/migrations/0007_post_collections_m2m.sql +0 -94
- package/src/db/migrations/0008_add_collection_dividers.sql +0 -8
- package/src/db/migrations/0009_drop_collection_show_divider.sql +0 -2
- package/src/db/migrations/0010_add_performance_indexes.sql +0 -16
- package/src/db/migrations/0011_add_path_registry.sql +0 -23
- package/src/db/migrations/0012_add_tiptap_columns.sql +0 -2
- package/src/db/migrations/0013_replace_featured_with_visibility.sql +0 -8
- package/src/db/migrations/meta/0003_snapshot.json +0 -821
- package/src/lib/__tests__/sqid.test.ts +0 -65
- package/src/lib/sqid.ts +0 -79
- package/src/routes/api/__tests__/pages.test.ts +0 -218
- package/src/routes/api/pages.ts +0 -73
- package/src/routes/dash/__tests__/pages.test.ts +0 -226
- package/src/routes/dash/index.tsx +0 -109
- package/src/routes/dash/media.tsx +0 -135
- package/src/routes/dash/pages.tsx +0 -245
- package/src/routes/dash/posts.tsx +0 -338
- package/src/routes/dash/redirects.tsx +0 -263
- package/src/routes/pages/post.tsx +0 -59
- package/src/services/__tests__/page.test.ts +0 -298
- package/src/services/__tests__/path-registry.test.ts +0 -165
- package/src/services/__tests__/redirect.test.ts +0 -159
- package/src/services/page.ts +0 -216
- package/src/services/path-registry.ts +0 -160
- package/src/services/redirect.ts +0 -97
- package/src/ui/dash/PageForm.tsx +0 -187
- package/src/ui/dash/PostList.tsx +0 -95
- package/src/ui/dash/media/MediaListContent.tsx +0 -206
- package/src/ui/dash/media/ViewMediaContent.tsx +0 -208
- package/src/ui/dash/pages/PagesContent.tsx +0 -75
- package/src/ui/dash/posts/PostForm.tsx +0 -260
- package/src/ui/layouts/DashLayout.tsx +0 -247
- package/src/ui/pages/SinglePage.tsx +0 -23
- package/src/ui/shared/ThreadView.tsx +0 -136
|
@@ -4,9 +4,9 @@ import type { Bindings } from "../../../types.js";
|
|
|
4
4
|
import type { AppVariables } from "../../../types/app-context.js";
|
|
5
5
|
import { createTestDatabase } from "../../../__tests__/helpers/db.js";
|
|
6
6
|
import { createPostService } from "../../../services/post.js";
|
|
7
|
+
import { createPathService } from "../../../services/path.js";
|
|
7
8
|
import { createSettingsService } from "../../../services/settings.js";
|
|
8
9
|
import { createMediaService } from "../../../services/media.js";
|
|
9
|
-
import { createPathRegistryService } from "../../../services/path-registry.js";
|
|
10
10
|
import { resolveConfig } from "../../../lib/resolve-config.js";
|
|
11
11
|
import { rssRoutes } from "../rss.js";
|
|
12
12
|
|
|
@@ -14,12 +14,11 @@ type Env = { Bindings: Bindings; Variables: AppVariables };
|
|
|
14
14
|
|
|
15
15
|
function createFeedTestApp(envOverrides: Partial<Bindings> = {}) {
|
|
16
16
|
const { db } = createTestDatabase();
|
|
17
|
+
const pathService = createPathService(db as never);
|
|
17
18
|
|
|
18
19
|
const services = {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
createPathRegistryService(db as never),
|
|
22
|
-
),
|
|
20
|
+
paths: pathService,
|
|
21
|
+
posts: createPostService(db as never, { slugIdLength: 5 }, pathService),
|
|
23
22
|
settings: createSettingsService(db as never),
|
|
24
23
|
media: createMediaService(db as never),
|
|
25
24
|
};
|
|
@@ -54,15 +53,15 @@ describe("RSS Feed Routes", () => {
|
|
|
54
53
|
await services.posts.create({
|
|
55
54
|
format: "note",
|
|
56
55
|
title: "Regular Post",
|
|
57
|
-
|
|
56
|
+
bodyMarkdown: "Not featured",
|
|
58
57
|
status: "published",
|
|
59
58
|
});
|
|
60
59
|
await services.posts.create({
|
|
61
60
|
format: "note",
|
|
62
61
|
title: "Featured Post",
|
|
63
|
-
|
|
62
|
+
bodyMarkdown: "This is featured",
|
|
64
63
|
status: "published",
|
|
65
|
-
|
|
64
|
+
featured: true,
|
|
66
65
|
});
|
|
67
66
|
|
|
68
67
|
const res = await app.request("/feed");
|
|
@@ -79,7 +78,7 @@ describe("RSS Feed Routes", () => {
|
|
|
79
78
|
await services.posts.create({
|
|
80
79
|
format: "note",
|
|
81
80
|
title: "Regular Post",
|
|
82
|
-
|
|
81
|
+
bodyMarkdown: "Not featured",
|
|
83
82
|
status: "published",
|
|
84
83
|
});
|
|
85
84
|
|
|
@@ -107,15 +106,15 @@ describe("RSS Feed Routes", () => {
|
|
|
107
106
|
await services.posts.create({
|
|
108
107
|
format: "note",
|
|
109
108
|
title: "Regular Post",
|
|
110
|
-
|
|
109
|
+
bodyMarkdown: "Not featured",
|
|
111
110
|
status: "published",
|
|
112
111
|
});
|
|
113
112
|
await services.posts.create({
|
|
114
113
|
format: "note",
|
|
115
114
|
title: "Featured Post",
|
|
116
|
-
|
|
115
|
+
bodyMarkdown: "This is featured",
|
|
117
116
|
status: "published",
|
|
118
|
-
|
|
117
|
+
featured: true,
|
|
119
118
|
});
|
|
120
119
|
|
|
121
120
|
const res = await app.request("/feed/atom.xml");
|
|
@@ -137,20 +136,20 @@ describe("RSS Feed Routes", () => {
|
|
|
137
136
|
await services.posts.create({
|
|
138
137
|
format: "note",
|
|
139
138
|
title: "Regular Post",
|
|
140
|
-
|
|
139
|
+
bodyMarkdown: "Not featured",
|
|
141
140
|
status: "published",
|
|
142
141
|
});
|
|
143
142
|
await services.posts.create({
|
|
144
143
|
format: "note",
|
|
145
144
|
title: "Featured Post",
|
|
146
|
-
|
|
145
|
+
bodyMarkdown: "This is featured",
|
|
147
146
|
status: "published",
|
|
148
|
-
|
|
147
|
+
featured: true,
|
|
149
148
|
});
|
|
150
149
|
await services.posts.create({
|
|
151
150
|
format: "note",
|
|
152
151
|
title: "Draft Post",
|
|
153
|
-
|
|
152
|
+
bodyMarkdown: "Draft",
|
|
154
153
|
status: "draft",
|
|
155
154
|
});
|
|
156
155
|
|
|
@@ -169,7 +168,7 @@ describe("RSS Feed Routes", () => {
|
|
|
169
168
|
await services.posts.create({
|
|
170
169
|
format: "note",
|
|
171
170
|
title: "My Note",
|
|
172
|
-
|
|
171
|
+
bodyMarkdown: "A note",
|
|
173
172
|
status: "published",
|
|
174
173
|
});
|
|
175
174
|
await services.posts.create({
|
|
@@ -200,7 +199,7 @@ describe("RSS Feed Routes", () => {
|
|
|
200
199
|
await services.posts.create({
|
|
201
200
|
format: "note",
|
|
202
201
|
title: "My Note",
|
|
203
|
-
|
|
202
|
+
bodyMarkdown: "A note",
|
|
204
203
|
status: "published",
|
|
205
204
|
});
|
|
206
205
|
await services.posts.create({
|
|
@@ -236,15 +235,15 @@ describe("RSS Feed Routes", () => {
|
|
|
236
235
|
await services.posts.create({
|
|
237
236
|
format: "note",
|
|
238
237
|
title: "Regular Post",
|
|
239
|
-
|
|
238
|
+
bodyMarkdown: "Not featured",
|
|
240
239
|
status: "published",
|
|
241
240
|
});
|
|
242
241
|
await services.posts.create({
|
|
243
242
|
format: "note",
|
|
244
243
|
title: "Featured Post",
|
|
245
|
-
|
|
244
|
+
bodyMarkdown: "This is featured",
|
|
246
245
|
status: "published",
|
|
247
|
-
|
|
246
|
+
featured: true,
|
|
248
247
|
});
|
|
249
248
|
|
|
250
249
|
const res = await app.request("/feed/all/atom.xml");
|
|
@@ -264,7 +263,7 @@ describe("RSS Feed Routes", () => {
|
|
|
264
263
|
await services.posts.create({
|
|
265
264
|
format: "note",
|
|
266
265
|
title: "My Note",
|
|
267
|
-
|
|
266
|
+
bodyMarkdown: "A note",
|
|
268
267
|
status: "published",
|
|
269
268
|
});
|
|
270
269
|
await services.posts.create({
|
|
@@ -292,9 +291,9 @@ describe("RSS Feed Routes", () => {
|
|
|
292
291
|
await services.posts.create({
|
|
293
292
|
format: "note",
|
|
294
293
|
title: `Post ${i}`,
|
|
295
|
-
|
|
294
|
+
bodyMarkdown: `Body ${i}`,
|
|
296
295
|
status: "published",
|
|
297
|
-
|
|
296
|
+
featured: true,
|
|
298
297
|
});
|
|
299
298
|
}
|
|
300
299
|
|
|
@@ -318,7 +317,7 @@ describe("RSS Feed Routes", () => {
|
|
|
318
317
|
await services.posts.create({
|
|
319
318
|
format: "note",
|
|
320
319
|
title: `Post ${i}`,
|
|
321
|
-
|
|
320
|
+
bodyMarkdown: `Body ${i}`,
|
|
322
321
|
status: "published",
|
|
323
322
|
});
|
|
324
323
|
}
|
|
@@ -346,7 +345,7 @@ describe("RSS Feed Routes", () => {
|
|
|
346
345
|
await services.posts.create({
|
|
347
346
|
format: "note",
|
|
348
347
|
title: `Post ${i}`,
|
|
349
|
-
|
|
348
|
+
bodyMarkdown: `Body ${i}`,
|
|
350
349
|
status: "published",
|
|
351
350
|
});
|
|
352
351
|
}
|
|
@@ -369,9 +368,9 @@ describe("RSS Feed Routes", () => {
|
|
|
369
368
|
await services.posts.create({
|
|
370
369
|
format: "note",
|
|
371
370
|
title: `Post ${i}`,
|
|
372
|
-
|
|
371
|
+
bodyMarkdown: `Body ${i}`,
|
|
373
372
|
status: "published",
|
|
374
|
-
|
|
373
|
+
featured: true,
|
|
375
374
|
});
|
|
376
375
|
}
|
|
377
376
|
|
package/src/routes/feed/rss.ts
CHANGED
|
@@ -22,8 +22,9 @@ type Env = { Bindings: Bindings; Variables: AppVariables };
|
|
|
22
22
|
export const rssRoutes = new Hono<Env>();
|
|
23
23
|
|
|
24
24
|
interface FeedOptions {
|
|
25
|
-
|
|
25
|
+
featured?: boolean;
|
|
26
26
|
excludeUnlisted?: boolean;
|
|
27
|
+
excludePrivate?: boolean;
|
|
27
28
|
format?: Format;
|
|
28
29
|
}
|
|
29
30
|
|
|
@@ -48,8 +49,9 @@ async function buildFeedData(
|
|
|
48
49
|
const posts = await c.var.services.posts.list({
|
|
49
50
|
status: "published",
|
|
50
51
|
excludeReplies: true,
|
|
51
|
-
|
|
52
|
+
featured: opts?.featured,
|
|
52
53
|
excludeUnlisted: opts?.excludeUnlisted,
|
|
54
|
+
excludePrivate: opts?.excludePrivate ?? true,
|
|
53
55
|
format: opts?.format,
|
|
54
56
|
limit: feedLimit,
|
|
55
57
|
});
|
|
@@ -99,7 +101,7 @@ function parseFormatQuery(c: Context<Env>): Format | undefined {
|
|
|
99
101
|
|
|
100
102
|
// RSS 2.0 — /feed
|
|
101
103
|
rssRoutes.get("/", async (c) => {
|
|
102
|
-
const feedData = await buildFeedData(c, {
|
|
104
|
+
const feedData = await buildFeedData(c, { featured: true });
|
|
103
105
|
const xml = defaultRssRenderer(feedData);
|
|
104
106
|
|
|
105
107
|
return new Response(xml, {
|
|
@@ -111,7 +113,7 @@ rssRoutes.get("/", async (c) => {
|
|
|
111
113
|
|
|
112
114
|
// Atom — /feed/atom.xml
|
|
113
115
|
rssRoutes.get("/atom.xml", async (c) => {
|
|
114
|
-
const feedData = await buildFeedData(c, {
|
|
116
|
+
const feedData = await buildFeedData(c, { featured: true });
|
|
115
117
|
const xml = defaultAtomRenderer(feedData);
|
|
116
118
|
|
|
117
119
|
return new Response(xml, {
|
|
@@ -6,11 +6,7 @@ import { Hono } from "hono";
|
|
|
6
6
|
import type { Bindings } from "../../types.js";
|
|
7
7
|
import type { AppVariables } from "../../types/app-context.js";
|
|
8
8
|
import { defaultSitemapRenderer } from "../../lib/feed.js";
|
|
9
|
-
import {
|
|
10
|
-
createMediaContext,
|
|
11
|
-
toPostViewsFromPosts,
|
|
12
|
-
toPageView,
|
|
13
|
-
} from "../../lib/view.js";
|
|
9
|
+
import { createMediaContext, toPostViewsFromPosts } from "../../lib/view.js";
|
|
14
10
|
|
|
15
11
|
type Env = { Bindings: Bindings; Variables: AppVariables };
|
|
16
12
|
|
|
@@ -24,23 +20,17 @@ sitemapRoutes.get("/sitemap.xml", async (c) => {
|
|
|
24
20
|
const posts = await c.var.services.posts.list({
|
|
25
21
|
status: "published",
|
|
26
22
|
excludeReplies: true,
|
|
23
|
+
excludePrivate: true,
|
|
27
24
|
limit: 1000,
|
|
28
25
|
});
|
|
29
26
|
|
|
30
|
-
// Fetch published pages
|
|
31
|
-
const publishedPages = await c.var.services.pages.list({
|
|
32
|
-
status: "published",
|
|
33
|
-
});
|
|
34
|
-
|
|
35
27
|
// Transform to View Models
|
|
36
28
|
const mediaCtx = createMediaContext(appConfig);
|
|
37
29
|
const postViews = toPostViewsFromPosts(posts, mediaCtx);
|
|
38
|
-
const pageViews = publishedPages.map(toPageView);
|
|
39
30
|
|
|
40
31
|
const xml = defaultSitemapRenderer({
|
|
41
32
|
siteUrl,
|
|
42
33
|
posts: postViews,
|
|
43
|
-
pages: pageViews,
|
|
44
34
|
});
|
|
45
35
|
|
|
46
36
|
return new Response(xml, {
|
|
@@ -10,7 +10,6 @@ import { describe, it, expect, beforeEach } from "vitest";
|
|
|
10
10
|
import { createTestDatabase } from "../../../__tests__/helpers/db.js";
|
|
11
11
|
import { createCollectionService } from "../../../services/collection.js";
|
|
12
12
|
import { createPostService } from "../../../services/post.js";
|
|
13
|
-
import { createPathRegistryService } from "../../../services/path-registry.js";
|
|
14
13
|
import type { Database } from "../../../db/index.js";
|
|
15
14
|
|
|
16
15
|
describe("Collections Listing Page - Data Logic", () => {
|
|
@@ -22,7 +21,7 @@ describe("Collections Listing Page - Data Logic", () => {
|
|
|
22
21
|
const testDb = createTestDatabase();
|
|
23
22
|
db = testDb.db as unknown as Database;
|
|
24
23
|
collectionService = createCollectionService(db);
|
|
25
|
-
postService = createPostService(db,
|
|
24
|
+
postService = createPostService(db, { slugIdLength: 5 });
|
|
26
25
|
});
|
|
27
26
|
|
|
28
27
|
it("returns collections with post counts", async () => {
|
|
@@ -38,11 +37,11 @@ describe("Collections Listing Page - Data Logic", () => {
|
|
|
38
37
|
// Add posts to recipes collection via junction table
|
|
39
38
|
const p1 = await postService.create({
|
|
40
39
|
format: "note",
|
|
41
|
-
|
|
40
|
+
bodyMarkdown: "Recipe 1",
|
|
42
41
|
});
|
|
43
42
|
const p2 = await postService.create({
|
|
44
43
|
format: "note",
|
|
45
|
-
|
|
44
|
+
bodyMarkdown: "Recipe 2",
|
|
46
45
|
});
|
|
47
46
|
await collectionService.addPost(recipes.id, p1.id);
|
|
48
47
|
await collectionService.addPost(recipes.id, p2.id);
|
|
@@ -78,11 +77,11 @@ describe("Collections Listing Page - Data Logic", () => {
|
|
|
78
77
|
|
|
79
78
|
const post = await postService.create({
|
|
80
79
|
format: "note",
|
|
81
|
-
|
|
80
|
+
bodyMarkdown: "Will be deleted",
|
|
82
81
|
});
|
|
83
82
|
const post2 = await postService.create({
|
|
84
83
|
format: "note",
|
|
85
|
-
|
|
84
|
+
bodyMarkdown: "Will remain",
|
|
86
85
|
});
|
|
87
86
|
|
|
88
87
|
await collectionService.addPost(col.id, post.id);
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
import { describe, it, expect, beforeEach } from "vitest";
|
|
10
10
|
import { createTestDatabase } from "../../../__tests__/helpers/db.js";
|
|
11
11
|
import { createPostService } from "../../../services/post.js";
|
|
12
|
-
import { createPathRegistryService } from "../../../services/path-registry.js";
|
|
13
12
|
import type { Database } from "../../../db/index.js";
|
|
14
13
|
|
|
15
14
|
describe("Featured Page - Data Logic", () => {
|
|
@@ -19,76 +18,96 @@ describe("Featured Page - Data Logic", () => {
|
|
|
19
18
|
beforeEach(() => {
|
|
20
19
|
const testDb = createTestDatabase();
|
|
21
20
|
db = testDb.db as unknown as Database;
|
|
22
|
-
postService = createPostService(db,
|
|
21
|
+
postService = createPostService(db, { slugIdLength: 5 });
|
|
23
22
|
});
|
|
24
23
|
|
|
25
24
|
it("returns only featured published posts", async () => {
|
|
26
25
|
await postService.create({
|
|
27
26
|
format: "note",
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
bodyMarkdown: "Featured post",
|
|
28
|
+
featured: true,
|
|
30
29
|
status: "published",
|
|
31
30
|
});
|
|
32
31
|
await postService.create({
|
|
33
32
|
format: "note",
|
|
34
|
-
|
|
33
|
+
bodyMarkdown: "Normal post",
|
|
35
34
|
status: "published",
|
|
36
35
|
});
|
|
37
36
|
await postService.create({
|
|
38
37
|
format: "note",
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
bodyMarkdown: "Draft featured",
|
|
39
|
+
featured: true,
|
|
41
40
|
status: "draft",
|
|
42
41
|
});
|
|
43
42
|
|
|
44
43
|
const posts = await postService.list({
|
|
45
|
-
|
|
44
|
+
featured: true,
|
|
46
45
|
status: "published",
|
|
47
|
-
excludeReplies: true,
|
|
48
46
|
});
|
|
49
47
|
|
|
50
48
|
expect(posts).toHaveLength(1);
|
|
51
|
-
expect(posts[0]?.
|
|
49
|
+
expect(posts[0]?.bodyText).toBe("Featured post");
|
|
52
50
|
});
|
|
53
51
|
|
|
54
52
|
it("returns empty list when no featured posts exist", async () => {
|
|
55
53
|
await postService.create({
|
|
56
54
|
format: "note",
|
|
57
|
-
|
|
55
|
+
bodyMarkdown: "Normal post",
|
|
58
56
|
status: "published",
|
|
59
57
|
});
|
|
60
58
|
|
|
61
59
|
const posts = await postService.list({
|
|
62
|
-
|
|
60
|
+
featured: true,
|
|
63
61
|
status: "published",
|
|
64
|
-
excludeReplies: true,
|
|
65
62
|
});
|
|
66
63
|
|
|
67
64
|
expect(posts).toHaveLength(0);
|
|
68
65
|
});
|
|
69
66
|
|
|
70
|
-
it("
|
|
67
|
+
it("includes featured reply posts", async () => {
|
|
71
68
|
const root = await postService.create({
|
|
72
69
|
format: "note",
|
|
73
|
-
|
|
74
|
-
visibility: "featured",
|
|
70
|
+
bodyMarkdown: "Root post",
|
|
75
71
|
status: "published",
|
|
76
72
|
});
|
|
77
73
|
|
|
78
|
-
//
|
|
79
|
-
await postService.create({
|
|
74
|
+
// Create a reply and feature it independently
|
|
75
|
+
const reply = await postService.create({
|
|
80
76
|
format: "note",
|
|
81
|
-
|
|
77
|
+
bodyMarkdown: "Reply to root",
|
|
82
78
|
replyToId: root.id,
|
|
83
79
|
});
|
|
80
|
+
await postService.update(reply.id, { featured: true });
|
|
84
81
|
|
|
85
82
|
const posts = await postService.list({
|
|
86
|
-
|
|
83
|
+
featured: true,
|
|
87
84
|
status: "published",
|
|
88
|
-
excludeReplies: true,
|
|
89
85
|
});
|
|
90
86
|
|
|
91
87
|
expect(posts).toHaveLength(1);
|
|
92
|
-
expect(posts[0]?.
|
|
88
|
+
expect(posts[0]?.bodyText).toBe("Reply to root");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("featured root and featured reply both appear", async () => {
|
|
92
|
+
const root = await postService.create({
|
|
93
|
+
format: "note",
|
|
94
|
+
bodyMarkdown: "Featured root",
|
|
95
|
+
featured: true,
|
|
96
|
+
status: "published",
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const reply = await postService.create({
|
|
100
|
+
format: "note",
|
|
101
|
+
bodyMarkdown: "Featured reply",
|
|
102
|
+
replyToId: root.id,
|
|
103
|
+
});
|
|
104
|
+
await postService.update(reply.id, { featured: true });
|
|
105
|
+
|
|
106
|
+
const posts = await postService.list({
|
|
107
|
+
featured: true,
|
|
108
|
+
status: "published",
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
expect(posts).toHaveLength(2);
|
|
93
112
|
});
|
|
94
113
|
});
|