@jant/core 0.6.15 → 0.7.0
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/README.md +11 -11
- package/bin/commands/assets/upload.js +192 -15
- package/bin/commands/import-site.js +67 -4
- package/bin/commands/reset-password.js +21 -8
- package/bin/commands/site/snapshot/export.js +1 -1
- package/bin/commands/site/snapshot/import.js +1 -1
- package/bin/lib/d1-query.js +5 -16
- package/bin/lib/node-env.js +40 -4
- package/bin/lib/site-selection.js +85 -29
- package/bin/lib/wrangler-cli.js +28 -2
- package/bin/lib/wrangler-json.js +35 -0
- package/dist/{app-C-oi_t8W.js → app-K_Aa1MMn.js} +52623 -13193
- package/dist/client/.vite/manifest.json +255 -90
- package/dist/client/_assets/chunks/confirm-D7GrwsCN.js +45 -0
- package/dist/client/_assets/chunks/create-editor-CD3FhrOB.js +257 -0
- package/dist/client/_assets/chunks/{native-DpcrFAPh.js → emoji-mart-C4RpRKcU.js} +716 -1
- package/dist/client/_assets/chunks/footnote-rail-CmeoVtnU.js +1 -0
- package/dist/client/_assets/chunks/heic-to-CuP2Qlsw.js +1 -0
- package/dist/client/_assets/chunks/jant-locale-picker-DL6mIOT5.js +69 -0
- package/dist/client/_assets/chunks/lit-DW8VmJAT.js +2 -0
- package/dist/client/_assets/chunks/mediabunny-DRaCQ1r-.js +31 -0
- package/dist/client/_assets/chunks/rolldown-runtime-hePW80VL.js +1 -0
- package/dist/client/_assets/chunks/settings-paths-BcdySNx6.js +84 -0
- package/dist/client/_assets/chunks/site-header-nav-DzXsFk05.js +1 -0
- package/dist/client/_assets/chunks/slug-format-CRXO1AL5.js +1 -0
- package/dist/client/_assets/chunks/slugify-373citbs.js +1 -0
- package/dist/client/_assets/chunks/sortable-list-CgaL2jCs.js +2 -0
- package/dist/client/_assets/chunks/types-D5iF3H1a.js +1 -0
- package/dist/client/_assets/chunks/unsafe-html-B5ZEXaxg.js +1 -0
- package/dist/client/_assets/chunks/unsafe-svg-0QCkP0vZ.js +2 -0
- package/dist/client/_assets/client-GiYENVw8.css +2 -0
- package/dist/client/_assets/client-VnFxJN7G.js +295 -0
- package/dist/client/_assets/client-auth-k8gJ6QJj.js +828 -0
- package/dist/client/_assets/client-author-DQ8R-8KR.css +2 -0
- package/dist/client/_assets/client-compose-B_kDtWkW.js +2004 -0
- package/dist/client/_assets/client-manage-M90aSTOk.js +2170 -0
- package/dist/client/_assets/client-settings-DfYs9n1F.js +1112 -0
- package/dist/{export-CsFx6F_M.js → github-sync-BPAvT999.js} +2343 -110
- package/dist/index.js +2 -5
- package/dist/node.js +5 -7
- package/package.json +3 -3
- package/src/__tests__/auth-session-freshness.test.ts +57 -0
- package/src/__tests__/basecoat-variants.test.ts +121 -0
- package/src/__tests__/bin/assets-upload.test.ts +68 -0
- package/src/__tests__/export-hugo-build.test.ts +260 -0
- package/src/__tests__/export-service.test.ts +231 -0
- package/src/__tests__/helpers/component-css.ts +91 -0
- package/src/__tests__/helpers/db.ts +33 -0
- package/src/__tests__/helpers/export-fixtures.ts +3 -0
- package/src/__tests__/mise-config.test.ts +22 -0
- package/src/__tests__/stylesheet-audience.test.ts +159 -0
- package/src/__tests__/stylesheet-breakpoints.test.ts +183 -0
- package/src/app.tsx +71 -16
- package/src/auth.ts +18 -1
- package/src/client/__tests__/collection-page-actions.test.ts +51 -2
- package/src/client/__tests__/compose-bridge-image-upload.test.ts +196 -0
- package/src/client/__tests__/compose-bridge-video-poster.test.ts +159 -0
- package/src/client/__tests__/compose-bridge.test.ts +524 -2
- package/src/client/__tests__/compose-launch.test.ts +62 -1
- package/src/client/__tests__/compose-shortcuts.test.ts +57 -8
- package/src/client/__tests__/compose-triggers.test.ts +90 -0
- package/src/client/__tests__/copy-field.test.ts +162 -0
- package/src/client/__tests__/custom-url-menu.test.ts +127 -6
- package/src/client/__tests__/image-processor.test.ts +324 -2
- package/src/client/__tests__/lazy-entries.test.ts +92 -0
- package/src/client/__tests__/media-scroll-hint.test.ts +155 -0
- package/src/client/__tests__/runtime-paths.test.ts +84 -0
- package/src/client/__tests__/smart-collection-page-actions.test.ts +158 -0
- package/src/client/__tests__/toast.test.ts +88 -1
- package/src/client/__tests__/video-processor-probe.test.ts +175 -0
- package/src/client/__tests__/video-processor.test.ts +181 -0
- package/src/client/audio-processor.ts +24 -15
- package/src/client/audio-waveform.ts +49 -0
- package/src/client/collection-dialog-host.ts +72 -0
- package/src/client/collection-navigation.ts +51 -16
- package/src/client/collection-page-actions.ts +26 -0
- package/src/client/components/__tests__/compose-format-convert.test.ts +0 -19
- package/src/client/components/__tests__/jant-collection-dialog.test.ts +329 -0
- package/src/client/components/__tests__/jant-collection-directory.test.ts +274 -10
- package/src/client/components/__tests__/jant-collection-form.test.ts +59 -178
- package/src/client/components/__tests__/jant-command-palette.test.ts +79 -0
- package/src/client/components/__tests__/jant-compose-dialog-draft-storage.test.ts +340 -0
- package/src/client/components/__tests__/jant-compose-dialog.test.ts +3283 -389
- package/src/client/components/__tests__/jant-compose-editor.test.ts +581 -86
- package/src/client/components/__tests__/jant-compose-fullscreen.test.ts +34 -89
- package/src/client/components/__tests__/jant-locale-picker.test.ts +207 -0
- package/src/client/components/__tests__/jant-nav-manager.test.ts +234 -15
- package/src/client/components/__tests__/jant-post-menu.test.ts +413 -2
- package/src/client/components/__tests__/jant-post-picker.test.ts +197 -0
- package/src/client/components/__tests__/jant-settings-avatar.test.ts +15 -12
- package/src/client/components/__tests__/jant-settings-general.test.ts +541 -172
- package/src/client/components/__tests__/jant-settings-language.test.ts +851 -0
- package/src/client/components/__tests__/jant-smart-collection-dialog.test.ts +665 -0
- package/src/client/components/collection-dialog-types.ts +49 -0
- package/src/client/components/collection-manager-types.ts +32 -1
- package/src/client/components/collection-types.ts +1 -15
- package/src/client/components/compose-format-convert.ts +5 -1
- package/src/client/components/compose-types.ts +121 -3
- package/src/client/components/jant-collection-dialog.ts +722 -0
- package/src/client/components/jant-collection-directory.ts +567 -182
- package/src/client/components/jant-collection-form.ts +53 -232
- package/src/client/components/jant-command-palette.ts +106 -49
- package/src/client/components/jant-compose-dialog.ts +2757 -1194
- package/src/client/components/jant-compose-editor.ts +866 -397
- package/src/client/components/jant-compose-fullscreen.ts +53 -47
- package/src/client/components/jant-config-editor.ts +65 -53
- package/src/client/components/jant-confirm-dialog.ts +13 -11
- package/src/client/components/jant-locale-picker.ts +418 -0
- package/src/client/components/jant-media-lightbox.ts +146 -136
- package/src/client/components/jant-nav-manager.ts +690 -366
- package/src/client/components/jant-post-menu.ts +1142 -268
- package/src/client/components/jant-post-picker.ts +324 -0
- package/src/client/components/jant-repo-picker.ts +138 -106
- package/src/client/components/jant-settings-avatar.ts +31 -27
- package/src/client/components/jant-settings-general.ts +617 -543
- package/src/client/components/jant-settings-language.ts +1087 -0
- package/src/client/components/jant-smart-collection-dialog.ts +1021 -0
- package/src/client/components/jant-text-preview.ts +94 -86
- package/src/client/components/nav-manager-types.ts +62 -1
- package/src/client/components/settings-types.ts +14 -29
- package/src/client/components/smart-collection-conditions.ts +285 -0
- package/src/client/components/smart-collection-dialog-types.ts +68 -0
- package/src/client/compose-bridge.ts +336 -242
- package/src/client/compose-launch.ts +89 -2
- package/src/client/compose-shortcuts.ts +9 -7
- package/src/client/compose-triggers.ts +50 -0
- package/src/client/copy-field.ts +108 -0
- package/src/client/custom-url-menu.ts +60 -4
- package/src/client/icons.ts +14 -0
- package/src/client/image-plan.ts +165 -0
- package/src/client/image-processor.ts +195 -117
- package/src/client/image-worker-client.ts +45 -0
- package/src/client/image-worker.ts +135 -0
- package/src/client/lazy-entries.ts +95 -0
- package/src/client/lazy-slugify.ts +2 -2
- package/src/client/media-scroll-hint.ts +43 -2
- package/src/client/mediabunny.ts +29 -0
- package/src/client/post-picker.ts +41 -0
- package/src/client/post-refresh.ts +135 -0
- package/src/client/runtime-paths.ts +74 -1
- package/src/client/settings-bridge.ts +4 -10
- package/src/client/site-header-nav.js +18 -6
- package/src/client/smart-collection-dialog-host.ts +116 -0
- package/src/client/smart-collection-page-actions.ts +208 -0
- package/src/client/tiptap/__tests__/bubble-menu.test.ts +110 -0
- package/src/client/tiptap/__tests__/floating-position.test.ts +136 -1
- package/src/client/tiptap/__tests__/inline-image-upload.test.ts +37 -0
- package/src/client/tiptap/__tests__/link-input-rules.test.ts +121 -0
- package/src/client/tiptap/bubble-menu.ts +47 -16
- package/src/client/tiptap/floating-position.ts +216 -2
- package/src/client/tiptap/inline-image-upload.ts +7 -3
- package/src/client/tiptap/link-input-rules.ts +4 -4
- package/src/client/tiptap/link-toolbar.ts +22 -9
- package/src/client/toast.ts +143 -38
- package/src/client/types/vite-worker.d.ts +12 -0
- package/src/client/upload-with-metadata.ts +3 -13
- package/src/client/video-processor.ts +351 -107
- package/src/client-auth.ts +14 -31
- package/src/client-compose.ts +19 -0
- package/src/client-manage.ts +13 -0
- package/src/client-settings.ts +14 -0
- package/src/client-site.ts +10 -3
- package/src/client.ts +4 -0
- package/src/db/__tests__/backfill-nav-label-mirrors.test.ts +149 -0
- package/src/db/__tests__/backfill-thread-activity.test.ts +234 -0
- package/src/db/__tests__/schema-enum-sources.test.ts +33 -0
- package/src/db/__tests__/smart-collection-placement.test.ts +402 -0
- package/src/db/__tests__/thread-activity.test.ts +113 -0
- package/src/db/backfills/0005_split_thread_activity_from_quiet_replies.sql +68 -0
- package/src/db/backfills/0006_clear_mirrored_page_nav_labels.sql +31 -0
- package/src/db/migrations/0031_many_ego.sql +3 -0
- package/src/db/migrations/0032_married_tomas.sql +3 -0
- package/src/db/migrations/0033_busy_johnny_storm.sql +198 -0
- package/src/db/migrations/0034_cheerful_rumiko_fujikawa.sql +35 -0
- package/src/db/migrations/meta/0031_snapshot.json +2562 -0
- package/src/db/migrations/meta/0032_snapshot.json +2582 -0
- package/src/db/migrations/meta/0033_snapshot.json +2816 -0
- package/src/db/migrations/meta/0034_snapshot.json +2816 -0
- package/src/db/migrations/meta/_journal.json +28 -0
- package/src/db/migrations/pg/0029_rare_hairball.sql +3 -0
- package/src/db/migrations/pg/0030_abandoned_nighthawk.sql +3 -0
- package/src/db/migrations/pg/0031_strong_ultimatum.sql +128 -0
- package/src/db/migrations/pg/0032_furry_multiple_man.sql +6 -0
- package/src/db/migrations/pg/meta/0029_snapshot.json +3289 -0
- package/src/db/migrations/pg/meta/0030_snapshot.json +3329 -0
- package/src/db/migrations/pg/meta/0031_snapshot.json +3660 -0
- package/src/db/migrations/pg/meta/0032_snapshot.json +3660 -0
- package/src/db/migrations/pg/meta/_journal.json +28 -0
- package/src/db/pg/schema.ts +213 -27
- package/src/db/post-visibility.ts +117 -0
- package/src/db/schema.ts +242 -27
- package/src/db/thread-activity.ts +101 -0
- package/src/i18n/__tests__/detect.test.ts +26 -81
- package/src/i18n/__tests__/supported-locales.test.ts +83 -0
- package/src/i18n/context.tsx +12 -2
- package/src/i18n/detect.ts +7 -66
- package/src/i18n/locales/glossary.zh-Hans.yml +44 -4
- package/src/i18n/locales/glossary.zh-Hant.yml +44 -4
- package/src/i18n/locales/public/en.po +568 -168
- package/src/i18n/locales/public/en.ts +1 -1
- package/src/i18n/locales/public/zh-Hans.po +562 -162
- package/src/i18n/locales/public/zh-Hans.ts +1 -1
- package/src/i18n/locales/public/zh-Hant.po +562 -162
- package/src/i18n/locales/public/zh-Hant.ts +1 -1
- package/src/i18n/locales/settings/en.po +551 -69
- package/src/i18n/locales/settings/en.ts +1 -1
- package/src/i18n/locales/settings/zh-Hans.po +597 -115
- package/src/i18n/locales/settings/zh-Hans.ts +1 -1
- package/src/i18n/locales/settings/zh-Hant.po +610 -128
- package/src/i18n/locales/settings/zh-Hant.ts +1 -1
- package/src/i18n/locales.ts +94 -0
- package/src/i18n/middleware.ts +12 -2
- package/src/i18n/supported-locales.ts +80 -0
- package/src/lib/__tests__/api-settings.test.ts +11 -2
- package/src/lib/__tests__/asset-path.test.ts +92 -0
- package/src/lib/__tests__/deferred.test.ts +90 -0
- package/src/lib/__tests__/discover-ping.test.ts +89 -0
- package/src/lib/__tests__/discover.test.ts +410 -0
- package/src/lib/__tests__/feed-policy.test.ts +26 -0
- package/src/lib/__tests__/feed.test.ts +1691 -12
- package/src/lib/__tests__/filter-dimensions.test.ts +341 -0
- package/src/lib/__tests__/hosted-signin.test.ts +1 -1
- package/src/lib/__tests__/http-cache.test.ts +162 -0
- package/src/lib/__tests__/jant-docs-dev.test.ts +21 -0
- package/src/lib/__tests__/jant-docs.test.ts +23 -0
- package/src/lib/__tests__/lang-detect.test.ts +231 -0
- package/src/lib/__tests__/markdown.test.ts +16 -0
- package/src/lib/__tests__/media-helpers.test.ts +81 -0
- package/src/lib/__tests__/navigation.test.ts +135 -1
- package/src/lib/__tests__/resolve-config.test.ts +64 -3
- package/src/lib/__tests__/schemas.test.ts +42 -4
- package/src/lib/__tests__/site-unavailable-page.test.ts +25 -0
- package/src/lib/__tests__/slug.test.ts +88 -0
- package/src/lib/__tests__/slugify.test.ts +85 -0
- package/src/lib/__tests__/storage.test.ts +32 -0
- package/src/lib/__tests__/thread-fold.test.ts +113 -0
- package/src/lib/__tests__/translit.test.ts +87 -0
- package/src/lib/__tests__/upload-sideload.test.ts +14 -0
- package/src/lib/__tests__/url-fetch.test.ts +1 -2
- package/src/lib/__tests__/url.test.ts +93 -34
- package/src/lib/__tests__/view-language.test.ts +413 -0
- package/src/lib/__tests__/worker-response-cache.test.ts +90 -0
- package/src/lib/address.ts +57 -0
- package/src/lib/api-posts.ts +12 -0
- package/src/lib/asset-path.ts +98 -1
- package/src/lib/build-env.ts +16 -0
- package/src/lib/collection-groups.ts +5 -1
- package/src/lib/collection-paths.ts +3 -10
- package/src/lib/constants.ts +28 -3
- package/src/lib/copy-field.ts +36 -0
- package/src/lib/crypto.ts +40 -0
- package/src/lib/csp-builder.ts +2 -1
- package/src/lib/deferred.ts +79 -0
- package/src/lib/discover-ping.ts +141 -0
- package/src/lib/discover.ts +437 -0
- package/src/lib/env.ts +134 -0
- package/src/lib/errors.ts +33 -0
- package/src/lib/feed-policy.ts +236 -2
- package/src/lib/feed.ts +1021 -66
- package/src/lib/filter-dimensions.ts +1349 -0
- package/src/lib/github-sync-site-config.ts +3 -0
- package/src/lib/hosted-signin.ts +1 -1
- package/src/lib/http-cache.ts +148 -0
- package/src/lib/hugo-markdown.ts +21 -0
- package/src/lib/icons.ts +9 -2
- package/src/lib/ids.ts +3 -0
- package/src/lib/jant-docs.ts +42 -0
- package/src/lib/lang-detect.ts +308 -0
- package/src/lib/link-preview.ts +25 -0
- package/src/lib/markdown-manager.ts +6 -1
- package/src/lib/media-helpers.ts +13 -1
- package/src/lib/navigation.ts +78 -11
- package/src/lib/pagination.ts +28 -24
- package/src/lib/per-language-surfaces.ts +67 -0
- package/src/lib/post-display.ts +42 -9
- package/src/lib/post-meta.ts +19 -0
- package/src/lib/render.tsx +55 -7
- package/src/lib/resolve-config.ts +53 -5
- package/src/lib/schemas.ts +201 -10
- package/src/lib/site-header-fragment.tsx +2 -1
- package/src/lib/site-unavailable-page.ts +47 -0
- package/src/lib/slug.ts +51 -7
- package/src/lib/slugify.ts +113 -0
- package/src/lib/startup-config.ts +4 -6
- package/src/lib/storage.ts +7 -0
- package/src/lib/summary.ts +50 -0
- package/src/lib/thread-fold.ts +161 -0
- package/src/lib/time.ts +32 -0
- package/src/lib/timeline.ts +81 -10
- package/src/lib/tiptap-render.ts +5 -4
- package/src/lib/translit.ts +288 -0
- package/src/lib/upload.ts +16 -13
- package/src/lib/url.ts +188 -24
- package/src/lib/version.ts +10 -8
- package/src/lib/view-language.ts +436 -0
- package/src/lib/view.ts +79 -23
- package/src/lib/viewer-context.ts +62 -0
- package/src/middleware/__tests__/auth.test.ts +70 -2
- package/src/middleware/__tests__/cache-control.test.ts +71 -3
- package/src/middleware/__tests__/onboarding.test.ts +76 -5
- package/src/middleware/__tests__/secure-headers.test.ts +1 -1
- package/src/middleware/__tests__/session.test.ts +181 -33
- package/src/middleware/auth.ts +50 -31
- package/src/middleware/cache-control.ts +75 -10
- package/src/middleware/config.ts +6 -6
- package/src/middleware/error-handler.ts +12 -0
- package/src/middleware/onboarding.ts +32 -10
- package/src/middleware/secure-headers.ts +1 -1
- package/src/middleware/session.ts +96 -8
- package/src/node/__tests__/cli-migrate.test.ts +21 -19
- package/src/node/__tests__/cli-reset-password.test.ts +81 -8
- package/src/node/__tests__/cli-runtime-target.test.ts +48 -1
- package/src/node/__tests__/cli-site-selection.test.ts +128 -38
- package/src/node/__tests__/runtime.test.ts +37 -0
- package/src/node/index.ts +1 -0
- package/src/preset.css +76 -22
- package/src/routes/__tests__/feed-validator.test.ts +156 -0
- package/src/routes/api/__tests__/collections.test.ts +114 -0
- package/src/routes/api/__tests__/discover.test.ts +222 -0
- package/src/routes/api/__tests__/nav-items.test.ts +212 -2
- package/src/routes/api/__tests__/palette.test.ts +44 -0
- package/src/routes/api/__tests__/post-translations.test.ts +829 -0
- package/src/routes/api/__tests__/settings.test.ts +24 -3
- package/src/routes/api/__tests__/telegram.test.ts +6 -5
- package/src/routes/api/collections.ts +49 -6
- package/src/routes/api/custom-urls.ts +0 -1
- package/src/routes/api/discover.ts +95 -0
- package/src/routes/api/export.ts +3 -0
- package/src/routes/api/internal/__tests__/sites.test.ts +42 -2
- package/src/routes/api/nav-items.ts +55 -8
- package/src/routes/api/posts.ts +172 -9
- package/src/routes/api/public/__tests__/archive.test.ts +111 -0
- package/src/routes/api/public/__tests__/posts.test.ts +38 -0
- package/src/routes/api/public/archive.ts +77 -81
- package/src/routes/api/public/posts.ts +30 -6
- package/src/routes/api/smart-collections.ts +132 -0
- package/src/routes/api/telegram.ts +2 -40
- package/src/routes/api/uploads.ts +1 -2
- package/src/routes/auth/__tests__/setup-auth.test.ts +137 -0
- package/src/routes/auth/__tests__/setup-discover.test.ts +204 -0
- package/src/routes/auth/__tests__/setup-flow.test.ts +270 -0
- package/src/routes/auth/__tests__/setup-page.test.tsx +329 -0
- package/src/routes/auth/__tests__/setup-steps.test.ts +310 -0
- package/src/routes/auth/__tests__/setup.test.ts +278 -26
- package/src/routes/auth/__tests__/signin.test.ts +135 -0
- package/src/routes/auth/setup.tsx +934 -186
- package/src/routes/auth/signin.tsx +10 -8
- package/src/routes/compose.tsx +11 -2
- package/src/routes/dash/__tests__/custom-urls-archive.test.ts +44 -0
- package/src/routes/dash/__tests__/custom-urls-page.test.ts +49 -0
- package/src/routes/dash/__tests__/delete-account.test.ts +106 -0
- package/src/routes/dash/__tests__/settings-discover.test.ts +213 -0
- package/src/routes/dash/custom-urls.tsx +1 -37
- package/src/routes/dash/settings.tsx +502 -41
- package/src/routes/discover-announce.ts +96 -0
- package/src/routes/feed/__tests__/feed.test.ts +165 -2
- package/src/routes/feed/__tests__/sitemap.test.ts +68 -1
- package/src/routes/feed/feed.ts +69 -40
- package/src/routes/feed/sitemap.ts +95 -11
- package/src/routes/pages/__tests__/archive-indexing.test.ts +200 -0
- package/src/routes/pages/__tests__/archive-params.test.ts +657 -1
- package/src/routes/pages/__tests__/collection-routing.test.ts +16 -0
- package/src/routes/pages/__tests__/collections-feed-links.test.ts +72 -0
- package/src/routes/pages/__tests__/collections.test.ts +9 -3
- package/src/routes/pages/__tests__/custom-archive-url.test.ts +119 -0
- package/src/routes/pages/__tests__/featured.test.ts +6 -2
- package/src/routes/pages/__tests__/feed-autodiscovery.test.ts +148 -0
- package/src/routes/pages/__tests__/language-routing.test.ts +679 -0
- package/src/routes/pages/__tests__/post-preview-partial.test.ts +96 -0
- package/src/routes/pages/__tests__/preview.test.ts +3 -1
- package/src/routes/pages/__tests__/smart-collection.test.ts +298 -0
- package/src/routes/pages/__tests__/subscribe.test.ts +248 -0
- package/src/routes/pages/archive.tsx +507 -357
- package/src/routes/pages/collection.tsx +94 -96
- package/src/routes/pages/collections.tsx +38 -50
- package/src/routes/pages/featured.tsx +32 -13
- package/src/routes/pages/home.tsx +25 -6
- package/src/routes/pages/language.tsx +113 -0
- package/src/routes/pages/latest.tsx +26 -16
- package/src/routes/pages/new.tsx +3 -0
- package/src/routes/pages/page.tsx +183 -19
- package/src/routes/pages/partials.tsx +41 -0
- package/src/routes/pages/search.tsx +18 -3
- package/src/routes/pages/smart-collection.tsx +340 -0
- package/src/routes/pages/subscribe.tsx +182 -0
- package/src/runtime/__tests__/index.test.ts +19 -0
- package/src/runtime/__tests__/node.test.ts +129 -4
- package/src/runtime/cloudflare.ts +21 -2
- package/src/runtime/index.ts +27 -1
- package/src/runtime/node.ts +18 -1
- package/src/runtime/site.ts +95 -24
- package/src/services/__tests__/auth.test.ts +116 -7
- package/src/services/__tests__/collection.test.ts +139 -4
- package/src/services/__tests__/language.test.ts +495 -0
- package/src/services/__tests__/navigation.test.ts +213 -10
- package/src/services/__tests__/path.test.ts +180 -0
- package/src/services/__tests__/post-language.test.ts +830 -0
- package/src/services/__tests__/post-timeline.test.ts +142 -11
- package/src/services/__tests__/post.test.ts +323 -9
- package/src/services/__tests__/settings.test.ts +228 -17
- package/src/services/__tests__/site-admin.test.ts +5 -5
- package/src/services/__tests__/smart-collection.test.ts +651 -0
- package/src/services/about-page.ts +22 -1
- package/src/services/auth.ts +51 -49
- package/src/services/bootstrap.ts +188 -38
- package/src/services/collection-directory-position.ts +76 -0
- package/src/services/collection.ts +330 -47
- package/src/services/custom-url.ts +27 -22
- package/src/services/export-theme/assets/client-site.css +1 -1
- package/src/services/export-theme/assets/client-site.js +123 -123
- package/src/services/export-theme/layouts/_default/rss.xml +77 -1
- package/src/services/export-theme/layouts/partials/feed-post-content.xml +105 -2
- package/src/services/export-theme/layouts/partials/media-gallery.html +35 -21
- package/src/services/export-theme/layouts/partials/pagination.html +14 -13
- package/src/services/export-theme/layouts/partials/post-card.html +8 -4
- package/src/services/export-theme/layouts/partials/reply.html +2 -1
- package/src/services/export-theme/layouts/partials/thread-preview.html +40 -30
- package/src/services/export-theme/styles/main.css +13 -1
- package/src/services/export.ts +281 -24
- package/src/services/index.ts +34 -3
- package/src/services/language.ts +412 -0
- package/src/services/mcp.ts +3 -1
- package/src/services/media.ts +14 -6
- package/src/services/navigation.ts +429 -67
- package/src/services/path.ts +225 -7
- package/src/services/post.ts +1318 -252
- package/src/services/search.ts +48 -2
- package/src/services/settings.ts +238 -43
- package/src/services/site-admin.ts +24 -7
- package/src/services/site.ts +77 -1
- package/src/services/smart-collection.ts +636 -0
- package/src/services/telegram.ts +20 -22
- package/src/services/upload-session.ts +1 -3
- package/src/style-author.css +27 -0
- package/src/styles/components-author.css +1622 -0
- package/src/styles/components.css +24 -1585
- package/src/styles/site-media.css +20 -6
- package/src/styles/tokens.css +144 -13
- package/src/styles/ui-author.css +7602 -0
- package/src/styles/ui.css +1224 -7276
- package/src/types/app-context.ts +7 -0
- package/src/types/bindings.ts +3 -0
- package/src/types/config.ts +94 -15
- package/src/types/constants.ts +188 -16
- package/src/types/entities.ts +92 -1
- package/src/types/operations.ts +64 -2
- package/src/types/props.ts +168 -30
- package/src/types/views.ts +61 -1
- package/src/ui/__tests__/font-themes.test.ts +52 -12
- package/src/ui/compose/ComposeDialog.tsx +215 -21
- package/src/ui/compose/ComposePrompt.tsx +1 -5
- package/src/ui/compose/__tests__/ComposeDialog.test.tsx +125 -0
- package/src/ui/dash/appearance/AdvancedContent.tsx +2 -2
- package/src/ui/dash/appearance/CodeInjectionContent.tsx +12 -16
- package/src/ui/dash/appearance/NavigationContent.tsx +117 -16
- package/src/ui/dash/appearance/__tests__/NavigationContent.test.tsx +33 -11
- package/src/ui/dash/appearance/__tests__/system-nav-descriptions.test.ts +44 -0
- package/src/ui/dash/appearance/system-nav-descriptions.ts +75 -0
- package/src/ui/dash/settings/AccountMenuContent.tsx +2 -2
- package/src/ui/dash/settings/ApiTokensContent.tsx +2 -1
- package/src/ui/dash/settings/ConfigEditorContent.tsx +35 -16
- package/src/ui/dash/settings/GeneralContent.tsx +275 -113
- package/src/ui/dash/settings/LanguageContent.tsx +409 -0
- package/src/ui/dash/settings/SettingsRootContent.tsx +19 -1
- package/src/ui/dash/settings/__tests__/GeneralContent.test.tsx +324 -4
- package/src/ui/dash/settings/__tests__/LanguageContent.test.tsx +144 -0
- package/src/ui/dash/settings/__tests__/discover-copy.test.ts +66 -0
- package/src/ui/dash/settings/discover-copy.ts +116 -0
- package/src/ui/feed/LinkCard.tsx +55 -45
- package/src/ui/feed/LinkPreview.tsx +2 -7
- package/src/ui/feed/NoteCard.tsx +9 -4
- package/src/ui/feed/PostStatusBadges.tsx +103 -17
- package/src/ui/feed/QuoteCard.tsx +55 -30
- package/src/ui/feed/ThreadPreview.tsx +6 -2
- package/src/ui/feed/__tests__/thread-preview.test.ts +13 -16
- package/src/ui/feed/__tests__/timeline-cards.test.ts +314 -49
- package/src/ui/feed/thread-preview-state.ts +20 -6
- package/src/ui/font-themes.ts +39 -29
- package/src/ui/layouts/BaseLayout.tsx +155 -10
- package/src/ui/layouts/SiteLayout.tsx +192 -34
- package/src/ui/layouts/__tests__/BaseLayout.test.tsx +196 -17
- package/src/ui/layouts/__tests__/SiteLayout.test.tsx +109 -85
- package/src/ui/pages/ArchivePage.tsx +401 -301
- package/src/ui/pages/CollectionPage.tsx +86 -76
- package/src/ui/pages/CollectionsPage.tsx +5 -0
- package/src/ui/pages/ComposePage.tsx +8 -0
- package/src/ui/pages/PostPage.tsx +47 -0
- package/src/ui/pages/SearchPage.tsx +3 -3
- package/src/ui/pages/SmartCollectionPage.tsx +434 -0
- package/src/ui/pages/SubscribePage.tsx +236 -0
- package/src/ui/pages/__tests__/ArchivePage.test.tsx +122 -3
- package/src/ui/pages/__tests__/collections-directory-rows.test.tsx +92 -0
- package/src/ui/pages/__tests__/collections-view-links.test.tsx +81 -0
- package/src/ui/shared/CollectionDirectory.tsx +178 -3
- package/src/ui/shared/CollectionsManager.tsx +70 -17
- package/src/ui/shared/CopyField.tsx +127 -0
- package/src/ui/shared/DraftPreviewBar.tsx +25 -9
- package/src/ui/shared/EmptyPostContent.tsx +23 -0
- package/src/ui/shared/MediaGallery.tsx +125 -46
- package/src/ui/shared/Pagination.tsx +20 -5
- package/src/ui/shared/PostFooter.tsx +55 -23
- package/src/ui/shared/__tests__/archive-labels.test.ts +100 -0
- package/src/ui/shared/__tests__/media-gallery.test.ts +210 -2
- package/src/ui/shared/__tests__/navigation-labels.test.ts +16 -22
- package/src/ui/shared/__tests__/pagination.test.ts +38 -24
- package/src/ui/shared/__tests__/post-footer.test.ts +32 -0
- package/src/ui/shared/archive-labels.ts +98 -0
- package/src/ui/shared/collection-management-labels.ts +94 -16
- package/src/ui/shared/custom-icons.ts +5 -0
- package/src/ui/shared/navigation-labels.ts +45 -71
- package/src/ui/shared/post-article-attributes.ts +8 -0
- package/src/ui/shared/smart-collection-labels.ts +343 -0
- package/dist/app-BxCOR3Uc.js +0 -6
- package/dist/client/_assets/chunks/heic-to-DUUaO23q.js +0 -1
- package/dist/client/_assets/chunks/module-DcsAZQZ_.js +0 -716
- package/dist/client/_assets/chunks/url-pLre2DM_.js +0 -1
- package/dist/client/_assets/client-B_eGKN5p.css +0 -2
- package/dist/client/_assets/client-DxY5BFe8.js +0 -296
- package/dist/client/_assets/client-auth-CakPESv9.js +0 -5533
- package/dist/env-OHRKGcMj.js +0 -281
- package/dist/github-api-BgSiE71w.js +0 -176
- package/dist/github-app-BbklkFmU.js +0 -275
- package/dist/github-sync-Cq1pzzOI.js +0 -431
- package/dist/github-sync-ppWXN3jb.js +0 -4
- package/dist/url-BMYO-Zlt.js +0 -395
- package/src/client/__tests__/collection-created-notice.test.ts +0 -36
- package/src/client/__tests__/collection-form-bridge.test.ts +0 -216
- package/src/client/__tests__/post-form-bridge.test.ts +0 -82
- package/src/client/collection-created-notice.ts +0 -66
- package/src/client/collection-form-bridge.ts +0 -191
- package/src/client/components/__tests__/jant-post-form.test.ts +0 -193
- package/src/client/components/jant-post-form.ts +0 -422
- package/src/client/components/post-form-template.ts +0 -352
- package/src/client/components/post-form-types.ts +0 -96
- package/src/client/media-metadata.ts +0 -247
- package/src/client/post-form-bridge.ts +0 -193
- package/src/ui/pages/CollectionEditorPage.tsx +0 -175
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from "vitest";
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
2
2
|
import {
|
|
3
3
|
createTestDatabase,
|
|
4
4
|
DEFAULT_TEST_SITE_ID,
|
|
@@ -170,7 +170,6 @@ describe("SettingsService", () => {
|
|
|
170
170
|
siteDescription: "",
|
|
171
171
|
siteFooter: "",
|
|
172
172
|
siteLanguage: "en",
|
|
173
|
-
cjkSerifFont: "off",
|
|
174
173
|
showJantBrandingOnHome: false,
|
|
175
174
|
mainRssFeed: "featured",
|
|
176
175
|
timeZone: "UTC",
|
|
@@ -361,6 +360,57 @@ describe("SettingsService", () => {
|
|
|
361
360
|
const result = await settingsService.isOnboardingComplete();
|
|
362
361
|
expect(result).toBe(true);
|
|
363
362
|
});
|
|
363
|
+
|
|
364
|
+
it("reports the three first-run states", async () => {
|
|
365
|
+
expect(await settingsService.getOnboardingStatus()).toBe("pending");
|
|
366
|
+
|
|
367
|
+
await settingsService.markSiteProvisioned();
|
|
368
|
+
expect(await settingsService.getOnboardingStatus()).toBe("provisioned");
|
|
369
|
+
// A provisioned site is real, but setup is not finished with it.
|
|
370
|
+
expect(await settingsService.isOnboardingComplete()).toBe(false);
|
|
371
|
+
|
|
372
|
+
await settingsService.completeOnboarding();
|
|
373
|
+
expect(await settingsService.getOnboardingStatus()).toBe("completed");
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
it("finishes setup when the author confirms the language they write in", async () => {
|
|
377
|
+
await settingsService.markSiteProvisioned();
|
|
378
|
+
// The control plane's guess, taken from the locale the owner browsed it
|
|
379
|
+
// in, is what the site starts with.
|
|
380
|
+
await settingsService.set("SITE_LANGUAGE", "zh-Hans");
|
|
381
|
+
|
|
382
|
+
await settingsService.confirmFirstRunLanguage(
|
|
383
|
+
{ siteLanguage: "en", browserLanguage: "zh-Hans" },
|
|
384
|
+
{ oldLanguage: "zh-Hans" },
|
|
385
|
+
);
|
|
386
|
+
|
|
387
|
+
expect(await settingsService.get("SITE_LANGUAGE")).toBe("en");
|
|
388
|
+
// English site, Chinese dashboard — the split the question exists for.
|
|
389
|
+
expect(await settingsService.get("DASHBOARD_LANGUAGE")).toBe("zh-Hans");
|
|
390
|
+
expect(await settingsService.isOnboardingComplete()).toBe(true);
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it("leaves the dashboard following when the browser sent none", async () => {
|
|
394
|
+
await settingsService.confirmFirstRunLanguage(
|
|
395
|
+
{ siteLanguage: "zh-TW", browserLanguage: "" },
|
|
396
|
+
{ oldLanguage: "en" },
|
|
397
|
+
);
|
|
398
|
+
|
|
399
|
+
expect(await settingsService.get("SITE_LANGUAGE")).toBe("zh-TW");
|
|
400
|
+
expect(await settingsService.get("DASHBOARD_LANGUAGE")).toBeNull();
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
it("leaves the dashboard following the language the author confirmed", async () => {
|
|
404
|
+
// An English browser says nothing about someone who just answered
|
|
405
|
+
// "Simplified Chinese" — the dashboard follows that answer.
|
|
406
|
+
await settingsService.confirmFirstRunLanguage(
|
|
407
|
+
{ siteLanguage: "zh-Hans", browserLanguage: "en-US" },
|
|
408
|
+
{ oldLanguage: "en" },
|
|
409
|
+
);
|
|
410
|
+
|
|
411
|
+
expect(await settingsService.get("SITE_LANGUAGE")).toBe("zh-Hans");
|
|
412
|
+
expect(await settingsService.get("DASHBOARD_LANGUAGE")).toBeNull();
|
|
413
|
+
});
|
|
364
414
|
});
|
|
365
415
|
|
|
366
416
|
describe("grouped settings updates", () => {
|
|
@@ -390,7 +440,6 @@ describe("SettingsService", () => {
|
|
|
390
440
|
const result = await settingsService.updateLocaleSettings(
|
|
391
441
|
{
|
|
392
442
|
siteLanguage: "zh-Hans",
|
|
393
|
-
cjkSerifFont: "zh-Hans",
|
|
394
443
|
timeZone: "America/New_York",
|
|
395
444
|
},
|
|
396
445
|
{
|
|
@@ -400,29 +449,32 @@ describe("SettingsService", () => {
|
|
|
400
449
|
|
|
401
450
|
expect(result.languageChanged).toBe(true);
|
|
402
451
|
expect(await settingsService.get("SITE_LANGUAGE")).toBe("zh-Hans");
|
|
403
|
-
expect(await settingsService.get("CJK_SERIF_FONT")).toBe("zh-Hans");
|
|
404
452
|
expect(await settingsService.get("TIME_ZONE")).toBe("America/New_York");
|
|
405
453
|
});
|
|
406
454
|
|
|
407
|
-
|
|
408
|
-
|
|
455
|
+
// The Language and General pages each own part of this group, so an absent
|
|
456
|
+
// field has to mean "leave it alone" rather than "clear it".
|
|
457
|
+
it("leaves out-of-scope fields untouched", async () => {
|
|
458
|
+
await settingsService.set("SITE_LANGUAGE", "ja");
|
|
459
|
+
await settingsService.set("TIME_ZONE", "Asia/Tokyo");
|
|
460
|
+
|
|
409
461
|
await settingsService.updateLocaleSettings(
|
|
410
|
-
{
|
|
411
|
-
|
|
412
|
-
cjkSerifFont: "off",
|
|
413
|
-
timeZone: "UTC",
|
|
414
|
-
},
|
|
415
|
-
{ oldLanguage: "en" },
|
|
462
|
+
{ timeZone: "America/New_York" },
|
|
463
|
+
{ oldLanguage: "ja" },
|
|
416
464
|
);
|
|
465
|
+
expect(await settingsService.get("SITE_LANGUAGE")).toBe("ja");
|
|
417
466
|
|
|
418
|
-
|
|
467
|
+
await settingsService.updateLocaleSettings(
|
|
468
|
+
{ siteLanguage: "en" },
|
|
469
|
+
{ oldLanguage: "ja" },
|
|
470
|
+
);
|
|
471
|
+
expect(await settingsService.get("TIME_ZONE")).toBe("America/New_York");
|
|
419
472
|
});
|
|
420
473
|
|
|
421
474
|
it("stores the base locale when language input is blank", async () => {
|
|
422
475
|
const result = await settingsService.updateLocaleSettings(
|
|
423
476
|
{
|
|
424
477
|
siteLanguage: "",
|
|
425
|
-
cjkSerifFont: "off",
|
|
426
478
|
timeZone: "UTC",
|
|
427
479
|
},
|
|
428
480
|
{
|
|
@@ -439,7 +491,6 @@ describe("SettingsService", () => {
|
|
|
439
491
|
{
|
|
440
492
|
siteLanguage: "fr",
|
|
441
493
|
dashboardLanguage: "zh-Hant",
|
|
442
|
-
cjkSerifFont: "off",
|
|
443
494
|
timeZone: "UTC",
|
|
444
495
|
},
|
|
445
496
|
{ oldLanguage: "fr", oldDashboardLanguage: "" },
|
|
@@ -456,7 +507,6 @@ describe("SettingsService", () => {
|
|
|
456
507
|
{
|
|
457
508
|
siteLanguage: "en",
|
|
458
509
|
dashboardLanguage: "",
|
|
459
|
-
cjkSerifFont: "off",
|
|
460
510
|
timeZone: "UTC",
|
|
461
511
|
},
|
|
462
512
|
{ oldLanguage: "en", oldDashboardLanguage: "zh-Hans" },
|
|
@@ -481,7 +531,6 @@ describe("SettingsService", () => {
|
|
|
481
531
|
{
|
|
482
532
|
siteLanguage: "en",
|
|
483
533
|
dashboardLanguage: "fr",
|
|
484
|
-
cjkSerifFont: "off",
|
|
485
534
|
timeZone: "UTC",
|
|
486
535
|
},
|
|
487
536
|
{ oldLanguage: "en" },
|
|
@@ -509,4 +558,166 @@ describe("SettingsService", () => {
|
|
|
509
558
|
).toBeNull();
|
|
510
559
|
});
|
|
511
560
|
});
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* The ping exists so a self-hosted site can be found at all, and it says
|
|
564
|
+
* "read me now" rather than "list me". What it fires on is therefore the
|
|
565
|
+
* interesting part: the two moments the answer changes, and neither of the
|
|
566
|
+
* moments it does not.
|
|
567
|
+
*/
|
|
568
|
+
describe("updateDiscoverSetting", () => {
|
|
569
|
+
it("stores the choice explicitly, including off", async () => {
|
|
570
|
+
await settingsService.updateDiscoverSetting("off", { demoMode: false });
|
|
571
|
+
expect(await settingsService.get("DISCOVER")).toBe("off");
|
|
572
|
+
|
|
573
|
+
await settingsService.updateDiscoverSetting("featured", {
|
|
574
|
+
demoMode: false,
|
|
575
|
+
});
|
|
576
|
+
expect(await settingsService.get("DISCOVER")).toBe("featured");
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
// A site that has never used the control has never told anyone it exists,
|
|
580
|
+
// so confirming the default is exactly as much of an opt-in as ticking a
|
|
581
|
+
// box that was off.
|
|
582
|
+
it("announces when an untouched site opts in", async () => {
|
|
583
|
+
const result = await settingsService.updateDiscoverSetting("latest", {
|
|
584
|
+
demoMode: false,
|
|
585
|
+
});
|
|
586
|
+
expect(result.shouldAnnounce).toBe(true);
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
it("announces when a site that had opted out comes back", async () => {
|
|
590
|
+
await settingsService.updateDiscoverSetting("off", { demoMode: false });
|
|
591
|
+
const result = await settingsService.updateDiscoverSetting("latest", {
|
|
592
|
+
demoMode: false,
|
|
593
|
+
});
|
|
594
|
+
expect(result.shouldAnnounce).toBe(true);
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
// The directory already knows about a listed site; which of its posts it
|
|
598
|
+
// draws from is not news.
|
|
599
|
+
it("says nothing when an enrolled site changes which posts it offers", async () => {
|
|
600
|
+
await settingsService.updateDiscoverSetting("latest", {
|
|
601
|
+
demoMode: false,
|
|
602
|
+
});
|
|
603
|
+
const result = await settingsService.updateDiscoverSetting("featured", {
|
|
604
|
+
demoMode: false,
|
|
605
|
+
});
|
|
606
|
+
expect(result.shouldAnnounce).toBe(false);
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
// The half that used to be missing. A directory that is not told keeps the
|
|
610
|
+
// blog until its next scheduled read of the feed, and the owner watches
|
|
611
|
+
// something they just removed sit there for another hour.
|
|
612
|
+
it("announces when a listed site opts out", async () => {
|
|
613
|
+
await settingsService.updateDiscoverSetting("latest", {
|
|
614
|
+
demoMode: false,
|
|
615
|
+
});
|
|
616
|
+
const result = await settingsService.updateDiscoverSetting("off", {
|
|
617
|
+
demoMode: false,
|
|
618
|
+
});
|
|
619
|
+
expect(result.shouldAnnounce).toBe(true);
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
// Nothing changed, so there is nothing to say: this site was not in any
|
|
623
|
+
// directory a moment ago either.
|
|
624
|
+
it("says nothing when a site that was never listed sets off", async () => {
|
|
625
|
+
const result = await settingsService.updateDiscoverSetting("off", {
|
|
626
|
+
demoMode: false,
|
|
627
|
+
});
|
|
628
|
+
expect(result.shouldAnnounce).toBe(false);
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
it("never announces a demo site", async () => {
|
|
632
|
+
const result = await settingsService.updateDiscoverSetting("latest", {
|
|
633
|
+
demoMode: true,
|
|
634
|
+
});
|
|
635
|
+
expect(result.shouldAnnounce).toBe(false);
|
|
636
|
+
});
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* The stored outcome is the owner's record of the announcement, and it does
|
|
641
|
+
* not always reach them — a hosted site's settings page hides the status
|
|
642
|
+
* block entirely. The log is how a deployment answers "did that get through"
|
|
643
|
+
* when the dashboard cannot.
|
|
644
|
+
*/
|
|
645
|
+
describe("announceToDiscover", () => {
|
|
646
|
+
afterEach(() => {
|
|
647
|
+
vi.restoreAllMocks();
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
function stubDirectory(response: Response | Error) {
|
|
651
|
+
return vi
|
|
652
|
+
.spyOn(globalThis, "fetch")
|
|
653
|
+
.mockImplementation(() =>
|
|
654
|
+
response instanceof Error
|
|
655
|
+
? Promise.reject(response)
|
|
656
|
+
: Promise.resolve(response.clone()),
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
it("records and logs an announcement that got through", async () => {
|
|
661
|
+
stubDirectory(new Response(null, { status: 202 }));
|
|
662
|
+
const log = vi.spyOn(console, "log").mockImplementation(() => {});
|
|
663
|
+
|
|
664
|
+
const outcome = await settingsService.announceToDiscover({
|
|
665
|
+
endpoint: "https://cloud.example/api/discover/ping",
|
|
666
|
+
feedUrl: "https://blog.example/latest/feed",
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
expect(outcome.ok).toBe(true);
|
|
670
|
+
expect(
|
|
671
|
+
JSON.parse(
|
|
672
|
+
(await settingsService.get("DISCOVER_ANNOUNCE_STATE")) ?? "",
|
|
673
|
+
),
|
|
674
|
+
).toMatchObject({
|
|
675
|
+
ok: true,
|
|
676
|
+
feedUrl: "https://blog.example/latest/feed",
|
|
677
|
+
});
|
|
678
|
+
expect(log).toHaveBeenCalledWith(
|
|
679
|
+
expect.stringContaining("https://cloud.example/api/discover/ping"),
|
|
680
|
+
);
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
// The failure this exists for: a directory that answers, but not about
|
|
684
|
+
// this site. Silently stored, it reads from the dashboard like a success.
|
|
685
|
+
it("logs the reason an announcement failed", async () => {
|
|
686
|
+
stubDirectory(new Response(null, { status: 404 }));
|
|
687
|
+
const error = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
688
|
+
|
|
689
|
+
const outcome = await settingsService.announceToDiscover({
|
|
690
|
+
endpoint: "https://jant.me/api/discover/ping",
|
|
691
|
+
feedUrl: "https://blog.example/latest/feed",
|
|
692
|
+
});
|
|
693
|
+
|
|
694
|
+
expect(outcome).toMatchObject({ ok: false, status: 404 });
|
|
695
|
+
expect(error).toHaveBeenCalledWith(
|
|
696
|
+
expect.stringContaining("The directory answered 404."),
|
|
697
|
+
);
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
// The caller orphans this promise behind `waitUntil`, so a rejection has
|
|
701
|
+
// nobody to reject to — on a Node runtime an unhandled one ends the
|
|
702
|
+
// process. A settings row that could not be written is worth a log, not
|
|
703
|
+
// the site.
|
|
704
|
+
it("resolves even when the outcome cannot be recorded", async () => {
|
|
705
|
+
stubDirectory(new Response(null, { status: 202 }));
|
|
706
|
+
vi.spyOn(console, "log").mockImplementation(() => {});
|
|
707
|
+
const error = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
708
|
+
vi.spyOn(settingsService, "set").mockRejectedValue(
|
|
709
|
+
new Error("D1_ERROR: database is locked"),
|
|
710
|
+
);
|
|
711
|
+
|
|
712
|
+
const outcome = await settingsService.announceToDiscover({
|
|
713
|
+
endpoint: "https://jant.me/api/discover/ping",
|
|
714
|
+
feedUrl: "https://blog.example/latest/feed",
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
expect(outcome.ok).toBe(true);
|
|
718
|
+
expect(error).toHaveBeenCalledWith(
|
|
719
|
+
expect.stringContaining("database is locked"),
|
|
720
|
+
);
|
|
721
|
+
});
|
|
722
|
+
});
|
|
512
723
|
});
|
|
@@ -53,9 +53,9 @@ describe("SiteAdminService", () => {
|
|
|
53
53
|
|
|
54
54
|
expect(navigationRows).toEqual([
|
|
55
55
|
{ systemKey: "featured", placement: "header" },
|
|
56
|
-
{ systemKey: "collections", placement: "header" },
|
|
57
56
|
{ systemKey: "archive", placement: "header" },
|
|
58
|
-
{ systemKey: "
|
|
57
|
+
{ systemKey: "collections", placement: "more" },
|
|
58
|
+
{ systemKey: "subscribe", placement: "more" },
|
|
59
59
|
{ systemKey: "settings", placement: "more" },
|
|
60
60
|
]);
|
|
61
61
|
});
|
|
@@ -182,12 +182,12 @@ describe("SiteAdminService", () => {
|
|
|
182
182
|
expect(recovered.site.id).toBe(first.site.id);
|
|
183
183
|
expect(navigationRows.map((row) => row.systemKey)).toEqual([
|
|
184
184
|
"featured",
|
|
185
|
-
"collections",
|
|
186
185
|
"archive",
|
|
187
|
-
"
|
|
186
|
+
"collections",
|
|
187
|
+
"subscribe",
|
|
188
188
|
"settings",
|
|
189
189
|
]);
|
|
190
|
-
expect(onboarding.value).toBe("
|
|
190
|
+
expect(onboarding.value).toBe("provisioned");
|
|
191
191
|
});
|
|
192
192
|
|
|
193
193
|
it("rejects reuse of an idempotency key with different key or primary host", async () => {
|