jamdesk 1.1.170 → 1.1.172

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 (54) hide show
  1. package/README.md +2 -2
  2. package/dist/__tests__/unit/docs-config.test.js +9 -0
  3. package/dist/__tests__/unit/docs-config.test.js.map +1 -1
  4. package/dist/__tests__/unit/migrate-mdx.test.js +24 -0
  5. package/dist/__tests__/unit/migrate-mdx.test.js.map +1 -1
  6. package/dist/__tests__/unit/migrate-resolve-theme.test.js +6 -0
  7. package/dist/__tests__/unit/migrate-resolve-theme.test.js.map +1 -1
  8. package/dist/__tests__/unit/prompt-vendoring.test.d.ts +2 -0
  9. package/dist/__tests__/unit/prompt-vendoring.test.d.ts.map +1 -0
  10. package/dist/__tests__/unit/prompt-vendoring.test.js +20 -0
  11. package/dist/__tests__/unit/prompt-vendoring.test.js.map +1 -0
  12. package/dist/__tests__/unit/vendored-sync.test.js +3 -0
  13. package/dist/__tests__/unit/vendored-sync.test.js.map +1 -1
  14. package/dist/commands/migrate/types.d.ts +1 -1
  15. package/dist/commands/migrate/types.d.ts.map +1 -1
  16. package/dist/commands/migrate/types.js +5 -0
  17. package/dist/commands/migrate/types.js.map +1 -1
  18. package/dist/index.js +2 -2
  19. package/dist/index.js.map +1 -1
  20. package/dist/lib/deps.js +1 -1
  21. package/dist/lib/docs-config.d.ts +1 -1
  22. package/dist/lib/docs-config.d.ts.map +1 -1
  23. package/dist/lib/docs-config.js +1 -1
  24. package/dist/lib/docs-config.js.map +1 -1
  25. package/dist/lib/normalize-config.js +1 -1
  26. package/dist/lib/normalize-config.js.map +1 -1
  27. package/package.json +2 -2
  28. package/templates/quickstart.mdx +1 -1
  29. package/vendored/components/AIActionsMenu.tsx +5 -17
  30. package/vendored/components/mdx/Card.tsx +1 -0
  31. package/vendored/components/mdx/MDXComponents.tsx +2 -0
  32. package/vendored/components/mdx/Prompt.tsx +381 -0
  33. package/vendored/components/mdx/ai-action-icons.tsx +7 -0
  34. package/vendored/components/mdx/prompt-actions.ts +137 -0
  35. package/vendored/components/navigation/Sidebar.tsx +23 -14
  36. package/vendored/lib/ai-service-urls.ts +8 -0
  37. package/vendored/lib/build/error-parser.ts +1 -1
  38. package/vendored/lib/docs-types.ts +3 -3
  39. package/vendored/lib/extract-highlights.ts +1 -1
  40. package/vendored/lib/inject-prompt-source.ts +259 -0
  41. package/vendored/lib/layout-helpers.tsx +30 -1
  42. package/vendored/lib/mdx-syntax-fixes.ts +143 -0
  43. package/vendored/lib/mdx.ts +2 -1
  44. package/vendored/lib/normalize-config.ts +1 -1
  45. package/vendored/lib/preprocess-mdx.ts +10 -223
  46. package/vendored/lib/prompt-source-codec.ts +27 -0
  47. package/vendored/lib/render-doc-page.tsx +4 -1
  48. package/vendored/lib/snippet-loader-isr.ts +2 -0
  49. package/vendored/lib/validate-config.ts +4 -4
  50. package/vendored/schema/docs-schema.json +122 -1
  51. package/vendored/themes/halo/variables.css +514 -0
  52. package/vendored/themes/index.ts +26 -0
  53. package/vendored/themes/types.ts +1 -0
  54. package/vendored/workspace-package-lock.json +85 -1
@@ -9,36 +9,16 @@
9
9
  import { ASSET_PREFIX, appendAssetVersion } from './docs-types';
10
10
  import { convertDeprecatedComponents } from './deprecated-components';
11
11
  import { filterVisibility } from './visibility-filter';
12
+ import {
13
+ applyJsxSyntaxFixes,
14
+ JSX_CONTENT_COMPONENTS,
15
+ } from './mdx-syntax-fixes';
12
16
  import { logger } from '../shared/logger';
13
17
 
14
- /**
15
- * JSX components that contain markdown content requiring special preprocessing.
16
- * Used by ensureBlankLinesInJsx, normalizeJsxIndentation, and unindentJsxAfterListItems.
17
- */
18
- const JSX_CONTENT_COMPONENTS = [
19
- 'Card',
20
- 'Columns',
21
- 'Note',
22
- 'Warning',
23
- 'Tip',
24
- 'Info',
25
- 'Check',
26
- 'Danger',
27
- 'Accordion',
28
- 'AccordionGroup',
29
- 'Tab',
30
- 'Tabs',
31
- 'Step',
32
- 'Steps',
33
- 'Expandable',
34
- 'Update',
35
- 'Frame',
36
- 'Panel',
37
- 'View',
38
- 'Varning',
39
- 'Avertissement',
40
- 'Visibility',
41
- ] as const;
18
+ export {
19
+ unindentClosingTagAfterList,
20
+ unindentJsxAfterListItems,
21
+ } from './mdx-syntax-fixes';
42
22
 
43
23
  // Match a fenced code block (``` or ~~~), used to mask code-block content
44
24
  // before scanning for top-level snippet imports — otherwise import lines
@@ -543,191 +523,6 @@ export function normalizeJsxIndentation(content: string): string {
543
523
  return result.join('\n');
544
524
  }
545
525
 
546
- /**
547
- * Un-indent a closing JSX tag absorbed into the previous markdown list item.
548
- *
549
- * Distinct from `unindentJsxAfterListItems` below: that one rewrites indented
550
- * *opening* tags inside list context. Here the opening tag is at root level
551
- * and only the closing tag is indented after the list — markdown reads it as
552
- * listItem continuation, so MDX compiles see the parent component as unclosed
553
- * ("Expected the closing tag `</Card>` either after the end of `listItem`...").
554
- *
555
- * CLI mirror: `builder/cli/src/lib/mdx-syntax-fixes.ts` — keep regex in sync.
556
- */
557
- export function unindentClosingTagAfterList(content: string): string {
558
- // Hot-path prefilter — preprocessMdx runs on every page render, and most
559
- // MDX has no indented closing tags at all. Skip the split+walk in that case.
560
- if (!/^\s+<\/[A-Z]/m.test(content)) return content;
561
-
562
- const closingTagPattern = /^(\s+)(<\/[A-Z][\w-]*>)\s*$/;
563
- const listItemPattern = /^\s*(?:[-*+]\s|\d+\.\s)/;
564
- const lines = content.split('\n');
565
- const out: string[] = [];
566
- let lastNonBlank = '';
567
-
568
- for (const line of lines) {
569
- const closing = line.match(closingTagPattern);
570
- if (closing && listItemPattern.test(lastNonBlank)) {
571
- out.push(closing[2]);
572
- lastNonBlank = closing[2];
573
- continue;
574
- }
575
- out.push(line);
576
- if (line.trim() !== '') lastNonBlank = line;
577
- }
578
-
579
- return out.join('\n');
580
- }
581
-
582
- /**
583
- * Un-indent JSX blocks that follow markdown list items.
584
- *
585
- * In markdown, 4+ spaces of indentation after a list item creates a continuation
586
- * of that list item. When a JSX component like <Frame> is indented this way,
587
- * MDX cannot properly parse the JSX within the list item context.
588
- *
589
- * Error: "Expected a closing tag for `<Frame>` before the end of `listItem`"
590
- *
591
- * This function detects JSX blocks that are indented after list items and
592
- * removes the indentation to make them standalone blocks, not part of the list.
593
- *
594
- * Before:
595
- * - **List item text**
596
- *
597
- * <Frame>
598
- * <iframe ...></iframe>
599
- * </Frame>
600
- *
601
- * After:
602
- * - **List item text**
603
- *
604
- * <Frame>
605
- * <iframe ...></iframe>
606
- * </Frame>
607
- *
608
- * @param content - Raw MDX content
609
- * @returns Content with un-indented JSX blocks
610
- */
611
- export function unindentJsxAfterListItems(content: string): string {
612
- const componentPattern = JSX_CONTENT_COMPONENTS.join('|');
613
- const lines = content.split('\n');
614
- const result: string[] = [];
615
-
616
- // Track if we're in a list context (saw a list item recently)
617
- let inListContext = false;
618
- // Track the base indentation of JSX block we're un-indenting
619
- let jsxBlockIndent = 0;
620
- // Track if we're inside a JSX block that needs un-indenting
621
- let unindentingJsxBlock = false;
622
- let jsxBlockDepth = 0;
623
- // Track which component we're inside
624
- let currentComponent = '';
625
-
626
- for (let i = 0; i < lines.length; i++) {
627
- const line = lines[i];
628
- const trimmed = line.trim();
629
- const currentIndent = line.match(/^(\s*)/)?.[1].length ?? 0;
630
-
631
- // Check if this is a list item (unordered or ordered)
632
- const isListItem = /^[-*+]\s/.test(trimmed) || /^\d+\.\s/.test(trimmed);
633
-
634
- if (isListItem) {
635
- inListContext = true;
636
- result.push(line);
637
- continue;
638
- }
639
-
640
- // Blank lines don't exit list context
641
- if (!trimmed) {
642
- result.push(line);
643
- continue;
644
- }
645
-
646
- // Check for JSX opening tag that's indented (4+ spaces) in list context
647
- // Handle both single-line tags (<Frame>) and multi-line tags (<Card\n title="...">)
648
- const openingTagMatch = trimmed.match(
649
- new RegExp(`^<(${componentPattern})(?:\\s|>|$|/>)`)
650
- );
651
-
652
- // Handle any indentation level > 0, not just 4+ spaces
653
- // Nested list items use 2-space indentation, not 4-space
654
- if (openingTagMatch && inListContext && currentIndent > 0 && !unindentingJsxBlock) {
655
- // Start un-indenting this JSX block
656
- unindentingJsxBlock = true;
657
- jsxBlockIndent = currentIndent;
658
- jsxBlockDepth = 1;
659
- currentComponent = openingTagMatch[1];
660
-
661
- // Check if it's a self-closing tag on this line
662
- if (trimmed.endsWith('/>')) {
663
- unindentingJsxBlock = false;
664
- jsxBlockDepth = 0;
665
- inListContext = false;
666
- }
667
-
668
- // If the previous line was NOT blank (JSX immediately follows list item text),
669
- // insert a blank line to properly separate the JSX from the list context.
670
- // This prevents "lazy line" errors in MDX parsing.
671
- const prevLine = result.length > 0 ? result[result.length - 1] : '';
672
- if (prevLine.trim() !== '') {
673
- result.push('');
674
- }
675
-
676
- // Remove the indentation
677
- result.push(trimmed);
678
- continue;
679
- }
680
-
681
- // If we're un-indenting a JSX block, process the content
682
- if (unindentingJsxBlock) {
683
- // Check for nested opening tags of the same component
684
- const nestedOpenMatch = trimmed.match(
685
- new RegExp(`^<(${currentComponent})(?:\\s[^>]*)?>`)
686
- );
687
- if (nestedOpenMatch && !trimmed.endsWith('/>')) {
688
- jsxBlockDepth++;
689
- }
690
-
691
- // Check for closing tag
692
- const closingTagMatch = trimmed.match(
693
- new RegExp(`^</(${currentComponent})>`)
694
- );
695
- if (closingTagMatch) {
696
- jsxBlockDepth--;
697
-
698
- if (jsxBlockDepth === 0) {
699
- // End of the JSX block
700
- unindentingJsxBlock = false;
701
- inListContext = false;
702
- currentComponent = '';
703
- // Output the closing tag without indentation
704
- result.push(trimmed);
705
- continue;
706
- }
707
- }
708
-
709
- // Remove the base indentation from all lines in the block
710
- if (currentIndent >= jsxBlockIndent) {
711
- const reducedIndent = currentIndent - jsxBlockIndent;
712
- result.push(' '.repeat(reducedIndent) + trimmed);
713
- } else {
714
- result.push(trimmed);
715
- }
716
- continue;
717
- }
718
-
719
- // Only root-level (0 indent) non-blank content exits list context
720
- // Content with any indentation could be nested list continuation
721
- if (currentIndent === 0) {
722
- inListContext = false;
723
- }
724
-
725
- result.push(line);
726
- }
727
-
728
- return result.join('\n');
729
- }
730
-
731
526
  /**
732
527
  * Props that can contain image paths in MDX content.
733
528
  * - src: standard HTML img and MDX Image components
@@ -1117,16 +912,8 @@ export function preprocessMdx(content: string, options?: { assetVersion?: string
1117
912
  // Convert noStyle to data-no-style for React compatibility
1118
913
  processed = convertNoStyleToDataAttr(processed);
1119
914
 
1120
- // Un-indent absorbed closing tags FIRST — handles the case where the
1121
- // opening tag is at root level but the closing tag got indented after a
1122
- // list. unindentJsxAfterListItems below only catches cases where the
1123
- // opening tag itself is indented inside list context.
1124
- processed = unindentClosingTagAfterList(processed);
1125
-
1126
- // Un-indent JSX blocks that follow list items to prevent
1127
- // "Expected closing tag before end of listItem" errors
1128
- // This must run BEFORE ensureBlankLinesInJsx since it changes block structure
1129
- processed = unindentJsxAfterListItems(processed);
915
+ // Repair list-adjacent JSX before blank-line and indentation normalization.
916
+ processed = applyJsxSyntaxFixes(processed);
1130
917
 
1131
918
  // Ensure blank lines around markdown block content inside JSX components
1132
919
  // This must run BEFORE normalizeJsxIndentation since it needs original line structure
@@ -0,0 +1,27 @@
1
+ const BINARY_CHUNK_SIZE = 32 * 1024;
2
+
3
+ export function encodePromptSource(source: string): string {
4
+ const bytes = new TextEncoder().encode(source);
5
+ let binary = '';
6
+
7
+ for (let offset = 0; offset < bytes.length; offset += BINARY_CHUNK_SIZE) {
8
+ binary += String.fromCharCode(
9
+ ...bytes.subarray(offset, offset + BINARY_CHUNK_SIZE),
10
+ );
11
+ }
12
+
13
+ return btoa(binary);
14
+ }
15
+
16
+ export function decodePromptSource(encoded: string): string {
17
+ try {
18
+ const binary = atob(encoded);
19
+ const bytes = new Uint8Array(binary.length);
20
+ for (let index = 0; index < binary.length; index++) {
21
+ bytes[index] = binary.charCodeAt(index);
22
+ }
23
+ return new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(bytes);
24
+ } catch {
25
+ return '';
26
+ }
27
+ }
@@ -44,6 +44,7 @@ import { tryOpenApiCandidatesInParallel, makeTryOpenApiSpec, formatFallbackWarni
44
44
  import { computeHasCodePanels } from './render-doc-page-helpers';
45
45
  import { logger } from '../shared/logger';
46
46
  import { preprocessMdx, containsPanel, containsView, buildSnippetAliasMap } from '@/lib/preprocess-mdx';
47
+ import { injectPromptSources } from '@/lib/inject-prompt-source';
47
48
  import { loadSnippetsForIsr } from '@/lib/snippet-loader-isr';
48
49
  import { PanelWrapper } from '@/components/mdx/PanelWrapper';
49
50
  import { ViewWrapper } from '@/components/mdx/View';
@@ -449,7 +450,9 @@ export async function renderDocPage(input: RenderInput): Promise<ReactElement> {
449
450
  let content = '';
450
451
  let preprocessError: string | null = null;
451
452
  try {
452
- content = preprocessMdx(rawContent, { assetVersion: config.assetVersion });
453
+ content = preprocessMdx(injectPromptSources(rawContent), {
454
+ assetVersion: config.assetVersion,
455
+ });
453
456
  } catch (err) {
454
457
  preprocessError = err instanceof Error ? err.message : String(err);
455
458
  logger.warn(`[MDX] preprocess failed for ${pagePath}: ${preprocessError}`);
@@ -15,6 +15,7 @@ import { transform } from '@babel/standalone';
15
15
  import { fetchSnippet } from './r2-content';
16
16
  import { extractSnippetImports, normalizeSnippetPath } from './preprocess-mdx';
17
17
  import { filterVisibility } from './visibility-filter';
18
+ import { injectPromptSources } from './inject-prompt-source';
18
19
  import { mdxSecurityOptions } from './mdx-security-options';
19
20
 
20
21
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -249,6 +250,7 @@ async function compilePlainMdxSnippet(
249
250
  source: string,
250
251
  builtInComponents: Record<string, AnyComponent>
251
252
  ): Promise<AnyComponent> {
253
+ source = injectPromptSources(source);
252
254
  const { compileMDX } = await import('next-mdx-remote/rsc');
253
255
  const { content } = await compileMDX({
254
256
  source,
@@ -26,7 +26,7 @@ import { BUILD_SERVICE_DIR } from './paths.js';
26
26
  export interface DocsConfig {
27
27
  name: string;
28
28
  projectId?: string;
29
- theme?: 'jam' | 'nebula' | 'pulsar';
29
+ theme?: 'jam' | 'nebula' | 'pulsar' | 'halo';
30
30
  navigation: NavigationConfig;
31
31
  integrations?: IntegrationsConfig;
32
32
  [key: string]: unknown;
@@ -169,7 +169,7 @@ export function parseConfig(content: string): DocsConfig {
169
169
  /**
170
170
  * Filter out noise from anyOf validation errors.
171
171
  *
172
- * The master schema uses a 3-branch anyOf (one per theme) and Ajv emits errors
172
+ * The master schema uses a 4-branch anyOf (one per theme) and Ajv emits errors
173
173
  * from every branch it tried, producing messages like `must be "nebula"` when
174
174
  * the user typed `theme: "jam"`. This helper:
175
175
  *
@@ -567,7 +567,7 @@ export async function validateConfig(
567
567
  }
568
568
 
569
569
  // Validate theme (case-insensitive — "MINT" still falls through to the Mintlify branch below).
570
- const validThemes = ['jam', 'nebula', 'pulsar'];
570
+ const validThemes = ['jam', 'nebula', 'pulsar', 'halo'];
571
571
  if (typeof config.theme === 'string') {
572
572
  const themeLower = config.theme.toLowerCase();
573
573
  if (!validThemes.includes(themeLower)) {
@@ -581,7 +581,7 @@ export async function validateConfig(
581
581
  };
582
582
  }
583
583
  // Normalize so downstream Ajv schema (lowercase enum) accepts it.
584
- config.theme = themeLower as 'jam' | 'nebula' | 'pulsar';
584
+ config.theme = themeLower as 'jam' | 'nebula' | 'pulsar' | 'halo';
585
585
  }
586
586
 
587
587
  if (legacyAnchors) {
@@ -421,7 +421,7 @@
421
421
  "top",
422
422
  "left"
423
423
  ],
424
- "description": "Controls where navigation tabs are displayed. `top` places tabs in the header bar, `left` places them at the top of the sidebar. Default depends on theme: jam/nebula default to `left`, pulsar defaults to `top`"
424
+ "description": "Controls where navigation tabs are displayed. `top` places tabs in the header bar, `left` places them at the top of the sidebar. All themes default to `left`"
425
425
  },
426
426
  "anchors": {
427
427
  "type": "array",
@@ -1956,6 +1956,127 @@
1956
1956
  "navigation"
1957
1957
  ],
1958
1958
  "additionalProperties": false
1959
+ },
1960
+ {
1961
+ "type": "object",
1962
+ "properties": {
1963
+ "theme": {
1964
+ "type": "string",
1965
+ "const": "halo"
1966
+ },
1967
+ "$schema": {
1968
+ "$ref": "#/anyOf/0/properties/$schema"
1969
+ },
1970
+ "projectId": {
1971
+ "$ref": "#/anyOf/0/properties/projectId"
1972
+ },
1973
+ "name": {
1974
+ "$ref": "#/anyOf/0/properties/name"
1975
+ },
1976
+ "description": {
1977
+ "$ref": "#/anyOf/0/properties/description"
1978
+ },
1979
+ "colors": {
1980
+ "$ref": "#/definitions/colorsSchema"
1981
+ },
1982
+ "logo": {
1983
+ "$ref": "#/anyOf/0/properties/logo"
1984
+ },
1985
+ "favicon": {
1986
+ "$ref": "#/anyOf/0/properties/favicon"
1987
+ },
1988
+ "api": {
1989
+ "$ref": "#/anyOf/0/properties/api"
1990
+ },
1991
+ "appearance": {
1992
+ "$ref": "#/anyOf/0/properties/appearance"
1993
+ },
1994
+ "background": {
1995
+ "$ref": "#/anyOf/0/properties/background"
1996
+ },
1997
+ "navbar": {
1998
+ "$ref": "#/anyOf/0/properties/navbar"
1999
+ },
2000
+ "tabsPosition": {
2001
+ "$ref": "#/anyOf/0/properties/tabsPosition"
2002
+ },
2003
+ "anchors": {
2004
+ "$ref": "#/anyOf/0/properties/anchors"
2005
+ },
2006
+ "navigation": {
2007
+ "$ref": "#/definitions/navigationSchema"
2008
+ },
2009
+ "footer": {
2010
+ "$ref": "#/anyOf/0/properties/footer"
2011
+ },
2012
+ "search": {
2013
+ "$ref": "#/anyOf/0/properties/search"
2014
+ },
2015
+ "seo": {
2016
+ "$ref": "#/anyOf/0/properties/seo"
2017
+ },
2018
+ "fonts": {
2019
+ "$ref": "#/anyOf/0/properties/fonts"
2020
+ },
2021
+ "icons": {
2022
+ "$ref": "#/anyOf/0/properties/icons"
2023
+ },
2024
+ "styling": {
2025
+ "$ref": "#/anyOf/0/properties/styling"
2026
+ },
2027
+ "redirects": {
2028
+ "$ref": "#/anyOf/0/properties/redirects",
2029
+ "description": "URL redirect rules for your documentation site. Each redirect maps a source path to a destination URL"
2030
+ },
2031
+ "integrations": {
2032
+ "$ref": "#/anyOf/0/properties/integrations"
2033
+ },
2034
+ "banner": {
2035
+ "$ref": "#/anyOf/0/properties/banner"
2036
+ },
2037
+ "errors": {
2038
+ "$ref": "#/anyOf/0/properties/errors"
2039
+ },
2040
+ "contextual": {
2041
+ "$ref": "#/anyOf/0/properties/contextual"
2042
+ },
2043
+ "thumbnails": {
2044
+ "$ref": "#/anyOf/0/properties/thumbnails"
2045
+ },
2046
+ "interaction": {
2047
+ "$ref": "#/anyOf/0/properties/interaction"
2048
+ },
2049
+ "metadata": {
2050
+ "$ref": "#/anyOf/0/properties/metadata"
2051
+ },
2052
+ "chat": {
2053
+ "$ref": "#/anyOf/0/properties/chat"
2054
+ },
2055
+ "analytics": {
2056
+ "$ref": "#/anyOf/0/properties/analytics"
2057
+ },
2058
+ "modeToggle": {
2059
+ "$ref": "#/anyOf/0/properties/modeToggle"
2060
+ },
2061
+ "layout": {
2062
+ "$ref": "#/anyOf/0/properties/layout"
2063
+ },
2064
+ "spellcheck": {
2065
+ "$ref": "#/anyOf/0/properties/spellcheck"
2066
+ },
2067
+ "auth": {
2068
+ "$ref": "#/anyOf/0/properties/auth"
2069
+ },
2070
+ "images": {
2071
+ "$ref": "#/anyOf/0/properties/images"
2072
+ }
2073
+ },
2074
+ "required": [
2075
+ "theme",
2076
+ "name",
2077
+ "navigation"
2078
+ ],
2079
+ "additionalProperties": false
1959
2080
  }
1960
2081
  ],
1961
2082
  "definitions": {