@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.
- 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/module-RjUF93sV.js +716 -0
- package/dist/client/assets/native-48B9X9Wg.js +1 -0
- package/dist/client/assets/url-FWFqPJPb.js +1 -0
- package/dist/client/client.css +1 -1
- package/dist/client/client.js +4564 -3013
- package/dist/index.js +12885 -8161
- package/package.json +23 -6
- package/src/__tests__/helpers/app.ts +10 -10
- package/src/__tests__/helpers/db.ts +91 -87
- package/src/app.tsx +157 -31
- 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/{lib → client}/avatar-upload.ts +4 -3
- package/src/{lib → client}/collection-form-bridge.ts +2 -2
- package/src/{ui → client}/components/__tests__/jant-collection-form.test.ts +26 -9
- package/src/client/components/__tests__/jant-compose-dialog.test.ts +1140 -0
- package/src/client/components/__tests__/jant-compose-editor.test.ts +504 -0
- package/src/{ui → client}/components/__tests__/jant-post-form.test.ts +37 -17
- package/src/{ui → client}/components/__tests__/jant-settings-avatar.test.ts +2 -2
- package/src/{ui → client}/components/__tests__/jant-settings-general.test.ts +3 -3
- package/src/client/components/collection-sidebar-types.ts +43 -0
- package/src/{ui → client}/components/collection-types.ts +3 -4
- package/src/client/components/compose-types.ts +174 -0
- package/src/client/components/jant-collection-form.ts +667 -0
- package/src/client/components/jant-collection-sidebar.ts +805 -0
- package/src/client/components/jant-compose-dialog.ts +2161 -0
- package/src/client/components/jant-compose-editor.ts +1813 -0
- package/src/client/components/jant-compose-fullscreen.ts +283 -0
- package/src/client/components/jant-media-lightbox.ts +259 -0
- package/src/{ui → client}/components/jant-nav-manager.ts +97 -298
- package/src/{ui → client}/components/jant-post-form.ts +141 -12
- package/src/client/components/jant-post-menu.ts +1019 -0
- package/src/{ui → client}/components/jant-settings-avatar.ts +3 -3
- package/src/{ui → client}/components/jant-settings-general.ts +38 -4
- package/src/client/components/jant-text-preview.ts +232 -0
- package/src/{ui → client}/components/nav-manager-types.ts +6 -18
- package/src/{ui → client}/components/post-form-template.ts +137 -38
- package/src/{ui → client}/components/post-form-types.ts +15 -4
- package/src/client/compose-bridge.ts +583 -0
- package/src/{lib → client}/image-processor.ts +26 -8
- package/src/client/lazy-slugify.ts +51 -0
- package/src/client/media-metadata.ts +247 -0
- package/src/client/multipart-upload.ts +160 -0
- package/src/{lib → client}/nav-manager-bridge.ts +1 -1
- package/src/{lib → client}/post-form-bridge.ts +53 -2
- package/src/{lib → client}/settings-bridge.ts +3 -15
- package/src/client/thread-context.ts +140 -0
- package/src/client/tiptap/bubble-menu.ts +205 -0
- package/src/client/tiptap/create-editor.ts +86 -0
- package/src/client/tiptap/exitable-marks.ts +73 -0
- package/src/client/tiptap/extensions.ts +65 -0
- package/src/client/tiptap/image-node.ts +482 -0
- package/src/client/tiptap/link-toolbar.ts +371 -0
- package/src/client/tiptap/more-break.ts +50 -0
- package/src/client/tiptap/paste-image.ts +129 -0
- package/src/client/tiptap/slash-commands.ts +438 -0
- package/src/{lib → client}/toast.ts +101 -3
- package/src/client/types/sortablejs.d.ts +44 -0
- package/src/client/upload-with-metadata.ts +54 -0
- package/src/client/video-processor.ts +207 -0
- package/src/client.ts +27 -17
- 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 -140
- 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 +783 -1087
- package/src/i18n/locales/en.ts +1 -1
- package/src/i18n/locales/zh-Hans.po +867 -812
- package/src/i18n/locales/zh-Hans.ts +1 -1
- package/src/i18n/locales/zh-Hant.po +878 -823
- 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__/resolve-config.test.ts +2 -2
- package/src/lib/__tests__/schemas.test.ts +186 -65
- 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__/url.test.ts +2 -2
- package/src/lib/__tests__/view.test.ts +140 -65
- package/src/lib/blurhash-placeholder.ts +102 -0
- package/src/lib/constants.ts +3 -1
- package/src/lib/emoji-catalog.ts +963 -0
- package/src/lib/errors.ts +11 -8
- package/src/lib/feed.ts +77 -31
- 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 +22 -12
- package/src/lib/nanoid.ts +29 -0
- package/src/lib/navigation.ts +1 -1
- package/src/lib/render.tsx +24 -5
- package/src/lib/resolve-config.ts +13 -2
- package/src/lib/schemas.ts +226 -58
- 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 +158 -0
- package/src/lib/theme.ts +11 -8
- package/src/lib/timeline.ts +76 -34
- package/src/lib/tiptap-render.ts +191 -0
- package/src/lib/tiptap-to-markdown.ts +305 -0
- package/src/lib/upload.ts +263 -14
- package/src/lib/url.ts +37 -22
- package/src/lib/view.ts +236 -55
- 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/error-handler.ts +3 -3
- package/src/middleware/onboarding.ts +1 -1
- package/src/middleware/secure-headers.ts +40 -0
- package/src/preset.css +83 -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 +57 -31
- 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 +81 -62
- package/src/routes/api/search.ts +3 -4
- package/src/routes/api/upload-multipart.ts +245 -0
- package/src/routes/api/upload.ts +92 -24
- package/src/routes/auth/__tests__/setup.test.ts +20 -60
- package/src/routes/auth/reset.tsx +5 -4
- package/src/routes/auth/setup.tsx +39 -31
- package/src/routes/auth/signin.tsx +13 -14
- package/src/routes/compose.tsx +27 -63
- package/src/routes/dash/__tests__/settings-avatar.test.ts +44 -9
- package/src/routes/dash/custom-urls.tsx +414 -0
- package/src/routes/dash/settings.tsx +475 -99
- package/src/routes/feed/__tests__/rss.test.ts +22 -23
- package/src/routes/feed/rss.ts +6 -2
- 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 +36 -18
- package/src/routes/pages/archive.tsx +177 -37
- package/src/routes/pages/collection.tsx +43 -14
- package/src/routes/pages/collections.tsx +11 -2
- package/src/routes/pages/featured.tsx +27 -3
- package/src/routes/pages/home.tsx +15 -14
- 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 +800 -230
- package/src/services/__tests__/search.test.ts +67 -10
- package/src/services/__tests__/settings.test.ts +3 -3
- 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 +764 -172
- package/src/services/search.ts +161 -74
- package/src/services/settings.ts +6 -2
- package/src/styles/components.css +293 -62
- package/src/styles/tokens.css +93 -5
- package/src/styles/ui.css +4349 -766
- package/src/types/bindings.ts +8 -0
- package/src/types/config.ts +34 -4
- package/src/types/constants.ts +17 -2
- package/src/types/entities.ts +83 -37
- package/src/types/operations.ts +20 -27
- package/src/types/props.ts +52 -17
- package/src/types/views.ts +48 -24
- package/src/ui/color-themes.ts +133 -23
- package/src/ui/compose/ComposeDialog.tsx +255 -16
- 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 +12 -2
- package/src/ui/dash/appearance/AdvancedContent.tsx +71 -59
- package/src/ui/dash/appearance/ColorThemeContent.tsx +48 -33
- package/src/ui/dash/appearance/FontThemeContent.tsx +65 -73
- package/src/ui/dash/appearance/NavigationContent.tsx +106 -135
- package/src/ui/dash/index.ts +0 -3
- package/src/ui/dash/settings/AccountContent.tsx +87 -146
- 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 +78 -0
- package/src/ui/dash/settings/GeneralContent.tsx +3 -62
- package/src/ui/dash/settings/SessionsContent.tsx +159 -0
- package/src/ui/dash/settings/SettingsRootContent.tsx +266 -0
- 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 +116 -103
- package/src/ui/pages/ArchivePage.tsx +923 -95
- package/src/ui/pages/CollectionPage.tsx +6 -35
- package/src/ui/pages/CollectionsPage.tsx +2 -1
- package/src/ui/pages/ComposePage.tsx +54 -0
- package/src/ui/pages/FeaturedPage.tsx +2 -1
- package/src/ui/pages/HomePage.tsx +1 -1
- package/src/ui/pages/PostPage.tsx +30 -45
- package/src/ui/pages/SearchPage.tsx +182 -38
- package/src/ui/shared/AdminBreadcrumb.tsx +29 -0
- package/src/ui/shared/CollectionsSidebar.tsx +239 -4
- package/src/ui/shared/MediaGallery.tsx +475 -41
- 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/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/meta/0003_snapshot.json +0 -821
- package/src/lib/__tests__/sqid.test.ts +0 -65
- package/src/lib/collections-reorder.ts +0 -28
- package/src/lib/compose-bridge.ts +0 -280
- package/src/lib/media-upload.ts +0 -148
- 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/appearance.tsx +0 -240
- package/src/routes/dash/collections.tsx +0 -211
- package/src/routes/dash/index.tsx +0 -103
- package/src/routes/dash/media.tsx +0 -132
- package/src/routes/dash/pages.tsx +0 -239
- package/src/routes/dash/posts.tsx +0 -334
- package/src/routes/dash/redirects.tsx +0 -257
- 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 -203
- package/src/services/path-registry.ts +0 -160
- package/src/services/redirect.ts +0 -97
- package/src/types/sortablejs.d.ts +0 -29
- package/src/ui/components/__tests__/jant-compose-dialog.test.ts +0 -512
- package/src/ui/components/__tests__/jant-compose-editor.test.ts +0 -272
- package/src/ui/components/compose-types.ts +0 -75
- package/src/ui/components/jant-collection-form.ts +0 -512
- package/src/ui/components/jant-compose-dialog.ts +0 -495
- package/src/ui/components/jant-compose-editor.ts +0 -814
- package/src/ui/dash/PageForm.tsx +0 -185
- package/src/ui/dash/PostList.tsx +0 -95
- package/src/ui/dash/appearance/AppearanceNav.tsx +0 -60
- package/src/ui/dash/collections/CollectionForm.tsx +0 -166
- package/src/ui/dash/collections/CollectionsListContent.tsx +0 -146
- package/src/ui/dash/collections/IconPickerGrid.tsx +0 -50
- package/src/ui/dash/collections/ViewCollectionContent.tsx +0 -103
- package/src/ui/dash/media/MediaListContent.tsx +0 -201
- package/src/ui/dash/media/ViewMediaContent.tsx +0 -208
- package/src/ui/dash/pages/PagesContent.tsx +0 -74
- package/src/ui/dash/posts/PostForm.tsx +0 -248
- package/src/ui/dash/settings/SettingsNav.tsx +0 -52
- package/src/ui/layouts/DashLayout.tsx +0 -165
- package/src/ui/pages/SinglePage.tsx +0 -23
- package/src/ui/shared/ThreadView.tsx +0 -136
- /package/src/{ui → client}/components/settings-types.ts +0 -0
|
@@ -11,7 +11,7 @@ describe("Compose Routes", () => {
|
|
|
11
11
|
const res = await app.request("/compose", {
|
|
12
12
|
method: "POST",
|
|
13
13
|
headers: { "Content-Type": "application/json" },
|
|
14
|
-
body: JSON.stringify({ format: "note",
|
|
14
|
+
body: JSON.stringify({ format: "note", bodyMarkdown: "Hello" }),
|
|
15
15
|
});
|
|
16
16
|
|
|
17
17
|
expect(res.status).toBe(302);
|
|
@@ -25,23 +25,22 @@ describe("Compose Routes", () => {
|
|
|
25
25
|
const res = await app.request("/compose", {
|
|
26
26
|
method: "POST",
|
|
27
27
|
headers: { "Content-Type": "application/json" },
|
|
28
|
-
body: JSON.stringify({ format: "note",
|
|
28
|
+
body: JSON.stringify({ format: "note", bodyMarkdown: "Hello world" }),
|
|
29
29
|
});
|
|
30
30
|
|
|
31
31
|
expect(res.status).toBe(200);
|
|
32
32
|
expect(res.headers.get("Content-Type")).toBe("text/event-stream");
|
|
33
33
|
|
|
34
34
|
const text = await res.text();
|
|
35
|
-
// SSE
|
|
35
|
+
// SSE closes the compose dialog and resets signals
|
|
36
36
|
expect(text).toContain("datastar-patch-elements");
|
|
37
|
-
expect(text).toContain(
|
|
38
|
-
expect(text).toContain("selector #timeline-items");
|
|
37
|
+
expect(text).toContain("compose-dialog");
|
|
39
38
|
|
|
40
39
|
// Verify post was created
|
|
41
40
|
const posts = await services.posts.list();
|
|
42
41
|
expect(posts).toHaveLength(1);
|
|
43
42
|
expect(posts[0].format).toBe("note");
|
|
44
|
-
expect(posts[0].
|
|
43
|
+
expect(posts[0].bodyText).toBe("Hello world");
|
|
45
44
|
expect(posts[0].status).toBe("published");
|
|
46
45
|
});
|
|
47
46
|
|
|
@@ -54,7 +53,7 @@ describe("Compose Routes", () => {
|
|
|
54
53
|
headers: { "Content-Type": "application/json" },
|
|
55
54
|
body: JSON.stringify({
|
|
56
55
|
format: "link",
|
|
57
|
-
|
|
56
|
+
bodyMarkdown: "Check this out",
|
|
58
57
|
url: "https://example.com",
|
|
59
58
|
}),
|
|
60
59
|
});
|
|
@@ -62,9 +61,6 @@ describe("Compose Routes", () => {
|
|
|
62
61
|
expect(res.status).toBe(200);
|
|
63
62
|
expect(res.headers.get("Content-Type")).toBe("text/event-stream");
|
|
64
63
|
|
|
65
|
-
const text = await res.text();
|
|
66
|
-
expect(text).toContain('data-format="link"');
|
|
67
|
-
|
|
68
64
|
const posts = await services.posts.list();
|
|
69
65
|
expect(posts).toHaveLength(1);
|
|
70
66
|
expect(posts[0].format).toBe("link");
|
|
@@ -80,7 +76,7 @@ describe("Compose Routes", () => {
|
|
|
80
76
|
headers: { "Content-Type": "application/json" },
|
|
81
77
|
body: JSON.stringify({
|
|
82
78
|
format: "quote",
|
|
83
|
-
|
|
79
|
+
bodyMarkdown: "Great insight",
|
|
84
80
|
quoteText: "The original quote",
|
|
85
81
|
url: "https://example.com/source",
|
|
86
82
|
}),
|
|
@@ -89,9 +85,6 @@ describe("Compose Routes", () => {
|
|
|
89
85
|
expect(res.status).toBe(200);
|
|
90
86
|
expect(res.headers.get("Content-Type")).toBe("text/event-stream");
|
|
91
87
|
|
|
92
|
-
const text = await res.text();
|
|
93
|
-
expect(text).toContain('data-format="quote"');
|
|
94
|
-
|
|
95
88
|
const posts = await services.posts.list();
|
|
96
89
|
expect(posts).toHaveLength(1);
|
|
97
90
|
expect(posts[0].format).toBe("quote");
|
|
@@ -107,7 +100,7 @@ describe("Compose Routes", () => {
|
|
|
107
100
|
headers: { "Content-Type": "application/json" },
|
|
108
101
|
body: JSON.stringify({
|
|
109
102
|
format: "note",
|
|
110
|
-
|
|
103
|
+
bodyMarkdown: "Draft content",
|
|
111
104
|
status: "draft",
|
|
112
105
|
}),
|
|
113
106
|
});
|
|
@@ -133,7 +126,7 @@ describe("Compose Routes", () => {
|
|
|
133
126
|
const res = await app.request("/compose", {
|
|
134
127
|
method: "POST",
|
|
135
128
|
headers: { "Content-Type": "application/json" },
|
|
136
|
-
body: JSON.stringify({ format: "invalid",
|
|
129
|
+
body: JSON.stringify({ format: "invalid", bodyMarkdown: "Hello" }),
|
|
137
130
|
});
|
|
138
131
|
|
|
139
132
|
expect(res.status).toBe(200);
|
|
@@ -163,7 +156,7 @@ describe("Compose Routes", () => {
|
|
|
163
156
|
headers: { "Content-Type": "application/json" },
|
|
164
157
|
body: JSON.stringify({
|
|
165
158
|
format: "note",
|
|
166
|
-
|
|
159
|
+
bodyMarkdown: "Post with media",
|
|
167
160
|
mediaIds: [media.id],
|
|
168
161
|
}),
|
|
169
162
|
});
|
|
@@ -186,7 +179,7 @@ describe("Compose Routes", () => {
|
|
|
186
179
|
const res = await app.request("/compose", {
|
|
187
180
|
method: "POST",
|
|
188
181
|
headers: { "Content-Type": "application/json" },
|
|
189
|
-
body: JSON.stringify({ format: "note",
|
|
182
|
+
body: JSON.stringify({ format: "note", bodyMarkdown: "Hello" }),
|
|
190
183
|
});
|
|
191
184
|
|
|
192
185
|
const text = await res.text();
|
|
@@ -202,7 +195,7 @@ describe("Compose Routes", () => {
|
|
|
202
195
|
const res = await app.request("/compose", {
|
|
203
196
|
method: "POST",
|
|
204
197
|
headers: { "Content-Type": "application/json" },
|
|
205
|
-
body: JSON.stringify({
|
|
198
|
+
body: JSON.stringify({ bodyMarkdown: "No format" }),
|
|
206
199
|
});
|
|
207
200
|
|
|
208
201
|
expect(res.status).toBe(200);
|
|
@@ -222,7 +215,7 @@ describe("Compose Routes", () => {
|
|
|
222
215
|
"Content-Type": "application/json",
|
|
223
216
|
Accept: "application/json",
|
|
224
217
|
},
|
|
225
|
-
body: JSON.stringify({ format: "note",
|
|
218
|
+
body: JSON.stringify({ format: "note", bodyMarkdown: "Hello JSON" }),
|
|
226
219
|
});
|
|
227
220
|
|
|
228
221
|
expect(res.status).toBe(200);
|
|
@@ -230,11 +223,11 @@ describe("Compose Routes", () => {
|
|
|
230
223
|
|
|
231
224
|
const data = await res.json();
|
|
232
225
|
expect(data.status).toBe("published");
|
|
233
|
-
expect(data.
|
|
226
|
+
expect(data.permalink).toBeDefined();
|
|
234
227
|
|
|
235
228
|
const posts = await services.posts.list();
|
|
236
229
|
expect(posts).toHaveLength(1);
|
|
237
|
-
expect(posts[0].
|
|
230
|
+
expect(posts[0].bodyText).toBe("Hello JSON");
|
|
238
231
|
});
|
|
239
232
|
|
|
240
233
|
it("returns JSON for draft", async () => {
|
|
@@ -249,7 +242,7 @@ describe("Compose Routes", () => {
|
|
|
249
242
|
},
|
|
250
243
|
body: JSON.stringify({
|
|
251
244
|
format: "note",
|
|
252
|
-
|
|
245
|
+
bodyMarkdown: "Draft JSON",
|
|
253
246
|
status: "draft",
|
|
254
247
|
}),
|
|
255
248
|
});
|
|
@@ -274,7 +267,7 @@ describe("Compose Routes", () => {
|
|
|
274
267
|
"Content-Type": "application/json",
|
|
275
268
|
Accept: "application/json",
|
|
276
269
|
},
|
|
277
|
-
body: JSON.stringify({ format: "invalid",
|
|
270
|
+
body: JSON.stringify({ format: "invalid", bodyMarkdown: "Hello" }),
|
|
278
271
|
});
|
|
279
272
|
|
|
280
273
|
expect(res.status).toBe(422);
|
|
@@ -13,9 +13,10 @@ describe("Collections API Routes", () => {
|
|
|
13
13
|
|
|
14
14
|
const body = await res.json();
|
|
15
15
|
expect(body.collections).toEqual([]);
|
|
16
|
+
expect(body.sidebarItems).toEqual([]);
|
|
16
17
|
});
|
|
17
18
|
|
|
18
|
-
it("returns collections with post counts", async () => {
|
|
19
|
+
it("returns collections with post counts and sidebar items", async () => {
|
|
19
20
|
const { app, services } = createTestApp();
|
|
20
21
|
app.route("/api/collections", collectionsApiRoutes);
|
|
21
22
|
|
|
@@ -25,7 +26,7 @@ describe("Collections API Routes", () => {
|
|
|
25
26
|
});
|
|
26
27
|
const post = await services.posts.create({
|
|
27
28
|
format: "note",
|
|
28
|
-
|
|
29
|
+
bodyMarkdown: "tech post",
|
|
29
30
|
});
|
|
30
31
|
await services.collections.addPost(col.id, post.id);
|
|
31
32
|
|
|
@@ -35,6 +36,10 @@ describe("Collections API Routes", () => {
|
|
|
35
36
|
expect(body.collections).toHaveLength(1);
|
|
36
37
|
expect(body.collections[0].slug).toBe("tech");
|
|
37
38
|
expect(body.collections[0].postCount).toBe(1);
|
|
39
|
+
|
|
40
|
+
expect(body.sidebarItems).toHaveLength(1);
|
|
41
|
+
expect(body.sidebarItems[0].type).toBe("collection");
|
|
42
|
+
expect(body.sidebarItems[0].collectionId).toBe(col.id);
|
|
38
43
|
});
|
|
39
44
|
});
|
|
40
45
|
|
|
@@ -60,7 +65,7 @@ describe("Collections API Routes", () => {
|
|
|
60
65
|
const { app } = createTestApp();
|
|
61
66
|
app.route("/api/collections", collectionsApiRoutes);
|
|
62
67
|
|
|
63
|
-
const res = await app.request("/api/collections
|
|
68
|
+
const res = await app.request("/api/collections/!!invalid!!");
|
|
64
69
|
expect(res.status).toBe(400);
|
|
65
70
|
});
|
|
66
71
|
|
|
@@ -68,7 +73,9 @@ describe("Collections API Routes", () => {
|
|
|
68
73
|
const { app } = createTestApp();
|
|
69
74
|
app.route("/api/collections", collectionsApiRoutes);
|
|
70
75
|
|
|
71
|
-
const res = await app.request(
|
|
76
|
+
const res = await app.request(
|
|
77
|
+
`/api/collections/${"00000000-0000-0000-0000-000000009999"}`,
|
|
78
|
+
);
|
|
72
79
|
expect(res.status).toBe(404);
|
|
73
80
|
});
|
|
74
81
|
});
|
|
@@ -122,46 +129,6 @@ describe("Collections API Routes", () => {
|
|
|
122
129
|
});
|
|
123
130
|
});
|
|
124
131
|
|
|
125
|
-
describe("PUT /api/collections/reorder", () => {
|
|
126
|
-
it("returns 401 when not authenticated", async () => {
|
|
127
|
-
const { app } = createTestApp({ authenticated: false });
|
|
128
|
-
app.route("/api/collections", collectionsApiRoutes);
|
|
129
|
-
|
|
130
|
-
const res = await app.request("/api/collections/reorder", {
|
|
131
|
-
method: "PUT",
|
|
132
|
-
headers: { "Content-Type": "application/json" },
|
|
133
|
-
body: JSON.stringify({ ids: [1, 2] }),
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
expect(res.status).toBe(401);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it("reorders collections when authenticated", async () => {
|
|
140
|
-
const { app, services } = createTestApp({ authenticated: true });
|
|
141
|
-
app.route("/api/collections", collectionsApiRoutes);
|
|
142
|
-
|
|
143
|
-
const col1 = await services.collections.create({
|
|
144
|
-
slug: "first",
|
|
145
|
-
title: "First",
|
|
146
|
-
});
|
|
147
|
-
const col2 = await services.collections.create({
|
|
148
|
-
slug: "second",
|
|
149
|
-
title: "Second",
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
const res = await app.request("/api/collections/reorder", {
|
|
153
|
-
method: "PUT",
|
|
154
|
-
headers: { "Content-Type": "application/json" },
|
|
155
|
-
body: JSON.stringify({ ids: [col2.id, col1.id] }),
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
expect(res.status).toBe(200);
|
|
159
|
-
const body = await res.json();
|
|
160
|
-
expect(body.collections[0].slug).toBe("second");
|
|
161
|
-
expect(body.collections[1].slug).toBe("first");
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
|
|
165
132
|
describe("PUT /api/collections/:id", () => {
|
|
166
133
|
it("updates a collection when authenticated", async () => {
|
|
167
134
|
const { app, services } = createTestApp({ authenticated: true });
|
|
@@ -187,11 +154,14 @@ describe("Collections API Routes", () => {
|
|
|
187
154
|
const { app } = createTestApp({ authenticated: true });
|
|
188
155
|
app.route("/api/collections", collectionsApiRoutes);
|
|
189
156
|
|
|
190
|
-
const res = await app.request(
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
157
|
+
const res = await app.request(
|
|
158
|
+
`/api/collections/${"00000000-0000-0000-0000-000000009999"}`,
|
|
159
|
+
{
|
|
160
|
+
method: "PUT",
|
|
161
|
+
headers: { "Content-Type": "application/json" },
|
|
162
|
+
body: JSON.stringify({ title: "test" }),
|
|
163
|
+
},
|
|
164
|
+
);
|
|
195
165
|
|
|
196
166
|
expect(res.status).toBe(404);
|
|
197
167
|
});
|
|
@@ -239,14 +209,87 @@ describe("Collections API Routes", () => {
|
|
|
239
209
|
const { app } = createTestApp({ authenticated: true });
|
|
240
210
|
app.route("/api/collections", collectionsApiRoutes);
|
|
241
211
|
|
|
242
|
-
const res = await app.request(
|
|
243
|
-
|
|
244
|
-
|
|
212
|
+
const res = await app.request(
|
|
213
|
+
`/api/collections/${"00000000-0000-0000-0000-000000009999"}`,
|
|
214
|
+
{ method: "DELETE" },
|
|
215
|
+
);
|
|
245
216
|
|
|
246
217
|
expect(res.status).toBe(404);
|
|
247
218
|
});
|
|
248
219
|
});
|
|
249
220
|
|
|
221
|
+
describe("POST /api/collections/sidebar-items", () => {
|
|
222
|
+
it("creates a divider sidebar item", async () => {
|
|
223
|
+
const { app } = createTestApp({ authenticated: true });
|
|
224
|
+
app.route("/api/collections", collectionsApiRoutes);
|
|
225
|
+
|
|
226
|
+
const res = await app.request("/api/collections/sidebar-items", {
|
|
227
|
+
method: "POST",
|
|
228
|
+
headers: { "Content-Type": "application/json" },
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
expect(res.status).toBe(201);
|
|
232
|
+
const body = await res.json();
|
|
233
|
+
expect(body.type).toBe("divider");
|
|
234
|
+
expect(body.collectionId).toBeNull();
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
describe("DELETE /api/collections/sidebar-items/:id", () => {
|
|
239
|
+
it("deletes a sidebar item", async () => {
|
|
240
|
+
const { app, services } = createTestApp({ authenticated: true });
|
|
241
|
+
app.route("/api/collections", collectionsApiRoutes);
|
|
242
|
+
|
|
243
|
+
const item = await services.collections.createSidebarItem("divider");
|
|
244
|
+
|
|
245
|
+
const res = await app.request(
|
|
246
|
+
`/api/collections/sidebar-items/${item.id}`,
|
|
247
|
+
{ method: "DELETE" },
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
expect(res.status).toBe(200);
|
|
251
|
+
const body = await res.json();
|
|
252
|
+
expect(body.success).toBe(true);
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
describe("PUT /api/collections/sidebar-items/:id/move", () => {
|
|
257
|
+
it("moves a sidebar item", async () => {
|
|
258
|
+
const { app, services } = createTestApp({ authenticated: true });
|
|
259
|
+
app.route("/api/collections", collectionsApiRoutes);
|
|
260
|
+
|
|
261
|
+
await services.collections.create({ slug: "a", title: "A" });
|
|
262
|
+
await services.collections.create({ slug: "b", title: "B" });
|
|
263
|
+
await services.collections.create({ slug: "c", title: "C" });
|
|
264
|
+
|
|
265
|
+
const items = await services.collections.listSidebarItems();
|
|
266
|
+
expect(items).toHaveLength(3);
|
|
267
|
+
const itemA = items[0];
|
|
268
|
+
const itemB = items[1];
|
|
269
|
+
const itemC = items[2];
|
|
270
|
+
|
|
271
|
+
// Move C between A and B
|
|
272
|
+
const res = await app.request(
|
|
273
|
+
`/api/collections/sidebar-items/${itemC?.id ?? ""}/move`,
|
|
274
|
+
{
|
|
275
|
+
method: "PUT",
|
|
276
|
+
headers: { "Content-Type": "application/json" },
|
|
277
|
+
body: JSON.stringify({
|
|
278
|
+
after: itemA?.id ?? "",
|
|
279
|
+
before: itemB?.id ?? "",
|
|
280
|
+
}),
|
|
281
|
+
},
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
expect(res.status).toBe(200);
|
|
285
|
+
|
|
286
|
+
const reordered = await services.collections.listSidebarItems();
|
|
287
|
+
expect(reordered[0]?.id).toBe(itemA?.id);
|
|
288
|
+
expect(reordered[1]?.id).toBe(itemC?.id);
|
|
289
|
+
expect(reordered[2]?.id).toBe(itemB?.id);
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
|
|
250
293
|
describe("POST /api/collections/:id/posts", () => {
|
|
251
294
|
it("adds a post to a collection", async () => {
|
|
252
295
|
const { app, services } = createTestApp({ authenticated: true });
|
|
@@ -258,7 +301,7 @@ describe("Collections API Routes", () => {
|
|
|
258
301
|
});
|
|
259
302
|
const post = await services.posts.create({
|
|
260
303
|
format: "note",
|
|
261
|
-
|
|
304
|
+
bodyMarkdown: "test",
|
|
262
305
|
});
|
|
263
306
|
|
|
264
307
|
const res = await app.request(`/api/collections/${col.id}/posts`, {
|
|
@@ -279,14 +322,17 @@ describe("Collections API Routes", () => {
|
|
|
279
322
|
|
|
280
323
|
const post = await services.posts.create({
|
|
281
324
|
format: "note",
|
|
282
|
-
|
|
325
|
+
bodyMarkdown: "test",
|
|
283
326
|
});
|
|
284
327
|
|
|
285
|
-
const res = await app.request(
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
328
|
+
const res = await app.request(
|
|
329
|
+
`/api/collections/${"00000000-0000-0000-0000-000000009999"}/posts`,
|
|
330
|
+
{
|
|
331
|
+
method: "POST",
|
|
332
|
+
headers: { "Content-Type": "application/json" },
|
|
333
|
+
body: JSON.stringify({ postId: post.id }),
|
|
334
|
+
},
|
|
335
|
+
);
|
|
290
336
|
|
|
291
337
|
expect(res.status).toBe(404);
|
|
292
338
|
});
|
|
@@ -303,7 +349,9 @@ describe("Collections API Routes", () => {
|
|
|
303
349
|
const res = await app.request(`/api/collections/${col.id}/posts`, {
|
|
304
350
|
method: "POST",
|
|
305
351
|
headers: { "Content-Type": "application/json" },
|
|
306
|
-
body: JSON.stringify({
|
|
352
|
+
body: JSON.stringify({
|
|
353
|
+
postId: "00000000-0000-0000-0000-000000000001",
|
|
354
|
+
}),
|
|
307
355
|
});
|
|
308
356
|
|
|
309
357
|
expect(res.status).toBe(401);
|
|
@@ -321,7 +369,7 @@ describe("Collections API Routes", () => {
|
|
|
321
369
|
});
|
|
322
370
|
const post = await services.posts.create({
|
|
323
371
|
format: "note",
|
|
324
|
-
|
|
372
|
+
bodyMarkdown: "test",
|
|
325
373
|
});
|
|
326
374
|
|
|
327
375
|
await services.collections.addPost(col.id, post.id);
|
|
@@ -92,21 +92,8 @@ describe("Nav Items API Routes", () => {
|
|
|
92
92
|
});
|
|
93
93
|
});
|
|
94
94
|
|
|
95
|
-
describe("PUT /api/nav-items/
|
|
96
|
-
it("
|
|
97
|
-
const { app } = createTestApp({ authenticated: false });
|
|
98
|
-
app.route("/api/nav-items", navItemsApiRoutes);
|
|
99
|
-
|
|
100
|
-
const res = await app.request("/api/nav-items/reorder", {
|
|
101
|
-
method: "PUT",
|
|
102
|
-
headers: { "Content-Type": "application/json" },
|
|
103
|
-
body: JSON.stringify({ ids: [1, 2] }),
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
expect(res.status).toBe(401);
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it("reorders nav items when authenticated", async () => {
|
|
95
|
+
describe("PUT /api/nav-items/:id/move", () => {
|
|
96
|
+
it("moves a nav item between two others", async () => {
|
|
110
97
|
const { app, services } = createTestApp({ authenticated: true });
|
|
111
98
|
app.route("/api/nav-items", navItemsApiRoutes);
|
|
112
99
|
|
|
@@ -120,18 +107,44 @@ describe("Nav Items API Routes", () => {
|
|
|
120
107
|
label: "Second",
|
|
121
108
|
url: "/second",
|
|
122
109
|
});
|
|
110
|
+
const item3 = await services.navItems.create({
|
|
111
|
+
type: "link",
|
|
112
|
+
label: "Third",
|
|
113
|
+
url: "/third",
|
|
114
|
+
});
|
|
123
115
|
|
|
124
|
-
//
|
|
125
|
-
const res = await app.request(
|
|
116
|
+
// Move Third between First and Second
|
|
117
|
+
const res = await app.request(`/api/nav-items/${item3.id}/move`, {
|
|
126
118
|
method: "PUT",
|
|
127
119
|
headers: { "Content-Type": "application/json" },
|
|
128
|
-
body: JSON.stringify({
|
|
120
|
+
body: JSON.stringify({
|
|
121
|
+
after: item1.id,
|
|
122
|
+
before: item2.id,
|
|
123
|
+
}),
|
|
129
124
|
});
|
|
130
125
|
|
|
131
126
|
expect(res.status).toBe(200);
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
expect(
|
|
127
|
+
|
|
128
|
+
const items = await services.navItems.list();
|
|
129
|
+
expect(items[0]?.label).toBe("First");
|
|
130
|
+
expect(items[1]?.label).toBe("Third");
|
|
131
|
+
expect(items[2]?.label).toBe("Second");
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("returns 404 for non-existent item", async () => {
|
|
135
|
+
const { app } = createTestApp({ authenticated: true });
|
|
136
|
+
app.route("/api/nav-items", navItemsApiRoutes);
|
|
137
|
+
|
|
138
|
+
const res = await app.request(
|
|
139
|
+
`/api/nav-items/${"00000000-0000-0000-0000-000000009999"}/move`,
|
|
140
|
+
{
|
|
141
|
+
method: "PUT",
|
|
142
|
+
headers: { "Content-Type": "application/json" },
|
|
143
|
+
body: JSON.stringify({ after: null, before: null }),
|
|
144
|
+
},
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
expect(res.status).toBe(404);
|
|
135
148
|
});
|
|
136
149
|
});
|
|
137
150
|
|
|
@@ -161,11 +174,14 @@ describe("Nav Items API Routes", () => {
|
|
|
161
174
|
const { app } = createTestApp({ authenticated: true });
|
|
162
175
|
app.route("/api/nav-items", navItemsApiRoutes);
|
|
163
176
|
|
|
164
|
-
const res = await app.request(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
177
|
+
const res = await app.request(
|
|
178
|
+
`/api/nav-items/${"00000000-0000-0000-0000-000000009999"}`,
|
|
179
|
+
{
|
|
180
|
+
method: "PUT",
|
|
181
|
+
headers: { "Content-Type": "application/json" },
|
|
182
|
+
body: JSON.stringify({ label: "test" }),
|
|
183
|
+
},
|
|
184
|
+
);
|
|
169
185
|
|
|
170
186
|
expect(res.status).toBe(404);
|
|
171
187
|
});
|
|
@@ -212,9 +228,10 @@ describe("Nav Items API Routes", () => {
|
|
|
212
228
|
const { app } = createTestApp({ authenticated: true });
|
|
213
229
|
app.route("/api/nav-items", navItemsApiRoutes);
|
|
214
230
|
|
|
215
|
-
const res = await app.request(
|
|
216
|
-
|
|
217
|
-
|
|
231
|
+
const res = await app.request(
|
|
232
|
+
`/api/nav-items/${"00000000-0000-0000-0000-000000009999"}`,
|
|
233
|
+
{ method: "DELETE" },
|
|
234
|
+
);
|
|
218
235
|
|
|
219
236
|
expect(res.status).toBe(404);
|
|
220
237
|
});
|