@jant/core 0.6.2 → 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/{app-Ct9c4zYF.js → app-B-wKZB8f.js} +267 -205
  2. package/dist/app-qwMcaTML.js +6 -0
  3. package/dist/client/.vite/manifest.json +3 -3
  4. package/dist/client/_assets/{client-Bp2IPjDe.js → client-B1XjvRqE.js} +1 -1
  5. package/dist/client/_assets/client-BMPMuwvV.css +2 -0
  6. package/dist/client/_assets/{client-auth-C4hQWqH1.js → client-auth-B9T2QFl2.js} +21 -21
  7. package/dist/{export-O2w3AsZX.js → export-CzuQyg5h.js} +28 -15
  8. package/dist/{github-sync-BUzIYouS.js → github-sync-CerNYCAn.js} +2 -2
  9. package/dist/{github-sync-D49RADci.js → github-sync-Dbrb1DS5.js} +5 -2
  10. package/dist/index.js +3 -3
  11. package/dist/node.js +4 -4
  12. package/package.json +1 -1
  13. package/src/__tests__/export-service.test.ts +127 -0
  14. package/src/app.tsx +7 -0
  15. package/src/client/components/__tests__/jant-collection-directory.test.ts +0 -42
  16. package/src/client/components/collection-manager-types.ts +0 -2
  17. package/src/client/components/jant-collection-directory.ts +0 -23
  18. package/src/i18n/locales/public/en.po +0 -12
  19. package/src/i18n/locales/public/zh-Hans.po +0 -12
  20. package/src/i18n/locales/public/zh-Hant.po +0 -12
  21. package/src/lib/github-sync-site-config.ts +4 -2
  22. package/src/middleware/__tests__/cache-control.test.ts +50 -0
  23. package/src/middleware/cache-control.ts +60 -0
  24. package/src/services/export-theme/styles/main.css +4 -3
  25. package/src/services/export.ts +47 -17
  26. package/src/services/github-sync.ts +8 -2
  27. package/src/styles/ui.css +23 -46
  28. package/src/ui/feed/ThreadPreview.tsx +17 -9
  29. package/src/ui/feed/__tests__/thread-preview.test.ts +131 -6
  30. package/src/ui/feed/thread-preview-state.ts +43 -0
  31. package/src/ui/pages/CollectionsPage.tsx +0 -22
  32. package/src/ui/shared/CollectionsManager.tsx +6 -41
  33. package/dist/app-CUZaVgsC.js +0 -6
  34. package/dist/client/_assets/client-YVrRjAid.css +0 -2
@@ -1,7 +1,7 @@
1
1
  import { _ as toPublicPath, a as getSitePathPrefix, c as normalizePath, d as sanitizeUrl, f as slugify, g as toPublicHref, h as toAbsoluteSiteUrl, i as getSiteOrigin, m as toAbsoluteAssetUrl, n as extractDisplayDomain, o as isFullUrl, p as stripSitePathPrefix, r as extractDomain, s as isSafeInternalRedirect, t as buildSiteUrl, u as normalizeSiteUrl, y as __exportAll } from "./url-XF0GbKGO.js";
2
- import { A as JANT_POSITIVE_LOGO_PNG_FILENAME, B as getJantLogoHref, C as formatYearMonth, D as HOME_BRANDING_LINK_LABEL, E as toISOString, F as getJantBundledAsset, G as base64ToUint8Array, H as JANT_LOGO_PATH_DATA, I as getJantIconFilename, L as getJantIconHref, M as getDefaultJantAppleTouchIconBytes, N as getDefaultJantFaviconIcoBytes, O as HOME_BRANDING_PREFIX, P as getJantBrandPackHref, R as getJantLogoFilename, S as formatTime, U as JANT_LOGO_VIEW_BOX, V as getJantPositiveLogoPngHref, W as arrayBufferToBase64, _ as getMediaUrl, b as formatRelativeAge, d as extractSummaryHtml, f as renderTiptapDocument, g as getImageUrl, h as escapeHtml, i as tiptapJsonToMarkdown, j as JANT_REPO_URL, k as JANT_BRAND_PACK_FILENAME, l as extractBodyText, m as trimTiptapBody, o as render, p as renderTiptapJson, s as toPlainText, t as createExportService, u as extractSummary, v as getPublicUrlForProvider, w as now, x as formatRelativeTime, y as formatDate, z as getJantLogoFills } from "./export-O2w3AsZX.js";
2
+ import { A as JANT_POSITIVE_LOGO_PNG_FILENAME, B as getJantLogoHref, C as formatYearMonth, D as HOME_BRANDING_LINK_LABEL, E as toISOString, F as getJantBundledAsset, G as base64ToUint8Array, H as JANT_LOGO_PATH_DATA, I as getJantIconFilename, L as getJantIconHref, M as getDefaultJantAppleTouchIconBytes, N as getDefaultJantFaviconIcoBytes, O as HOME_BRANDING_PREFIX, P as getJantBrandPackHref, R as getJantLogoFilename, S as formatTime, U as JANT_LOGO_VIEW_BOX, V as getJantPositiveLogoPngHref, W as arrayBufferToBase64, _ as getMediaUrl, b as formatRelativeAge, d as extractSummaryHtml, f as renderTiptapDocument, g as getImageUrl, h as escapeHtml, i as tiptapJsonToMarkdown, j as JANT_REPO_URL, k as JANT_BRAND_PACK_FILENAME, l as extractBodyText, m as trimTiptapBody, o as render, p as renderTiptapJson, s as toPlainText, t as createExportService, u as extractSummary, v as getPublicUrlForProvider, w as now, x as formatRelativeTime, y as formatDate, z as getJantLogoFills } from "./export-CzuQyg5h.js";
3
3
  import { S as getTelegramWebhookSecret, T as coalesceDisplayText, _ as getInternalAdminToken, a as getConfiguredSingleSiteUrl, b as getSiteResolutionMode, c as getDevApiToken, d as getHostedControlPlaneBaseUrl, f as getHostedControlPlaneDomainCheckSecret, g as getHostedControlPlaneSsoSecret, h as getHostedControlPlaneProviderLabel$1, i as getConfiguredSingleSitePathPrefix, l as getEnvString, m as getHostedControlPlaneInternalToken, n as getAuthSecret, o as getConfiguredStorageDriver, p as getHostedControlPlaneInternalBaseUrl, r as getConfiguredSingleSiteOrigin, s as getCorsOrigins, u as getGitHubAppConfig, v as getLocalStoragePath, w as shouldUseSecureCookies, x as getTelegramBotPool } from "./env-CoSe-1y4.js";
4
- import { l as markdownToTiptapJson, o as createGitHubSyncService } from "./github-sync-D49RADci.js";
4
+ import { l as markdownToTiptapJson, o as createGitHubSyncService } from "./github-sync-Dbrb1DS5.js";
5
5
  import { a as listInstallationReposPage, n as getInstallation, o as searchInstallationRepos, t as buildInstallUrl } from "./github-app-DeX6Td1O.js";
6
6
  import { r as parseRepoSlug, t as createGitHubClient } from "./github-api-UD4u_7fa.js";
7
7
  import { I18n } from "@lingui/core";
@@ -3419,10 +3419,10 @@ function normalizeThemeColorForMeta(color) {
3419
3419
  * internal paths (e.g. `/_assets/client-HASH.js`) embedded by the Worker build
3420
3420
  * from the Vite client manifest. Used only in production (IS_VITE_DEV=false).
3421
3421
  */ var IS_VITE_DEV = typeof __JANT_DEV__ !== "undefined" && __JANT_DEV__ === true;
3422
- var CORE_VERSION = "0.6.2-8079c34aafb81d4b";
3423
- var CLIENT_JS_FILE = "/_assets/client-Bp2IPjDe.js";
3424
- var CLIENT_AUTH_JS_FILE = "/_assets/client-auth-C4hQWqH1.js";
3425
- var CLIENT_CSS_FILE = "/_assets/client-YVrRjAid.css";
3422
+ var CORE_VERSION = "0.6.4-619b1a90eba61395";
3423
+ var CLIENT_JS_FILE = "/_assets/client-B1XjvRqE.js";
3424
+ var CLIENT_AUTH_JS_FILE = "/_assets/client-auth-B9T2QFl2.js";
3425
+ var CLIENT_CSS_FILE = "/_assets/client-BMPMuwvV.css";
3426
3426
  var CLIENT_CJK_CSS_FILE = "/_assets/client-cjk-B7Z0snDu.css";
3427
3427
  var CLIENT_CJK_TC_CSS_FILE = "/_assets/client-cjk-tc-BesJYrb2.css";
3428
3428
  var CLIENT_CJK_JP_CSS_FILE = "/_assets/client-cjk-jp-DZwrTzQC.css";
@@ -3740,7 +3740,7 @@ var IconSprite = () => {
3740
3740
  const cjkSerifFont = appConfig?.cjkSerifFont ?? "off";
3741
3741
  const cjkStylesheetPath = cjkSerifFont === "zh-Hans" ? IS_VITE_DEV ? assetPath("/src/style-cjk.css") : toPublicAssetPath(CLIENT_CJK_CSS_FILE, assetBasePath) : cjkSerifFont === "zh-Hant" ? IS_VITE_DEV ? assetPath("/src/style-cjk-tc.css") : toPublicAssetPath(CLIENT_CJK_TC_CSS_FILE, assetBasePath) : cjkSerifFont === "ja" ? IS_VITE_DEV ? assetPath("/src/style-cjk-jp.css") : toPublicAssetPath(CLIENT_CJK_JP_CSS_FILE, assetBasePath) : cjkSerifFont === "ko" ? IS_VITE_DEV ? assetPath("/src/style-cjk-kr.css") : toPublicAssetPath(CLIENT_CJK_KR_CSS_FILE, assetBasePath) : null;
3742
3742
  const clientScriptPath = IS_VITE_DEV ? resolvedClientBundle === "full" ? assetPath("/src/client-auth.ts") : assetPath("/src/client.ts") : toPublicAssetPath(resolvedClientBundle === "full" ? CLIENT_AUTH_JS_FILE : CLIENT_JS_FILE, assetBasePath);
3743
- const faviconAssetVersion = resolvedFaviconVersion || "0.6.2-8079c34aafb81d4b";
3743
+ const faviconAssetVersion = resolvedFaviconVersion || "0.6.4-619b1a90eba61395";
3744
3744
  const resolvedFaviconHref = faviconHref ?? (faviconAssetVersion ? toPublicPath(`/favicon.ico?v=${faviconAssetVersion}`, sitePathPrefix) : toPublicPath("/favicon.ico", sitePathPrefix));
3745
3745
  const resolvedAppleTouchHref = appleTouchHref ?? (faviconAssetVersion ? toPublicPath(`/apple-touch-icon.png?v=${faviconAssetVersion}`, sitePathPrefix) : toPublicPath("/apple-touch-icon.png", sitePathPrefix));
3746
3746
  const socialImageHref = resolvedSocialImagePath ? toAbsoluteAssetUrl(resolvedSocialImagePath, appConfig?.siteUrl || "", sitePathPrefix) : "";
@@ -10112,6 +10112,35 @@ function getThreadPreviewState({ secondReply, penultimateReply, latestReply, tot
10112
10112
  ].filter((post) => post !== void 0).map((post) => post.id));
10113
10113
  return { hiddenCount: Math.max(0, totalReplyCount - visibleReplyIds.size) };
10114
10114
  }
10115
+ /**
10116
+ * A lone root post shorter than this (plain-text code points) comfortably
10117
+ * fits the thread-context height cap. Pairs with the
10118
+ * `--site-thread-context-max-height` token (160px) in tokens.css — revisit
10119
+ * both together if that cap changes.
10120
+ */ var SHORT_ROOT_CHAR_LIMIT = 120;
10121
+ /**
10122
+ * First-paint guess for whether the thread-context shell will overflow its
10123
+ * height cap, used to pick the initial "Show more" toggle visibility.
10124
+ *
10125
+ * The client (thread-context.ts) always re-measures and corrects this, so a
10126
+ * wrong guess costs at most a one-time flash on load — never a wrong final
10127
+ * state. Kept deliberately coarse:
10128
+ *
10129
+ * - 3+ post threads stack 2+ cards in the shell — effectively always overflow.
10130
+ * - A lone root carrying media is tall regardless of its text length.
10131
+ * - Otherwise fall back to a plain-text length threshold. Only clearly short
10132
+ * roots flip to "fits"; anything at or above the limit keeps the historical
10133
+ * "assume overflow" default, so this can only remove flashes, never add them.
10134
+ *
10135
+ * @param rootPost - the thread's root post (the only post in a 2-post thread's
10136
+ * shell)
10137
+ * @param totalReplyCount - replies in the thread; `>= 2` means 3+ posts total
10138
+ * @returns whether to render the toggle visible on first paint
10139
+ */ function threadContextAssumesOverflow({ rootPost, totalReplyCount }) {
10140
+ if (totalReplyCount >= 2) return true;
10141
+ if (rootPost.media.length > 0 || Boolean(rootPost.previewImageUrl)) return true;
10142
+ return [...rootPost.summary ?? ""].length >= SHORT_ROOT_CHAR_LIMIT;
10143
+ }
10115
10144
  //#endregion
10116
10145
  //#region src/ui/feed/ThreadPreview.tsx
10117
10146
  /**
@@ -10133,6 +10162,10 @@ var ThreadPreview = ({ rootPost, secondReply, penultimateReply, latestReply, tot
10133
10162
  latestReply,
10134
10163
  totalReplyCount
10135
10164
  });
10165
+ const assumeOverflow = threadContextAssumesOverflow({
10166
+ rootPost,
10167
+ totalReplyCount
10168
+ });
10136
10169
  const hiddenPostsLabel = i18n._({ id: "oO0hKx" }, { count: hiddenCount });
10137
10170
  const showMoreLabel = i18n._({ id: "fMPkxb" });
10138
10171
  const showLessLabel = i18n._({ id: "6lGV3K" });
@@ -10192,6 +10225,7 @@ var ThreadPreview = ({ rootPost, secondReply, penultimateReply, latestReply, tot
10192
10225
  "data-label-more": showMoreLabel,
10193
10226
  "data-label-less": showLessLabel,
10194
10227
  "aria-expanded": "false",
10228
+ hidden: !assumeOverflow,
10195
10229
  children: [/* @__PURE__ */ jsxDEV$1("span", {
10196
10230
  class: "thread-context-toggle-label",
10197
10231
  children: showMoreLabel
@@ -15153,18 +15187,13 @@ var CollectionDirectory = ({ items, emptyMessage, sitePathPrefix = "" }) => {
15153
15187
  //#endregion
15154
15188
  //#region src/ui/shared/CollectionsManager.tsx
15155
15189
  var escapeJson = (data) => JSON.stringify(data).replace(/</g, "\\u003c");
15156
- var countCollections$1 = (items) => items.filter((item) => item.type === "collection" && item.collection).length;
15157
15190
  var CollectionsManager = ({ items, sitePathPrefix = "" }) => {
15158
15191
  const { i18n } = useLingui();
15159
15192
  const collectionsHref = toPublicPath(getCollectionsDirectoryPath(), sitePathPrefix);
15160
15193
  const newCollectionHref = toPublicPath(`${getNewCollectionPath()}?returnTo=${encodeURIComponent(collectionsHref)}`, sitePathPrefix);
15161
- const collectionCount = countCollections$1(items);
15162
- const collectionCountLabel = `${collectionCount} ${collectionCount === 1 ? i18n._({ id: "sgr2wQ" }) : i18n._({ id: "CAh1km" })}`;
15163
15194
  const mutationLabels = getCollectionMutationLabels(i18n);
15164
15195
  const labels = {
15165
15196
  collectionsTitle: i18n._({ id: "DoJzLz" }),
15166
- collectionSingular: i18n._({ id: "sgr2wQ" }),
15167
- collectionPlural: i18n._({ id: "CAh1km" }),
15168
15197
  organize: i18n._({ id: "nV6twc" }),
15169
15198
  done: i18n._({ id: "DPfwMq" }),
15170
15199
  organizeHint: i18n._({ id: "r7kcaA" }),
@@ -15187,192 +15216,182 @@ var CollectionsManager = ({ items, sitePathPrefix = "" }) => {
15187
15216
  class: "collections-page-header",
15188
15217
  children: /* @__PURE__ */ jsxDEV$1("div", {
15189
15218
  class: "collections-page-heading page-intro",
15190
- children: [
15191
- /* @__PURE__ */ jsxDEV$1("div", {
15192
- class: "page-intro-title-row",
15193
- children: /* @__PURE__ */ jsxDEV$1("h1", {
15194
- class: "page-intro-title",
15195
- children: labels.collectionsTitle
15196
- })
15197
- }),
15198
- /* @__PURE__ */ jsxDEV$1("div", {
15199
- class: "page-intro-meta-row",
15200
- children: [/* @__PURE__ */ jsxDEV$1("p", {
15201
- class: "page-intro-meta",
15202
- "data-collections-count": true,
15203
- children: collectionCountLabel
15219
+ children: [/* @__PURE__ */ jsxDEV$1("div", {
15220
+ class: "page-intro-title-row",
15221
+ children: [/* @__PURE__ */ jsxDEV$1("h1", {
15222
+ class: "page-intro-title",
15223
+ children: labels.collectionsTitle
15224
+ }), /* @__PURE__ */ jsxDEV$1("div", {
15225
+ class: "collections-page-actions",
15226
+ children: [/* @__PURE__ */ jsxDEV$1("div", {
15227
+ class: "collections-page-action-group",
15228
+ "data-collections-reorder-actions": true,
15229
+ hidden: true,
15230
+ children: [/* @__PURE__ */ jsxDEV$1("button", {
15231
+ type: "button",
15232
+ class: "btn-outline",
15233
+ "data-collections-action": "divider",
15234
+ children: labels.newDivider
15235
+ }), /* @__PURE__ */ jsxDEV$1("button", {
15236
+ type: "button",
15237
+ class: "btn-outline",
15238
+ "data-collections-action": "done",
15239
+ children: labels.done
15240
+ })]
15204
15241
  }), /* @__PURE__ */ jsxDEV$1("div", {
15205
- class: "collections-page-actions",
15206
- children: [/* @__PURE__ */ jsxDEV$1("div", {
15207
- class: "collections-page-action-group",
15208
- "data-collections-reorder-actions": true,
15209
- hidden: true,
15242
+ class: "collections-page-action-group",
15243
+ "data-collections-toolbar": true,
15244
+ children: [/* @__PURE__ */ jsxDEV$1("a", {
15245
+ href: newCollectionHref,
15246
+ class: "collections-page-toolbar-button",
15247
+ "aria-label": labels.newCollection,
15248
+ title: labels.newCollection,
15249
+ children: /* @__PURE__ */ jsxDEV$1("svg", {
15250
+ xmlns: "http://www.w3.org/2000/svg",
15251
+ width: "18",
15252
+ height: "18",
15253
+ viewBox: "0 0 24 24",
15254
+ fill: "none",
15255
+ stroke: "currentColor",
15256
+ "stroke-width": "2",
15257
+ "stroke-linecap": "round",
15258
+ "stroke-linejoin": "round",
15259
+ "aria-hidden": "true",
15260
+ children: [/* @__PURE__ */ jsxDEV$1("path", { d: "M12 5v14" }), /* @__PURE__ */ jsxDEV$1("path", { d: "M5 12h14" })]
15261
+ })
15262
+ }), /* @__PURE__ */ jsxDEV$1("div", {
15263
+ class: "relative",
15210
15264
  children: [/* @__PURE__ */ jsxDEV$1("button", {
15211
15265
  type: "button",
15212
- class: "btn-outline",
15213
- "data-collections-action": "divider",
15214
- children: labels.newDivider
15215
- }), /* @__PURE__ */ jsxDEV$1("button", {
15216
- type: "button",
15217
- class: "btn-outline",
15218
- "data-collections-action": "done",
15219
- children: labels.done
15220
- })]
15221
- }), /* @__PURE__ */ jsxDEV$1("div", {
15222
- class: "collections-page-action-group",
15223
- "data-collections-toolbar": true,
15224
- children: [/* @__PURE__ */ jsxDEV$1("a", {
15225
- href: newCollectionHref,
15226
15266
  class: "collections-page-toolbar-button",
15227
- "aria-label": labels.newCollection,
15228
- title: labels.newCollection,
15267
+ "aria-label": labels.moreActions,
15268
+ "aria-expanded": "false",
15269
+ "aria-haspopup": "menu",
15270
+ title: labels.moreActions,
15271
+ "data-collections-action": "toggle-menu",
15229
15272
  children: /* @__PURE__ */ jsxDEV$1("svg", {
15230
15273
  xmlns: "http://www.w3.org/2000/svg",
15231
- width: "16",
15232
- height: "16",
15274
+ width: "18",
15275
+ height: "18",
15233
15276
  viewBox: "0 0 24 24",
15234
- fill: "none",
15235
- stroke: "currentColor",
15236
- "stroke-width": "2",
15237
- "stroke-linecap": "round",
15238
- "stroke-linejoin": "round",
15239
- children: [/* @__PURE__ */ jsxDEV$1("path", { d: "M12 5v14" }), /* @__PURE__ */ jsxDEV$1("path", { d: "M5 12h14" })]
15240
- })
15241
- }), /* @__PURE__ */ jsxDEV$1("div", {
15242
- class: "relative",
15243
- children: [/* @__PURE__ */ jsxDEV$1("button", {
15244
- type: "button",
15245
- class: "collections-page-toolbar-button collections-page-more-btn",
15246
- "aria-label": labels.moreActions,
15247
- "aria-expanded": "false",
15248
- "aria-haspopup": "menu",
15249
- title: labels.moreActions,
15250
- "data-collections-action": "toggle-menu",
15251
- children: /* @__PURE__ */ jsxDEV$1("svg", {
15252
- xmlns: "http://www.w3.org/2000/svg",
15253
- width: "16",
15254
- height: "16",
15255
- viewBox: "0 0 24 24",
15256
- fill: "currentColor",
15257
- children: [
15258
- /* @__PURE__ */ jsxDEV$1("circle", {
15259
- cx: "5",
15260
- cy: "12",
15261
- r: "2"
15262
- }),
15263
- /* @__PURE__ */ jsxDEV$1("circle", {
15264
- cx: "12",
15265
- cy: "12",
15266
- r: "2"
15267
- }),
15268
- /* @__PURE__ */ jsxDEV$1("circle", {
15269
- cx: "19",
15270
- cy: "12",
15271
- r: "2"
15272
- })
15273
- ]
15274
- })
15275
- }), /* @__PURE__ */ jsxDEV$1("div", {
15276
- class: "collections-page-menu",
15277
- "data-collections-more-menu": true,
15278
- hidden: true,
15277
+ fill: "currentColor",
15279
15278
  children: [
15280
- /* @__PURE__ */ jsxDEV$1("button", {
15281
- type: "button",
15282
- class: "collections-page-menu-item",
15283
- "data-collections-action": "organize",
15284
- children: [/* @__PURE__ */ jsxDEV$1("span", {
15285
- class: "collections-page-menu-item-icon",
15286
- "aria-hidden": "true",
15287
- children: /* @__PURE__ */ jsxDEV$1("svg", {
15288
- xmlns: "http://www.w3.org/2000/svg",
15289
- width: "16",
15290
- height: "16",
15291
- viewBox: "0 0 24 24",
15292
- fill: "none",
15293
- stroke: "currentColor",
15294
- "stroke-width": "2",
15295
- "stroke-linecap": "round",
15296
- "stroke-linejoin": "round",
15297
- children: [
15298
- /* @__PURE__ */ jsxDEV$1("path", { d: "M8 6h13" }),
15299
- /* @__PURE__ */ jsxDEV$1("path", { d: "M8 12h13" }),
15300
- /* @__PURE__ */ jsxDEV$1("path", { d: "M8 18h13" }),
15301
- /* @__PURE__ */ jsxDEV$1("path", { d: "M3 6h.01" }),
15302
- /* @__PURE__ */ jsxDEV$1("path", { d: "M3 12h.01" }),
15303
- /* @__PURE__ */ jsxDEV$1("path", { d: "M3 18h.01" })
15304
- ]
15305
- })
15306
- }), /* @__PURE__ */ jsxDEV$1("span", {
15307
- class: "collections-page-menu-item-label",
15308
- children: labels.organize
15309
- })]
15279
+ /* @__PURE__ */ jsxDEV$1("circle", {
15280
+ cx: "5",
15281
+ cy: "12",
15282
+ r: "2"
15310
15283
  }),
15311
- /* @__PURE__ */ jsxDEV$1("button", {
15312
- type: "button",
15313
- class: "collections-page-menu-item",
15314
- "data-collections-action": "link",
15315
- children: [/* @__PURE__ */ jsxDEV$1("span", {
15316
- class: "collections-page-menu-item-icon",
15317
- "aria-hidden": "true",
15318
- children: /* @__PURE__ */ jsxDEV$1("svg", {
15319
- xmlns: "http://www.w3.org/2000/svg",
15320
- width: "16",
15321
- height: "16",
15322
- viewBox: "0 0 24 24",
15323
- fill: "none",
15324
- stroke: "currentColor",
15325
- "stroke-width": "2",
15326
- "stroke-linecap": "round",
15327
- "stroke-linejoin": "round",
15328
- children: [/* @__PURE__ */ jsxDEV$1("path", { d: "M10 13a5 5 0 0 0 7.54.54l2.92-2.92a5 5 0 0 0-7.07-7.08L11.7 5.24" }), /* @__PURE__ */ jsxDEV$1("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-2.92 2.92a5 5 0 0 0 7.07 7.08l1.69-1.7" })]
15329
- })
15330
- }), /* @__PURE__ */ jsxDEV$1("span", {
15331
- class: "collections-page-menu-item-label",
15332
- children: labels.newLink
15333
- })]
15284
+ /* @__PURE__ */ jsxDEV$1("circle", {
15285
+ cx: "12",
15286
+ cy: "12",
15287
+ r: "2"
15334
15288
  }),
15335
- /* @__PURE__ */ jsxDEV$1("button", {
15336
- type: "button",
15337
- class: "collections-page-menu-item",
15338
- "data-collections-action": "divider",
15339
- children: [/* @__PURE__ */ jsxDEV$1("span", {
15340
- class: "collections-page-menu-item-icon",
15341
- "aria-hidden": "true",
15342
- children: /* @__PURE__ */ jsxDEV$1("svg", {
15343
- xmlns: "http://www.w3.org/2000/svg",
15344
- width: "16",
15345
- height: "16",
15346
- viewBox: "0 0 24 24",
15347
- fill: "none",
15348
- stroke: "currentColor",
15349
- "stroke-width": "2",
15350
- "stroke-linecap": "round",
15351
- "stroke-linejoin": "round",
15352
- children: [
15353
- /* @__PURE__ */ jsxDEV$1("path", { d: "M4 8h16" }),
15354
- /* @__PURE__ */ jsxDEV$1("path", { d: "M4 16h6" }),
15355
- /* @__PURE__ */ jsxDEV$1("path", { d: "M14 16h6" })
15356
- ]
15357
- })
15358
- }), /* @__PURE__ */ jsxDEV$1("span", {
15359
- class: "collections-page-menu-item-label",
15360
- children: labels.newDivider
15361
- })]
15289
+ /* @__PURE__ */ jsxDEV$1("circle", {
15290
+ cx: "19",
15291
+ cy: "12",
15292
+ r: "2"
15362
15293
  })
15363
15294
  ]
15364
- })]
15295
+ })
15296
+ }), /* @__PURE__ */ jsxDEV$1("div", {
15297
+ class: "collections-page-menu",
15298
+ "data-collections-more-menu": true,
15299
+ hidden: true,
15300
+ children: [
15301
+ /* @__PURE__ */ jsxDEV$1("button", {
15302
+ type: "button",
15303
+ class: "collections-page-menu-item",
15304
+ "data-collections-action": "organize",
15305
+ children: [/* @__PURE__ */ jsxDEV$1("span", {
15306
+ class: "collections-page-menu-item-icon",
15307
+ "aria-hidden": "true",
15308
+ children: /* @__PURE__ */ jsxDEV$1("svg", {
15309
+ xmlns: "http://www.w3.org/2000/svg",
15310
+ width: "16",
15311
+ height: "16",
15312
+ viewBox: "0 0 24 24",
15313
+ fill: "none",
15314
+ stroke: "currentColor",
15315
+ "stroke-width": "2",
15316
+ "stroke-linecap": "round",
15317
+ "stroke-linejoin": "round",
15318
+ children: [
15319
+ /* @__PURE__ */ jsxDEV$1("path", { d: "M8 6h13" }),
15320
+ /* @__PURE__ */ jsxDEV$1("path", { d: "M8 12h13" }),
15321
+ /* @__PURE__ */ jsxDEV$1("path", { d: "M8 18h13" }),
15322
+ /* @__PURE__ */ jsxDEV$1("path", { d: "M3 6h.01" }),
15323
+ /* @__PURE__ */ jsxDEV$1("path", { d: "M3 12h.01" }),
15324
+ /* @__PURE__ */ jsxDEV$1("path", { d: "M3 18h.01" })
15325
+ ]
15326
+ })
15327
+ }), /* @__PURE__ */ jsxDEV$1("span", {
15328
+ class: "collections-page-menu-item-label",
15329
+ children: labels.organize
15330
+ })]
15331
+ }),
15332
+ /* @__PURE__ */ jsxDEV$1("button", {
15333
+ type: "button",
15334
+ class: "collections-page-menu-item",
15335
+ "data-collections-action": "link",
15336
+ children: [/* @__PURE__ */ jsxDEV$1("span", {
15337
+ class: "collections-page-menu-item-icon",
15338
+ "aria-hidden": "true",
15339
+ children: /* @__PURE__ */ jsxDEV$1("svg", {
15340
+ xmlns: "http://www.w3.org/2000/svg",
15341
+ width: "16",
15342
+ height: "16",
15343
+ viewBox: "0 0 24 24",
15344
+ fill: "none",
15345
+ stroke: "currentColor",
15346
+ "stroke-width": "2",
15347
+ "stroke-linecap": "round",
15348
+ "stroke-linejoin": "round",
15349
+ children: [/* @__PURE__ */ jsxDEV$1("path", { d: "M10 13a5 5 0 0 0 7.54.54l2.92-2.92a5 5 0 0 0-7.07-7.08L11.7 5.24" }), /* @__PURE__ */ jsxDEV$1("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-2.92 2.92a5 5 0 0 0 7.07 7.08l1.69-1.7" })]
15350
+ })
15351
+ }), /* @__PURE__ */ jsxDEV$1("span", {
15352
+ class: "collections-page-menu-item-label",
15353
+ children: labels.newLink
15354
+ })]
15355
+ }),
15356
+ /* @__PURE__ */ jsxDEV$1("button", {
15357
+ type: "button",
15358
+ class: "collections-page-menu-item",
15359
+ "data-collections-action": "divider",
15360
+ children: [/* @__PURE__ */ jsxDEV$1("span", {
15361
+ class: "collections-page-menu-item-icon",
15362
+ "aria-hidden": "true",
15363
+ children: /* @__PURE__ */ jsxDEV$1("svg", {
15364
+ xmlns: "http://www.w3.org/2000/svg",
15365
+ width: "16",
15366
+ height: "16",
15367
+ viewBox: "0 0 24 24",
15368
+ fill: "none",
15369
+ stroke: "currentColor",
15370
+ "stroke-width": "2",
15371
+ "stroke-linecap": "round",
15372
+ "stroke-linejoin": "round",
15373
+ children: [
15374
+ /* @__PURE__ */ jsxDEV$1("path", { d: "M4 8h16" }),
15375
+ /* @__PURE__ */ jsxDEV$1("path", { d: "M4 16h6" }),
15376
+ /* @__PURE__ */ jsxDEV$1("path", { d: "M14 16h6" })
15377
+ ]
15378
+ })
15379
+ }), /* @__PURE__ */ jsxDEV$1("span", {
15380
+ class: "collections-page-menu-item-label",
15381
+ children: labels.newDivider
15382
+ })]
15383
+ })
15384
+ ]
15365
15385
  })]
15366
15386
  })]
15367
15387
  })]
15368
- }),
15369
- /* @__PURE__ */ jsxDEV$1("p", {
15370
- class: "page-intro-description",
15371
- "data-collections-hint": true,
15372
- hidden: true,
15373
- children: labels.organizeHint
15374
- })
15375
- ]
15388
+ })]
15389
+ }), /* @__PURE__ */ jsxDEV$1("p", {
15390
+ class: "page-intro-description",
15391
+ "data-collections-hint": true,
15392
+ hidden: true,
15393
+ children: labels.organizeHint
15394
+ })]
15376
15395
  })
15377
15396
  }), /* @__PURE__ */ jsxDEV$1("jant-collections-manager", {
15378
15397
  items: escapeJson(items),
@@ -15391,12 +15410,9 @@ var CollectionsManager = ({ items, sitePathPrefix = "" }) => {
15391
15410
  * Collections Listing Page
15392
15411
  *
15393
15412
  * Single-column directory of collections.
15394
- */ var countCollections = (items) => items.filter((item) => item.type === "collection" && item.collection).length;
15395
- var CollectionsPage = ({ items, isAuthenticated, sitePathPrefix = "" }) => {
15413
+ */ var CollectionsPage = ({ items, isAuthenticated, sitePathPrefix = "" }) => {
15396
15414
  const { i18n } = useLingui();
15397
- const collectionCount = countCollections(items);
15398
15415
  const emptyMessage = i18n._({ id: "kr39oD" });
15399
- const collectionCountLabel = `${collectionCount} ${collectionCount === 1 ? i18n._({ id: "sgr2wQ" }) : i18n._({ id: "CAh1km" })}`;
15400
15416
  if (isAuthenticated) return /* @__PURE__ */ jsxDEV$1("div", {
15401
15417
  class: "py-6",
15402
15418
  "data-page": "collections",
@@ -15414,19 +15430,13 @@ var CollectionsPage = ({ items, isAuthenticated, sitePathPrefix = "" }) => {
15414
15430
  class: "collections-page-header",
15415
15431
  children: /* @__PURE__ */ jsxDEV$1("div", {
15416
15432
  class: "collections-page-heading page-intro",
15417
- children: [/* @__PURE__ */ jsxDEV$1("div", {
15433
+ children: /* @__PURE__ */ jsxDEV$1("div", {
15418
15434
  class: "page-intro-title-row",
15419
15435
  children: /* @__PURE__ */ jsxDEV$1("h1", {
15420
15436
  class: "page-intro-title",
15421
15437
  children: i18n._({ id: "DoJzLz" })
15422
15438
  })
15423
- }), /* @__PURE__ */ jsxDEV$1("div", {
15424
- class: "page-intro-meta-row",
15425
- children: /* @__PURE__ */ jsxDEV$1("p", {
15426
- class: "page-intro-meta",
15427
- children: collectionCountLabel
15428
- })
15429
- })]
15439
+ })
15430
15440
  })
15431
15441
  }), /* @__PURE__ */ jsxDEV$1(CollectionDirectory, {
15432
15442
  items,
@@ -21058,8 +21068,10 @@ async function syncHostedControlPlaneSiteAvatar(input) {
21058
21068
  * call site had its own near-identical copy.
21059
21069
  *
21060
21070
  * The shape mirrors `routes/api/export.ts` so `jant site export` and
21061
- * `jant github sync` produce byte-identical Hugo sites (modulo media
21062
- * files, which Sync intentionally skips). If you add a field to the
21071
+ * `jant github sync` produce matching Hugo sites. They differ only in
21072
+ * media: `site export` bundles attachment bytes into `static/media/` for
21073
+ * a self-contained archive, while Sync links attachments by URL and
21074
+ * never writes their bytes into the repo. If you add a field to the
21063
21075
  * export route, add it here too.
21064
21076
  */ async function buildSyncSiteConfig(c) {
21065
21077
  const { services, appConfig, allSettings, themeStyle } = c.var;
@@ -21168,7 +21180,7 @@ async function syncHostedControlPlaneSiteAvatar(input) {
21168
21180
  return;
21169
21181
  }
21170
21182
  await markSyncPending(settings);
21171
- const { createGitHubSyncService } = await import("./github-sync-BUzIYouS.js");
21183
+ const { createGitHubSyncService } = await import("./github-sync-CerNYCAn.js");
21172
21184
  const { getGitHubAppConfig } = await import("./env-CoSe-1y4.js").then((n) => n.t);
21173
21185
  const run = runBackgroundSync(settings, createGitHubSyncService(c.var.services, c.var.currentSite.id, await buildSyncSiteConfig(c), {
21174
21186
  storage: c.var.storage,
@@ -21956,7 +21968,7 @@ settingsRoutes.post("/github-sync/connect", async (c) => {
21956
21968
  await c.var.services.settings.set("GITHUB_SYNC_AUTH_MODE", "pat");
21957
21969
  await c.var.services.settings.set("GITHUB_SYNC_APP_INSTALLATION_ID", "");
21958
21970
  await c.var.services.settings.set("GITHUB_SYNC_ENABLED", "true");
21959
- const { createGitHubSyncService } = await import("./github-sync-BUzIYouS.js");
21971
+ const { createGitHubSyncService } = await import("./github-sync-CerNYCAn.js");
21960
21972
  const syncService = createGitHubSyncService(c.var.services, c.var.currentSite.id, await buildSyncSiteConfig(c), {
21961
21973
  storage: c.var.storage,
21962
21974
  githubApp: getGitHubAppConfig(c.env)
@@ -21975,7 +21987,7 @@ settingsRoutes.post("/github-sync/connect", async (c) => {
21975
21987
  return dsRedirect(publicPath(c, "/settings/github-sync"));
21976
21988
  });
21977
21989
  settingsRoutes.post("/github-sync/push", async (c) => {
21978
- const { createGitHubSyncService } = await import("./github-sync-BUzIYouS.js");
21990
+ const { createGitHubSyncService } = await import("./github-sync-CerNYCAn.js");
21979
21991
  const syncService = createGitHubSyncService(c.var.services, c.var.currentSite.id, await buildSyncSiteConfig(c), {
21980
21992
  storage: c.var.storage,
21981
21993
  githubApp: getGitHubAppConfig(c.env)
@@ -21995,7 +22007,7 @@ settingsRoutes.post("/github-sync/push", async (c) => {
21995
22007
  });
21996
22008
  });
21997
22009
  settingsRoutes.post("/github-sync/disconnect", async (c) => {
21998
- const { createGitHubSyncService } = await import("./github-sync-BUzIYouS.js");
22010
+ const { createGitHubSyncService } = await import("./github-sync-CerNYCAn.js");
21999
22011
  await createGitHubSyncService(c.var.services, c.var.currentSite.id, await buildSyncSiteConfig(c), { githubApp: getGitHubAppConfig(c.env) }).teardownWebhook();
22000
22012
  return dsRedirect(publicPath(c, "/settings/github-sync"));
22001
22013
  });
@@ -22186,7 +22198,7 @@ function buildRepoPickerLabels(c) {
22186
22198
  const { parseRepoSlug, createGitHubClient } = await import("./github-api-UD4u_7fa.js").then((n) => n.n);
22187
22199
  const parsed = parseRepoSlug(repo);
22188
22200
  if (!parsed) return wantsJson ? c.json({ error: "Invalid repository format." }, 400) : c.text("Invalid repository format.", 400);
22189
- const { classifyRepoForSync } = await import("./github-sync-BUzIYouS.js");
22201
+ const { classifyRepoForSync } = await import("./github-sync-CerNYCAn.js");
22190
22202
  const ghClient = createGitHubClient(() => getInstallationTokenFromApp(app, installationId));
22191
22203
  let classification;
22192
22204
  try {
@@ -22216,7 +22228,7 @@ function buildRepoPickerLabels(c) {
22216
22228
  await c.var.services.settings.set("GITHUB_SYNC_REPO", repo);
22217
22229
  await c.var.services.settings.set("GITHUB_SYNC_TOKEN", "");
22218
22230
  await c.var.services.settings.set("GITHUB_SYNC_ENABLED", "true");
22219
- const { createGitHubSyncService } = await import("./github-sync-BUzIYouS.js");
22231
+ const { createGitHubSyncService } = await import("./github-sync-CerNYCAn.js");
22220
22232
  const syncService = createGitHubSyncService(c.var.services, c.var.currentSite.id, await buildSyncSiteConfig(c), {
22221
22233
  storage: c.var.storage,
22222
22234
  githubApp: app
@@ -22332,7 +22344,7 @@ function requireGitHubApp(c) {
22332
22344
  const { parseRepoSlug, createGitHubClient } = await import("./github-api-UD4u_7fa.js").then((n) => n.n);
22333
22345
  const parsed = parseRepoSlug(repo);
22334
22346
  if (!parsed) return c.json({ error: "Invalid repository format." }, 400);
22335
- const { classifyRepoForSync } = await import("./github-sync-BUzIYouS.js");
22347
+ const { classifyRepoForSync } = await import("./github-sync-CerNYCAn.js");
22336
22348
  const client = createGitHubClient(() => getInstallationTokenFromApp(app, installationId));
22337
22349
  try {
22338
22350
  const classification = await classifyRepoForSync(client, parsed.owner, parsed.repo, c.var.currentSite.id);
@@ -27866,6 +27878,55 @@ manifestRoutes.get("/manifest.webmanifest", (c) => {
27866
27878
  };
27867
27879
  }
27868
27880
  //#endregion
27881
+ //#region src/middleware/cache-control.ts
27882
+ /**
27883
+ * Cache-Control Middleware
27884
+ *
27885
+ * Sets a safe default `Cache-Control` on responses that don't declare one.
27886
+ *
27887
+ * Almost every Jant page is auth-variant: the same URL renders differently
27888
+ * for the signed-in author (nav, the "more" menu, edit affordances) than for
27889
+ * an anonymous visitor. A shared/CDN cache keyed only by URL must therefore
27890
+ * never store these pages — otherwise it serves a stale or wrong-audience
27891
+ * snapshot, which both breaks the UI ("you still look signed out", "your edit
27892
+ * didn't take effect") and can leak the authenticated dashboard to the public.
27893
+ *
27894
+ * Jant is self-hosted software that runs behind whatever reverse proxy or CDN
27895
+ * the operator chooses, so it cannot rely on infrastructure config to get
27896
+ * this right — it must declare its own cache policy. The critical mistake is
27897
+ * emitting `Cache-Control: public`: that word is an explicit invitation for
27898
+ * any shared cache to store the response.
27899
+ *
27900
+ * Routes that serve genuinely public, auth-invariant resources (media, feeds,
27901
+ * sitemaps, favicons, manifests, static assets) set their own `Cache-Control`
27902
+ * explicitly; this middleware leaves those untouched and only fills in the
27903
+ * default for the un-annotated dynamic responses.
27904
+ */ /**
27905
+ * Default cache directive for dynamic, potentially auth-variant responses.
27906
+ * `private` forbids shared/CDN caches from storing the response; `no-store`
27907
+ * prevents any cache (including the browser) from keeping a copy.
27908
+ */ var DEFAULT_CACHE_CONTROL = "private, no-store";
27909
+ /**
27910
+ * Middleware that defaults a missing `Cache-Control` header to
27911
+ * `private, no-store`.
27912
+ *
27913
+ * Runs after the route handler: if the handler (or an inner middleware)
27914
+ * already set `Cache-Control`, that explicit value wins. Only responses that
27915
+ * declare nothing receive the safe default.
27916
+ *
27917
+ * @returns Hono middleware enforcing the default cache policy.
27918
+ *
27919
+ * @example
27920
+ * ```ts
27921
+ * app.use("*", defaultCacheControl());
27922
+ * ```
27923
+ */ function defaultCacheControl() {
27924
+ return async (c, next) => {
27925
+ await next();
27926
+ if (!c.res.headers.has("Cache-Control")) c.res.headers.set("Cache-Control", DEFAULT_CACHE_CONTROL);
27927
+ };
27928
+ }
27929
+ //#endregion
27869
27930
  //#region src/middleware/onboarding.ts
27870
27931
  /**
27871
27932
  * Onboarding Middleware
@@ -32714,7 +32775,7 @@ function createSiteAdminService(db, databaseSchema = sqliteSchemaBundle, databas
32714
32775
  const themeCss = buildThemeStyle(activeTheme, appConfig.themeMode, fontOverrides);
32715
32776
  const navItemList = await navItems.list();
32716
32777
  const appleTouchKey = allSettings[SETTINGS_KEYS.SITE_FAVICON_APPLE_TOUCH];
32717
- const { createExportService } = await import("./export-O2w3AsZX.js").then((n) => n.n);
32778
+ const { createExportService } = await import("./export-CzuQyg5h.js").then((n) => n.n);
32718
32779
  const exportService = createExportService({
32719
32780
  collections,
32720
32781
  media: mediaService,
@@ -34151,6 +34212,7 @@ async function servePublicStorage(c) {
34151
34212
  await next();
34152
34213
  });
34153
34214
  app.use("*", attachSession());
34215
+ app.use("*", defaultCacheControl());
34154
34216
  app.use("*", async (c, next) => {
34155
34217
  const redirectUrl = await getHostedCanonicalRedirect({
34156
34218
  currentSite: c.var.currentSite,
@@ -0,0 +1,6 @@
1
+ import "./url-XF0GbKGO.js";
2
+ import { t as createApp } from "./app-B-wKZB8f.js";
3
+ import "./export-CzuQyg5h.js";
4
+ import "./env-CoSe-1y4.js";
5
+ import "./github-sync-Dbrb1DS5.js";
6
+ export { createApp };