jamdesk 1.1.164 → 1.1.165

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jamdesk",
3
- "version": "1.1.164",
3
+ "version": "1.1.165",
4
4
  "description": "CLI for Jamdesk — build, preview, and deploy documentation sites from MDX. Dev server with hot reload, 50+ components, OpenAPI support, AI search, and Mintlify migration",
5
5
  "keywords": [
6
6
  "jamdesk",
@@ -684,14 +684,23 @@ const TRUSTED_PROXY_HEADERS = [
684
684
  'x-jd-project-name',
685
685
  'x-jd-project-logo',
686
686
  // Canonical override: middleware writes this when serving *.jamdesk.app
687
- // directly for a hostAtDocs project that has a registered custom
688
- // domain. The page render path uses it to emit the public-face canonical
689
- // instead of the upstream subdomain URL.
687
+ // directly for a project (ANY hosting mode) whose registered custom
688
+ // domain passed domain-side validation (domain:<host> mapping points back
689
+ // at the slug + domainStatus active). The page render path uses it to
690
+ // emit the public-face canonical instead of the upstream subdomain URL.
690
691
  'x-jd-canonical-host',
691
- // Set when *.jamdesk.app serves a hostAtDocs project that has NOT
692
- // registered a custom domain yet page emits robots: noindex so the
693
- // upstream URL doesn't compete with the (yet-to-arrive) public face
694
- // in search results.
692
+ // The registered domain's OWN serving mode ('true' | 'false', from
693
+ // domainCfg:<host>) decides whether the canonical URL carries the
694
+ // /docs prefix. Only meaningful alongside x-jd-canonical-host; absent
695
+ // for legacy domains without a domainCfg record (page falls back to the
696
+ // projectCfg-derived hostAtDocs).
697
+ 'x-jd-canonical-at-docs',
698
+ // Set when *.jamdesk.app serves a hostAtDocs project with no
699
+ // domain-validated custom domain (none registered, or the projectCfg
700
+ // mirror failed domain-side validation) — page emits robots: noindex so
701
+ // the upstream URL doesn't compete with the public face in search
702
+ // results. NEVER set for hostAtDocs=false tenants without a domain:
703
+ // their subdomain IS the public site.
695
704
  'x-jd-noindex',
696
705
  ] as const;
697
706
 
@@ -703,15 +712,25 @@ const TRUSTED_PROXY_HEADERS = [
703
712
  export interface BuildProjectHeadersOptions {
704
713
  /**
705
714
  * Public-face canonical host. Set when serving *.jamdesk.app directly
706
- * for a hostAtDocs project that has a registered custom domain — the
707
- * page render path emits this host in <link rel="canonical"> instead
708
- * of the upstream subdomain.
715
+ * for a project (any hosting mode) whose registered custom domain passed
716
+ * domain-side validation — the page render path emits this host in
717
+ * <link rel="canonical"> instead of the upstream subdomain.
709
718
  */
710
719
  canonicalHost?: string;
720
+ /**
721
+ * The registered domain's OWN serving mode (domainCfg:<host>.hostAtDocs).
722
+ * Decides whether the canonical URL carries the /docs prefix — the
723
+ * projectCfg-side hostAtDocs describes how the SUBDOMAIN serves, which
724
+ * can diverge from the domain's live mode. undefined = legacy domain
725
+ * with no domainCfg record; the page falls back to the projectCfg-derived
726
+ * hostAtDocs. Only emitted when canonicalHost is set.
727
+ */
728
+ canonicalAtDocs?: boolean;
711
729
  /**
712
730
  * When true, emit `x-jd-noindex: true` so the page emits a robots
713
- * noindex tag. Used for *.jamdesk.app subdomains of hostAtDocs
714
- * projects without a custom domain yet.
731
+ * noindex tag. Used for *.jamdesk.app subdomains of hostAtDocs projects
732
+ * without a domain-validated custom domain. Never set for
733
+ * hostAtDocs=false tenants — their subdomain is the public site.
715
734
  */
716
735
  noindex?: boolean;
717
736
  }
@@ -724,6 +743,8 @@ export interface BuildProjectHeadersOptions {
724
743
  * - x-host-at-docs — whether docs are mounted at /docs
725
744
  * - x-jd-language — locale code if the path starts with one (e.g. /fr/...)
726
745
  * - x-jd-canonical-host — public-face host (opts.canonicalHost)
746
+ * - x-jd-canonical-at-docs — domain's own /docs mode (opts.canonicalAtDocs;
747
+ * only alongside x-jd-canonical-host)
727
748
  * - x-jd-noindex — "true" when opts.noindex is set
728
749
  *
729
750
  * Strips any client-supplied copies of those headers from the inbound
@@ -763,6 +784,10 @@ export function buildProjectHeaders(
763
784
 
764
785
  if (opts.canonicalHost) {
765
786
  newHeaders.set('x-jd-canonical-host', opts.canonicalHost);
787
+ // Only meaningful with a canonical host; getBaseUrl ignores it otherwise.
788
+ if (opts.canonicalAtDocs !== undefined) {
789
+ newHeaders.set('x-jd-canonical-at-docs', opts.canonicalAtDocs ? 'true' : 'false');
790
+ }
766
791
  }
767
792
  if (opts.noindex) {
768
793
  newHeaders.set('x-jd-noindex', 'true');
@@ -132,14 +132,21 @@ export function parseCacheKey(cacheKey: string): { projectSlug: string; pagePath
132
132
  *
133
133
  * Header priority (highest first):
134
134
  * 1. x-jd-canonical-host — internal override set by middleware when a
135
- * hostAtDocs project is served directly via *.jamdesk.app and has a
136
- * registered customDomain. Forces the canonical to the public face.
135
+ * project (any hosting mode) is served directly via *.jamdesk.app and
136
+ * its registered customDomain passed domain-side validation. Forces
137
+ * the canonical to the public face. When present, the companion
138
+ * x-jd-canonical-at-docs header (the DOMAIN's own serving mode, from
139
+ * domainCfg:<host>) overrides the hostAtDocs param for the /docs
140
+ * prefix decision — projectCfg's hostAtDocs describes how the
141
+ * subdomain serves, which can diverge from the live domain mode.
142
+ * Companion header absent (legacy domains without a domainCfg record)
143
+ * → the hostAtDocs param decides, as before.
137
144
  * 2. x-jamdesk-forwarded-host — set by the Cloudflare Worker proxy
138
145
  * (e.g. jamdesk.com → forwarded `jamdesk.com`).
139
146
  * 3. host header — direct request hostname.
140
147
  * 4. Subdomain fallback `<slug>.jamdesk.app` (no headers available).
141
148
  *
142
- * Both override headers are in TRUSTED_PROXY_HEADERS so a client can't
149
+ * All override headers are in TRUSTED_PROXY_HEADERS so a client can't
143
150
  * spoof them.
144
151
  *
145
152
  * When hostAtDocs=true, includes /docs path prefix (forwarded-host and
@@ -157,7 +164,13 @@ export function getBaseUrl(headers: Headers, projectSlug: string, hostAtDocs = f
157
164
 
158
165
  if (host) {
159
166
  const hostname = host.split(':')[0];
160
- return hostAtDocs ? `https://${hostname}/docs` : `https://${hostname}`;
167
+ // Domain-mode override: only consulted when the canonical-host override
168
+ // is active (the companion header is only ever set alongside it).
169
+ const canonicalAtDocs = canonicalHost
170
+ ? headers.get('x-jd-canonical-at-docs')
171
+ : null;
172
+ const atDocs = canonicalAtDocs !== null ? canonicalAtDocs === 'true' : hostAtDocs;
173
+ return atDocs ? `https://${hostname}/docs` : `https://${hostname}`;
161
174
  }
162
175
 
163
176
  // Fallback to subdomain URL (subdomains always serve at root, never /docs)
@@ -256,10 +256,11 @@ export async function buildDocMetadata(input: RenderInput): Promise<Metadata> {
256
256
  const { slug: slugInput, projectSlug, hostAtDocs, requestHeaders } = input;
257
257
 
258
258
  // Middleware sets `x-jd-noindex: true` when serving a hostAtDocs project
259
- // directly via *.jamdesk.app and the project has no registered custom
260
- // domain yet. The upstream subdomain shouldn't compete with the (yet-to-
261
- // arrive) public face in search results emit robots noindex so Google
262
- // skips it. See proxy.ts → projectHeaderOptsForCanonical for the source.
259
+ // directly via *.jamdesk.app and the project has no domain-validated
260
+ // custom domain (none registered, or the registration is stale/inactive).
261
+ // The upstream subdomain shouldn't compete with the public face in search
262
+ // results — emit robots noindex so Google skips it. See proxy.ts →
263
+ // projectHeaderOptsForCanonical for the source.
263
264
  const noindexHeader = requestHeaders?.get('x-jd-noindex') === 'true';
264
265
 
265
266
  if (isIsrMode()) {
@@ -43,10 +43,11 @@ const CONTENT_TYPES: Record<string, string> = {
43
43
  * have no business being served from a non-canonical host.
44
44
  *
45
45
  * `x-jd-noindex: true` is set by `proxy.ts` (`projectHeaderOptsForCanonical`)
46
- * when a project uses `hostAtDocs` WITHOUT a custom domain — i.e. its public
47
- * face is the raw `<slug>.jamdesk.app` subdomain with no canonical elsewhere.
48
- * Once a custom domain is registered, the header is replaced by a canonical-
49
- * host override and noindex is no longer set.
46
+ * when a project uses `hostAtDocs` WITHOUT a domain-validated custom domain
47
+ * — i.e. its public face is the raw `<slug>.jamdesk.app` subdomain with no
48
+ * canonical elsewhere. Once a custom domain is registered AND active, the
49
+ * header is replaced by a canonical-host override and noindex is no longer
50
+ * set.
50
51
  *
51
52
  * `robots.txt` is handled separately — it returns a Disallow-all directive,
52
53
  * not a 404, so crawlers get an explicit "don't crawl" signal.