@lukoweb/apitogo 0.2.31 → 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.
- package/dist/cli/cli.js +436 -153
- package/dist/declarations/app/entry.server.d.ts +2 -2
- package/dist/declarations/app/main.d.ts +3 -1
- package/dist/declarations/cli/platform/client/platform-api.d.ts +0 -4
- package/dist/declarations/cli/platform/helpers/deploy-artifact-hash.d.ts +1 -1
- package/dist/declarations/cli/platform/helpers/package-files.d.ts +1 -1
- package/dist/declarations/cli/platform/helpers/zip.d.ts +1 -1
- package/dist/declarations/cli/platform/tools/infrastructure.d.ts +0 -4
- package/dist/declarations/config/effective-redirects.d.ts +6 -0
- package/dist/declarations/config/header-navigation-guard.d.ts +2 -0
- package/dist/declarations/config/resolve-modules.d.ts +1 -4
- package/dist/declarations/config/validators/HeaderNavigationSchema.d.ts +1 -2
- package/docs/cli/commands.md +19 -0
- package/docs/configuration/gateway.md +52 -0
- package/docs/guides/customer-account.md +11 -1
- package/docs/mcp/tools.md +101 -102
- package/package.json +2 -1
- package/src/app/demo.tsx +78 -77
- package/src/app/entry.client.tsx +115 -107
- package/src/app/entry.server.tsx +164 -160
- package/src/app/main.tsx +175 -167
- package/src/app/standalone.tsx +61 -60
- package/src/config/effective-redirects.ts +31 -0
- package/src/config/header-navigation-guard.ts +13 -0
- package/src/config/resolve-modules.ts +331 -354
- package/src/config/v2/home-redirect.ts +104 -98
- package/src/config/v2/index.ts +127 -126
- package/src/config/v2/ledger.ts +242 -235
- package/src/config/v2/resolve.ts +12 -4
- package/src/config/v2/rules.ts +716 -714
- package/src/config/v2/services.ts +799 -663
- package/src/config/v2/workspace.ts +17 -1
- package/src/config/validators/HeaderNavigationSchema.ts +42 -44
- package/src/lib/assets/powered-by-icon.png +0 -0
- package/src/lib/authentication/providers/dev-portal-auth-pages.tsx +667 -602
- package/src/lib/authentication/providers/dev-portal.tsx +476 -448
- package/src/lib/components/HeaderNavigation.tsx +176 -176
- package/src/lib/components/MobileTopNavigation.tsx +283 -283
- package/src/lib/components/navigation/PoweredByZudoku.tsx +42 -39
- package/src/vite/plugin-offroot-resolve.ts +68 -67
- 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
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
if (!resolved.
|
|
313
|
-
return
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
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;
|