@lukoweb/apitogo 0.2.30 → 0.2.34

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 (44) hide show
  1. package/dist/cli/cli.js +794 -248
  2. package/dist/declarations/app/entry.server.d.ts +2 -2
  3. package/dist/declarations/app/main.d.ts +3 -1
  4. package/dist/declarations/cli/platform/client/platform-api.d.ts +16 -5
  5. package/dist/declarations/cli/platform/helpers/deploy-artifact-hash.d.ts +1 -1
  6. package/dist/declarations/cli/platform/helpers/package-files.d.ts +1 -1
  7. package/dist/declarations/cli/platform/helpers/platform-plan.d.ts +1 -1
  8. package/dist/declarations/cli/platform/helpers/zip.d.ts +1 -1
  9. package/dist/declarations/cli/platform/tools/infrastructure.d.ts +0 -4
  10. package/dist/declarations/config/effective-redirects.d.ts +6 -0
  11. package/dist/declarations/config/header-navigation-guard.d.ts +2 -0
  12. package/dist/declarations/config/resolve-modules.d.ts +1 -4
  13. package/dist/declarations/config/validators/HeaderNavigationSchema.d.ts +1 -2
  14. package/docs/cli/commands.md +151 -75
  15. package/docs/cli/go-live.md +135 -123
  16. package/docs/cli/walkthrough.md +40 -1
  17. package/docs/configuration/gateway.md +52 -0
  18. package/docs/guides/customer-account.md +33 -2
  19. package/docs/mcp/tools.md +101 -102
  20. package/package.json +2 -1
  21. package/src/app/demo.tsx +78 -77
  22. package/src/app/entry.client.tsx +115 -107
  23. package/src/app/entry.server.tsx +164 -160
  24. package/src/app/main.tsx +175 -167
  25. package/src/app/standalone.tsx +61 -60
  26. package/src/config/effective-redirects.ts +31 -0
  27. package/src/config/header-navigation-guard.ts +13 -0
  28. package/src/config/resolve-modules.ts +331 -354
  29. package/src/config/v2/home-redirect.ts +104 -98
  30. package/src/config/v2/index.ts +127 -126
  31. package/src/config/v2/ledger.ts +242 -235
  32. package/src/config/v2/resolve.ts +12 -4
  33. package/src/config/v2/rules.ts +716 -714
  34. package/src/config/v2/services.ts +799 -663
  35. package/src/config/v2/workspace.ts +17 -1
  36. package/src/config/validators/HeaderNavigationSchema.ts +42 -44
  37. package/src/lib/assets/powered-by-icon.png +0 -0
  38. package/src/lib/authentication/providers/dev-portal-auth-pages.tsx +667 -602
  39. package/src/lib/authentication/providers/dev-portal.tsx +476 -448
  40. package/src/lib/components/HeaderNavigation.tsx +176 -176
  41. package/src/lib/components/MobileTopNavigation.tsx +283 -283
  42. package/src/lib/components/navigation/PoweredByZudoku.tsx +42 -39
  43. package/src/vite/plugin-offroot-resolve.ts +68 -67
  44. package/src/vite/prerender/prerender.ts +242 -242
@@ -1,354 +1,331 @@
1
- import { DEFAULT_LANDING_CONTENT } from "./default-landing-content.js";
2
- import {
3
- type ResolvedModulesConfig,
4
- ModulesSchema,
5
- type LandingContentConfig,
6
- type ResolvedLandingContent,
7
- type DashboardContentConfig,
8
- type ProfileContentConfig,
9
- type PlansContentConfig,
10
- type ResolvedDashboardContent,
11
- type ResolvedProfileContent,
12
- type ResolvedPlansContent,
13
- } from "./validators/ModulesSchema.js";
14
- import type { ZudokuConfig } from "./validators/ZudokuConfig.js";
15
-
16
- const DEFAULT_DOCS_FILES = "/pages/**/*.{md,mdx}";
17
-
18
- const hasExplicitModules = (config: ZudokuConfig) =>
19
- config.modules !== undefined;
20
-
21
- export const joinPanelPath = (basePath: string, routePath: string): string => {
22
- if (routePath.startsWith("/")) {
23
- return routePath.replace(/\/+$/, "") || "/";
24
- }
25
-
26
- const base = basePath.replace(/\/+$/, "");
27
- const route = routePath.replace(/^\/+/, "");
28
-
29
- if (!base) {
30
- return `/${route}`;
31
- }
32
-
33
- return `/${`${base}/${route}`.replace(/^\/+/, "")}`;
34
- };
35
-
36
- const mergeLandingSection = <T extends { enabled?: boolean }>(
37
- defaults: T | undefined,
38
- override: T | undefined,
39
- ): T | undefined => {
40
- if (override?.enabled === false) {
41
- return undefined;
42
- }
43
-
44
- if (!defaults && !override) {
45
- return undefined;
46
- }
47
-
48
- return { ...defaults, ...override } as T;
49
- };
50
-
51
- const buildDefaultLandingContent = (
52
- config: ZudokuConfig,
53
- ): ResolvedLandingContent => {
54
- const siteTitle =
55
- config.metadata?.applicationName ?? config.site?.title ?? "API ToGo";
56
-
57
- return {
58
- ...DEFAULT_LANDING_CONTENT,
59
- hero: {
60
- ...DEFAULT_LANDING_CONTENT.hero,
61
- title: `${siteTitle} APIs that ship`,
62
- },
63
- primaryAction: {
64
- ...DEFAULT_LANDING_CONTENT.primaryAction,
65
- href: "/introduction",
66
- label: "Get started",
67
- },
68
- secondaryAction: {
69
- ...DEFAULT_LANDING_CONTENT.secondaryAction,
70
- href: "/api",
71
- label: "API Reference",
72
- },
73
- pricingCta: DEFAULT_LANDING_CONTENT.pricingCta
74
- ? {
75
- ...DEFAULT_LANDING_CONTENT.pricingCta,
76
- primaryAction: {
77
- label: "Get started",
78
- href: "/introduction",
79
- },
80
- secondaryAction: {
81
- label: "See pricing",
82
- href: "/pricing",
83
- },
84
- }
85
- : undefined,
86
- };
87
- };
88
-
89
- export const resolveLandingContent = (
90
- config: ZudokuConfig,
91
- content?: LandingContentConfig,
92
- options?: { useDefaults?: boolean },
93
- ): ResolvedLandingContent => {
94
- const siteTitle =
95
- config.metadata?.applicationName ?? config.site?.title ?? "API ToGo";
96
-
97
- if (options?.useDefaults === true) {
98
- const defaults = buildDefaultLandingContent(config);
99
- const footer = mergeLandingSection(defaults.footer, content?.footer);
100
-
101
- return {
102
- hero: {
103
- ...defaults.hero,
104
- ...content?.hero,
105
- title: content?.hero?.title ?? defaults.hero?.title,
106
- description:
107
- content?.hero?.description ??
108
- config.metadata?.description ??
109
- defaults.hero?.description,
110
- codeExample: content?.hero?.codeExample ?? defaults.hero?.codeExample,
111
- titleAccent:
112
- content?.hero?.titleAccent ??
113
- (content?.hero?.title ? undefined : defaults.hero?.titleAccent),
114
- },
115
- featuresSection:
116
- defaults.featuresSection || content?.featuresSection
117
- ? { ...defaults.featuresSection, ...content?.featuresSection }
118
- : undefined,
119
- features: content?.features ?? defaults.features,
120
- primaryAction: content?.primaryAction ?? defaults.primaryAction,
121
- secondaryAction: content?.secondaryAction ?? defaults.secondaryAction,
122
- // A configured footer replaces the "Built with API ToGo" powered-by line.
123
- showPoweredBy:
124
- content?.showPoweredBy ?? (footer ? false : defaults.showPoweredBy),
125
- trust: mergeLandingSection(defaults.trust, content?.trust),
126
- apiShowcase: mergeLandingSection(
127
- defaults.apiShowcase,
128
- content?.apiShowcase,
129
- ),
130
- pricingCta: mergeLandingSection(defaults.pricingCta, content?.pricingCta),
131
- footer,
132
- };
133
- }
134
-
135
- const hasContent = content !== undefined && Object.keys(content).length > 0;
136
-
137
- if (!hasContent) {
138
- return {
139
- hero: { title: siteTitle },
140
- showPoweredBy: true,
141
- };
142
- }
143
-
144
- const footer = content.footer
145
- ? mergeLandingSection(undefined, content.footer)
146
- : undefined;
147
-
148
- return {
149
- hero: {
150
- ...content.hero,
151
- title: content.hero?.title ?? siteTitle,
152
- },
153
- featuresSection: content.featuresSection,
154
- features: content.features,
155
- primaryAction: content.primaryAction,
156
- secondaryAction: content.secondaryAction,
157
- // A configured footer replaces the "Built with API ToGo" powered-by line.
158
- showPoweredBy: content.showPoweredBy ?? !footer,
159
- trust: content.trust
160
- ? mergeLandingSection(undefined, content.trust)
161
- : undefined,
162
- apiShowcase: content.apiShowcase
163
- ? mergeLandingSection(undefined, content.apiShowcase)
164
- : undefined,
165
- pricingCta: content.pricingCta
166
- ? mergeLandingSection(undefined, content.pricingCta)
167
- : undefined,
168
- footer,
169
- };
170
- };
171
-
172
- const DEFAULT_DASHBOARD_QUICK_LINKS: ResolvedDashboardContent["quickLinks"] = [
173
- { label: "Documentation", href: "/introduction" },
174
- { label: "API Reference", href: "/api" },
175
- ];
176
-
177
- export const resolveDashboardContent = (
178
- content?: DashboardContentConfig,
179
- ): ResolvedDashboardContent => ({
180
- title: content?.title ?? "Dashboard",
181
- subtitle: content?.subtitle ?? "Account",
182
- description:
183
- content?.description ??
184
- "Overview of your account activity, documentation shortcuts, and next steps.",
185
- quickLinks: content?.quickLinks ?? DEFAULT_DASHBOARD_QUICK_LINKS,
186
- });
187
-
188
- export const resolveProfileContent = (
189
- content?: ProfileContentConfig,
190
- ): ResolvedProfileContent => ({
191
- title: content?.title ?? "Profile",
192
- description:
193
- content?.description ??
194
- "View your account details and manage profile settings.",
195
- });
196
-
197
- export const resolvePlansContent = (
198
- content?: PlansContentConfig,
199
- ): ResolvedPlansContent => ({
200
- title: content?.title ?? "Plans & billing",
201
- description:
202
- content?.description ??
203
- "Manage subscription tiers, billing details, and usage limits.",
204
- tiers: content?.tiers,
205
- });
206
-
207
- export const resolveModulesConfig = (
208
- config: ZudokuConfig,
209
- ): ResolvedModulesConfig => {
210
- const parsedModules = ModulesSchema.parse(config.modules);
211
- const modules = parsedModules ?? {};
212
- const explicit = hasExplicitModules(config);
213
-
214
- const docsModule = modules.docs;
215
- const docsEnabled = explicit ? (docsModule?.enabled ?? true) : true;
216
-
217
- const landingModule = modules.landing;
218
- const landingEnabled = landingModule?.enabled ?? false;
219
-
220
- const userPanelModule = modules.userPanel;
221
- const dashboardConfig = userPanelModule?.dashboard;
222
- const userManagementConfig = userPanelModule?.userManagement;
223
- const apiKeysModuleConfig = userPanelModule?.apiKeys;
224
- const plansConfig = userPanelModule?.plans;
225
-
226
- const dashboardEnabled = dashboardConfig?.enabled ?? false;
227
-
228
- const userManagementEnabled = explicit
229
- ? (userManagementConfig?.enabled ?? !!config.authentication)
230
- : !!config.authentication;
231
-
232
- const apiKeysEnabled = explicit
233
- ? (apiKeysModuleConfig?.enabled ?? false)
234
- : false;
235
-
236
- const billingEnabled =
237
- (config as { __meta?: { pricingEnabled?: boolean } }).__meta
238
- ?.pricingEnabled === true || plansConfig?.enabled === true;
239
-
240
- const plansEnabled = billingEnabled;
241
-
242
- const userPanelEnabled =
243
- userPanelModule?.enabled ??
244
- (dashboardEnabled ||
245
- userManagementEnabled ||
246
- apiKeysEnabled ||
247
- plansEnabled);
248
-
249
- const basePath = userPanelModule?.basePath ?? "/account";
250
-
251
- return {
252
- docs: {
253
- enabled: docsEnabled,
254
- files: docsModule?.files,
255
- publishMarkdown: docsModule?.publishMarkdown,
256
- defaultOptions: docsModule?.defaultOptions,
257
- llms: docsModule?.llms,
258
- },
259
- landing: {
260
- enabled: landingEnabled,
261
- path: landingModule?.path ?? "/",
262
- component: landingModule?.component,
263
- layout: landingModule?.layout ?? "landing",
264
- content: resolveLandingContent(config, landingModule?.content, {
265
- useDefaults: landingModule?.useDefaults === true,
266
- }),
267
- },
268
- userPanel: {
269
- enabled: userPanelEnabled,
270
- basePath,
271
- dashboard: {
272
- enabled: dashboardEnabled,
273
- path: joinPanelPath(basePath, dashboardConfig?.path ?? "dashboard"),
274
- content: resolveDashboardContent(dashboardConfig?.content),
275
- },
276
- userManagement: {
277
- enabled: userManagementEnabled,
278
- routes: {
279
- login: userManagementConfig?.routes?.login ?? "/signin",
280
- register: userManagementConfig?.routes?.register ?? "/signup",
281
- profile: joinPanelPath(
282
- basePath,
283
- userManagementConfig?.routes?.profile ?? "profile",
284
- ),
285
- logout: userManagementConfig?.routes?.logout ?? "/signout",
286
- },
287
- content: resolveProfileContent(userManagementConfig?.content),
288
- },
289
- apiKeys: {
290
- enabled: apiKeysEnabled,
291
- path: joinPanelPath(
292
- basePath,
293
- apiKeysModuleConfig?.path ?? "settings/api-keys",
294
- ),
295
- },
296
- plans: {
297
- enabled: plansEnabled,
298
- path: joinPanelPath(basePath, plansConfig?.path ?? "plans"),
299
- content: resolvePlansContent(plansConfig?.content),
300
- items: plansConfig?.items,
301
- },
302
- },
303
- };
304
- };
305
-
306
- export const getEffectiveRedirects = (
307
- config: ZudokuConfig,
308
- resolved: ResolvedModulesConfig,
309
- ) => {
310
- const redirects = config.redirects ?? [];
311
-
312
- if (!resolved.landing.enabled) {
313
- return redirects;
314
- }
315
-
316
- const landingPath = normalizePath(resolved.landing.path);
317
-
318
- return redirects.filter(
319
- (redirect) => normalizePath(redirect.from) !== landingPath,
320
- );
321
- };
322
-
323
- const normalizePath = (path: string) => {
324
- if (path === "/") {
325
- return "/";
326
- }
327
-
328
- return path.replace(/\/+$/, "") || "/";
329
- };
330
-
331
- export const getEffectiveDocsConfig = (
332
- _config: ZudokuConfig,
333
- resolved: ResolvedModulesConfig,
334
- ) => {
335
- if (!resolved.docs.enabled) {
336
- return undefined;
337
- }
338
-
339
- return {
340
- files: resolved.docs.files ?? [DEFAULT_DOCS_FILES],
341
- publishMarkdown: resolved.docs.publishMarkdown ?? false,
342
- defaultOptions: resolved.docs.defaultOptions,
343
- llms: resolved.docs.llms,
344
- };
345
- };
346
-
347
- export const isDocsModuleEnabled = (config: ZudokuConfig) =>
348
- resolveModulesConfig(config).docs.enabled;
349
-
350
- export const isLandingModuleEnabled = (config: ZudokuConfig) =>
351
- resolveModulesConfig(config).landing.enabled;
352
-
353
- export const isUserPanelModuleEnabled = (config: ZudokuConfig) =>
354
- resolveModulesConfig(config).userPanel.enabled;
1
+ import { DEFAULT_LANDING_CONTENT } from "./default-landing-content.js";
2
+ import {
3
+ type ResolvedModulesConfig,
4
+ ModulesSchema,
5
+ type LandingContentConfig,
6
+ type ResolvedLandingContent,
7
+ type DashboardContentConfig,
8
+ type ProfileContentConfig,
9
+ type PlansContentConfig,
10
+ type ResolvedDashboardContent,
11
+ type ResolvedProfileContent,
12
+ type ResolvedPlansContent,
13
+ } from "./validators/ModulesSchema.js";
14
+ import type { ZudokuConfig } from "./validators/ZudokuConfig.js";
15
+
16
+ const DEFAULT_DOCS_FILES = "/pages/**/*.{md,mdx}";
17
+
18
+ const hasExplicitModules = (config: ZudokuConfig) =>
19
+ config.modules !== undefined;
20
+
21
+ export const joinPanelPath = (basePath: string, routePath: string): string => {
22
+ if (routePath.startsWith("/")) {
23
+ return routePath.replace(/\/+$/, "") || "/";
24
+ }
25
+
26
+ const base = basePath.replace(/\/+$/, "");
27
+ const route = routePath.replace(/^\/+/, "");
28
+
29
+ if (!base) {
30
+ return `/${route}`;
31
+ }
32
+
33
+ return `/${`${base}/${route}`.replace(/^\/+/, "")}`;
34
+ };
35
+
36
+ const mergeLandingSection = <T extends { enabled?: boolean }>(
37
+ defaults: T | undefined,
38
+ override: T | undefined,
39
+ ): T | undefined => {
40
+ if (override?.enabled === false) {
41
+ return undefined;
42
+ }
43
+
44
+ if (!defaults && !override) {
45
+ return undefined;
46
+ }
47
+
48
+ return { ...defaults, ...override } as T;
49
+ };
50
+
51
+ const buildDefaultLandingContent = (
52
+ config: ZudokuConfig,
53
+ ): ResolvedLandingContent => {
54
+ const siteTitle =
55
+ config.metadata?.applicationName ?? config.site?.title ?? "API ToGo";
56
+
57
+ return {
58
+ ...DEFAULT_LANDING_CONTENT,
59
+ hero: {
60
+ ...DEFAULT_LANDING_CONTENT.hero,
61
+ title: `${siteTitle} APIs that ship`,
62
+ },
63
+ primaryAction: {
64
+ ...DEFAULT_LANDING_CONTENT.primaryAction,
65
+ href: "/introduction",
66
+ label: "Get started",
67
+ },
68
+ secondaryAction: {
69
+ ...DEFAULT_LANDING_CONTENT.secondaryAction,
70
+ href: "/api",
71
+ label: "API Reference",
72
+ },
73
+ pricingCta: DEFAULT_LANDING_CONTENT.pricingCta
74
+ ? {
75
+ ...DEFAULT_LANDING_CONTENT.pricingCta,
76
+ primaryAction: {
77
+ label: "Get started",
78
+ href: "/introduction",
79
+ },
80
+ secondaryAction: {
81
+ label: "See pricing",
82
+ href: "/pricing",
83
+ },
84
+ }
85
+ : undefined,
86
+ };
87
+ };
88
+
89
+ export const resolveLandingContent = (
90
+ config: ZudokuConfig,
91
+ content?: LandingContentConfig,
92
+ options?: { useDefaults?: boolean },
93
+ ): ResolvedLandingContent => {
94
+ const siteTitle =
95
+ config.metadata?.applicationName ?? config.site?.title ?? "API ToGo";
96
+
97
+ if (options?.useDefaults === true) {
98
+ const defaults = buildDefaultLandingContent(config);
99
+ const footer = mergeLandingSection(defaults.footer, content?.footer);
100
+
101
+ return {
102
+ hero: {
103
+ ...defaults.hero,
104
+ ...content?.hero,
105
+ title: content?.hero?.title ?? defaults.hero?.title,
106
+ description:
107
+ content?.hero?.description ??
108
+ config.metadata?.description ??
109
+ defaults.hero?.description,
110
+ codeExample: content?.hero?.codeExample ?? defaults.hero?.codeExample,
111
+ titleAccent:
112
+ content?.hero?.titleAccent ??
113
+ (content?.hero?.title ? undefined : defaults.hero?.titleAccent),
114
+ },
115
+ featuresSection:
116
+ defaults.featuresSection || content?.featuresSection
117
+ ? { ...defaults.featuresSection, ...content?.featuresSection }
118
+ : undefined,
119
+ features: content?.features ?? defaults.features,
120
+ primaryAction: content?.primaryAction ?? defaults.primaryAction,
121
+ secondaryAction: content?.secondaryAction ?? defaults.secondaryAction,
122
+ // A configured footer replaces the "Built with API ToGo" powered-by line.
123
+ showPoweredBy:
124
+ content?.showPoweredBy ?? (footer ? false : defaults.showPoweredBy),
125
+ trust: mergeLandingSection(defaults.trust, content?.trust),
126
+ apiShowcase: mergeLandingSection(
127
+ defaults.apiShowcase,
128
+ content?.apiShowcase,
129
+ ),
130
+ pricingCta: mergeLandingSection(defaults.pricingCta, content?.pricingCta),
131
+ footer,
132
+ };
133
+ }
134
+
135
+ const hasContent = content !== undefined && Object.keys(content).length > 0;
136
+
137
+ if (!hasContent) {
138
+ return {
139
+ hero: { title: siteTitle },
140
+ showPoweredBy: true,
141
+ };
142
+ }
143
+
144
+ const footer = content.footer
145
+ ? mergeLandingSection(undefined, content.footer)
146
+ : undefined;
147
+
148
+ return {
149
+ hero: {
150
+ ...content.hero,
151
+ title: content.hero?.title ?? siteTitle,
152
+ },
153
+ featuresSection: content.featuresSection,
154
+ features: content.features,
155
+ primaryAction: content.primaryAction,
156
+ secondaryAction: content.secondaryAction,
157
+ // A configured footer replaces the "Built with API ToGo" powered-by line.
158
+ showPoweredBy: content.showPoweredBy ?? !footer,
159
+ trust: content.trust
160
+ ? mergeLandingSection(undefined, content.trust)
161
+ : undefined,
162
+ apiShowcase: content.apiShowcase
163
+ ? mergeLandingSection(undefined, content.apiShowcase)
164
+ : undefined,
165
+ pricingCta: content.pricingCta
166
+ ? mergeLandingSection(undefined, content.pricingCta)
167
+ : undefined,
168
+ footer,
169
+ };
170
+ };
171
+
172
+ const DEFAULT_DASHBOARD_QUICK_LINKS: ResolvedDashboardContent["quickLinks"] = [
173
+ { label: "Documentation", href: "/introduction" },
174
+ { label: "API Reference", href: "/api" },
175
+ ];
176
+
177
+ export const resolveDashboardContent = (
178
+ content?: DashboardContentConfig,
179
+ ): ResolvedDashboardContent => ({
180
+ title: content?.title ?? "Dashboard",
181
+ subtitle: content?.subtitle ?? "Account",
182
+ description:
183
+ content?.description ??
184
+ "Overview of your account activity, documentation shortcuts, and next steps.",
185
+ quickLinks: content?.quickLinks ?? DEFAULT_DASHBOARD_QUICK_LINKS,
186
+ });
187
+
188
+ export const resolveProfileContent = (
189
+ content?: ProfileContentConfig,
190
+ ): ResolvedProfileContent => ({
191
+ title: content?.title ?? "Profile",
192
+ description:
193
+ content?.description ??
194
+ "View your account details and manage profile settings.",
195
+ });
196
+
197
+ export const resolvePlansContent = (
198
+ content?: PlansContentConfig,
199
+ ): ResolvedPlansContent => ({
200
+ title: content?.title ?? "Plans & billing",
201
+ description:
202
+ content?.description ??
203
+ "Manage subscription tiers, billing details, and usage limits.",
204
+ tiers: content?.tiers,
205
+ });
206
+
207
+ export const resolveModulesConfig = (
208
+ config: ZudokuConfig,
209
+ ): ResolvedModulesConfig => {
210
+ const parsedModules = ModulesSchema.parse(config.modules);
211
+ const modules = parsedModules ?? {};
212
+ const explicit = hasExplicitModules(config);
213
+
214
+ const docsModule = modules.docs;
215
+ const docsEnabled = explicit ? (docsModule?.enabled ?? true) : true;
216
+
217
+ const landingModule = modules.landing;
218
+ const landingEnabled = landingModule?.enabled ?? false;
219
+
220
+ const userPanelModule = modules.userPanel;
221
+ const dashboardConfig = userPanelModule?.dashboard;
222
+ const userManagementConfig = userPanelModule?.userManagement;
223
+ const apiKeysModuleConfig = userPanelModule?.apiKeys;
224
+ const plansConfig = userPanelModule?.plans;
225
+
226
+ const dashboardEnabled = dashboardConfig?.enabled ?? false;
227
+
228
+ const userManagementEnabled = explicit
229
+ ? (userManagementConfig?.enabled ?? !!config.authentication)
230
+ : !!config.authentication;
231
+
232
+ const apiKeysEnabled = explicit
233
+ ? (apiKeysModuleConfig?.enabled ?? false)
234
+ : false;
235
+
236
+ const billingEnabled =
237
+ (config as { __meta?: { pricingEnabled?: boolean } }).__meta
238
+ ?.pricingEnabled === true || plansConfig?.enabled === true;
239
+
240
+ const plansEnabled = billingEnabled;
241
+
242
+ const userPanelEnabled =
243
+ userPanelModule?.enabled ??
244
+ (dashboardEnabled ||
245
+ userManagementEnabled ||
246
+ apiKeysEnabled ||
247
+ plansEnabled);
248
+
249
+ const basePath = userPanelModule?.basePath ?? "/account";
250
+
251
+ return {
252
+ docs: {
253
+ enabled: docsEnabled,
254
+ files: docsModule?.files,
255
+ publishMarkdown: docsModule?.publishMarkdown,
256
+ defaultOptions: docsModule?.defaultOptions,
257
+ llms: docsModule?.llms,
258
+ },
259
+ landing: {
260
+ enabled: landingEnabled,
261
+ path: landingModule?.path ?? "/",
262
+ component: landingModule?.component,
263
+ layout: landingModule?.layout ?? "landing",
264
+ content: resolveLandingContent(config, landingModule?.content, {
265
+ useDefaults: landingModule?.useDefaults === true,
266
+ }),
267
+ },
268
+ userPanel: {
269
+ enabled: userPanelEnabled,
270
+ basePath,
271
+ dashboard: {
272
+ enabled: dashboardEnabled,
273
+ path: joinPanelPath(basePath, dashboardConfig?.path ?? "dashboard"),
274
+ content: resolveDashboardContent(dashboardConfig?.content),
275
+ },
276
+ userManagement: {
277
+ enabled: userManagementEnabled,
278
+ routes: {
279
+ login: userManagementConfig?.routes?.login ?? "/signin",
280
+ register: userManagementConfig?.routes?.register ?? "/signup",
281
+ profile: joinPanelPath(
282
+ basePath,
283
+ userManagementConfig?.routes?.profile ?? "profile",
284
+ ),
285
+ logout: userManagementConfig?.routes?.logout ?? "/signout",
286
+ },
287
+ content: resolveProfileContent(userManagementConfig?.content),
288
+ },
289
+ apiKeys: {
290
+ enabled: apiKeysEnabled,
291
+ path: joinPanelPath(
292
+ basePath,
293
+ apiKeysModuleConfig?.path ?? "settings/api-keys",
294
+ ),
295
+ },
296
+ plans: {
297
+ enabled: plansEnabled,
298
+ path: joinPanelPath(basePath, plansConfig?.path ?? "plans"),
299
+ content: resolvePlansContent(plansConfig?.content),
300
+ items: plansConfig?.items,
301
+ },
302
+ },
303
+ };
304
+ };
305
+
306
+ export { getEffectiveRedirects } from "./effective-redirects.js";
307
+
308
+ export const getEffectiveDocsConfig = (
309
+ _config: ZudokuConfig,
310
+ resolved: ResolvedModulesConfig,
311
+ ) => {
312
+ if (!resolved.docs.enabled) {
313
+ return undefined;
314
+ }
315
+
316
+ return {
317
+ files: resolved.docs.files ?? [DEFAULT_DOCS_FILES],
318
+ publishMarkdown: resolved.docs.publishMarkdown ?? false,
319
+ defaultOptions: resolved.docs.defaultOptions,
320
+ llms: resolved.docs.llms,
321
+ };
322
+ };
323
+
324
+ export const isDocsModuleEnabled = (config: ZudokuConfig) =>
325
+ resolveModulesConfig(config).docs.enabled;
326
+
327
+ export const isLandingModuleEnabled = (config: ZudokuConfig) =>
328
+ resolveModulesConfig(config).landing.enabled;
329
+
330
+ export const isUserPanelModuleEnabled = (config: ZudokuConfig) =>
331
+ resolveModulesConfig(config).userPanel.enabled;