@jant/core 0.6.16 → 0.7.1
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/export.js +3 -1
- package/bin/commands/import-site.js +749 -220
- package/bin/commands/reset-password.js +21 -8
- package/bin/commands/setup.js +136 -0
- package/bin/commands/site/export.js +71 -34
- package/bin/commands/site/pull-media.js +2 -6
- package/bin/commands/site/snapshot/export.js +19 -61
- package/bin/commands/site/snapshot/import.js +23 -24
- package/bin/lib/d1-query.js +92 -18
- package/bin/lib/hugo-markdown.js +4 -0
- package/bin/lib/node-env.js +40 -4
- package/bin/lib/site-pull-media.js +21 -28
- package/bin/lib/site-selection.js +94 -29
- package/bin/lib/site-snapshot.js +338 -3
- package/bin/lib/sql-export.js +68 -5
- package/bin/lib/wrangler-cli.js +37 -2
- package/bin/lib/wrangler-json.js +35 -0
- package/bin/lib/zip-archive.js +187 -0
- package/dist/{app-C7_4oab9.js → app-ZcaI1kPN.js} +53190 -13529
- 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-B-m7X7S5.js +261 -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-BJyd-LXE.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-BkscJx69.js +2 -0
- package/dist/client/_assets/client-DAhoqPdr.css +2 -0
- package/dist/client/_assets/client-auth-CAMfTrKW.js +828 -0
- package/dist/client/_assets/client-author-DQ8R-8KR.css +2 -0
- package/dist/client/_assets/client-compose-D6rExKVK.js +2004 -0
- package/dist/client/_assets/client-knSEyUJO.js +295 -0
- package/dist/client/_assets/client-manage-sVOkqVbH.js +2170 -0
- package/dist/client/_assets/client-settings-CGR_nZ78.js +1112 -0
- package/dist/github-sync-Gw4orAHk.js +8398 -0
- package/dist/index.js +2 -5
- package/dist/node.js +11 -9
- package/package.json +15 -5
- 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__/dev-scripts.test.ts +203 -0
- package/src/__tests__/export-collection-order.test.ts +276 -0
- package/src/__tests__/export-feed-ids.test.ts +184 -0
- package/src/__tests__/export-feed-order.test.ts +294 -0
- package/src/__tests__/export-hugo-build.test.ts +390 -0
- package/src/__tests__/export-import-roundtrip.test.ts +94 -0
- package/src/__tests__/export-service.test.ts +842 -28
- package/src/__tests__/export-smart-collection.test.ts +329 -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__/helpers/hugo-site.ts +146 -0
- package/src/__tests__/import-site-command.test.ts +487 -1
- package/src/__tests__/mise-config.test.ts +75 -4
- package/src/__tests__/node-dev-tasks.test.ts +264 -0
- package/src/__tests__/site-export-canonical-import.test.ts +149 -0
- package/src/__tests__/snapshot-canonical-replay.test.ts +179 -0
- package/src/__tests__/snapshot-settings.test.ts +97 -0
- package/src/__tests__/snapshot-tables.test.ts +219 -0
- package/src/__tests__/sql-export.test.ts +173 -0
- package/src/__tests__/stylesheet-audience.test.ts +159 -0
- package/src/__tests__/stylesheet-breakpoints.test.ts +183 -0
- package/src/__tests__/zip-archive.test.ts +106 -0
- package/src/app.tsx +86 -22
- 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 +272 -0
- package/src/client/__tests__/compose-launch.test.ts +62 -1
- package/src/client/__tests__/compose-shortcuts.test.ts +38 -9
- 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 +23 -0
- 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__/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 +28 -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 +1250 -53
- package/src/client/components/__tests__/jant-compose-editor.test.ts +544 -40
- package/src/client/components/__tests__/jant-compose-fullscreen.test.ts +0 -1
- 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 +561 -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-types.ts +75 -1
- 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 +100 -49
- package/src/client/components/jant-compose-dialog.ts +1486 -707
- package/src/client/components/jant-compose-editor.ts +673 -336
- package/src/client/components/jant-compose-fullscreen.ts +51 -43
- 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 +1086 -282
- package/src/client/components/jant-post-picker.ts +324 -0
- package/src/client/components/jant-repo-picker-types.ts +6 -1
- package/src/client/components/jant-repo-picker.ts +137 -108
- package/src/client/components/jant-settings-avatar.ts +31 -27
- package/src/client/components/jant-settings-general.ts +622 -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 +214 -141
- package/src/client/compose-launch.ts +76 -2
- package/src/client/compose-shortcuts.ts +6 -8
- 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/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__/list-editing.test.ts +224 -86
- package/src/client/tiptap/__tests__/mark-exit.test.ts +1 -2
- package/src/client/tiptap/__tests__/markdown-clipboard.test.ts +26 -0
- package/src/client/tiptap/bubble-menu.ts +47 -16
- package/src/client/tiptap/extensions.ts +0 -3
- package/src/client/tiptap/floating-position.ts +216 -2
- package/src/client/tiptap/inline-image-upload.ts +7 -3
- package/src/client/tiptap/link-toolbar.ts +22 -9
- package/src/client/tiptap/structural-keymap.ts +158 -47
- package/src/client/toast.ts +13 -0
- 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__/d1-query.test.ts +56 -1
- 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/backfills/0006_clear_mirrored_page_nav_labels.sql +31 -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/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 +21 -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/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 +21 -0
- package/src/db/pg/schema.ts +195 -27
- package/src/db/post-visibility.ts +117 -0
- package/src/db/schema.ts +222 -27
- 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 +490 -158
- package/src/i18n/locales/public/en.ts +1 -1
- package/src/i18n/locales/public/zh-Hans.po +487 -155
- package/src/i18n/locales/public/zh-Hans.ts +1 -1
- package/src/i18n/locales/public/zh-Hant.po +487 -155
- package/src/i18n/locales/public/zh-Hant.ts +1 -1
- package/src/i18n/locales/settings/en.po +555 -73
- package/src/i18n/locales/settings/en.ts +1 -1
- package/src/i18n/locales/settings/zh-Hans.po +601 -119
- package/src/i18n/locales/settings/zh-Hans.ts +1 -1
- package/src/i18n/locales/settings/zh-Hant.po +614 -132
- 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 +1526 -15
- package/src/lib/__tests__/filter-dimensions.test.ts +341 -0
- package/src/lib/__tests__/github-sync-repo-name.test.ts +40 -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__/image.test.ts +27 -1
- 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-to-tiptap.test.ts +105 -0
- package/src/lib/__tests__/markdown.test.ts +10 -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 +131 -3
- package/src/lib/__tests__/schemas.test.ts +69 -5
- package/src/lib/__tests__/site-unavailable-page.test.ts +25 -0
- package/src/lib/__tests__/slug.test.ts +70 -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__/timeline.test.ts +87 -0
- package/src/lib/__tests__/tiptap-to-markdown.test.ts +172 -4
- 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 +78 -72
- 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 +439 -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 +926 -73
- package/src/lib/filter-dimensions.ts +1349 -0
- package/src/lib/github-sync-repo-name.ts +45 -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 +62 -0
- package/src/lib/icons.ts +9 -2
- package/src/lib/ids.ts +3 -0
- package/src/lib/image.ts +17 -4
- package/src/lib/jant-docs.ts +42 -0
- package/src/lib/lang-detect.ts +308 -0
- package/src/lib/markdown-manager.ts +392 -2
- 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-body-html.ts +11 -4
- package/src/lib/post-meta.ts +19 -0
- package/src/lib/render.tsx +55 -7
- package/src/lib/resolve-config.ts +111 -6
- package/src/lib/schemas.ts +251 -15
- 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 +43 -2
- package/src/lib/tiptap-render.ts +1 -2
- package/src/lib/tiptap-to-markdown.ts +13 -7
- package/src/lib/upload.ts +16 -13
- package/src/lib/url.ts +159 -86
- package/src/lib/version.ts +10 -8
- package/src/lib/view-language.ts +436 -0
- package/src/lib/view.ts +53 -25
- 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-setup.test.ts +163 -0
- package/src/node/__tests__/cli-site-selection.test.ts +128 -38
- package/src/node/__tests__/cli-site-snapshot.test.ts +67 -0
- package/src/node/__tests__/cli-snapshot-meta.test.ts +20 -0
- package/src/node/__tests__/runtime.test.ts +75 -0
- package/src/node/index.ts +3 -0
- package/src/node/request-handler.ts +3 -1
- 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__/post-translations.test.ts +829 -0
- package/src/routes/api/__tests__/posts.test.ts +24 -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/__tests__/upload.test.ts +34 -0
- 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 +6 -3
- package/src/routes/api/internal/__tests__/sites.test.ts +42 -2
- package/src/routes/api/internal/sites.ts +0 -1
- package/src/routes/api/nav-items.ts +55 -8
- package/src/routes/api/posts.ts +161 -0
- package/src/routes/api/public/__tests__/archive.test.ts +111 -0
- package/src/routes/api/public/archive.ts +77 -81
- package/src/routes/api/public/posts.ts +44 -7
- package/src/routes/api/smart-collections.ts +132 -0
- package/src/routes/api/telegram.ts +2 -40
- package/src/routes/api/upload.ts +10 -3
- 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 +9 -0
- 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__/github-sync-app.test.ts +365 -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 +714 -111
- package/src/routes/discover-announce.ts +96 -0
- package/src/routes/feed/__tests__/feed.test.ts +165 -2
- 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 +370 -6
- 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__/feed-autodiscovery.test.ts +148 -0
- package/src/routes/pages/__tests__/language-routing.test.ts +679 -0
- package/src/routes/pages/__tests__/post-page-round-trips.test.ts +211 -0
- package/src/routes/pages/__tests__/post-preview-partial.test.ts +96 -0
- 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/__tests__/thread-order.test.ts +179 -0
- package/src/routes/pages/archive.tsx +487 -379
- package/src/routes/pages/collection.tsx +94 -96
- package/src/routes/pages/collections.tsx +38 -50
- package/src/routes/pages/featured.tsx +43 -18
- 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 +228 -45
- package/src/routes/pages/partials.tsx +41 -0
- package/src/routes/pages/search.tsx +22 -5
- 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/__tests__/readiness.test.ts +23 -0
- package/src/runtime/cloudflare.ts +21 -2
- package/src/runtime/index.ts +27 -1
- package/src/runtime/node.ts +67 -1
- package/src/runtime/readiness.ts +15 -0
- package/src/runtime/site.ts +95 -24
- package/src/services/__tests__/auth.test.ts +116 -7
- package/src/services/__tests__/bootstrap-setup-instance.test.ts +230 -0
- package/src/services/__tests__/collection.test.ts +108 -4
- package/src/services/__tests__/custom-url.test.ts +34 -0
- package/src/services/__tests__/github-app-installations.test.ts +153 -0
- package/src/services/__tests__/github-sync-push.test.ts +46 -0
- package/src/services/__tests__/language.test.ts +495 -0
- package/src/services/__tests__/media.test.ts +31 -0
- package/src/services/__tests__/navigation.test.ts +213 -10
- package/src/services/__tests__/path.test.ts +236 -0
- package/src/services/__tests__/post-language.test.ts +830 -0
- package/src/services/__tests__/post-timeline.test.ts +127 -0
- package/src/services/__tests__/post.test.ts +120 -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 +408 -39
- package/src/services/collection-directory-position.ts +76 -0
- package/src/services/collection.ts +331 -46
- package/src/services/custom-url.ts +29 -24
- 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/alias.html +27 -1
- package/src/services/export-theme/layouts/_default/list.html +2 -63
- package/src/services/export-theme/layouts/_default/rss.xml +103 -38
- package/src/services/export-theme/layouts/collections/list.html +3 -3
- package/src/services/export-theme/layouts/featured/list.html +1 -4
- package/src/services/export-theme/layouts/index.html +40 -26
- package/src/services/export-theme/layouts/partials/collection-members.html +100 -0
- package/src/services/export-theme/layouts/partials/collection-threads.html +33 -0
- package/src/services/export-theme/layouts/partials/featured-members.html +35 -0
- package/src/services/export-theme/layouts/partials/featured-thread.html +1 -1
- package/src/services/export-theme/layouts/partials/feed-post-content.xml +105 -2
- package/src/services/export-theme/layouts/partials/footer.html +1 -1
- package/src/services/export-theme/layouts/partials/head.html +1 -1
- package/src/services/export-theme/layouts/partials/header.html +5 -3
- package/src/services/export-theme/layouts/partials/jant-data.html +23 -0
- package/src/services/export-theme/layouts/partials/latest-members.html +48 -0
- 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/smart-collection-members.html +129 -0
- package/src/services/export-theme/layouts/partials/thread-preview.html +41 -31
- package/src/services/export-theme/layouts/post/list.html +1 -1
- package/src/services/export-theme/layouts/smart_collection/list.html +24 -0
- package/src/services/export-theme/styles/main.css +13 -2
- package/src/services/export-theme/theme.toml +1 -1
- package/src/services/export.ts +880 -72
- package/src/services/github-app-installations.ts +171 -4
- package/src/services/github-sync.ts +69 -15
- package/src/services/index.ts +34 -3
- package/src/services/language.ts +412 -0
- package/src/services/mcp.ts +22 -2
- package/src/services/media.ts +22 -7
- package/src/services/navigation.ts +429 -67
- package/src/services/path.ts +254 -6
- package/src/services/post.ts +1234 -190
- package/src/services/search.ts +39 -2
- package/src/services/settings.ts +238 -43
- package/src/services/site-admin.ts +27 -14
- package/src/services/site.ts +160 -32
- 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 -1571
- package/src/styles/site-media.css +16 -2
- package/src/styles/tokens.css +82 -12
- package/src/styles/ui-author.css +7602 -0
- package/src/styles/ui.css +1090 -7216
- package/src/types/app-context.ts +23 -0
- package/src/types/bindings.ts +8 -0
- package/src/types/config.ts +94 -15
- package/src/types/constants.ts +188 -16
- package/src/types/entities.ts +87 -1
- package/src/types/operations.ts +74 -2
- package/src/types/props.ts +157 -31
- package/src/types/views.ts +55 -1
- package/src/ui/__tests__/font-themes.test.ts +52 -12
- package/src/ui/compose/ComposeDialog.tsx +201 -7
- 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 +277 -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/NoteCard.tsx +9 -4
- package/src/ui/feed/PostStatusBadges.tsx +90 -43
- 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 +282 -289
- 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 +65 -9
- 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/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 +20 -11
- 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/navigation-labels.ts +45 -71
- package/src/ui/shared/post-article-attributes.ts +2 -0
- package/src/ui/shared/smart-collection-labels.ts +343 -0
- package/dist/app-C75Zc8dD.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-CU9pEbk5.js +0 -1
- package/dist/client/_assets/client-Bq0vre8Y.js +0 -296
- package/dist/client/_assets/client-D3VZyG4L.css +0 -2
- package/dist/client/_assets/client-auth-F2rb9WfF.js +0 -5571
- package/dist/env-BPYViDJJ.js +0 -281
- package/dist/export-Dl5KCiEs.js +0 -5562
- package/dist/github-api-BNF35Lkx.js +0 -176
- package/dist/github-app-DdiD-bC4.js +0 -275
- package/dist/github-sync-Bqg62IvV.js +0 -4
- package/dist/github-sync-HdK2EgvJ.js +0 -431
- package/dist/url-CbLAtlZe.js +0 -900
- 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/client/tiptap/exitable-marks.ts +0 -73
- package/src/ui/pages/CollectionEditorPage.tsx +0 -175
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
import { x as __exportAll } from "./url-CbLAtlZe.js";
|
|
2
|
-
//#region src/lib/github-api.ts
|
|
3
|
-
var github_api_exports = /* @__PURE__ */ __exportAll({
|
|
4
|
-
GitHubApiError: () => GitHubApiError,
|
|
5
|
-
createGitHubClient: () => createGitHubClient,
|
|
6
|
-
parseRepoSlug: () => parseRepoSlug
|
|
7
|
-
});
|
|
8
|
-
/**
|
|
9
|
-
* GitHub REST API client for content sync.
|
|
10
|
-
*
|
|
11
|
-
* Pure fetch-based — no npm dependencies. Works in both Cloudflare Workers
|
|
12
|
-
* and Node 18+.
|
|
13
|
-
*/ var API_BASE = "https://api.github.com";
|
|
14
|
-
var COMMON_HEADERS = {
|
|
15
|
-
Accept: "application/vnd.github+json",
|
|
16
|
-
"X-GitHub-Api-Version": "2022-11-28",
|
|
17
|
-
"User-Agent": "jant-github-sync"
|
|
18
|
-
};
|
|
19
|
-
var GitHubApiError = class extends Error {
|
|
20
|
-
status;
|
|
21
|
-
body;
|
|
22
|
-
url;
|
|
23
|
-
constructor(status, body, url) {
|
|
24
|
-
super(`GitHub API ${status}: ${body} (${url})`), this.status = status, this.body = body, this.url = url;
|
|
25
|
-
this.name = "GitHubApiError";
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
/**
|
|
29
|
-
* Create a GitHub API client.
|
|
30
|
-
*
|
|
31
|
-
* Accepts either a static token (PAT) or a provider function that returns a
|
|
32
|
-
* fresh token on each request (used for short-lived GitHub App installation
|
|
33
|
-
* tokens which need to be refreshed before expiry — the provider handles
|
|
34
|
-
* caching internally).
|
|
35
|
-
*/ function createGitHubClient(auth) {
|
|
36
|
-
const getToken = typeof auth === "string" ? async () => auth : auth;
|
|
37
|
-
async function request(method, path, body) {
|
|
38
|
-
const url = `${API_BASE}${path}`;
|
|
39
|
-
const token = await getToken();
|
|
40
|
-
const res = await fetch(url, {
|
|
41
|
-
method,
|
|
42
|
-
headers: {
|
|
43
|
-
...COMMON_HEADERS,
|
|
44
|
-
Authorization: `Bearer ${token}`,
|
|
45
|
-
...body !== void 0 ? { "Content-Type": "application/json" } : {}
|
|
46
|
-
},
|
|
47
|
-
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
48
|
-
});
|
|
49
|
-
if (!res.ok) {
|
|
50
|
-
const text = await res.text();
|
|
51
|
-
throw new GitHubApiError(res.status, text, url);
|
|
52
|
-
}
|
|
53
|
-
if (res.status === 204) return void 0;
|
|
54
|
-
return await res.json();
|
|
55
|
-
}
|
|
56
|
-
async function requestOrNull(method, path) {
|
|
57
|
-
const url = `${API_BASE}${path}`;
|
|
58
|
-
const token = await getToken();
|
|
59
|
-
const res = await fetch(url, {
|
|
60
|
-
method,
|
|
61
|
-
headers: {
|
|
62
|
-
...COMMON_HEADERS,
|
|
63
|
-
Authorization: `Bearer ${token}`
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
if (res.status === 404) return null;
|
|
67
|
-
if (!res.ok) {
|
|
68
|
-
const text = await res.text();
|
|
69
|
-
throw new GitHubApiError(res.status, text, url);
|
|
70
|
-
}
|
|
71
|
-
return await res.json();
|
|
72
|
-
}
|
|
73
|
-
return {
|
|
74
|
-
async getRepo(owner, repo) {
|
|
75
|
-
return request("GET", `/repos/${owner}/${repo}`);
|
|
76
|
-
},
|
|
77
|
-
async getRef(owner, repo, ref) {
|
|
78
|
-
return { sha: (await request("GET", `/repos/${owner}/${repo}/git/ref/${ref}`)).object.sha };
|
|
79
|
-
},
|
|
80
|
-
async getCommit(owner, repo, sha) {
|
|
81
|
-
const data = await request("GET", `/repos/${owner}/${repo}/git/commits/${sha}`);
|
|
82
|
-
return {
|
|
83
|
-
sha: data.sha,
|
|
84
|
-
treeSha: data.tree.sha
|
|
85
|
-
};
|
|
86
|
-
},
|
|
87
|
-
async updateRef(owner, repo, ref, sha) {
|
|
88
|
-
await request("PATCH", `/repos/${owner}/${repo}/git/refs/${ref}`, {
|
|
89
|
-
sha,
|
|
90
|
-
force: false
|
|
91
|
-
});
|
|
92
|
-
},
|
|
93
|
-
async createRef(owner, repo, ref, sha) {
|
|
94
|
-
await request("POST", `/repos/${owner}/${repo}/git/refs`, {
|
|
95
|
-
ref: `refs/${ref}`,
|
|
96
|
-
sha
|
|
97
|
-
});
|
|
98
|
-
},
|
|
99
|
-
async getFileContent(owner, repo, path, ref) {
|
|
100
|
-
return requestOrNull("GET", `/repos/${owner}/${repo}/contents/${path}${ref ? `?ref=${encodeURIComponent(ref)}` : ""}`);
|
|
101
|
-
},
|
|
102
|
-
async createOrUpdateFile(owner, repo, path, opts) {
|
|
103
|
-
const body = {
|
|
104
|
-
message: opts.message,
|
|
105
|
-
content: btoa(unescape(encodeURIComponent(opts.content)))
|
|
106
|
-
};
|
|
107
|
-
if (opts.sha) body.sha = opts.sha;
|
|
108
|
-
if (opts.branch) body.branch = opts.branch;
|
|
109
|
-
return { sha: (await request("PUT", `/repos/${owner}/${repo}/contents/${path}`, body)).content.sha };
|
|
110
|
-
},
|
|
111
|
-
async deleteFile(owner, repo, path, opts) {
|
|
112
|
-
await request("DELETE", `/repos/${owner}/${repo}/contents/${path}`, {
|
|
113
|
-
message: opts.message,
|
|
114
|
-
sha: opts.sha,
|
|
115
|
-
...opts.branch ? { branch: opts.branch } : {}
|
|
116
|
-
});
|
|
117
|
-
},
|
|
118
|
-
async createBlob(owner, repo, content, encoding) {
|
|
119
|
-
return request("POST", `/repos/${owner}/${repo}/git/blobs`, {
|
|
120
|
-
content,
|
|
121
|
-
encoding
|
|
122
|
-
});
|
|
123
|
-
},
|
|
124
|
-
async createTree(owner, repo, items, baseTree) {
|
|
125
|
-
return request("POST", `/repos/${owner}/${repo}/git/trees`, {
|
|
126
|
-
tree: items,
|
|
127
|
-
...baseTree ? { base_tree: baseTree } : {}
|
|
128
|
-
});
|
|
129
|
-
},
|
|
130
|
-
async getTree(owner, repo, sha, opts) {
|
|
131
|
-
return request("GET", `/repos/${owner}/${repo}/git/trees/${sha}${opts?.recursive ? "?recursive=1" : ""}`);
|
|
132
|
-
},
|
|
133
|
-
async createCommit(owner, repo, opts) {
|
|
134
|
-
return request("POST", `/repos/${owner}/${repo}/git/commits`, {
|
|
135
|
-
message: opts.message,
|
|
136
|
-
tree: opts.tree,
|
|
137
|
-
parents: opts.parents
|
|
138
|
-
});
|
|
139
|
-
},
|
|
140
|
-
async createWebhook(owner, repo, opts) {
|
|
141
|
-
return request("POST", `/repos/${owner}/${repo}/hooks`, {
|
|
142
|
-
name: "web",
|
|
143
|
-
active: true,
|
|
144
|
-
events: opts.events,
|
|
145
|
-
config: {
|
|
146
|
-
url: opts.url,
|
|
147
|
-
secret: opts.secret,
|
|
148
|
-
content_type: "json",
|
|
149
|
-
insecure_ssl: "0"
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
},
|
|
153
|
-
async listWebhooks(owner, repo) {
|
|
154
|
-
return request("GET", `/repos/${owner}/${repo}/hooks`);
|
|
155
|
-
},
|
|
156
|
-
async deleteWebhook(owner, repo, hookId) {
|
|
157
|
-
await request("DELETE", `/repos/${owner}/${repo}/hooks/${hookId}`);
|
|
158
|
-
}
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* Parse an `owner/repo` string into its parts.
|
|
163
|
-
*
|
|
164
|
-
* @returns `{ owner, repo }` or `null` if the format is invalid.
|
|
165
|
-
*/ function parseRepoSlug(slug) {
|
|
166
|
-
const match = /^([a-zA-Z0-9_.-]+)\/([a-zA-Z0-9_.-]+)$/.exec(slug.trim());
|
|
167
|
-
if (!match) return null;
|
|
168
|
-
const [, owner, repo] = match;
|
|
169
|
-
if (!owner || !repo) return null;
|
|
170
|
-
return {
|
|
171
|
-
owner,
|
|
172
|
-
repo
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
//#endregion
|
|
176
|
-
export { github_api_exports as n, parseRepoSlug as r, createGitHubClient as t };
|
|
@@ -1,275 +0,0 @@
|
|
|
1
|
-
import { x as __exportAll } from "./url-CbLAtlZe.js";
|
|
2
|
-
//#region src/lib/github-app.ts
|
|
3
|
-
var github_app_exports = /* @__PURE__ */ __exportAll({
|
|
4
|
-
buildInstallUrl: () => buildInstallUrl,
|
|
5
|
-
createAppJwt: () => createAppJwt,
|
|
6
|
-
getInstallation: () => getInstallation,
|
|
7
|
-
getInstallationToken: () => getInstallationToken,
|
|
8
|
-
listInstallationReposPage: () => listInstallationReposPage,
|
|
9
|
-
searchInstallationRepos: () => searchInstallationRepos
|
|
10
|
-
});
|
|
11
|
-
/**
|
|
12
|
-
* GitHub App authentication helpers.
|
|
13
|
-
*
|
|
14
|
-
* Implements the App → installation token exchange using Web Crypto so it
|
|
15
|
-
* runs unchanged in Cloudflare Workers and Node 18+.
|
|
16
|
-
*
|
|
17
|
-
* Flow:
|
|
18
|
-
* 1. Sign a short-lived JWT with the App's RSA private key (RS256).
|
|
19
|
-
* 2. Exchange the JWT for a per-installation access token.
|
|
20
|
-
* 3. Cache the installation token in-process until shortly before expiry.
|
|
21
|
-
*
|
|
22
|
-
* The installation token can then be passed to `createGitHubClient` the same
|
|
23
|
-
* way a PAT is — the downstream client is auth-agnostic.
|
|
24
|
-
*/ var GITHUB_API = "https://api.github.com";
|
|
25
|
-
var tokenCache = /* @__PURE__ */ new Map();
|
|
26
|
-
var CACHE_SAFETY_MARGIN_SECONDS = 60;
|
|
27
|
-
function cacheKey(appId, installationId) {
|
|
28
|
-
return `${appId}:${installationId}`;
|
|
29
|
-
}
|
|
30
|
-
function base64UrlEncode(input) {
|
|
31
|
-
let bytes;
|
|
32
|
-
if (typeof input === "string") bytes = new TextEncoder().encode(input);
|
|
33
|
-
else if (input instanceof Uint8Array) bytes = input;
|
|
34
|
-
else bytes = new Uint8Array(input);
|
|
35
|
-
let binary = "";
|
|
36
|
-
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
37
|
-
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* ASN.1 DER length encoding (short form for < 128, long form otherwise).
|
|
41
|
-
* Used to wrap a PKCS#1 key inside a PKCS#8 envelope.
|
|
42
|
-
*/ function encodeDerLength(len) {
|
|
43
|
-
if (len < 128) return [len];
|
|
44
|
-
if (len <= 255) return [129, len];
|
|
45
|
-
if (len <= 65535) return [
|
|
46
|
-
130,
|
|
47
|
-
len >> 8 & 255,
|
|
48
|
-
len & 255
|
|
49
|
-
];
|
|
50
|
-
throw new Error("Private key too large to encode");
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Wrap a PKCS#1 `RSAPrivateKey` DER blob in a PKCS#8 `PrivateKeyInfo` envelope.
|
|
54
|
-
* Web Crypto's `importKey("pkcs8", ...)` only accepts PKCS#8, but GitHub
|
|
55
|
-
* hands out PKCS#1 PEMs (`-----BEGIN RSA PRIVATE KEY-----`) by default, so
|
|
56
|
-
* we wrap on the fly when we detect that header.
|
|
57
|
-
*/ function wrapPkcs1AsPkcs8(pkcs1) {
|
|
58
|
-
const rsaAlgorithmIdentifier = [
|
|
59
|
-
48,
|
|
60
|
-
13,
|
|
61
|
-
6,
|
|
62
|
-
9,
|
|
63
|
-
42,
|
|
64
|
-
134,
|
|
65
|
-
72,
|
|
66
|
-
134,
|
|
67
|
-
247,
|
|
68
|
-
13,
|
|
69
|
-
1,
|
|
70
|
-
1,
|
|
71
|
-
1,
|
|
72
|
-
5,
|
|
73
|
-
0
|
|
74
|
-
];
|
|
75
|
-
const version = [
|
|
76
|
-
2,
|
|
77
|
-
1,
|
|
78
|
-
0
|
|
79
|
-
];
|
|
80
|
-
const octetStringHeader = [4, ...encodeDerLength(pkcs1.length)];
|
|
81
|
-
const bodyLen = version.length + rsaAlgorithmIdentifier.length + octetStringHeader.length + pkcs1.length;
|
|
82
|
-
const outerHeader = [48, ...encodeDerLength(bodyLen)];
|
|
83
|
-
const out = new Uint8Array(outerHeader.length + bodyLen);
|
|
84
|
-
let off = 0;
|
|
85
|
-
out.set(outerHeader, off);
|
|
86
|
-
off += outerHeader.length;
|
|
87
|
-
out.set(version, off);
|
|
88
|
-
off += version.length;
|
|
89
|
-
out.set(rsaAlgorithmIdentifier, off);
|
|
90
|
-
off += rsaAlgorithmIdentifier.length;
|
|
91
|
-
out.set(octetStringHeader, off);
|
|
92
|
-
off += octetStringHeader.length;
|
|
93
|
-
out.set(pkcs1, off);
|
|
94
|
-
return out;
|
|
95
|
-
}
|
|
96
|
-
function pemToPkcs8(pem) {
|
|
97
|
-
const isPkcs1 = /-----BEGIN RSA PRIVATE KEY-----/.test(pem);
|
|
98
|
-
const cleaned = pem.replace(/-----BEGIN [^-]+-----/g, "").replace(/-----END [^-]+-----/g, "").replace(/\s+/g, "");
|
|
99
|
-
if (!cleaned) throw new Error("Empty GitHub App private key");
|
|
100
|
-
const binary = atob(cleaned);
|
|
101
|
-
const rawDer = new Uint8Array(binary.length);
|
|
102
|
-
for (let i = 0; i < binary.length; i++) rawDer[i] = binary.charCodeAt(i);
|
|
103
|
-
const pkcs8 = isPkcs1 ? wrapPkcs1AsPkcs8(rawDer) : rawDer;
|
|
104
|
-
const out = new ArrayBuffer(pkcs8.byteLength);
|
|
105
|
-
new Uint8Array(out).set(pkcs8);
|
|
106
|
-
return out;
|
|
107
|
-
}
|
|
108
|
-
async function importPrivateKey(pem) {
|
|
109
|
-
return crypto.subtle.importKey("pkcs8", pemToPkcs8(pem), {
|
|
110
|
-
name: "RSASSA-PKCS1-v1_5",
|
|
111
|
-
hash: "SHA-256"
|
|
112
|
-
}, false, ["sign"]);
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Create a JWT signed with the GitHub App's private key.
|
|
116
|
-
*
|
|
117
|
-
* GitHub allows up to 10 minutes; we issue 9 minutes with a 60s backdated `iat`
|
|
118
|
-
* to tolerate clock skew.
|
|
119
|
-
*/ async function createAppJwt(appId, privateKeyPem) {
|
|
120
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
121
|
-
const header = {
|
|
122
|
-
alg: "RS256",
|
|
123
|
-
typ: "JWT"
|
|
124
|
-
};
|
|
125
|
-
const payload = {
|
|
126
|
-
iat: now - 60,
|
|
127
|
-
exp: now + 540,
|
|
128
|
-
iss: appId
|
|
129
|
-
};
|
|
130
|
-
const signingInput = `${base64UrlEncode(JSON.stringify(header))}.${base64UrlEncode(JSON.stringify(payload))}`;
|
|
131
|
-
const key = await importPrivateKey(privateKeyPem);
|
|
132
|
-
return `${signingInput}.${base64UrlEncode(await crypto.subtle.sign("RSASSA-PKCS1-v1_5", key, new TextEncoder().encode(signingInput)))}`;
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Fetch (or reuse) a short-lived installation access token.
|
|
136
|
-
*
|
|
137
|
-
* Results are cached in-process until `CACHE_SAFETY_MARGIN_SECONDS` before the
|
|
138
|
-
* real expiry so the same token can be reused across a burst of API calls.
|
|
139
|
-
*/ async function getInstallationToken(app, installationId) {
|
|
140
|
-
const key = cacheKey(app.appId, installationId);
|
|
141
|
-
const cached = tokenCache.get(key);
|
|
142
|
-
const nowSec = Math.floor(Date.now() / 1e3);
|
|
143
|
-
if (cached && cached.expiresAt > nowSec) return cached.token;
|
|
144
|
-
const jwt = await createAppJwt(app.appId, app.privateKey);
|
|
145
|
-
const res = await fetch(`${GITHUB_API}/app/installations/${installationId}/access_tokens`, {
|
|
146
|
-
method: "POST",
|
|
147
|
-
headers: {
|
|
148
|
-
Accept: "application/vnd.github+json",
|
|
149
|
-
Authorization: `Bearer ${jwt}`,
|
|
150
|
-
"User-Agent": "jant-github-sync",
|
|
151
|
-
"X-GitHub-Api-Version": "2022-11-28"
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
if (!res.ok) {
|
|
155
|
-
const body = await res.text();
|
|
156
|
-
throw new Error(`GitHub App token exchange failed (${res.status}): ${body}`);
|
|
157
|
-
}
|
|
158
|
-
const data = await res.json();
|
|
159
|
-
const expiresAt = Math.floor(new Date(data.expires_at).getTime() / 1e3) - CACHE_SAFETY_MARGIN_SECONDS;
|
|
160
|
-
tokenCache.set(key, {
|
|
161
|
-
token: data.token,
|
|
162
|
-
expiresAt
|
|
163
|
-
});
|
|
164
|
-
return data.token;
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Build the URL users visit to install the GitHub App on their account/org.
|
|
168
|
-
*
|
|
169
|
-
* `state` is a CSRF token the caller should verify on the redirect back.
|
|
170
|
-
*/ function buildInstallUrl(slug, state) {
|
|
171
|
-
const params = new URLSearchParams({ state });
|
|
172
|
-
return `https://github.com/apps/${encodeURIComponent(slug)}/installations/new?${params.toString()}`;
|
|
173
|
-
}
|
|
174
|
-
/**
|
|
175
|
-
* Fetch metadata for a given installation, including the account it's
|
|
176
|
-
* installed on. Uses an App JWT because the target endpoint is
|
|
177
|
-
* `/app/installations/{id}`, which is App-scoped, not installation-scoped.
|
|
178
|
-
*/ async function getInstallation(app, installationId) {
|
|
179
|
-
const jwt = await createAppJwt(app.appId, app.privateKey);
|
|
180
|
-
const res = await fetch(`${GITHUB_API}/app/installations/${encodeURIComponent(installationId)}`, { headers: {
|
|
181
|
-
Accept: "application/vnd.github+json",
|
|
182
|
-
Authorization: `Bearer ${jwt}`,
|
|
183
|
-
"User-Agent": "jant-github-sync",
|
|
184
|
-
"X-GitHub-Api-Version": "2022-11-28"
|
|
185
|
-
} });
|
|
186
|
-
if (!res.ok) {
|
|
187
|
-
const body = await res.text();
|
|
188
|
-
throw new Error(`Fetching installation failed (${res.status}): ${body}`);
|
|
189
|
-
}
|
|
190
|
-
const data = await res.json();
|
|
191
|
-
const type = data.account.type === "Organization" ? "Organization" : "User";
|
|
192
|
-
return { account: {
|
|
193
|
-
login: data.account.login,
|
|
194
|
-
type,
|
|
195
|
-
avatarUrl: data.account.avatar_url ?? ""
|
|
196
|
-
} };
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Fetch a single page of installation repositories.
|
|
200
|
-
*
|
|
201
|
-
* Used by the picker for lazy-loading. Callers can either stop after the
|
|
202
|
-
* first page (UI does local filtering) or keep paging for larger accounts.
|
|
203
|
-
* For search, prefer `searchInstallationRepos` — this endpoint does not
|
|
204
|
-
* support a query parameter.
|
|
205
|
-
*/ async function listInstallationReposPage(app, installationId, page, perPage = 100) {
|
|
206
|
-
const token = await getInstallationToken(app, installationId);
|
|
207
|
-
const res = await fetch(`${GITHUB_API}/installation/repositories?per_page=${perPage}&page=${page}`, { headers: {
|
|
208
|
-
Accept: "application/vnd.github+json",
|
|
209
|
-
Authorization: `Bearer ${token}`,
|
|
210
|
-
"User-Agent": "jant-github-sync",
|
|
211
|
-
"X-GitHub-Api-Version": "2022-11-28"
|
|
212
|
-
} });
|
|
213
|
-
if (!res.ok) {
|
|
214
|
-
const body = await res.text();
|
|
215
|
-
throw new Error(`Listing installation repos failed: ${res.status} ${body}`);
|
|
216
|
-
}
|
|
217
|
-
const data = await res.json();
|
|
218
|
-
const repos = data.repositories.slice().sort((a, b) => {
|
|
219
|
-
const at = Date.parse(a.updated_at ?? a.created_at ?? "") || 0;
|
|
220
|
-
return (Date.parse(b.updated_at ?? b.created_at ?? "") || 0) - at;
|
|
221
|
-
}).map((r) => ({
|
|
222
|
-
fullName: r.full_name,
|
|
223
|
-
name: r.name,
|
|
224
|
-
private: r.private,
|
|
225
|
-
defaultBranch: r.default_branch
|
|
226
|
-
}));
|
|
227
|
-
const hasMore = repos.length === perPage;
|
|
228
|
-
return {
|
|
229
|
-
repos,
|
|
230
|
-
totalCount: data.total_count,
|
|
231
|
-
hasMore,
|
|
232
|
-
nextPage: hasMore ? page + 1 : null
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
/**
|
|
236
|
-
* Search the installation's repositories via `GET /search/repositories`.
|
|
237
|
-
*
|
|
238
|
-
* GitHub's Search API doesn't scope automatically to an installation, so
|
|
239
|
-
* we filter server-side by the installation's account login. This keeps
|
|
240
|
-
* results relevant while still covering repos past the first 100.
|
|
241
|
-
*
|
|
242
|
-
* The `q` string is wrapped (caller passes raw user input, we add the
|
|
243
|
-
* scope qualifier). Uses the installation token for auth.
|
|
244
|
-
*/ async function searchInstallationRepos(app, installationId, accountLogin, q, perPage = 30) {
|
|
245
|
-
const token = await getInstallationToken(app, installationId);
|
|
246
|
-
const fullQuery = `${q} in:name user:${accountLogin} fork:true`;
|
|
247
|
-
const params = new URLSearchParams({
|
|
248
|
-
q: fullQuery,
|
|
249
|
-
per_page: String(perPage),
|
|
250
|
-
sort: "updated",
|
|
251
|
-
order: "desc"
|
|
252
|
-
});
|
|
253
|
-
const res = await fetch(`${GITHUB_API}/search/repositories?${params.toString()}`, { headers: {
|
|
254
|
-
Accept: "application/vnd.github+json",
|
|
255
|
-
Authorization: `Bearer ${token}`,
|
|
256
|
-
"User-Agent": "jant-github-sync",
|
|
257
|
-
"X-GitHub-Api-Version": "2022-11-28"
|
|
258
|
-
} });
|
|
259
|
-
if (!res.ok) {
|
|
260
|
-
const body = await res.text();
|
|
261
|
-
throw new Error(`Searching repos failed: ${res.status} ${body}`);
|
|
262
|
-
}
|
|
263
|
-
const data = await res.json();
|
|
264
|
-
return {
|
|
265
|
-
repos: data.items.map((r) => ({
|
|
266
|
-
fullName: r.full_name,
|
|
267
|
-
name: r.name,
|
|
268
|
-
private: r.private,
|
|
269
|
-
defaultBranch: r.default_branch
|
|
270
|
-
})),
|
|
271
|
-
totalCount: data.total_count
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
//#endregion
|
|
275
|
-
export { listInstallationReposPage as a, github_app_exports as i, getInstallation as n, searchInstallationRepos as o, getInstallationToken as r, buildInstallUrl as t };
|