zudoku 0.79.1 → 0.80.0

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 (130) hide show
  1. package/dist/cli/cli.js +352 -249
  2. package/dist/declarations/app/ssrCacheControl.d.ts +1 -0
  3. package/dist/declarations/config/create-plugin.d.ts +2 -1
  4. package/dist/declarations/config/validators/InputNavigationSchema.d.ts +13 -0
  5. package/dist/declarations/config/validators/NavigationSchema.d.ts +7 -1
  6. package/dist/declarations/config/validators/ZudokuConfig.d.ts +1 -0
  7. package/dist/declarations/index.d.ts +1 -0
  8. package/dist/declarations/lib/authentication/components/CallbackHandler.d.ts +1 -1
  9. package/dist/declarations/lib/authentication/cookie-sync.d.ts +1 -0
  10. package/dist/declarations/lib/authentication/utils/redirectAfterAuth.d.ts +4 -0
  11. package/dist/declarations/lib/components/Anchor.d.ts +5 -0
  12. package/dist/declarations/lib/components/index.d.ts +2 -0
  13. package/dist/declarations/lib/components/navigation/NavigationFilterContext.d.ts +3 -1
  14. package/dist/declarations/lib/components/navigation/NavigationFrames.d.ts +6 -0
  15. package/dist/declarations/lib/components/navigation/StackRows.d.ts +12 -0
  16. package/dist/declarations/lib/components/navigation/motionFeatures.d.ts +1 -0
  17. package/dist/declarations/lib/components/navigation/useNavigationFrame.d.ts +15 -0
  18. package/dist/declarations/lib/components/navigation/utils.d.ts +16 -1
  19. package/dist/declarations/lib/core/plugin-config.d.ts +2 -0
  20. package/dist/declarations/lib/graphiql/GraphiQLViewer.d.ts +29 -0
  21. package/dist/declarations/lib/graphiql/index.d.ts +2 -0
  22. package/dist/declarations/lib/graphiql/loadGraphiQLFromCdn.d.ts +45 -0
  23. package/dist/declarations/lib/hooks/index.d.ts +1 -0
  24. package/dist/declarations/lib/plugins/openapi/ApiHeader.d.ts +1 -2
  25. package/dist/declarations/lib/plugins/openapi/ParameterList.d.ts +2 -1
  26. package/dist/declarations/lib/plugins/openapi/ParameterListItem.d.ts +1 -1
  27. package/dist/declarations/lib/plugins/openapi/PlaygroundDialogWrapper.d.ts +3 -2
  28. package/dist/declarations/lib/plugins/openapi/RequestBodySidecarBox.d.ts +2 -2
  29. package/dist/declarations/lib/plugins/openapi/ResponsesSidecarBox.d.ts +12 -4
  30. package/dist/declarations/lib/plugins/openapi/SchemaInfo.d.ts +4 -1
  31. package/dist/declarations/lib/plugins/openapi/Sidecar.d.ts +3 -3
  32. package/dist/declarations/lib/plugins/openapi/SidecarExamples.d.ts +2 -2
  33. package/dist/declarations/lib/plugins/openapi/components/ResponseContent.d.ts +2 -2
  34. package/dist/declarations/lib/plugins/openapi/graphql/gql.d.ts +1 -1
  35. package/dist/declarations/lib/plugins/openapi/graphql/graphql.d.ts +136 -466
  36. package/dist/declarations/lib/plugins/openapi/index.d.ts +3 -3
  37. package/dist/declarations/lib/plugins/openapi/interfaces.d.ts +2 -2
  38. package/dist/declarations/lib/plugins/openapi/playground/BodyPanel.d.ts +2 -2
  39. package/dist/declarations/lib/plugins/openapi/playground/ExamplesDropdown.d.ts +3 -3
  40. package/dist/declarations/lib/plugins/openapi/playground/GraphiQL.d.ts +2 -7
  41. package/dist/declarations/lib/plugins/openapi/playground/Playground.d.ts +5 -3
  42. package/dist/declarations/lib/plugins/openapi/playground/result-panel/ResponseTab.d.ts +2 -1
  43. package/dist/declarations/lib/plugins/openapi/playground/result-panel/ResultPanel.d.ts +2 -1
  44. package/dist/declarations/lib/plugins/openapi/playground/result-panel/convertToTypes.d.ts +2 -2
  45. package/dist/declarations/lib/plugins/openapi/util/extractOperationSecuritySchemes.d.ts +2 -1
  46. package/dist/declarations/lib/plugins/openapi/util/graphqlEndpoint.d.ts +1 -0
  47. package/dist/declarations/lib/plugins/openapi/util/shouldShowInfoPage.d.ts +1 -0
  48. package/dist/declarations/vite/index.d.ts +3 -0
  49. package/dist/flat-config.d.ts +7 -0
  50. package/docs/components/sidecar-box.mdx +131 -0
  51. package/docs/configuration/api-catalog.md +62 -43
  52. package/docs/configuration/api-reference.md +5 -4
  53. package/docs/configuration/navigation.mdx +70 -7
  54. package/package.json +25 -22
  55. package/src/app/entry.server.tsx +7 -5
  56. package/src/app/main.css +2 -1
  57. package/src/app/ssrCacheControl.ts +20 -0
  58. package/src/config/create-plugin.ts +47 -28
  59. package/src/config/loader.ts +92 -34
  60. package/src/config/validators/InputNavigationSchema.ts +10 -0
  61. package/src/config/validators/NavigationSchema.ts +16 -2
  62. package/src/config/validators/ZudokuConfig.ts +32 -3
  63. package/src/index.ts +1 -0
  64. package/src/lib/authentication/components/CallbackHandler.tsx +9 -2
  65. package/src/lib/authentication/cookie-sync.ts +39 -6
  66. package/src/lib/authentication/providers/supabase.tsx +7 -1
  67. package/src/lib/authentication/ui/EmailLinkCallbackUi.tsx +2 -1
  68. package/src/lib/authentication/ui/ZudokuAuthUi.tsx +5 -4
  69. package/src/lib/authentication/utils/redirectAfterAuth.ts +25 -0
  70. package/src/lib/components/Anchor.tsx +29 -0
  71. package/src/lib/components/context/ZudokuContext.ts +3 -0
  72. package/src/lib/components/index.ts +2 -0
  73. package/src/lib/components/navigation/Navigation.tsx +30 -41
  74. package/src/lib/components/navigation/NavigationCategory.tsx +28 -16
  75. package/src/lib/components/navigation/NavigationFilterContext.tsx +15 -1
  76. package/src/lib/components/navigation/NavigationFrames.tsx +104 -0
  77. package/src/lib/components/navigation/NavigationItem.tsx +33 -21
  78. package/src/lib/components/navigation/NavigationWrapper.tsx +29 -2
  79. package/src/lib/components/navigation/StackRows.tsx +65 -0
  80. package/src/lib/components/navigation/motionFeatures.ts +2 -0
  81. package/src/lib/components/navigation/useNavigationFrame.ts +107 -0
  82. package/src/lib/components/navigation/utils.ts +60 -6
  83. package/src/lib/core/plugin-config.ts +25 -0
  84. package/src/lib/graphiql/GraphiQLViewer.tsx +247 -0
  85. package/src/lib/graphiql/graphiql-sri.json +11 -0
  86. package/src/lib/graphiql/graphiql.css +6 -0
  87. package/src/lib/graphiql/index.ts +7 -0
  88. package/src/lib/graphiql/loadGraphiQLFromCdn.ts +191 -0
  89. package/src/lib/hooks/index.ts +1 -0
  90. package/src/lib/plugins/openapi/ApiHeader.tsx +1 -3
  91. package/src/lib/plugins/openapi/GeneratedExampleSidecarBox.tsx +1 -1
  92. package/src/lib/plugins/openapi/OperationList.tsx +1 -6
  93. package/src/lib/plugins/openapi/OperationListItem.tsx +2 -1
  94. package/src/lib/plugins/openapi/ParamInfos.tsx +1 -1
  95. package/src/lib/plugins/openapi/ParameterList.tsx +5 -1
  96. package/src/lib/plugins/openapi/ParameterListItem.tsx +1 -1
  97. package/src/lib/plugins/openapi/PlaygroundDialogWrapper.tsx +22 -5
  98. package/src/lib/plugins/openapi/RequestBodySidecarBox.tsx +3 -3
  99. package/src/lib/plugins/openapi/ResponsesSidecarBox.tsx +17 -9
  100. package/src/lib/plugins/openapi/SchemaInfo.tsx +24 -4
  101. package/src/lib/plugins/openapi/SchemaList.tsx +1 -1
  102. package/src/lib/plugins/openapi/Sidecar.tsx +37 -38
  103. package/src/lib/plugins/openapi/SidecarExamples.tsx +3 -3
  104. package/src/lib/plugins/openapi/components/ResponseContent.tsx +2 -2
  105. package/src/lib/plugins/openapi/graphql/gql.ts +3 -3
  106. package/src/lib/plugins/openapi/graphql/graphql.ts +146 -524
  107. package/src/lib/plugins/openapi/index.tsx +8 -1
  108. package/src/lib/plugins/openapi/interfaces.ts +2 -2
  109. package/src/lib/plugins/openapi/playground/BodyPanel.tsx +2 -2
  110. package/src/lib/plugins/openapi/playground/ExamplesDropdown.tsx +3 -3
  111. package/src/lib/plugins/openapi/playground/GraphiQL.tsx +10 -33
  112. package/src/lib/plugins/openapi/playground/GraphiQLDialog.tsx +16 -1
  113. package/src/lib/plugins/openapi/playground/Playground.tsx +5 -2
  114. package/src/lib/plugins/openapi/playground/result-panel/ResponseTab.tsx +7 -5
  115. package/src/lib/plugins/openapi/playground/result-panel/ResultPanel.tsx +18 -0
  116. package/src/lib/plugins/openapi/playground/result-panel/convertToTypes.ts +28 -9
  117. package/src/lib/plugins/openapi/util/extractOperationSecuritySchemes.ts +5 -4
  118. package/src/lib/plugins/openapi/util/getRoutes.tsx +27 -14
  119. package/src/lib/plugins/openapi/util/graphqlEndpoint.ts +6 -1
  120. package/src/lib/plugins/openapi/util/shouldShowInfoPage.ts +15 -0
  121. package/src/lib/shiki.ts +1 -1
  122. package/src/lib/ui/EmbeddedCodeBlock.tsx +2 -2
  123. package/src/lib/{plugins/openapi → ui}/SidecarBox.tsx +1 -1
  124. package/src/vite/dev-server.ts +11 -4
  125. package/src/vite/index.ts +9 -0
  126. package/src/vite/plugin-api.ts +20 -4
  127. package/src/vite/plugin-docs.ts +3 -2
  128. package/src/vite/plugin-theme.ts +6 -2
  129. /package/dist/declarations/lib/{plugins/openapi → ui}/SidecarBox.d.ts +0 -0
  130. /package/src/lib/{plugins/openapi/playground → graphiql}/graphiql-theme.css +0 -0
package/dist/cli/cli.js CHANGED
@@ -85,9 +85,9 @@ var init_transform_config = __esm({
85
85
  }
86
86
  return result;
87
87
  };
88
- runPluginTransformConfig = async (config2) => {
89
- const plugins = config2.plugins ?? [];
90
- let result = config2;
88
+ runPluginTransformConfig = async (config) => {
89
+ const plugins = config.plugins ?? [];
90
+ let result = config;
91
91
  for (const plugin of plugins.filter(isTransformConfigPlugin)) {
92
92
  const merge = (partial) => mergeConfig(result, partial);
93
93
  const transformed = await plugin.transformConfig?.({
@@ -506,8 +506,8 @@ var init_plugin_theme = __esm({
506
506
  // Handle the virtual module for dynamic theme content
507
507
  async load(id) {
508
508
  if (id !== resolvedVirtualModuleId) return;
509
- const config2 = getCurrentConfig();
510
- const themeConfig = config2.theme ?? {};
509
+ const config = getCurrentConfig();
510
+ const themeConfig = config.theme ?? {};
511
511
  const themeCss = [];
512
512
  const fonts = await processFonts(themeConfig);
513
513
  if (fonts.imports.length > 0) {
@@ -583,10 +583,18 @@ ${generateCss(themeConfig.dark)}
583
583
  if (fonts.families.serif) {
584
584
  rootVars.push(` --font-serif: ${fonts.families.serif};`);
585
585
  }
586
- const shikiThemes = config2.syntaxHighlighting?.themes ?? defaultHighlightOptions.themes;
586
+ const shikiThemes = config.syntaxHighlighting?.themes ?? defaultHighlightOptions.themes;
587
587
  const [lightTheme, darkTheme] = (await Promise.all([
588
- import(`@shikijs/themes/${shikiThemes.light}`).then((m) => m.default),
589
- import(`@shikijs/themes/${shikiThemes.dark}`).then((m) => m.default)
588
+ import(
589
+ /* @vite-ignore */
590
+ `@shikijs/themes/${shikiThemes.light}`
591
+ ).then((m) => m.default),
592
+ import(
593
+ /* @vite-ignore */
594
+ `@shikijs/themes/${shikiThemes.dark}`
595
+ ).then(
596
+ (m) => m.default
597
+ )
590
598
  ])).map(normalizeTheme);
591
599
  rootVars.push(
592
600
  ` --shiki-light: ${lightTheme?.fg ?? "#000"};`,
@@ -603,12 +611,12 @@ ${rootVars.join("\n")}
603
611
  // This goes through the normal CSS pipeline so Tailwind can process it
604
612
  async transform(src, id) {
605
613
  if (!id.endsWith("/src/app/main.css")) return;
606
- const config2 = getCurrentConfig();
614
+ const config = getCurrentConfig();
607
615
  const files = new Set(
608
616
  [
609
- config2.__meta.rootDir,
610
- ...config2.__meta.dependencies,
611
- ...config2.__pluginDirs ?? []
617
+ config.__meta.rootDir,
618
+ ...config.__meta.dependencies,
619
+ ...config.__pluginDirs ?? []
612
620
  ].map((file) => path2.relative(path2.dirname(id), file))
613
621
  );
614
622
  const code = [...files].map((file) => `@source "${file}";`);
@@ -660,11 +668,11 @@ ${rootVars.join("\n")}
660
668
  ` --font-serif: var(--font-serif);`
661
669
  );
662
670
  code.push("}");
663
- const customCss = config2.theme?.customCss;
671
+ const customCss = config.theme?.customCss;
664
672
  if (customCss) {
665
673
  code.push(processCustomCss(customCss));
666
674
  }
667
- const defaultThemeImport = config2.theme?.noDefaultTheme ? "" : '@import "./defaultTheme.css" layer(theme);';
675
+ const defaultThemeImport = config.theme?.noDefaultTheme ? "" : '@import "./defaultTheme.css" layer(theme);';
668
676
  return src.replace(DEFAULT_THEME_REPLACE, defaultThemeImport).replace(MAIN_REPLACE, code.join("\n"));
669
677
  }
670
678
  };
@@ -2695,6 +2703,11 @@ var init_InputNavigationSchema = __esm({
2695
2703
  file: z5.string(),
2696
2704
  label: z5.string().optional(),
2697
2705
  path: z5.string().optional()
2706
+ }),
2707
+ z5.object({
2708
+ type: z5.literal("link"),
2709
+ to: z5.string(),
2710
+ label: z5.string().optional()
2698
2711
  })
2699
2712
  ]);
2700
2713
  DisplaySchema = z5.union([
@@ -2710,7 +2723,10 @@ var init_InputNavigationSchema = __esm({
2710
2723
  badge: BadgeSchema.optional(),
2711
2724
  collapsed: z5.boolean().optional(),
2712
2725
  collapsible: z5.boolean().optional(),
2713
- display: DisplaySchema
2726
+ display: DisplaySchema,
2727
+ // Turn a (plugin-generated) category into a stacked sub-nav
2728
+ // E.g. make each OpenAPI tag drill into its own panel. See `stack` above.
2729
+ stack: z5.boolean().optional()
2714
2730
  })
2715
2731
  });
2716
2732
  NavigationInsertRuleSchema = z5.object({
@@ -2762,7 +2778,8 @@ var init_InputNavigationSchema = __esm({
2762
2778
  target: z5.enum(["_self", "_blank"]).optional(),
2763
2779
  icon: IconSchema2.optional(),
2764
2780
  badge: BadgeSchema.optional(),
2765
- display: DisplaySchema
2781
+ display: DisplaySchema,
2782
+ stack: z5.boolean().optional()
2766
2783
  });
2767
2784
  InputNavigationCustomPageSchema = z5.object({
2768
2785
  type: z5.literal("custom-page"),
@@ -2795,7 +2812,8 @@ var init_InputNavigationSchema = __esm({
2795
2812
  collapsible: z5.boolean().optional(),
2796
2813
  collapsed: z5.boolean().optional(),
2797
2814
  link: InputNavigationCategoryLinkDocSchema.optional(),
2798
- display: DisplaySchema
2815
+ display: DisplaySchema,
2816
+ stack: z5.boolean().optional()
2799
2817
  });
2800
2818
  InputNavigationCategorySchema = BaseInputNavigationCategorySchema.extend({
2801
2819
  items: z5.lazy(() => InputNavigationItemSchema.array())
@@ -2919,20 +2937,35 @@ __export(ZudokuConfig_exports, {
2919
2937
  import colors from "picocolors";
2920
2938
  import { isValidElement as isValidElement2 } from "react";
2921
2939
  import { z as z7 } from "zod";
2922
- function validateConfig(config2, configPath) {
2923
- const validationResult = ZudokuConfig.safeParse(config2);
2940
+ function validateConfig(config, configPath) {
2941
+ warnUnsafeConfigKeys(config);
2942
+ const validationResult = ZudokuConfig.safeParse(config);
2924
2943
  if (!validationResult.success) {
2944
+ const prettyErrors = z7.prettifyError(validationResult.error);
2945
+ const location = configPath ? ` at ${configPath}` : "";
2925
2946
  if (process.env.NODE_ENV === "production") {
2926
2947
  throw new Error(
2927
- `Whoops, looks like there's an issue with your ${configPath ?? "config"}:
2928
- ${z7.prettifyError(validationResult.error)}`
2948
+ `Invalid Zudoku configuration${location}:
2949
+ ${prettyErrors}`
2929
2950
  );
2930
2951
  }
2931
- console.log(colors.yellow("Validation errors:"));
2932
- console.log(colors.yellow(z7.prettifyError(validationResult.error)));
2952
+ console.log(colors.yellow(`Invalid Zudoku configuration${location}:`));
2953
+ console.log(colors.yellow(prettyErrors));
2933
2954
  }
2934
2955
  }
2935
- var ThemeSchema, ApiCatalogCategorySchema, LanguageOption, AiAssistantCustomSchema, AiAssistantPresets, AiAssistantsSchema, ApiOptionsSchema, ApiConfigSchema, VersionConfigSchema, ApiSchema, ApiKeysSchema, LogoSchema, FooterSocialIcons, FooterSocialSchema, FooterSchema, SiteMapSchema, DEFAULT_DOCS_FILES, LlmsConfigSchema, DocsConfigSchema, Redirect, SearchSchema, SignUpUrlValueSchema, SignUpUrlSchema, SignUpOpenIdSchema, AuthenticationSchema, MetadataSchema, FontConfigSchema, FontsConfigSchema, CssObject, ThemeConfigSchema, SiteSchema, PlacementPosition, HeaderConfigSchema, ApiCatalogSchema, CdnUrlSchema, BaseConfigSchema, ZudokuConfig;
2956
+ function warnUnsafeConfigKeys(config) {
2957
+ if (typeof config !== "object" || config === null) return;
2958
+ const usedKeys = DEPRECATED_UNSAFE_KEYS.filter(
2959
+ (key) => Object.hasOwn(config, key)
2960
+ );
2961
+ if (usedKeys.length === 0) return;
2962
+ console.log(
2963
+ colors.yellow(
2964
+ `Warning: The following config ${usedKeys.length === 1 ? "option is" : "options are"} deprecated and will be removed soon: ${usedKeys.join(", ")}`
2965
+ )
2966
+ );
2967
+ }
2968
+ var ThemeSchema, ApiCatalogCategorySchema, LanguageOption, AiAssistantCustomSchema, AiAssistantPresets, AiAssistantsSchema, ApiOptionsSchema, ApiConfigSchema, VersionConfigSchema, ApiSchema, ApiKeysSchema, LogoSchema, FooterSocialIcons, FooterSocialSchema, FooterSchema, SiteMapSchema, DEFAULT_DOCS_FILES, LlmsConfigSchema, DocsConfigSchema, Redirect, SearchSchema, SignUpUrlValueSchema, SignUpUrlSchema, SignUpOpenIdSchema, AuthenticationSchema, MetadataSchema, FontConfigSchema, FontsConfigSchema, CssObject, ThemeConfigSchema, SiteSchema, PlacementPosition, HeaderConfigSchema, ApiCatalogSchema, CdnUrlSchema, BaseConfigSchema, ZudokuConfig, DEPRECATED_UNSAFE_KEYS;
2936
2969
  var init_ZudokuConfig = __esm({
2937
2970
  "src/config/validators/ZudokuConfig.ts"() {
2938
2971
  init_plugin_theme();
@@ -3471,6 +3504,7 @@ var init_ZudokuConfig = __esm({
3471
3504
  __pluginDirs: z7.array(z7.string())
3472
3505
  });
3473
3506
  ZudokuConfig = BaseConfigSchema.partial();
3507
+ DEPRECATED_UNSAFE_KEYS = ["UNSAFE_slotlets"];
3474
3508
  }
3475
3509
  });
3476
3510
 
@@ -3493,29 +3527,48 @@ async function getConfigFilePath(rootDir) {
3493
3527
  }
3494
3528
  async function loadZudokuConfigWithMeta(rootDir) {
3495
3529
  const configPath = await getConfigFilePath(rootDir);
3496
- const { module, dependencies } = await runnerImport(configPath, {
3497
- plugins: [virtualModuleStubPlugin],
3498
- environments: {
3499
- inline: {
3500
- resolve: {
3501
- // Prevent Node.js from trying to load zudoku's raw .ts source
3502
- // directly, which fails with ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING
3503
- // when --experimental-strip-types is enabled. Uses regex to also
3504
- // catch plugins that re-export from zudoku (e.g. @zuplo/zudoku-plugin-*).
3505
- noExternal: [/zudoku/]
3530
+ let module;
3531
+ let dependencies;
3532
+ try {
3533
+ ({ module, dependencies } = await runnerImport(configPath, {
3534
+ plugins: [virtualModuleStubPlugin],
3535
+ environments: {
3536
+ inline: {
3537
+ resolve: {
3538
+ // Prevent Node.js from trying to load zudoku's raw .ts source
3539
+ // directly, which fails with ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING
3540
+ // when --experimental-strip-types is enabled. Uses regex to also
3541
+ // catch plugins that re-export from zudoku (e.g. @zuplo/zudoku-plugin-*).
3542
+ noExternal: [/zudoku/]
3543
+ }
3506
3544
  }
3545
+ },
3546
+ server: {
3547
+ // this allows us to 'load' CSS files in the config
3548
+ // see https://github.com/vitejs/vite/pull/19577
3549
+ perEnvironmentStartEndDuringDev: true
3507
3550
  }
3508
- },
3509
- server: {
3510
- // this allows us to 'load' CSS files in the config
3511
- // see https://github.com/vitejs/vite/pull/19577
3512
- perEnvironmentStartEndDuringDev: true
3513
- }
3514
- });
3515
- const config2 = module.default;
3516
- validateConfig(config2, configPath);
3551
+ }));
3552
+ } catch (error) {
3553
+ const detail = error instanceof Error ? error.message : String(error);
3554
+ throw new Error(
3555
+ `Invalid Zudoku configuration at ${colors2.dim(configPath)}:
3556
+
3557
+ ${detail}`,
3558
+ { cause: error }
3559
+ );
3560
+ }
3561
+ if (module.default === void 0) {
3562
+ throw new Error(
3563
+ `Invalid Zudoku configuration at ${colors2.dim(configPath)}:
3564
+
3565
+ Config file must have a default export.`
3566
+ );
3567
+ }
3568
+ const config = module.default;
3569
+ validateConfig(config, configPath);
3517
3570
  const configWithMetadata = {
3518
- ...config2,
3571
+ ...config,
3519
3572
  __meta: {
3520
3573
  rootDir,
3521
3574
  moduleDir: getZudokuRootDir(),
@@ -3536,8 +3589,12 @@ function loadEnv(configEnv, rootDir) {
3536
3589
  return { publicEnv: publicEnv2, envPrefix: envPrefix2 };
3537
3590
  }
3538
3591
  async function hasConfigChanged() {
3592
+ const config = getConfig();
3539
3593
  if (!config || !modifiedTimes) return true;
3540
- const files = [config.__meta.configPath, ...config.__meta.dependencies];
3594
+ const files = [
3595
+ config.__meta.configPath,
3596
+ ...config.__meta.dependencies.filter(isFileSystemPath)
3597
+ ];
3541
3598
  try {
3542
3599
  const hasChanged = await Promise.all(
3543
3600
  files.map(async (depPath) => {
@@ -3552,8 +3609,12 @@ async function hasConfigChanged() {
3552
3609
  }
3553
3610
  }
3554
3611
  async function updateModifiedTimes() {
3612
+ const config = getConfig();
3555
3613
  if (!config) return;
3556
- const files = [config.__meta.configPath, ...config.__meta.dependencies];
3614
+ const files = [
3615
+ config.__meta.configPath,
3616
+ ...config.__meta.dependencies.filter(isFileSystemPath)
3617
+ ];
3557
3618
  modifiedTimes = /* @__PURE__ */ new Map();
3558
3619
  await Promise.all(
3559
3620
  files.map(async (depPath) => {
@@ -3564,29 +3625,38 @@ async function updateModifiedTimes() {
3564
3625
  }
3565
3626
  async function loadZudokuConfig(configEnv, rootDir) {
3566
3627
  const shouldReload = await hasConfigChanged();
3567
- if (!shouldReload && config && envPrefix && publicEnv) {
3568
- return { config, envPrefix, publicEnv };
3628
+ const existing = getConfig();
3629
+ if (!shouldReload && existing && envPrefix && publicEnv) {
3630
+ return { config: existing, envPrefix, publicEnv };
3569
3631
  }
3570
3632
  ({ publicEnv, envPrefix } = loadEnv(configEnv, rootDir));
3571
3633
  try {
3572
3634
  const loadedConfig = await loadZudokuConfigWithMeta(rootDir);
3573
- config = await runPluginTransformConfig(loadedConfig);
3635
+ const config = await runPluginTransformConfig(loadedConfig);
3636
+ setConfig(config);
3574
3637
  logger.info(
3575
3638
  colors2.cyan(`loaded config file `) + colors2.dim(config.__meta.configPath),
3576
3639
  { timestamp: true }
3577
3640
  );
3578
3641
  return { config, envPrefix, publicEnv };
3579
3642
  } catch (error) {
3580
- const errorMessage = error instanceof Error ? error.message : String(error);
3581
- if (config) {
3582
- return { config, envPrefix, publicEnv };
3643
+ const lastValid = getConfig();
3644
+ if (lastValid) {
3645
+ logger.error(
3646
+ colors2.red("Failed to reload config, using last valid config."),
3647
+ {
3648
+ timestamp: true,
3649
+ error: error instanceof Error ? error : new Error(String(error))
3650
+ }
3651
+ );
3652
+ return { config: lastValid, envPrefix, publicEnv };
3583
3653
  }
3584
- throw new Error(errorMessage, { cause: error });
3654
+ throw error;
3585
3655
  } finally {
3586
3656
  await updateModifiedTimes();
3587
3657
  }
3588
3658
  }
3589
- var config, envPrefix, publicEnv, modifiedTimes, zudokuConfigFiles, virtualModuleStubPlugin, getCurrentConfig;
3659
+ var configStore, getConfig, setConfig, envPrefix, publicEnv, modifiedTimes, zudokuConfigFiles, virtualModuleStubPlugin, isFileSystemPath, getCurrentConfig;
3590
3660
  var init_loader = __esm({
3591
3661
  "src/config/loader.ts"() {
3592
3662
  init_logger();
@@ -3595,6 +3665,11 @@ var init_loader = __esm({
3595
3665
  init_invariant();
3596
3666
  init_file_exists();
3597
3667
  init_ZudokuConfig();
3668
+ configStore = globalThis;
3669
+ getConfig = () => configStore.__zudokuConfig;
3670
+ setConfig = (next) => {
3671
+ configStore.__zudokuConfig = next;
3672
+ };
3598
3673
  zudokuConfigFiles = [
3599
3674
  "zudoku.config.js",
3600
3675
  "zudoku.config.jsx",
@@ -3611,7 +3686,9 @@ var init_loader = __esm({
3611
3686
  if (id.startsWith("\0virtual:")) return "export default {}";
3612
3687
  }
3613
3688
  };
3689
+ isFileSystemPath = (p) => !p.startsWith("\0") && !p.includes("virtual:");
3614
3690
  getCurrentConfig = () => {
3691
+ const config = getConfig();
3615
3692
  invariant(config, "Config not loaded");
3616
3693
  return config;
3617
3694
  };
@@ -3808,25 +3885,25 @@ var getClerkFrontendApi = (publishableKey) => {
3808
3885
  };
3809
3886
 
3810
3887
  // src/lib/auth/issuer.ts
3811
- var getIssuer = async (config2) => {
3812
- switch (config2.authentication?.type) {
3888
+ var getIssuer = async (config) => {
3889
+ switch (config.authentication?.type) {
3813
3890
  case "clerk": {
3814
- return `https://${getClerkFrontendApi(config2.authentication.clerkPubKey)}`;
3891
+ return `https://${getClerkFrontendApi(config.authentication.clerkPubKey)}`;
3815
3892
  }
3816
3893
  case "auth0": {
3817
- return `https://${config2.authentication.domain}/`;
3894
+ return `https://${config.authentication.domain}/`;
3818
3895
  }
3819
3896
  case "openid": {
3820
- return config2.authentication.issuer;
3897
+ return config.authentication.issuer;
3821
3898
  }
3822
3899
  case "supabase": {
3823
- return config2.authentication.supabaseUrl;
3900
+ return config.authentication.supabaseUrl;
3824
3901
  }
3825
3902
  case "azureb2c": {
3826
- return config2.authentication.issuer;
3903
+ return config.authentication.issuer;
3827
3904
  }
3828
3905
  case "firebase": {
3829
- return `https://securetoken.google.com/${config2.authentication.projectId}`;
3906
+ return `https://securetoken.google.com/${config.authentication.projectId}`;
3830
3907
  }
3831
3908
  case void 0: {
3832
3909
  return void 0;
@@ -3867,22 +3944,22 @@ init_joinUrl();
3867
3944
  var PROTECTED_CHUNK_DIR = "_protected";
3868
3945
  var MANIFEST_VERSION = 1;
3869
3946
  var MANIFEST_FILENAME = "zudoku-manifest.json";
3870
- var buildManifest = (config2) => {
3871
- const protectedRoutes = ProtectedRoutesSchema.parse(config2.protectedRoutes);
3947
+ var buildManifest = (config) => {
3948
+ const protectedRoutes = ProtectedRoutesSchema.parse(config.protectedRoutes);
3872
3949
  const routePatterns = protectedRoutes ? Object.keys(protectedRoutes) : [];
3873
3950
  return {
3874
3951
  version: MANIFEST_VERSION,
3875
- basePath: config2.basePath ?? "/",
3952
+ basePath: config.basePath ?? "/",
3876
3953
  ssrEntry: "server/entry.js",
3877
3954
  static: {
3878
- prefixes: [joinUrl(config2.basePath, "assets")]
3955
+ prefixes: [joinUrl(config.basePath, "assets")]
3879
3956
  },
3880
3957
  protected: {
3881
- chunkPrefix: joinUrl(config2.basePath, PROTECTED_CHUNK_DIR),
3958
+ chunkPrefix: joinUrl(config.basePath, PROTECTED_CHUNK_DIR),
3882
3959
  routePatterns
3883
3960
  },
3884
3961
  auth: {
3885
- sessionEndpoint: joinUrl(config2.basePath, "/__z/auth/session"),
3962
+ sessionEndpoint: joinUrl(config.basePath, "/__z/auth/session"),
3886
3963
  cookies: {
3887
3964
  access: ACCESS_TOKEN_COOKIE,
3888
3965
  refresh: REFRESH_TOKEN_COOKIE,
@@ -3947,9 +4024,9 @@ async function collectStyleUrls(server, entries) {
3947
4024
  var VIRTUAL_ENTRY = "virtual:ssr-css.css";
3948
4025
  function vitePluginSsrCss(pluginOpts) {
3949
4026
  let server;
3950
- const config2 = getCurrentConfig();
4027
+ const config = getCurrentConfig();
3951
4028
  const virtualHref = path5.join(
3952
- config2.basePath ?? "",
4029
+ config.basePath ?? "",
3953
4030
  `/@id/__x00__${VIRTUAL_ENTRY}?direct`
3954
4031
  );
3955
4032
  const cssModuleMap = /* @__PURE__ */ new Map();
@@ -4057,8 +4134,8 @@ var viteApiKeysPlugin = () => {
4057
4134
  },
4058
4135
  async load(id) {
4059
4136
  if (id === resolvedVirtualModuleId4) {
4060
- const config2 = getCurrentConfig();
4061
- if (!config2.apiKeys?.enabled || config2.__meta.mode === "standalone") {
4137
+ const config = getCurrentConfig();
4138
+ if (!config.apiKeys?.enabled || config.__meta.mode === "standalone") {
4062
4139
  return `export const configuredApiKeysPlugin = undefined;`;
4063
4140
  }
4064
4141
  const deploymentName = ZuploEnv.buildConfig?.deploymentName || getZuploSystemConfigurations(process.env.ZUPLO_SYSTEM_CONFIGURATIONS)?.__ZUPLO_DEPLOYMENT_NAME;
@@ -4134,8 +4211,8 @@ var getBuildConfig = async () => {
4134
4211
  ).then((m) => m.module.default);
4135
4212
  return validateBuildConfig(buildModule);
4136
4213
  };
4137
- function validateBuildConfig(config2) {
4138
- const validationResult = BuildConfigSchema2.safeParse(config2);
4214
+ function validateBuildConfig(config) {
4215
+ const validationResult = BuildConfigSchema2.safeParse(config);
4139
4216
  if (!validationResult.success) {
4140
4217
  if (process.env.NODE_ENV === "production") {
4141
4218
  throw new Error(z8.prettifyError(validationResult.error));
@@ -5455,11 +5532,11 @@ var SchemaManager = class {
5455
5532
  config;
5456
5533
  constructor({
5457
5534
  storeDir,
5458
- config: config2,
5535
+ config,
5459
5536
  processors
5460
5537
  }) {
5461
5538
  this.storeDir = storeDir;
5462
- this.config = config2;
5539
+ this.config = config;
5463
5540
  this.processors = [
5464
5541
  ({ schema: schema2 }) => upgrade(schema2).specification,
5465
5542
  flattenAllOfProcessor,
@@ -5537,7 +5614,7 @@ var SchemaManager = class {
5537
5614
  const existingSchema = schemas[index];
5538
5615
  const schemaVersion = processedSchema.info.version ?? FALLBACK_VERSION;
5539
5616
  const versionPath = existingSchema?.path && existingSchema.path.length > 0 ? existingSchema.path : paramsPath(params) || schemaVersion;
5540
- const config2 = ensureArray(this.config.apis ?? []).find(
5617
+ const config = ensureArray(this.config.apis ?? []).find(
5541
5618
  (c) => c.path === configuredPath
5542
5619
  );
5543
5620
  const processed = {
@@ -5553,7 +5630,7 @@ var SchemaManager = class {
5553
5630
  versionPath,
5554
5631
  configuredPath,
5555
5632
  params,
5556
- config2?.options
5633
+ config?.options
5557
5634
  ),
5558
5635
  processedJsonPath,
5559
5636
  processedTime
@@ -5639,10 +5716,10 @@ var SchemaManager = class {
5639
5716
  }
5640
5717
  return map;
5641
5718
  };
5642
- createSchemaPath = (inputPath, versionPath, apiPath, params, config2) => {
5719
+ createSchemaPath = (inputPath, versionPath, apiPath, params, config) => {
5643
5720
  const suffix = paramsSuffix(params);
5644
5721
  const extension = suffix ? ".json" : path7.extname(inputPath);
5645
- const fileName = config2?.schemaDownload?.fileName ?? this.config.defaults?.apis?.schemaDownload?.fileName ?? "schema";
5722
+ const fileName = config?.schemaDownload?.fileName ?? this.config.defaults?.apis?.schemaDownload?.fileName ?? "schema";
5646
5723
  return joinUrl(
5647
5724
  this.config.basePath,
5648
5725
  apiPath,
@@ -5733,10 +5810,10 @@ var NavigationResolver = class {
5733
5810
  globFiles = [];
5734
5811
  items = [];
5735
5812
  itemIndex = 0;
5736
- constructor(config2) {
5737
- this.rootDir = config2.__meta.rootDir;
5738
- this.globPatterns = DocsConfigSchema.parse(config2.docs ?? {}).files;
5739
- this.items = config2.navigation ?? [];
5813
+ constructor(config) {
5814
+ this.rootDir = config.__meta.rootDir;
5815
+ this.globPatterns = DocsConfigSchema.parse(config.docs ?? {}).files;
5816
+ this.items = config.navigation ?? [];
5740
5817
  }
5741
5818
  async initialize() {
5742
5819
  if (this.globFiles.length > 0) return;
@@ -5803,6 +5880,9 @@ var NavigationResolver = class {
5803
5880
  if (typeof item === "string") {
5804
5881
  return this.resolveLink(item);
5805
5882
  }
5883
+ if (item.type === "link") {
5884
+ return { type: "link", to: item.to, label: item.label };
5885
+ }
5806
5886
  const doc = await this.resolveDoc(item.file);
5807
5887
  return doc ? {
5808
5888
  ...item,
@@ -5890,11 +5970,11 @@ var viteNavigationPlugin = () => {
5890
5970
  },
5891
5971
  async load(id) {
5892
5972
  if (id !== resolvedVirtualModuleId2) return;
5893
- const config2 = getCurrentConfig();
5894
- const resolver = new NavigationResolver(config2);
5973
+ const config = getCurrentConfig();
5974
+ const resolver = new NavigationResolver(config);
5895
5975
  const resolvedNavigation = await resolver.resolve();
5896
5976
  const resolvedRules = await resolver.resolveRules(
5897
- config2.navigationRules ?? []
5977
+ config.navigationRules ?? []
5898
5978
  );
5899
5979
  const collectedIcons = /* @__PURE__ */ new Set();
5900
5980
  let hasMissingIcon = false;
@@ -5920,7 +6000,7 @@ var viteNavigationPlugin = () => {
5920
6000
  2
5921
6001
  );
5922
6002
  const headerNavigationCode = stringifyWithIcons(
5923
- config2.header?.navigation ?? []
6003
+ config.header?.navigation ?? []
5924
6004
  );
5925
6005
  const navigationCode = stringifyWithIcons(resolvedNavigation);
5926
6006
  const rulesCode = stringifyWithIcons(resolvedRules);
@@ -5928,7 +6008,7 @@ var viteNavigationPlugin = () => {
5928
6008
  invariant(navigationCode, "Failed to stringify navigation");
5929
6009
  invariant(rulesCode, "Failed to stringify navigation rules");
5930
6010
  await writePluginDebugCode(
5931
- config2.__meta.rootDir,
6011
+ config.__meta.rootDir,
5932
6012
  "navigation-plugin",
5933
6013
  `export const headerNavigation = ${headerNavigationCode};
5934
6014
  export const navigation = ${navigationCode};
@@ -6031,8 +6111,24 @@ var viteApiPlugin = async () => {
6031
6111
  const mainFiles = schemaManager.getFilesToReprocess(id);
6032
6112
  if (mainFiles.length === 0) return;
6033
6113
  console.log(`Re-processing schema ${id}`);
6034
- for (const inputConfig of mainFiles) {
6035
- await schemaManager.processSchema(inputConfig);
6114
+ try {
6115
+ for (const inputConfig of mainFiles) {
6116
+ await schemaManager.processSchema(inputConfig);
6117
+ }
6118
+ } catch (error) {
6119
+ const err = error instanceof Error ? error : new Error(String(error));
6120
+ server.config.logger.error(
6121
+ `Failed to re-process schema ${id}. Fix the error and save again.`,
6122
+ { error: err }
6123
+ );
6124
+ server.ws.send({
6125
+ type: "error",
6126
+ err: {
6127
+ message: `Failed to re-process schema ${id}: ${err.message}`,
6128
+ stack: err.stack ?? ""
6129
+ }
6130
+ });
6131
+ return;
6036
6132
  }
6037
6133
  schemaManager.getAllTrackedFiles().forEach((file) => server.watcher.add(file));
6038
6134
  invalidate(server);
@@ -6046,13 +6142,13 @@ var viteApiPlugin = async () => {
6046
6142
  },
6047
6143
  async load(id) {
6048
6144
  if (id !== resolvedVirtualModuleId4) return;
6049
- const config2 = getCurrentConfig();
6050
- if (!deepEqual2(schemaManager.config.apis, config2.apis)) {
6051
- schemaManager.config = config2;
6145
+ const config = getCurrentConfig();
6146
+ if (!deepEqual2(schemaManager.config.apis, config.apis)) {
6147
+ schemaManager.config = config;
6052
6148
  await schemaManager.processAllSchemas();
6053
6149
  schemaManager.getAllTrackedFiles().forEach((file) => this.addWatchFile(file));
6054
6150
  }
6055
- if (config2.__meta.mode === "standalone") {
6151
+ if (config.__meta.mode === "standalone") {
6056
6152
  return [
6057
6153
  "export const configuredApiPlugins = [];",
6058
6154
  "export const configuredApiCatalogPlugins = [];"
@@ -6063,12 +6159,12 @@ var viteApiPlugin = async () => {
6063
6159
  `const configuredApiPlugins = [];`,
6064
6160
  `const configuredApiCatalogPlugins = [];`
6065
6161
  ];
6066
- if (config2.apis) {
6162
+ if (config.apis) {
6067
6163
  code.push('import { openApiPlugin } from "zudoku/plugins/openapi";');
6068
6164
  code.push(
6069
6165
  `const apis = Array.isArray(config.apis) ? config.apis : [config.apis]`
6070
6166
  );
6071
- const apis = ensureArray(config2.apis);
6167
+ const apis = ensureArray(config.apis);
6072
6168
  const apiMetadata = [];
6073
6169
  const httpMethods = /* @__PURE__ */ new Set([
6074
6170
  "get",
@@ -6145,7 +6241,7 @@ var viteApiPlugin = async () => {
6145
6241
  ` disableSecurity: config.defaults?.apis?.disableSecurity ?? true,`,
6146
6242
  ` showVersionSelect: config.defaults?.apis?.showVersionSelect ?? "if-available",`,
6147
6243
  ` expandAllTags: config.defaults?.apis?.expandAllTags ?? true,`,
6148
- ` showInfoPage: config.defaults?.apis?.showInfoPage ?? true,`,
6244
+ ` showInfoPage: config.defaults?.apis?.showInfoPage,`,
6149
6245
  ` schemaDownload: config.defaults?.apis?.schemaDownload,`,
6150
6246
  ` transformExamples: config.defaults?.apis?.transformExamples,`,
6151
6247
  ` generateCodeSnippet: config.defaults?.apis?.generateCodeSnippet,`,
@@ -6170,7 +6266,7 @@ var viteApiPlugin = async () => {
6170
6266
  ` disableSecurity: config.defaults?.apis?.disableSecurity ?? true,`,
6171
6267
  ` showVersionSelect: config.defaults?.apis?.showVersionSelect ?? "if-available",`,
6172
6268
  ` expandAllTags: config.defaults?.apis?.expandAllTags ?? false,`,
6173
- ` showInfoPage: config.defaults?.apis?.showInfoPage ?? true,`,
6269
+ ` showInfoPage: config.defaults?.apis?.showInfoPage,`,
6174
6270
  ` schemaDownload: config.defaults?.apis?.schemaDownload,`,
6175
6271
  ` ...${JSON.stringify(apiConfig.options ?? {})},`,
6176
6272
  " },",
@@ -6178,11 +6274,11 @@ var viteApiPlugin = async () => {
6178
6274
  );
6179
6275
  }
6180
6276
  }
6181
- if (config2.catalogs) {
6277
+ if (config.catalogs) {
6182
6278
  code.push(
6183
6279
  'import { apiCatalogPlugin } from "zudoku/plugins/api-catalog";'
6184
6280
  );
6185
- const catalogs = ensureArray(config2.catalogs);
6281
+ const catalogs = ensureArray(config.catalogs);
6186
6282
  const categories = apis.flatMap((api) => api.categories ?? []).reduce((acc, catalog) => {
6187
6283
  if (!acc.has(catalog.label)) {
6188
6284
  acc.set(catalog.label ?? "", new Set(catalog.tags));
@@ -6228,12 +6324,12 @@ var viteApiPlugin = async () => {
6228
6324
  },
6229
6325
  async closeBundle() {
6230
6326
  if (this.environment.name === "ssr") return;
6231
- const config2 = getCurrentConfig();
6327
+ const config = getCurrentConfig();
6232
6328
  const pathMap = schemaManager.getUrlToFilePathMap();
6233
6329
  if (process.env.NODE_ENV !== "production") return;
6234
6330
  for (const [urlPath, inputPath] of pathMap) {
6235
6331
  const content = await fs2.readFile(inputPath, "utf-8");
6236
- const outputPath = path11.join(config2.__meta.rootDir, "dist", urlPath);
6332
+ const outputPath = path11.join(config.__meta.rootDir, "dist", urlPath);
6237
6333
  await fs2.mkdir(path11.dirname(outputPath), { recursive: true });
6238
6334
  await fs2.writeFile(outputPath, content, "utf-8");
6239
6335
  }
@@ -6257,16 +6353,16 @@ var viteAuthPlugin = () => {
6257
6353
  },
6258
6354
  async load(id) {
6259
6355
  if (id === resolvedVirtualModuleId4) {
6260
- const config2 = getCurrentConfig();
6261
- if (!config2.authentication || config2.__meta.mode === "standalone") {
6356
+ const config = getCurrentConfig();
6357
+ if (!config.authentication || config.__meta.mode === "standalone") {
6262
6358
  return `export const configuredAuthProvider = undefined;`;
6263
6359
  }
6264
6360
  return [
6265
6361
  `const config = {
6266
- ...${JSON.stringify(config2.authentication, null, 2)},
6267
- basePath: ${config2.basePath ? JSON.stringify(config2.basePath) : "undefined"},
6362
+ ...${JSON.stringify(config.authentication, null, 2)},
6363
+ basePath: ${config.basePath ? JSON.stringify(config.basePath) : "undefined"},
6268
6364
  };`,
6269
- `import authProvider from "zudoku/auth/${config2.authentication.type}";`,
6365
+ `import authProvider from "zudoku/auth/${config.authentication.type}";`,
6270
6366
  `export const configuredAuthProvider = authProvider(config);`
6271
6367
  ].join("\n");
6272
6368
  }
@@ -6349,8 +6445,8 @@ var viteCustomPagesPlugin = () => {
6349
6445
  },
6350
6446
  async load(id) {
6351
6447
  if (id === resolvedVirtualModuleId4) {
6352
- const config2 = getCurrentConfig();
6353
- if (config2.__meta.mode === "standalone" || !config2.navigation) {
6448
+ const config = getCurrentConfig();
6449
+ if (config.__meta.mode === "standalone" || !config.navigation) {
6354
6450
  return `export const configuredCustomPagesPlugin = undefined;`;
6355
6451
  }
6356
6452
  const code = [
@@ -6377,9 +6473,9 @@ var viteDocMetadataPlugin = () => ({
6377
6473
  enforce: "pre",
6378
6474
  name: "zudoku-doc-metadata-plugin",
6379
6475
  configureServer: async (server) => {
6380
- const config2 = getCurrentConfig();
6476
+ const config = getCurrentConfig();
6381
6477
  const files = await glob2("**/*.{md,mdx}", {
6382
- cwd: config2.__meta.rootDir,
6478
+ cwd: config.__meta.rootDir,
6383
6479
  ignore: ["node_modules", "dist"],
6384
6480
  absolute: true
6385
6481
  });
@@ -6457,12 +6553,12 @@ var navigationListItem = cva(
6457
6553
  // src/vite/plugin-docs.ts
6458
6554
  init_joinUrl();
6459
6555
  var ensureLeadingSlash = joinUrl;
6460
- var globMarkdownFiles = async (config2, options = { absolute: false }) => {
6461
- const docsConfig = DocsConfigSchema.parse(config2.docs ?? {});
6556
+ var globMarkdownFiles = async (config, options = { absolute: false }) => {
6557
+ const docsConfig = DocsConfigSchema.parse(config.docs ?? {});
6462
6558
  const fileMapping = {};
6463
6559
  for (const globPattern of docsConfig.files) {
6464
6560
  const globbedFiles = await glob3(globPattern, {
6465
- root: config2.__meta.rootDir,
6561
+ root: config.__meta.rootDir,
6466
6562
  ignore: ["**/node_modules/**", "**/dist/**", "**/.git/**"],
6467
6563
  // Always glob with relative paths to avoid issues on different OS
6468
6564
  absolute: false,
@@ -6473,7 +6569,7 @@ var globMarkdownFiles = async (config2, options = { absolute: false }) => {
6473
6569
  if (process.env.NODE_ENV !== "development") {
6474
6570
  const draftStatuses = await Promise.all(
6475
6571
  globbedFiles.map(async (file) => {
6476
- const absolutePath = path12.resolve(config2.__meta.rootDir, file);
6572
+ const absolutePath = path12.resolve(config.__meta.rootDir, file);
6477
6573
  const { data } = await readFrontmatter(absolutePath);
6478
6574
  return { file, isDraft: data.draft === true };
6479
6575
  })
@@ -6488,32 +6584,32 @@ var globMarkdownFiles = async (config2, options = { absolute: false }) => {
6488
6584
  }
6489
6585
  const relativePath = path12.posix.relative(parent, file);
6490
6586
  const routePath = ensureLeadingSlash(relativePath.replace(/\.mdx?$/, ""));
6491
- const filePath = options.absolute ? path12.resolve(config2.__meta.rootDir, file) : file;
6587
+ const filePath = options.absolute ? path12.resolve(config.__meta.rootDir, file) : file;
6492
6588
  fileMapping[routePath] = filePath;
6493
6589
  }
6494
6590
  }
6495
6591
  return fileMapping;
6496
6592
  };
6497
- var resolveCustomNavigationPaths = async (config2, fileMapping) => {
6498
- if (!config2.navigation && !config2.navigationRules) return fileMapping;
6499
- const resolver = new NavigationResolver(config2);
6593
+ var resolveCustomNavigationPaths = async (config, fileMapping) => {
6594
+ if (!config.navigation && !config.navigationRules) return fileMapping;
6595
+ const resolver = new NavigationResolver(config);
6500
6596
  const mapping = { ...fileMapping };
6501
6597
  const processItem = (item) => {
6502
- const doc = item.type === "doc" ? { file: item.file, path: item.path } : item.type === "category" && item.link ? { file: item.link.file, path: item.link.path } : void 0;
6598
+ const doc = item.type === "doc" ? { file: item.file, path: item.path } : item.type === "category" && item.link?.type === "doc" ? { file: item.link.file, path: item.link.path } : void 0;
6503
6599
  if (!doc || doc.path === doc.file) return;
6504
6600
  const fileRoutePath = ensureLeadingSlash(doc.file.replace(/\.mdx?$/, ""));
6505
6601
  const filePath = mapping[fileRoutePath];
6506
6602
  if (!filePath) return;
6507
6603
  const customPath = ensureLeadingSlash(doc.path);
6508
6604
  mapping[customPath] = filePath;
6509
- delete mapping[fileRoutePath];
6605
+ if (customPath !== fileRoutePath) delete mapping[fileRoutePath];
6510
6606
  };
6511
- if (config2.navigation) {
6607
+ if (config.navigation) {
6512
6608
  const resolvedNavigation = await resolver.resolve();
6513
6609
  traverseNavigation(resolvedNavigation, processItem);
6514
6610
  }
6515
- if (config2.navigationRules) {
6516
- const resolvedRules = await resolver.resolveRules(config2.navigationRules);
6611
+ if (config.navigationRules) {
6612
+ const resolvedRules = await resolver.resolveRules(config.navigationRules);
6517
6613
  for (const rule of resolvedRules) {
6518
6614
  if (rule.type === "insert") {
6519
6615
  traverseNavigation(rule.items, processItem);
@@ -6534,17 +6630,17 @@ var viteDocsPlugin = () => {
6534
6630
  },
6535
6631
  async load(id) {
6536
6632
  if (id !== resolvedVirtualModuleId4) return;
6537
- const config2 = getCurrentConfig();
6538
- if (config2.__meta.mode === "standalone") {
6633
+ const config = getCurrentConfig();
6634
+ if (config.__meta.mode === "standalone") {
6539
6635
  return `export const configuredDocsPlugin = undefined;`;
6540
6636
  }
6541
6637
  const code = [
6542
6638
  'import { markdownPlugin } from "zudoku/plugins/markdown";'
6543
6639
  ];
6544
- const docsConfig = DocsConfigSchema.parse(config2.docs ?? {});
6640
+ const docsConfig = DocsConfigSchema.parse(config.docs ?? {});
6545
6641
  const fileMapping = await resolveCustomNavigationPaths(
6546
- config2,
6547
- await globMarkdownFiles(config2, { absolute: false })
6642
+ config,
6643
+ await globMarkdownFiles(config, { absolute: false })
6548
6644
  );
6549
6645
  const globbedDocuments = {};
6550
6646
  for (const [routePath, file] of Object.entries(fileMapping)) {
@@ -6558,13 +6654,13 @@ var viteDocsPlugin = () => {
6558
6654
  ),
6559
6655
  `};`,
6560
6656
  `export const configuredDocsPlugin = markdownPlugin({`,
6561
- ` basePath: "${config2.basePath ?? ""}",`,
6657
+ ` basePath: "${config.basePath ?? ""}",`,
6562
6658
  ` fileImports,`,
6563
6659
  ` defaultOptions: ${JSON.stringify(docsConfig.defaultOptions)},`,
6564
6660
  ` publishMarkdown: ${JSON.stringify(docsConfig.publishMarkdown)},`,
6565
6661
  `});`
6566
6662
  );
6567
- await writePluginDebugCode(config2.__meta.rootDir, "docs-plugin", code);
6663
+ await writePluginDebugCode(config.__meta.rootDir, "docs-plugin", code);
6568
6664
  return code.join("\n");
6569
6665
  }
6570
6666
  };
@@ -6614,19 +6710,19 @@ var viteMarkdownExportPlugin = () => {
6614
6710
  return env.name === "ssr";
6615
6711
  },
6616
6712
  async buildStart() {
6617
- const config2 = getCurrentConfig();
6618
- const llmsConfig = config2.docs?.llms;
6619
- const needsMdFiles = config2.docs?.publishMarkdown || llmsConfig?.llmsTxt || llmsConfig?.llmsTxtFull;
6620
- if (config2.__meta.mode === "standalone" || !needsMdFiles) {
6713
+ const config = getCurrentConfig();
6714
+ const llmsConfig = config.docs?.llms;
6715
+ const needsMdFiles = config.docs?.publishMarkdown || llmsConfig?.llmsTxt || llmsConfig?.llmsTxtFull;
6716
+ if (config.__meta.mode === "standalone" || !needsMdFiles) {
6621
6717
  return;
6622
6718
  }
6623
6719
  markdownFiles = await resolveCustomNavigationPaths(
6624
- config2,
6625
- await globMarkdownFiles(config2, { absolute: true })
6720
+ config,
6721
+ await globMarkdownFiles(config, { absolute: true })
6626
6722
  );
6627
6723
  if (!llmsConfig?.includeProtected) {
6628
6724
  const protectedRoutes = ProtectedRoutesSchema.parse(
6629
- config2.protectedRoutes
6725
+ config.protectedRoutes
6630
6726
  );
6631
6727
  if (protectedRoutes) {
6632
6728
  const patterns = Object.keys(protectedRoutes);
@@ -6639,19 +6735,19 @@ var viteMarkdownExportPlugin = () => {
6639
6735
  }
6640
6736
  },
6641
6737
  async configureServer(server) {
6642
- const config2 = getCurrentConfig();
6643
- const llmsConfig = config2.docs?.llms;
6644
- const needsMdFiles = config2.docs?.publishMarkdown || llmsConfig?.llmsTxt || llmsConfig?.llmsTxtFull;
6738
+ const config = getCurrentConfig();
6739
+ const llmsConfig = config.docs?.llms;
6740
+ const needsMdFiles = config.docs?.publishMarkdown || llmsConfig?.llmsTxt || llmsConfig?.llmsTxtFull;
6645
6741
  if (!needsMdFiles) return;
6646
6742
  markdownFiles = await resolveCustomNavigationPaths(
6647
- config2,
6648
- await globMarkdownFiles(config2, { absolute: true })
6743
+ config,
6744
+ await globMarkdownFiles(config, { absolute: true })
6649
6745
  );
6650
6746
  server.middlewares.use(async (req, res, next) => {
6651
6747
  if (req.method !== "GET" || !req.url?.endsWith(".md")) {
6652
6748
  return next();
6653
6749
  }
6654
- const basePath = joinUrl(config2.basePath);
6750
+ const basePath = joinUrl(config.basePath);
6655
6751
  const routePath = resolveMarkdownRoutePath(req.url, basePath);
6656
6752
  const filePath = markdownFiles[routePath];
6657
6753
  if (!filePath) return next();
@@ -6666,16 +6762,16 @@ var viteMarkdownExportPlugin = () => {
6666
6762
  });
6667
6763
  },
6668
6764
  async closeBundle() {
6669
- const config2 = getCurrentConfig();
6670
- const llmsConfig = config2.docs?.llms;
6671
- const needsMdFiles = config2.docs?.publishMarkdown || llmsConfig?.llmsTxt || llmsConfig?.llmsTxtFull;
6765
+ const config = getCurrentConfig();
6766
+ const llmsConfig = config.docs?.llms;
6767
+ const needsMdFiles = config.docs?.publishMarkdown || llmsConfig?.llmsTxt || llmsConfig?.llmsTxtFull;
6672
6768
  if (process.env.NODE_ENV !== "production" || Object.keys(markdownFiles).length === 0 || !needsMdFiles) {
6673
6769
  return;
6674
6770
  }
6675
6771
  const distDir = path13.join(
6676
- config2.__meta.rootDir,
6772
+ config.__meta.rootDir,
6677
6773
  "dist",
6678
- config2.basePath ?? ""
6774
+ config.basePath ?? ""
6679
6775
  );
6680
6776
  markdownFileInfos = [];
6681
6777
  for (const [routePath, filePath] of Object.entries(markdownFiles)) {
@@ -6699,9 +6795,9 @@ var viteMarkdownExportPlugin = () => {
6699
6795
  console.warn(`Failed to export markdown for ${routePath}:`, error);
6700
6796
  }
6701
6797
  }
6702
- if (config2.docs?.llms?.llmsTxt || config2.docs?.llms?.llmsTxtFull) {
6798
+ if (config.docs?.llms?.llmsTxt || config.docs?.llms?.llmsTxtFull) {
6703
6799
  const markdownInfoPath = path13.join(
6704
- config2.__meta.rootDir,
6800
+ config.__meta.rootDir,
6705
6801
  "node_modules/.zudoku/markdown-info.json"
6706
6802
  );
6707
6803
  await writeFile2(
@@ -7119,12 +7215,12 @@ var rehypeExcerptWithMdxExport = () => (tree) => {
7119
7215
  tree.children.unshift(exportMdxjsConst("excerpt", excerpt));
7120
7216
  };
7121
7217
  var viteMdxPlugin = async () => {
7122
- const config2 = getCurrentConfig();
7218
+ const config = getCurrentConfig();
7123
7219
  const buildConfig = await getBuildConfig();
7124
7220
  const highlighter = await highlighterPromise;
7125
7221
  const defaultRemarkPlugins = [
7126
7222
  remarkStaticGeneration,
7127
- [remarkInjectFilepath, config2.__meta.rootDir],
7223
+ [remarkInjectFilepath, config.__meta.rootDir],
7128
7224
  remarkComment,
7129
7225
  remarkGfm,
7130
7226
  remarkFrontmatter,
@@ -7136,9 +7232,9 @@ var viteMdxPlugin = async () => {
7136
7232
  remarkDirective,
7137
7233
  remarkDirectiveRehype,
7138
7234
  remarkCodeTabs,
7139
- [remarkLinkRewrite, config2.basePath],
7140
- [remarkNormalizeImageUrl, config2.basePath],
7141
- ...config2.build?.remarkPlugins ?? []
7235
+ [remarkLinkRewrite, config.basePath],
7236
+ [remarkNormalizeImageUrl, config.basePath],
7237
+ ...config.build?.remarkPlugins ?? []
7142
7238
  ];
7143
7239
  const remarkPlugins = typeof buildConfig?.remarkPlugins === "function" ? buildConfig.remarkPlugins(defaultRemarkPlugins) : [...defaultRemarkPlugins, ...buildConfig?.remarkPlugins ?? []];
7144
7240
  const defaultRehypePlugins = [
@@ -7151,9 +7247,9 @@ var viteMdxPlugin = async () => {
7151
7247
  rehypeMetaAsAttributes,
7152
7248
  ...createConfiguredShikiRehypePlugins(
7153
7249
  highlighter,
7154
- config2.syntaxHighlighting?.themes
7250
+ config.syntaxHighlighting?.themes
7155
7251
  ),
7156
- ...config2.build?.rehypePlugins ?? []
7252
+ ...config.build?.rehypePlugins ?? []
7157
7253
  ];
7158
7254
  const rehypePlugins = typeof buildConfig?.rehypePlugins === "function" ? buildConfig.rehypePlugins(defaultRehypePlugins) : [...defaultRehypePlugins, ...buildConfig?.rehypePlugins ?? []];
7159
7255
  return {
@@ -7184,12 +7280,12 @@ var viteSearchPlugin = () => {
7184
7280
  },
7185
7281
  async load(id) {
7186
7282
  if (id !== resolvedVirtualModuleId4) return;
7187
- const config2 = getCurrentConfig();
7188
- if (!config2.search || config2.__meta.mode === "standalone") {
7283
+ const config = getCurrentConfig();
7284
+ if (!config.search || config.__meta.mode === "standalone") {
7189
7285
  return `export const configuredSearchPlugin = undefined;`;
7190
7286
  }
7191
7287
  const code = [];
7192
- if (config2.search.type === "inkeep") {
7288
+ if (config.search.type === "inkeep") {
7193
7289
  code.push(
7194
7290
  `import config from 'virtual:zudoku-config';`,
7195
7291
  `import { inkeepSearchPlugin } from "zudoku/plugins/search-inkeep";`,
@@ -7197,7 +7293,7 @@ var viteSearchPlugin = () => {
7197
7293
  );
7198
7294
  return code.join("\n");
7199
7295
  }
7200
- if (config2.search.type === "pagefind") {
7296
+ if (config.search.type === "pagefind") {
7201
7297
  code.push(
7202
7298
  `import config from 'virtual:zudoku-config';`,
7203
7299
  `import { pagefindSearchPlugin } from "zudoku/plugins/search-pagefind";`,
@@ -7227,10 +7323,10 @@ var viteShikiPlugin = () => {
7227
7323
  return {
7228
7324
  name: "vite-plugin-shiki-register",
7229
7325
  config() {
7230
- const config2 = getCurrentConfig();
7231
- const languages = config2.syntaxHighlighting?.languages ?? defaultLanguages;
7326
+ const config = getCurrentConfig();
7327
+ const languages = config.syntaxHighlighting?.languages ?? defaultLanguages;
7232
7328
  const themes = Object.values(
7233
- config2.syntaxHighlighting?.themes ?? defaultHighlightOptions.themes
7329
+ config.syntaxHighlighting?.themes ?? defaultHighlightOptions.themes
7234
7330
  );
7235
7331
  const shikiIds = [
7236
7332
  ...languages.map((lang) => `@shikijs/langs/${resolveLang(lang)}`),
@@ -7253,10 +7349,10 @@ var viteShikiPlugin = () => {
7253
7349
  },
7254
7350
  async load(id) {
7255
7351
  if (id !== resolvedVirtualModuleId4) return;
7256
- const config2 = getCurrentConfig();
7257
- const languages = config2.syntaxHighlighting?.languages ?? defaultLanguages;
7352
+ const config = getCurrentConfig();
7353
+ const languages = config.syntaxHighlighting?.languages ?? defaultLanguages;
7258
7354
  const themes = Object.values(
7259
- config2.syntaxHighlighting?.themes ?? defaultHighlightOptions.themes
7355
+ config.syntaxHighlighting?.themes ?? defaultHighlightOptions.themes
7260
7356
  );
7261
7357
  const highlighter = await highlighterPromise;
7262
7358
  await Promise.all([
@@ -7332,8 +7428,8 @@ var scopeMatchesPattern = (scope, pattern) => {
7332
7428
  }
7333
7429
  return matchPath2({ path: pattern, end: false }, root) != null;
7334
7430
  };
7335
- var getProtectedSourceMatcher = (config2) => {
7336
- const protectedRoutes = ProtectedRoutesSchema.parse(config2.protectedRoutes);
7431
+ var getProtectedSourceMatcher = (config) => {
7432
+ const protectedRoutes = ProtectedRoutesSchema.parse(config.protectedRoutes);
7337
7433
  const patterns = protectedRoutes ? Object.keys(protectedRoutes) : [];
7338
7434
  if (patterns.length === 0) {
7339
7435
  return { match: () => false, enabled: false, patterns };
@@ -7471,16 +7567,16 @@ var defineEnvVars = (vars) => Object.fromEntries(
7471
7567
  ])
7472
7568
  );
7473
7569
  async function getViteConfig(dir, configEnv, options = {}) {
7474
- const { config: config2, publicEnv: publicEnv2, envPrefix: envPrefix2 } = await loadZudokuConfig(
7570
+ const { config, publicEnv: publicEnv2, envPrefix: envPrefix2 } = await loadZudokuConfig(
7475
7571
  configEnv,
7476
7572
  dir
7477
7573
  );
7478
- const { match: isProtectedSource, enabled: hasProtectedSources } = getProtectedSourceMatcher(config2);
7574
+ const { match: isProtectedSource, enabled: hasProtectedSources } = getProtectedSourceMatcher(config);
7479
7575
  const shouldProtectChunks = hasProtectedSources && options.ssr === true;
7480
7576
  const isProtectedChunk = (chunk) => chunk.facadeModuleId && isProtectedSource(chunk.facadeModuleId) || chunk.moduleIds.some(isProtectedSource);
7481
7577
  const isWorker = options.adapter === "cloudflare";
7482
- const cdnUrl = CdnUrlSchema.parse(config2.cdnUrl);
7483
- const base = cdnUrl?.base ? joinUrl(cdnUrl.base, config2.basePath) : config2.basePath;
7578
+ const cdnUrl = CdnUrlSchema.parse(config.cdnUrl);
7579
+ const base = cdnUrl?.base ? joinUrl(cdnUrl.base, config.basePath) : config.basePath;
7484
7580
  if (cdnUrl && !hasLoggedCdnInfo) {
7485
7581
  logger.info(colors4.blue(`Using CDN URL:`));
7486
7582
  logger.info(colors4.blue(` base: `) + colors4.dim(cdnUrl.base));
@@ -7495,7 +7591,7 @@ async function getViteConfig(dir, configEnv, options = {}) {
7495
7591
  );
7496
7592
  if (ZuploEnv.isZuplo) {
7497
7593
  dotenv.config({
7498
- path: path16.resolve(config2.__meta.rootDir, "../.env.zuplo"),
7594
+ path: path16.resolve(config.__meta.rootDir, "../.env.zuplo"),
7499
7595
  quiet: true
7500
7596
  });
7501
7597
  }
@@ -7546,8 +7642,8 @@ async function getViteConfig(dir, configEnv, options = {}) {
7546
7642
  `${dir}/dist`,
7547
7643
  `${dir}/lib`,
7548
7644
  `${dir}/.git`,
7549
- `${config2.__meta.moduleDir}/src/vite`,
7550
- `${config2.__meta.moduleDir}/src/cli`
7645
+ `${config.__meta.moduleDir}/src/vite`,
7646
+ `${config.__meta.moduleDir}/src/cli`
7551
7647
  ]
7552
7648
  }
7553
7649
  },
@@ -7555,10 +7651,10 @@ async function getViteConfig(dir, configEnv, options = {}) {
7555
7651
  sourcemap: true,
7556
7652
  target: "es2022",
7557
7653
  chunkSizeWarningLimit: 1500,
7558
- outDir: path16.resolve(path16.join(dir, "dist", config2.basePath ?? "")),
7654
+ outDir: path16.resolve(path16.join(dir, "dist", config.basePath ?? "")),
7559
7655
  emptyOutDir: false,
7560
7656
  rolldownOptions: {
7561
- external: [joinUrl(config2.basePath, "/pagefind/pagefind.js")],
7657
+ external: [joinUrl(config.basePath, "/pagefind/pagefind.js")],
7562
7658
  logLevel: process.env.ZUDOKU_ENV === "internal" ? "info" : "warn",
7563
7659
  checks: {
7564
7660
  pluginTimings: process.env.ZUDOKU_ENV === "internal"
@@ -7586,12 +7682,12 @@ async function getViteConfig(dir, configEnv, options = {}) {
7586
7682
  },
7587
7683
  build: {
7588
7684
  outDir: path16.resolve(
7589
- path16.join(dir, "dist", config2.basePath ?? "", "server")
7685
+ path16.join(dir, "dist", config.basePath ?? "", "server")
7590
7686
  ),
7591
7687
  copyPublicDir: false,
7592
7688
  rolldownOptions: {
7593
7689
  logLevel: "warn",
7594
- input: ["zudoku/app/entry.server.tsx", config2.__meta.configPath]
7690
+ input: ["zudoku/app/entry.server.tsx", config.__meta.configPath]
7595
7691
  }
7596
7692
  }
7597
7693
  }
@@ -7599,7 +7695,7 @@ async function getViteConfig(dir, configEnv, options = {}) {
7599
7695
  experimental: {
7600
7696
  renderBuiltUrl(filename) {
7601
7697
  if (filename.startsWith(`${PROTECTED_CHUNK_DIR}/`)) {
7602
- return joinUrl(config2.basePath, `/${filename}`);
7698
+ return joinUrl(config.basePath, `/${filename}`);
7603
7699
  }
7604
7700
  if (cdnUrl?.base && [".js", ".css"].includes(path16.extname(filename))) {
7605
7701
  return joinUrl(cdnUrl.base, filename);
@@ -7638,7 +7734,7 @@ async function getViteConfig(dir, configEnv, options = {}) {
7638
7734
  }
7639
7735
  };
7640
7736
  const configRoots = await Promise.all(
7641
- (config2.__pluginDirs ?? []).map(findPackageRoot)
7737
+ (config.__pluginDirs ?? []).map(findPackageRoot)
7642
7738
  );
7643
7739
  configRoots.push(dir);
7644
7740
  let mergedViteConfig = viteConfig;
@@ -7709,10 +7805,10 @@ ${cssLinks}
7709
7805
  // src/vite/manifest.ts
7710
7806
  import { writeFile as writeFile3 } from "node:fs/promises";
7711
7807
  import path17 from "node:path";
7712
- var writeManifest = async (distDir, config2) => {
7808
+ var writeManifest = async (distDir, config) => {
7713
7809
  await writeFile3(
7714
7810
  path17.join(distDir, MANIFEST_FILENAME),
7715
- `${JSON.stringify(buildManifest(config2), null, 2)}
7811
+ `${JSON.stringify(buildManifest(config), null, 2)}
7716
7812
  `,
7717
7813
  "utf-8"
7718
7814
  );
@@ -7726,7 +7822,7 @@ import { cp, mkdir as mkdir3, writeFile as writeFile4 } from "node:fs/promises";
7726
7822
  import path18 from "node:path";
7727
7823
  var pkgJson = getZudokuPackageJson();
7728
7824
  function generateOutput({
7729
- config: config2,
7825
+ config,
7730
7826
  redirects,
7731
7827
  rewrites = []
7732
7828
  }) {
@@ -7751,7 +7847,7 @@ function generateOutput({
7751
7847
  }
7752
7848
  ],
7753
7849
  headers: {
7754
- "Set-Cookie": `__vdpl=${process.env.VERCEL_DEPLOYMENT_ID}; Path=${joinUrl(config2.basePath)}; SameSite=Strict; Secure; HttpOnly`
7850
+ "Set-Cookie": `__vdpl=${process.env.VERCEL_DEPLOYMENT_ID}; Path=${joinUrl(config.basePath)}; SameSite=Strict; Secure; HttpOnly`
7755
7851
  },
7756
7852
  continue: true
7757
7853
  });
@@ -7760,8 +7856,8 @@ function generateOutput({
7760
7856
  routes.push({ handle: "filesystem" });
7761
7857
  for (const rewrite of rewrites) {
7762
7858
  routes.push({
7763
- src: joinUrl(config2.basePath, rewrite.source),
7764
- dest: joinUrl(config2.basePath, rewrite.destination)
7859
+ src: joinUrl(config.basePath, rewrite.source),
7860
+ dest: joinUrl(config.basePath, rewrite.destination)
7765
7861
  });
7766
7862
  }
7767
7863
  }
@@ -7775,11 +7871,11 @@ function generateOutput({
7775
7871
  return output;
7776
7872
  }
7777
7873
  async function writeOutput(dir, {
7778
- config: config2,
7874
+ config,
7779
7875
  redirects,
7780
7876
  rewrites
7781
7877
  }) {
7782
- const output = generateOutput({ config: config2, redirects, rewrites });
7878
+ const output = generateOutput({ config, redirects, rewrites });
7783
7879
  const outputDir = process.env.VERCEL ? path18.join(dir, ".vercel/output") : path18.join(dir, "dist/.output");
7784
7880
  await mkdir3(outputDir, { recursive: true });
7785
7881
  const outputFile = path18.join(outputDir, "config.json");
@@ -7844,14 +7940,14 @@ async function generateSitemap({
7844
7940
  outputUrls,
7845
7941
  basePath,
7846
7942
  baseOutputDir,
7847
- config: config2,
7943
+ config,
7848
7944
  redirectUrls
7849
7945
  }) {
7850
- if (!config2) {
7946
+ if (!config) {
7851
7947
  return;
7852
7948
  }
7853
- const sitemap = new SitemapStream({ hostname: config2.siteUrl });
7854
- const outputDir = path19.resolve(baseOutputDir, config2.outDir ?? "");
7949
+ const sitemap = new SitemapStream({ hostname: config.siteUrl });
7950
+ const outputDir = path19.resolve(baseOutputDir, config.outDir ?? "");
7855
7951
  if (!existsSync(outputDir)) {
7856
7952
  await mkdir4(outputDir, { recursive: true });
7857
7953
  }
@@ -7859,18 +7955,18 @@ async function generateSitemap({
7859
7955
  const writeStream = createWriteStream(sitemapOutputPath);
7860
7956
  sitemap.pipe(writeStream);
7861
7957
  let lastmod;
7862
- if (config2.autoLastmod !== false) {
7958
+ if (config.autoLastmod !== false) {
7863
7959
  lastmod = (/* @__PURE__ */ new Date()).toISOString();
7864
7960
  }
7865
- const exclude = (typeof config2.exclude === "function" ? await config2.exclude() : config2.exclude) ?? [];
7961
+ const exclude = (typeof config.exclude === "function" ? await config.exclude() : config.exclude) ?? [];
7866
7962
  for (const url of outputUrls) {
7867
7963
  const shouldExclude = exclude.includes(url) || url.includes("*") || /(400|404|500)$/.test(url) || redirectUrls.has(url);
7868
7964
  if (shouldExclude) continue;
7869
7965
  sitemap.write({
7870
- url: new URL(joinUrl(basePath, url), config2.siteUrl).toString(),
7966
+ url: new URL(joinUrl(basePath, url), config.siteUrl).toString(),
7871
7967
  lastmod,
7872
- changefreq: config2.changefreq ?? "daily",
7873
- priority: config2.priority ?? 0.7
7968
+ changefreq: config.changefreq ?? "daily",
7969
+ priority: config.priority ?? 0.7
7874
7970
  });
7875
7971
  }
7876
7972
  sitemap.end();
@@ -7951,15 +8047,15 @@ var prerender = async ({
7951
8047
  const rawConfig = await import(serverConfigPath).then(
7952
8048
  (m) => m.default
7953
8049
  );
7954
- const config2 = await runPluginTransformConfig(rawConfig);
8050
+ const config = await runPluginTransformConfig(rawConfig);
7955
8051
  const buildConfig = await getBuildConfig();
7956
8052
  const module = await import(entryServerPath);
7957
8053
  const getRoutes = module.getRoutesByConfig;
7958
- const routes = getRoutes(config2);
8054
+ const routes = getRoutes(config);
7959
8055
  const paths = routesToPaths(routes);
7960
8056
  const rewrites = routesToRewrites(routes);
7961
- if (config2.redirects) {
7962
- for (const r of config2.redirects) {
8057
+ if (config.redirects) {
8058
+ for (const r of config.redirects) {
7963
8059
  paths.push(joinUrl(r.from));
7964
8060
  }
7965
8061
  }
@@ -7983,7 +8079,7 @@ var prerender = async ({
7983
8079
  }
7984
8080
  let completedCount = 0;
7985
8081
  let pagefindIndex;
7986
- if (config2.search?.type === "pagefind") {
8082
+ if (config.search?.type === "pagefind") {
7987
8083
  const { index, errors } = await createIndex();
7988
8084
  invariant(
7989
8085
  index,
@@ -8069,18 +8165,18 @@ var prerender = async ({
8069
8165
  );
8070
8166
  }
8071
8167
  }
8072
- const redirectUrls = getRedirectUrls(workerResults, config2.basePath);
8168
+ const redirectUrls = getRedirectUrls(workerResults, config.basePath);
8073
8169
  await generateSitemap({
8074
- basePath: config2.basePath,
8170
+ basePath: config.basePath,
8075
8171
  outputUrls: paths,
8076
- config: config2.sitemap,
8172
+ config: config.sitemap,
8077
8173
  baseOutputDir: distDir,
8078
8174
  redirectUrls
8079
8175
  });
8080
- if (config2.docs) {
8176
+ if (config.docs) {
8081
8177
  const { DocsConfigSchema: DocsConfigSchema2 } = await Promise.resolve().then(() => (init_ZudokuConfig(), ZudokuConfig_exports));
8082
8178
  const { generateLlmsTxtFiles: generateLlmsTxtFiles2 } = await Promise.resolve().then(() => (init_llms(), llms_exports));
8083
- const docsConfig = DocsConfigSchema2.parse(config2.docs);
8179
+ const docsConfig = DocsConfigSchema2.parse(config.docs);
8084
8180
  const llmsConfig = docsConfig.llms ?? {};
8085
8181
  const markdownInfoPath = path21.join(
8086
8182
  dir,
@@ -8094,10 +8190,10 @@ var prerender = async ({
8094
8190
  if (llmsConfig.llmsTxt || llmsConfig.llmsTxtFull) {
8095
8191
  await generateLlmsTxtFiles2({
8096
8192
  markdownFileInfos,
8097
- basePath: config2.basePath,
8193
+ basePath: config.basePath,
8098
8194
  outputUrls: paths,
8099
8195
  baseOutputDir: distDir,
8100
- siteName: config2.site?.title,
8196
+ siteName: config.site?.title,
8101
8197
  llmsTxt: llmsConfig.llmsTxt,
8102
8198
  llmsTxtFull: llmsConfig.llmsTxtFull,
8103
8199
  redirectUrls
@@ -8169,8 +8265,8 @@ var getContainerMemoryLimitMb = () => {
8169
8265
  import { mkdir as mkdir5, readdir, readFile as readFile3, rename, rm as rm2 } from "node:fs/promises";
8170
8266
  import path22 from "node:path";
8171
8267
  init_joinUrl();
8172
- var assertProtectedPatternsCovered = (config2) => {
8173
- const { patterns } = getProtectedSourceMatcher(config2);
8268
+ var assertProtectedPatternsCovered = (config) => {
8269
+ const { patterns } = getProtectedSourceMatcher(config);
8174
8270
  const unmatched = findUnmatchedProtectedPatterns(patterns);
8175
8271
  if (unmatched.length === 0) return;
8176
8272
  throw new Error(
@@ -8246,10 +8342,10 @@ These would be served publicly. Aborting build.`
8246
8342
  }
8247
8343
  await rm2(srcDir, { recursive: true, force: true });
8248
8344
  };
8249
- var assertCloudflareWranglerGatesProtected = async (dir, config2) => {
8250
- const { enabled } = getProtectedSourceMatcher(config2);
8345
+ var assertCloudflareWranglerGatesProtected = async (dir, config) => {
8346
+ const { enabled } = getProtectedSourceMatcher(config);
8251
8347
  if (!enabled) return;
8252
- const protectedPrefix = `${joinUrl(config2.basePath, PROTECTED_CHUNK_DIR)}/`;
8348
+ const protectedPrefix = `${joinUrl(config.basePath, PROTECTED_CHUNK_DIR)}/`;
8253
8349
  const candidates = ["wrangler.toml", "wrangler.jsonc", "wrangler.json"];
8254
8350
  for (const name of candidates) {
8255
8351
  const file = await readFile3(path22.join(dir, name), "utf-8").catch(
@@ -8294,7 +8390,7 @@ async function runBuild(options) {
8294
8390
  serverResult && !Array.isArray(serverResult) && "output" in serverResult,
8295
8391
  "SSR build failed to produce valid output"
8296
8392
  );
8297
- const { config: config2 } = await loadZudokuConfig(
8393
+ const { config } = await loadZudokuConfig(
8298
8394
  { mode: "production", command: "build" },
8299
8395
  dir
8300
8396
  );
@@ -8313,7 +8409,7 @@ async function runBuild(options) {
8313
8409
  const html = getBuildHtml({
8314
8410
  jsEntry: joinUrl(base, jsEntry),
8315
8411
  cssEntries: cssEntries.map((css) => joinUrl(base, css)),
8316
- dir: config2.site?.dir
8412
+ dir: config.site?.dir
8317
8413
  });
8318
8414
  if (ssr) {
8319
8415
  await bundleSSREntry({
@@ -8322,12 +8418,12 @@ async function runBuild(options) {
8322
8418
  serverOutDir,
8323
8419
  html
8324
8420
  });
8325
- assertProtectedPatternsCovered(config2);
8421
+ assertProtectedPatternsCovered(config);
8326
8422
  assertNoProtectedLeaks(clientResult.output);
8327
8423
  if (adapter !== "cloudflare") {
8328
8424
  await moveProtectedChunks(clientOutDir, serverOutDir);
8329
8425
  } else {
8330
- await assertCloudflareWranglerGatesProtected(dir, config2);
8426
+ await assertCloudflareWranglerGatesProtected(dir, config);
8331
8427
  }
8332
8428
  await writeFile6(
8333
8429
  path23.join(distDir, "package.json"),
@@ -8335,12 +8431,12 @@ async function runBuild(options) {
8335
8431
  `,
8336
8432
  "utf-8"
8337
8433
  );
8338
- await writeManifest(distDir, config2);
8434
+ await writeManifest(distDir, config);
8339
8435
  await rm3(path23.join(clientOutDir, "index.html"), { force: true });
8340
8436
  } else {
8341
8437
  await runPrerender({
8342
8438
  dir,
8343
- config: config2,
8439
+ config,
8344
8440
  html,
8345
8441
  clientOutDir,
8346
8442
  serverOutDir,
@@ -8356,14 +8452,14 @@ var findServerConfigFilename = (result) => {
8356
8452
  return entry.fileName;
8357
8453
  };
8358
8454
  var runPrerender = async (options) => {
8359
- const { dir, config: config2, html, clientOutDir, serverOutDir, serverResult } = options;
8360
- const issuer = await getIssuer(config2);
8455
+ const { dir, config, html, clientOutDir, serverOutDir, serverResult } = options;
8456
+ const issuer = await getIssuer(config);
8361
8457
  const serverConfigFilename = findServerConfigFilename(serverResult);
8362
8458
  try {
8363
8459
  const { workerResults, rewrites } = await prerender({
8364
8460
  html,
8365
8461
  dir,
8366
- basePath: config2.basePath,
8462
+ basePath: config.basePath,
8367
8463
  serverConfigFilename,
8368
8464
  writeRedirects: process.env.VERCEL === void 0
8369
8465
  });
@@ -8389,12 +8485,12 @@ var runPrerender = async (options) => {
8389
8485
  );
8390
8486
  }
8391
8487
  await writeOutput(dir, {
8392
- config: config2,
8488
+ config,
8393
8489
  redirects: workerResults.flatMap((r) => r.redirect ?? []),
8394
8490
  rewrites
8395
8491
  });
8396
8492
  if (ZuploEnv.isZuplo && issuer) {
8397
- const provider = config2.authentication?.type;
8493
+ const provider = config.authentication?.type;
8398
8494
  await writeFile6(
8399
8495
  path23.join(dir, DIST_DIR, ".output/zuplo.json"),
8400
8496
  JSON.stringify({ issuer, provider }, null, 2),
@@ -8696,6 +8792,7 @@ import fs3 from "node:fs/promises";
8696
8792
  import http from "node:http";
8697
8793
  import https from "node:https";
8698
8794
  import path27 from "node:path";
8795
+ import { stripVTControlCharacters } from "node:util";
8699
8796
  import { createHttpTerminator } from "http-terminator";
8700
8797
  import {
8701
8798
  createServer as createViteServer,
@@ -8732,7 +8829,7 @@ init_joinUrl();
8732
8829
  import path26 from "node:path";
8733
8830
  import { createIndex as createIndex2 } from "pagefind";
8734
8831
  import { isRunnableDevEnvironment } from "vite";
8735
- async function* buildPagefindDevIndex(vite, config2) {
8832
+ async function* buildPagefindDevIndex(vite, config) {
8736
8833
  const { index, errors } = await createIndex2();
8737
8834
  invariant(index, `Failed to create pagefind index: ${errors.join(", ")}`);
8738
8835
  const pagefindIndex = index;
@@ -8743,12 +8840,12 @@ async function* buildPagefindDevIndex(vite, config2) {
8743
8840
  const serverModule = await ssrEnvironment.runner.import(
8744
8841
  getAppServerEntryPath()
8745
8842
  );
8746
- const routes = serverModule.getRoutesByConfig(config2);
8843
+ const routes = serverModule.getRoutesByConfig(config);
8747
8844
  const paths = routesToPaths(routes);
8748
- const { basePath } = config2;
8845
+ const { basePath } = config;
8749
8846
  const template = getDevHtml({
8750
8847
  jsEntry: "/__z/entry.client.tsx",
8751
- dir: config2.site?.dir
8848
+ dir: config.site?.dir
8752
8849
  });
8753
8850
  const transformedTemplate = await vite.transformIndexHtml("/", template);
8754
8851
  let indexed = 0;
@@ -8797,14 +8894,14 @@ var DevServer = class {
8797
8894
  constructor(options) {
8798
8895
  this.#options = options;
8799
8896
  }
8800
- async createNodeServer(config2) {
8801
- if (!config2.https) return http.createServer();
8897
+ async createNodeServer(config) {
8898
+ if (!config.https) return http.createServer();
8802
8899
  this.protocol = "https";
8803
8900
  const { dir } = this.#options;
8804
8901
  const [key, cert, ca] = await Promise.all([
8805
- fs3.readFile(path27.resolve(dir, config2.https.key)),
8806
- fs3.readFile(path27.resolve(dir, config2.https.cert)),
8807
- config2.https.ca ? fs3.readFile(path27.resolve(dir, config2.https.ca)) : void 0
8902
+ fs3.readFile(path27.resolve(dir, config.https.key)),
8903
+ fs3.readFile(path27.resolve(dir, config.https.cert)),
8904
+ config.https.ca ? fs3.readFile(path27.resolve(dir, config.https.ca)) : void 0
8808
8905
  ]);
8809
8906
  return https.createServer({ key, cert, ca });
8810
8907
  }
@@ -8813,12 +8910,14 @@ var DevServer = class {
8813
8910
  mode: "development",
8814
8911
  command: "serve"
8815
8912
  };
8816
- const viteConfig = await getViteConfig(this.#options.dir, configEnv);
8817
- const { config: config2 } = await loadZudokuConfig(configEnv, this.#options.dir);
8913
+ const viteConfig = await getViteConfig(this.#options.dir, configEnv, {
8914
+ ssr: this.#options.ssr
8915
+ });
8916
+ const { config } = await loadZudokuConfig(configEnv, this.#options.dir);
8818
8917
  this.resolvedPort = await findAvailablePort(
8819
- this.#options.argPort ?? config2.port ?? DEFAULT_DEV_PORT
8918
+ this.#options.argPort ?? config.port ?? DEFAULT_DEV_PORT
8820
8919
  );
8821
- const server = await this.createNodeServer(config2);
8920
+ const server = await this.createNodeServer(config);
8822
8921
  const mergedViteConfig = mergeConfig3(viteConfig, {
8823
8922
  server: {
8824
8923
  hmr: { server }
@@ -8853,15 +8952,15 @@ var DevServer = class {
8853
8952
  const vite = await createViteServer(mergedViteConfig);
8854
8953
  const graphql = createGraphQLServer({ graphqlEndpoint: "/__z/graphql" });
8855
8954
  vite.middlewares.use((req, res, next) => {
8856
- if (req.method === "GET" && req.originalUrl === "/" && config2.basePath && config2.basePath !== "/") {
8857
- res.writeHead(307, { Location: config2.basePath });
8955
+ if (req.method === "GET" && req.originalUrl === "/" && config.basePath && config.basePath !== "/") {
8956
+ res.writeHead(307, { Location: config.basePath });
8858
8957
  res.end();
8859
8958
  return;
8860
8959
  }
8861
8960
  next();
8862
8961
  });
8863
8962
  vite.middlewares.use(graphql.graphqlEndpoint, graphql);
8864
- const sessionEndpoint = joinUrl(config2.basePath, "/__z/auth/session");
8963
+ const sessionEndpoint = joinUrl(config.basePath, "/__z/auth/session");
8865
8964
  vite.middlewares.use(sessionEndpoint, async (req, res) => {
8866
8965
  if (req.method !== "POST" && req.method !== "DELETE") {
8867
8966
  res.writeHead(405, { Allow: "POST, DELETE" });
@@ -8942,7 +9041,7 @@ var DevServer = class {
8942
9041
  printDiagnosticsToConsole(
8943
9042
  `Server-side rendering ${this.#options.ssr ? "enabled" : "disabled"}`
8944
9043
  );
8945
- if (config2.search?.type === "pagefind") {
9044
+ if (config.search?.type === "pagefind") {
8946
9045
  const pagefindPath = path27.join(
8947
9046
  vite.config.publicDir,
8948
9047
  "pagefind/pagefind.js"
@@ -9015,11 +9114,15 @@ var DevServer = class {
9015
9114
  const html = `<!DOCTYPE html><html><body><script type="module">
9016
9115
  import { ErrorOverlay } from '/@vite/client';
9017
9116
  document.body.appendChild(new ErrorOverlay(${JSON.stringify({
9018
- message: e instanceof Error ? e.message : String(e),
9019
- stack: e instanceof Error ? e.stack : ""
9117
+ message: stripVTControlCharacters(
9118
+ e instanceof Error ? e.message : String(e)
9119
+ ),
9120
+ stack: stripVTControlCharacters(
9121
+ e instanceof Error ? e.stack ?? "" : ""
9122
+ )
9020
9123
  })}));
9021
9124
  </script></body></html>`;
9022
- res.writeHead(500, { "Content-Type": "text/html" });
9125
+ res.writeHead(500, { "Content-Type": "text/html; charset=utf-8" });
9023
9126
  res.end(html);
9024
9127
  }
9025
9128
  });