jamdesk 1.1.198 → 1.1.200

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.
@@ -1 +1 @@
1
- {"version":3,"file":"frontmatter-utils.d.ts","sourceRoot":"","sources":["../../src/lib/frontmatter-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAkE7D;AAyFD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG;IAExD,IAAI,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;CACjB,CAIA;AAMD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"frontmatter-utils.d.ts","sourceRoot":"","sources":["../../src/lib/frontmatter-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAkE7D;AAyFD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG;IAExD,IAAI,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;CACjB,CAoBA;AAMD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
@@ -171,7 +171,23 @@ function hasFoldedContinuation(lines, i) {
171
171
  export function parseFrontmatterLenient(content) {
172
172
  const processed = preprocessFrontmatter(content);
173
173
  const { data, content: rawContent } = matter(processed);
174
- return { data, content: rawContent };
174
+ // Copied, never handed out by reference. gray-matter caches by content string
175
+ // and returns Object.assign({}, cached) on a hit — a SHALLOW copy, so `data`
176
+ // is ONE object shared by every parse of the same page, process-wide. A caller
177
+ // that wrote to it changed what every other caller read: a <meta> back-fill in
178
+ // buildDocMetadata surfaced as a duplicated page subtitle on every
179
+ // description-less page (#7). Callers get their own object; the cache stays
180
+ // pristine.
181
+ //
182
+ // Bounded on purpose, and NOT a guarantee that the whole class is closed:
183
+ // this protects TOP-LEVEL keys for callers who come through this function.
184
+ // Nested values (`data.seo`, tag arrays) are still shared by the spread, and
185
+ // three sites call `matter()` directly and bypass this entirely — build.ts,
186
+ // lib/docs.ts's readFrontmatterOnly, lib/api-page-panel-validator.ts. All are
187
+ // read-only today; a future writer through any of them re-opens the hole. A
188
+ // deep clone would cost a full walk on every page view of a force-dynamic
189
+ // route, which is the wrong trade for a leak that was one top-level key.
190
+ return { data: { ...data }, content: rawContent };
175
191
  }
176
192
  // frontmatterText lives in its own import-free leaf so ApiMarkdown.tsx (a
177
193
  // `'use client'` module) can share it without pulling gray-matter into the
@@ -1 +1 @@
1
- {"version":3,"file":"frontmatter-utils.js","sourceRoot":"","sources":["../../src/lib/frontmatter-utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"frontmatter-utils.js","sourceRoot":"","sources":["../../src/lib/frontmatter-utils.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jamdesk",
3
- "version": "1.1.198",
3
+ "version": "1.1.200",
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",
@@ -181,7 +181,23 @@ export function parseFrontmatterLenient(content: string): {
181
181
  } {
182
182
  const processed = preprocessFrontmatter(content);
183
183
  const { data, content: rawContent } = matter(processed);
184
- return { data, content: rawContent };
184
+ // Copied, never handed out by reference. gray-matter caches by content string
185
+ // and returns Object.assign({}, cached) on a hit — a SHALLOW copy, so `data`
186
+ // is ONE object shared by every parse of the same page, process-wide. A caller
187
+ // that wrote to it changed what every other caller read: a <meta> back-fill in
188
+ // buildDocMetadata surfaced as a duplicated page subtitle on every
189
+ // description-less page (#7). Callers get their own object; the cache stays
190
+ // pristine.
191
+ //
192
+ // Bounded on purpose, and NOT a guarantee that the whole class is closed:
193
+ // this protects TOP-LEVEL keys for callers who come through this function.
194
+ // Nested values (`data.seo`, tag arrays) are still shared by the spread, and
195
+ // three sites call `matter()` directly and bypass this entirely — build.ts,
196
+ // lib/docs.ts's readFrontmatterOnly, lib/api-page-panel-validator.ts. All are
197
+ // read-only today; a future writer through any of them re-opens the hole. A
198
+ // deep clone would cost a full walk on every page view of a force-dynamic
199
+ // route, which is the wrong trade for a leak that was one top-level key.
200
+ return { data: { ...data }, content: rawContent };
185
201
  }
186
202
 
187
203
  // frontmatterText lives in its own import-free leaf so ApiMarkdown.tsx (a
@@ -348,6 +348,79 @@ export async function resolveOpenApiMetaDescription(
348
348
  return null;
349
349
  }
350
350
 
351
+ /**
352
+ * The description used for `<meta>`, the OG/Twitter tags and the OG card
353
+ * image: authored frontmatter first, then the OpenAPI operation, then the
354
+ * page's first prose paragraph.
355
+ *
356
+ * Shared by `buildDocMetadata` and `renderDocPage` so the meta tags and the
357
+ * JSON-LD `image` resolve the SAME text. They used to disagree: only the
358
+ * metadata path resolved a description, so on pages with none authored the
359
+ * JSON-LD card URL omitted `description=` while og:image carried it, and the
360
+ * two URLs rendered two genuinely different cards — two OG renders and two CDN
361
+ * entries per page.
362
+ *
363
+ * The gate stays on the RAW value, not frontmatterText(): YAML hands back a
364
+ * Date for `description: 2026-01-01` and a number for `description: 404`.
365
+ * Both are truthy and must keep suppressing the fallbacks exactly as before.
366
+ *
367
+ * NEVER write the result back onto `data`. `parseFrontmatter` is gray-matter,
368
+ * whose cache returns a shallow copy that SHARES one `data` object per content
369
+ * string (gray-matter/index.js:39, `Object.assign({}, cached)`), so an
370
+ * assignment reached `renderDocPage`'s own parse of the same page and rendered
371
+ * as the page SUBTITLE: the operation description twice on every spec-backed
372
+ * page, and the first paragraph twice on every description-less prose page.
373
+ * The cache is module-global, so it persisted across requests rather than
374
+ * being a within-request ordering race. (#7 follow-up.)
375
+ */
376
+ export async function resolveDerivedDescription(
377
+ config: DocsConfig,
378
+ data: FrontmatterData,
379
+ content: string,
380
+ projectSlug: string | null | undefined,
381
+ ): Promise<string | undefined> {
382
+ let metaDescription: string | undefined = data.description;
383
+ if (metaDescription) return metaDescription;
384
+
385
+ if (typeof data.openapi === 'string' && data.openapi && config.api?.openapi) {
386
+ // Source the description from the OpenAPI operation before falling back to
387
+ // first-paragraph extraction (which is empty for prose-less API pages).
388
+ // The spec loader REUSES the render path's cached loaders — the ISR module
389
+ // cache (`r2:${slug}:${specPath}`, 10-min TTL) that `renderDocPage`
390
+ // populates when it renders the page's <ApiEndpoint>, or the static
391
+ // `getCachedSpec`. So the spec is the same warm parse the render already
392
+ // did: the marginal cost of this lookup is a cache hit, never an uncached
393
+ // fetch+parse. That matters because docs routes are force-dynamic, so this
394
+ // metadata runs on EVERY page view (every human + crawler). Mirrors the
395
+ // `useIsr`/`projectDir` derivation in `renderDocPage`'s OpenAPI branch.
396
+ const specPaths = collectLocalSpecPaths(config.api.openapi);
397
+ const useIsr = isIsrMode() && !!projectSlug;
398
+ const projectDir = useIsr ? null : getContentDir();
399
+ const loadSpecForMeta = async (sp: string): Promise<unknown | null> => {
400
+ try {
401
+ if (useIsr && projectSlug) {
402
+ const { resolveOpenApiSpec } = await import('@/lib/openapi-isr');
403
+ return await resolveOpenApiSpec(projectSlug, sp);
404
+ }
405
+ if (projectDir) {
406
+ const { api } = await getCachedSpec(sp, projectDir);
407
+ return api;
408
+ }
409
+ return null;
410
+ } catch {
411
+ // Any load/parse error degrades to generateAutoDescription below.
412
+ return null;
413
+ }
414
+ };
415
+ const sourced = await resolveOpenApiMetaDescription(
416
+ data.openapi, specPaths, loadSpecForMeta,
417
+ );
418
+ if (sourced) metaDescription = sourced;
419
+ }
420
+
421
+ return metaDescription || generateAutoDescription(content);
422
+ }
423
+
351
424
  export async function buildDocMetadata(input: RenderInput): Promise<Metadata> {
352
425
  const { slug: slugInput, projectSlug, hostAtDocs, docsPrefix, requestHeaders } = input;
353
426
  const linkPrefix = docsPrefix ?? (hostAtDocs ? '/docs' : '');
@@ -413,52 +486,20 @@ export async function buildDocMetadata(input: RenderInput): Promise<Metadata> {
413
486
  const parsed = parseFrontmatter(fileContents);
414
487
  const data = parsed.data as FrontmatterData;
415
488
 
416
- if (!data.description) {
417
- if (typeof data.openapi === 'string' && data.openapi && config.api?.openapi) {
418
- // Source the description from the OpenAPI operation before falling back to
419
- // first-paragraph extraction (which is empty for prose-less API pages).
420
- // The spec loader REUSES the render path's cached loaders — the ISR module
421
- // cache (`r2:${slug}:${specPath}`, 10-min TTL) that `renderDocPage`
422
- // populates when it renders the page's <ApiEndpoint>, or the static
423
- // `getCachedSpec`. So the spec is the same warm parse the render already
424
- // did: the marginal cost of this lookup is a cache hit, never an uncached
425
- // fetch+parse. That matters because docs routes are force-dynamic, so this
426
- // metadata runs on EVERY page view (every human + crawler). Mirrors the
427
- // `useIsr`/`projectDir` derivation in `renderDocPage`'s OpenAPI branch.
428
- const specPaths = collectLocalSpecPaths(config.api.openapi);
429
- const useIsr = isIsrMode() && !!projectSlug;
430
- const projectDir = useIsr ? null : getContentDir();
431
- const loadSpecForMeta = async (sp: string): Promise<unknown | null> => {
432
- try {
433
- if (useIsr && projectSlug) {
434
- const { resolveOpenApiSpec } = await import('@/lib/openapi-isr');
435
- return await resolveOpenApiSpec(projectSlug, sp);
436
- }
437
- if (projectDir) {
438
- const { api } = await getCachedSpec(sp, projectDir);
439
- return api;
440
- }
441
- return null;
442
- } catch {
443
- // Any load/parse error degrades to generateAutoDescription below.
444
- return null;
445
- }
446
- };
447
- const sourced = await resolveOpenApiMetaDescription(
448
- data.openapi, specPaths, loadSpecForMeta,
449
- );
450
- if (sourced) data.description = sourced;
451
- }
452
- if (!data.description) {
453
- data.description = generateAutoDescription(parsed.content);
454
- }
455
- }
489
+ const metaDescription = await resolveDerivedDescription(
490
+ config, data, parsed.content, projectSlug,
491
+ );
492
+
493
+ // buildSeoMetadata reads `frontmatter.description` for og:, twitter: and the
494
+ // OG card, so it must see the RESOLVED text — via a copy, never by mutating
495
+ // the shared `data`.
496
+ const seoFrontmatter = { ...data, description: metaDescription };
456
497
 
457
498
  const baseUrl = resolveBaseUrl(requestHeaders, projectSlug, hostAtDocs);
458
499
  const languages = config.navigation?.languages;
459
500
 
460
501
  const seoMetadata = buildSeoMetadata(
461
- config, data, pagePath, baseUrl, languages, isRootAlias, linkPrefix,
502
+ config, seoFrontmatter, pagePath, baseUrl, languages, isRootAlias, linkPrefix,
462
503
  localeFallback?.englishPath,
463
504
  );
464
505
 
@@ -488,7 +529,7 @@ export async function buildDocMetadata(input: RenderInput): Promise<Metadata> {
488
529
  title: titleValue,
489
530
  // Plain-texted, not just coerced: page descriptions render markdown, and
490
531
  // <meta name="description"> is read verbatim by every crawler and unfurler.
491
- description: metaDescriptionText(data.description),
532
+ description: metaDescriptionText(metaDescription),
492
533
  ...seoMetadata,
493
534
  ...robotsOverride,
494
535
  alternates: {
@@ -593,7 +634,15 @@ export async function renderDocPage(input: RenderInput): Promise<ReactElement> {
593
634
 
594
635
  const baseUrl = resolveBaseUrl(requestHeaders, projectSlug, hostAtDocs);
595
636
  const faqPairs = extractFaqPairs(rawContent);
596
- const ogImageUrl = buildPageOgImageUrl(config, data, baseUrl, linkPrefix);
637
+ // The same resolution buildDocMetadata performs, so og:image and the JSON-LD
638
+ // `image` point at ONE card. Passed as a copy — never a write onto the shared
639
+ // `data`, which is what caused #7 in the first place.
640
+ const ogDescription = await resolveDerivedDescription(
641
+ config, data, rawContent, projectSlug,
642
+ );
643
+ const ogImageUrl = buildPageOgImageUrl(
644
+ config, { ...data, description: ogDescription }, baseUrl, linkPrefix,
645
+ );
597
646
  // See frontmatterText: a YAML Date title throws when React renders it as a
598
647
  // child below, so every consumer in this function reads the coerced value.
599
648
  const titleText = frontmatterText(data.title);
@@ -879,7 +879,7 @@ const MAX_DESCRIPTION_LENGTH = 155;
879
879
  /** Patterns that indicate a paragraph is not prose (headings, components, images, comments, etc). */
880
880
  const NON_PROSE_PATTERNS = [
881
881
  /^#{1,6}\s/, // headings
882
- /^<[A-Z]/, // MDX components
882
+ /^<\/?[A-Z]/, // MDX components, opening AND closing (`</ResponseExample>`)
883
883
  /^!\[/, // images
884
884
  /^<!--/, // HTML comments
885
885
  /^>/, // blockquotes
@@ -834,9 +834,9 @@
834
834
  }
835
835
  },
836
836
  "node_modules/@jridgewell/sourcemap-codec": {
837
- "version": "1.5.5",
838
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
839
- "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
837
+ "version": "1.6.0",
838
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz",
839
+ "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==",
840
840
  "license": "MIT"
841
841
  },
842
842
  "node_modules/@jridgewell/trace-mapping": {
@@ -1918,9 +1918,9 @@
1918
1918
  }
1919
1919
  },
1920
1920
  "node_modules/@types/node": {
1921
- "version": "26.3.0",
1922
- "resolved": "https://registry.npmjs.org/@types/node/-/node-26.3.0.tgz",
1923
- "integrity": "sha512-L3fgrnchriRC2ExBflb8j4uZZURHZfQsmQeyVzhjcHW4kkwVyo8/0h1B2MVzMTrYUJYu6G7EWs14hW/L9putqw==",
1921
+ "version": "26.4.0",
1922
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-26.4.0.tgz",
1923
+ "integrity": "sha512-faiGnoIrLH/V8cibOMEAZ8pMw6oXqSukl29ra4mN8GdaB2ZewzeaLj+INpV5N+Z1eKWzY+IzaIZH2EIR6YZRNQ==",
1924
1924
  "license": "MIT",
1925
1925
  "dependencies": {
1926
1926
  "undici-types": "~8.3.0"
@@ -1958,9 +1958,9 @@
1958
1958
  "license": "MIT"
1959
1959
  },
1960
1960
  "node_modules/@ungap/structured-clone": {
1961
- "version": "1.3.4",
1962
- "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.4.tgz",
1963
- "integrity": "sha512-JL+CF0GeLHyPWI0rXu7UnxgiuOm9UQWzadi0OYOJNhNO2q6EZElpwlgXkNkfU1PzANDHq3YcwKVZprdvS+BrbQ==",
1961
+ "version": "1.4.0",
1962
+ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.4.0.tgz",
1963
+ "integrity": "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==",
1964
1964
  "license": "ISC"
1965
1965
  },
1966
1966
  "node_modules/@upsetjs/venn.js": {
@@ -2131,9 +2131,9 @@
2131
2131
  }
2132
2132
  },
2133
2133
  "node_modules/baseline-browser-mapping": {
2134
- "version": "2.11.19",
2135
- "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.19.tgz",
2136
- "integrity": "sha512-Grytf1xOxOEMTGRwx6rLGKkTabd4vMg3VrKdj/7joCmV0qgh4QwMMO6xh34YEXQqirAuUdgQGa5orJQQ+69RBw==",
2134
+ "version": "2.11.20",
2135
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.20.tgz",
2136
+ "integrity": "sha512-H0ulySigv6icDJ1F7SjtdCD6PrhTpdYCmP0CactWy1+ekh0AFd0o1Wn5T8b+hnTmdBx19u9yhL6wvCylXMY7zw==",
2137
2137
  "license": "Apache-2.0",
2138
2138
  "bin": {
2139
2139
  "baseline-browser-mapping": "dist/cli.cjs"
@@ -2925,9 +2925,9 @@
2925
2925
  "license": "MIT"
2926
2926
  },
2927
2927
  "node_modules/electron-to-chromium": {
2928
- "version": "1.5.415",
2929
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.415.tgz",
2930
- "integrity": "sha512-958V+Kbhtgz+SxXeEVKBjrlKRBIDAYvUJfwhjxMZ5S6ut9jAl7l9ZKBkBrvjyjZE36PabLUo2L8kEeV5O4vgJg==",
2928
+ "version": "1.5.417",
2929
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.417.tgz",
2930
+ "integrity": "sha512-4T+DTDWuMPM4aHlHwWdAVCVWwp7LDilnhzkj+c/Lbj91XSQrLuOmZSLtS9Q4iIqjlPUbPOnC624zDVVHCHaolQ==",
2931
2931
  "license": "ISC"
2932
2932
  },
2933
2933
  "node_modules/enhanced-resolve": {
@@ -2956,9 +2956,9 @@
2956
2956
  }
2957
2957
  },
2958
2958
  "node_modules/es-toolkit": {
2959
- "version": "1.51.0",
2960
- "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.51.0.tgz",
2961
- "integrity": "sha512-zC2lQGkM7QX+Gm6iM3+WIdZJzthsEd14LvRNJneSO2hzyz/zNBENR8+YXWo1cKxgPBtV6ksPYHELbcwBRzmdCw==",
2959
+ "version": "1.52.0",
2960
+ "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.52.0.tgz",
2961
+ "integrity": "sha512-XTNEJQh1tY1ZJVcf6ayP/2n4ZPyaHlW2FWs7xvw5ddPuhUVjLD3olQVQS7kf58JbAB48iL0uL/jerTrjtV3lDA==",
2962
2962
  "license": "MIT",
2963
2963
  "workspaces": [
2964
2964
  "docs",
@@ -5418,9 +5418,9 @@
5418
5418
  }
5419
5419
  },
5420
5420
  "node_modules/node-releases": {
5421
- "version": "2.0.53",
5422
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.53.tgz",
5423
- "integrity": "sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ==",
5421
+ "version": "2.0.54",
5422
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.54.tgz",
5423
+ "integrity": "sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==",
5424
5424
  "license": "MIT",
5425
5425
  "engines": {
5426
5426
  "node": ">=18"
@@ -6539,9 +6539,9 @@
6539
6539
  }
6540
6540
  },
6541
6541
  "node_modules/update-browserslist-db": {
6542
- "version": "1.3.1",
6543
- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.1.tgz",
6544
- "integrity": "sha512-ZZ61DsRsOnakl74HAmp3oSN4aXUmEWXf+i/yv0h7tIBfICc3VdrFErQKUUKPgu3AMsTUMbcongALEN4l6GSUrQ==",
6542
+ "version": "1.3.2",
6543
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz",
6544
+ "integrity": "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==",
6545
6545
  "funding": [
6546
6546
  {
6547
6547
  "type": "opencollective",