@lukoweb/apitogo 0.2.31 → 0.2.35

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 (41) hide show
  1. package/dist/cli/cli.js +440 -153
  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 +0 -4
  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/zip.d.ts +1 -1
  8. package/dist/declarations/cli/platform/tools/infrastructure.d.ts +0 -4
  9. package/dist/declarations/config/effective-redirects.d.ts +6 -0
  10. package/dist/declarations/config/header-navigation-guard.d.ts +2 -0
  11. package/dist/declarations/config/resolve-modules.d.ts +1 -4
  12. package/dist/declarations/config/validators/HeaderNavigationSchema.d.ts +1 -2
  13. package/docs/cli/commands.md +19 -0
  14. package/docs/configuration/gateway.md +52 -0
  15. package/docs/guides/customer-account.md +11 -1
  16. package/docs/mcp/tools.md +101 -102
  17. package/package.json +2 -1
  18. package/src/app/demo.tsx +78 -77
  19. package/src/app/entry.client.tsx +115 -107
  20. package/src/app/entry.server.tsx +164 -160
  21. package/src/app/main.tsx +175 -167
  22. package/src/app/standalone.tsx +61 -60
  23. package/src/config/effective-redirects.ts +31 -0
  24. package/src/config/header-navigation-guard.ts +13 -0
  25. package/src/config/resolve-modules.ts +331 -354
  26. package/src/config/v2/home-redirect.ts +104 -98
  27. package/src/config/v2/index.ts +127 -126
  28. package/src/config/v2/ledger.ts +242 -235
  29. package/src/config/v2/resolve.ts +12 -4
  30. package/src/config/v2/rules.ts +716 -714
  31. package/src/config/v2/services.ts +799 -663
  32. package/src/config/v2/workspace.ts +17 -1
  33. package/src/config/validators/HeaderNavigationSchema.ts +42 -44
  34. package/src/lib/assets/powered-by-icon.png +0 -0
  35. package/src/lib/authentication/providers/dev-portal-auth-pages.tsx +667 -602
  36. package/src/lib/authentication/providers/dev-portal.tsx +476 -448
  37. package/src/lib/components/HeaderNavigation.tsx +176 -176
  38. package/src/lib/components/MobileTopNavigation.tsx +283 -283
  39. package/src/lib/components/navigation/PoweredByZudoku.tsx +42 -39
  40. package/src/vite/plugin-offroot-resolve.ts +68 -67
  41. package/src/vite/prerender/prerender.ts +242 -242
package/src/app/main.tsx CHANGED
@@ -1,167 +1,175 @@
1
- import { Apitogo } from "@lukoweb/apitogo/components";
2
- import { Outlet } from "@lukoweb/apitogo/router";
3
- import type { RouteObject } from "react-router";
4
- import type { HighlighterCore } from "shiki";
5
- import { configuredApiKeysPlugin } from "virtual:zudoku-api-keys-plugin";
6
- import {
7
- configuredApiCatalogPlugins,
8
- configuredApiPlugins,
9
- } from "virtual:zudoku-api-plugins";
10
- import { configuredAuthProvider } from "virtual:zudoku-auth";
11
- import { configuredCustomPagesPlugin } from "virtual:zudoku-custom-pages-plugin";
12
- import { configuredDocsPlugin } from "virtual:zudoku-docs-plugin";
13
- import {
14
- configuredModulesPlugins,
15
- configuredModulesSlots,
16
- } from "virtual:zudoku-modules-plugin";
17
- import "virtual:zudoku-theme.css";
18
- import {
19
- configuredHeaderNavigation,
20
- configuredNavigation,
21
- configuredNavigationRules,
22
- } from "virtual:zudoku-navigation";
23
- import { configuredSearchPlugin } from "virtual:zudoku-search-plugin";
24
- import type { ApitogoConfig } from "../config/config.js";
25
- import {
26
- resolveModulesConfig,
27
- getEffectiveRedirects,
28
- } from "../config/resolve-modules.js";
29
- import { BuildCheck } from "../lib/components/BuildCheck.js";
30
- import "./main.css";
31
- import { Meta } from "../lib/components/Meta.js";
32
- import "./polyfills.js";
33
- import { StatusPage } from "../lib/components/StatusPage.js";
34
- import { isNavigationPlugin } from "../lib/core/plugins.js";
35
- import { RouteGuard } from "../lib/core/RouteGuard.js";
36
- import type { ZudokuContextOptions } from "../lib/core/ZudokuContext.js";
37
- import { RouterError } from "../lib/errors/RouterError.js";
38
- import { ZuploEnv } from "./env.js";
39
- import { processRoutes } from "./processRoutes.js";
40
- import { createRedirectRoutes } from "./utils/createRedirectRoutes.js";
41
-
42
- export const shikiReady: Promise<HighlighterCore> =
43
- import("../lib/shiki.js").then(async ({ highlighterPromise }) => {
44
- const highlighter = await highlighterPromise;
45
- const { registerShiki } = await import("virtual:zudoku-shiki-register");
46
- await registerShiki(highlighter);
47
- return highlighter;
48
- });
49
-
50
- export const convertApitogoConfigToOptions = (
51
- config: ApitogoConfig,
52
- ): ZudokuContextOptions => {
53
- const siteTitle =
54
- config.metadata?.applicationName ?? config.site?.title ?? "API ToGo";
55
-
56
- return {
57
- basePath: config.basePath,
58
- canonicalUrlOrigin: config.canonicalUrlOrigin,
59
- aiAssistants: config.aiAssistants,
60
- protectedRoutes: config.protectedRoutes,
61
- site: {
62
- ...config.site,
63
- showPoweredBy: ZuploEnv.buildConfig?.entitlements.devPortalZuploBranding,
64
- logo: config.site?.logo,
65
- },
66
- slots: { ...configuredModulesSlots, ...config.slots },
67
- metadata: {
68
- applicationName: siteTitle,
69
- defaultTitle: siteTitle,
70
- title: `%s - ${siteTitle}`,
71
- ...config.metadata,
72
- },
73
- header: {
74
- navigation: configuredHeaderNavigation,
75
- placements: config.header?.placements,
76
- },
77
- navigation: configuredNavigation,
78
- navigationRules: configuredNavigationRules,
79
- mdx: config.mdx,
80
- plugins: [
81
- ...(configuredAuthProvider ? [configuredAuthProvider] : []),
82
- ...(configuredDocsPlugin ? [configuredDocsPlugin] : []),
83
- ...configuredApiPlugins,
84
- ...(configuredSearchPlugin ? [configuredSearchPlugin] : []),
85
- ...(configuredApiKeysPlugin ? [configuredApiKeysPlugin] : []),
86
- ...(configuredCustomPagesPlugin ? [configuredCustomPagesPlugin] : []),
87
- ...configuredModulesPlugins,
88
- ...configuredApiCatalogPlugins,
89
- ...(config.plugins ?? []),
90
- ],
91
- syntaxHighlighting: {
92
- highlighterPromise: shikiReady,
93
- themes: config.syntaxHighlighting?.themes,
94
- },
95
- };
96
- };
97
-
98
- /**
99
- * @deprecated Use {@link convertApitogoConfigToOptions} instead.
100
- */
101
- export const convertZudokuConfigToOptions = convertApitogoConfigToOptions;
102
-
103
- export const getRoutesByOptions = (
104
- options: ZudokuContextOptions,
105
- enableStatusPages = true,
106
- ) => {
107
- const allPlugins = [
108
- ...(options.plugins ?? []),
109
- ...(options.authentication ? [options.authentication] : []),
110
- ];
111
-
112
- const routes = allPlugins
113
- .flatMap((plugin) => (isNavigationPlugin(plugin) ? plugin.getRoutes() : []))
114
- .concat(
115
- enableStatusPages
116
- ? [400, 404, 500].map((statusCode) => ({
117
- path: `/${statusCode}`,
118
- element: <StatusPage statusCode={statusCode} />,
119
- }))
120
- : [],
121
- )
122
- .concat([{ path: "*", element: <StatusPage statusCode={404} /> }])
123
- .map((route) => ({
124
- ...route,
125
- errorElement: <RouterError className="w-full m-0" />,
126
- }));
127
-
128
- // @TODO Detect conflicts in routes and log warning
129
-
130
- return routes;
131
- };
132
-
133
- export const getRoutesByConfig = (config: ApitogoConfig): RouteObject[] => {
134
- const resolvedModules = resolveModulesConfig(config);
135
- const options = convertApitogoConfigToOptions(config);
136
- const routes = getRoutesByOptions(
137
- options,
138
- import.meta.env.IS_ZUPLO || config.enableStatusPages,
139
- );
140
-
141
- return [
142
- ...createRedirectRoutes(getEffectiveRedirects(config, resolvedModules)),
143
- {
144
- element: (
145
- <Apitogo {...options} env={import.meta.env}>
146
- <BuildCheck
147
- buildId={import.meta.env.ZUPLO_BUILD_ID}
148
- environmentType={import.meta.env.ZUPLO_ENVIRONMENT_TYPE}
149
- />
150
- <Outlet />
151
- </Apitogo>
152
- ),
153
- hydrateFallbackElement: <div>Loading...</div>,
154
- children: [
155
- {
156
- element: (
157
- <Meta>
158
- <RouteGuard />
159
- </Meta>
160
- ),
161
- errorElement: <RouterError />,
162
- children: processRoutes(routes),
163
- },
164
- ],
165
- },
166
- ];
167
- };
1
+ import { Apitogo } from "@lukoweb/apitogo/components";
2
+ import { Outlet } from "@lukoweb/apitogo/router";
3
+ import type { RouteObject } from "react-router";
4
+ import type { HighlighterCore } from "shiki";
5
+ import { configuredApiKeysPlugin } from "virtual:zudoku-api-keys-plugin";
6
+ import {
7
+ configuredApiCatalogPlugins,
8
+ configuredApiPlugins,
9
+ } from "virtual:zudoku-api-plugins";
10
+ import { configuredAuthProvider } from "virtual:zudoku-auth";
11
+ import { configuredCustomPagesPlugin } from "virtual:zudoku-custom-pages-plugin";
12
+ import { configuredDocsPlugin } from "virtual:zudoku-docs-plugin";
13
+ import {
14
+ configuredModulesPlugins,
15
+ configuredModulesSlots,
16
+ } from "virtual:zudoku-modules-plugin";
17
+ import "virtual:zudoku-theme.css";
18
+ import {
19
+ configuredHeaderNavigation,
20
+ configuredNavigation,
21
+ configuredNavigationRules,
22
+ } from "virtual:zudoku-navigation";
23
+ import { configuredSearchPlugin } from "virtual:zudoku-search-plugin";
24
+ import type { ApitogoConfig } from "../config/config.js";
25
+ import { getEffectiveRedirects } from "../config/effective-redirects.js";
26
+ import type { ResolvedModulesConfig } from "../config/validators/ModulesSchema.js";
27
+ import { BuildCheck } from "../lib/components/BuildCheck.js";
28
+ import "./main.css";
29
+ import { Meta } from "../lib/components/Meta.js";
30
+ import "./polyfills.js";
31
+ import { StatusPage } from "../lib/components/StatusPage.js";
32
+ import { isNavigationPlugin } from "../lib/core/plugins.js";
33
+ import { RouteGuard } from "../lib/core/RouteGuard.js";
34
+ import type { ZudokuContextOptions } from "../lib/core/ZudokuContext.js";
35
+ import { RouterError } from "../lib/errors/RouterError.js";
36
+ import { ZuploEnv } from "./env.js";
37
+ import { processRoutes } from "./processRoutes.js";
38
+ import { createRedirectRoutes } from "./utils/createRedirectRoutes.js";
39
+
40
+ export const shikiReady: Promise<HighlighterCore> =
41
+ import("../lib/shiki.js").then(async ({ highlighterPromise }) => {
42
+ const highlighter = await highlighterPromise;
43
+ const { registerShiki } = await import("virtual:zudoku-shiki-register");
44
+ await registerShiki(highlighter);
45
+ return highlighter;
46
+ });
47
+
48
+ export const convertApitogoConfigToOptions = (
49
+ config: ApitogoConfig,
50
+ ): ZudokuContextOptions => {
51
+ const siteTitle =
52
+ config.metadata?.applicationName ?? config.site?.title ?? "API ToGo";
53
+
54
+ return {
55
+ basePath: config.basePath,
56
+ canonicalUrlOrigin: config.canonicalUrlOrigin,
57
+ aiAssistants: config.aiAssistants,
58
+ protectedRoutes: config.protectedRoutes,
59
+ site: {
60
+ ...config.site,
61
+ showPoweredBy: ZuploEnv.buildConfig?.entitlements.devPortalZuploBranding,
62
+ logo: config.site?.logo,
63
+ },
64
+ slots: { ...configuredModulesSlots, ...config.slots },
65
+ metadata: {
66
+ applicationName: siteTitle,
67
+ defaultTitle: siteTitle,
68
+ title: `%s - ${siteTitle}`,
69
+ ...config.metadata,
70
+ },
71
+ header: {
72
+ navigation: configuredHeaderNavigation,
73
+ placements: config.header?.placements,
74
+ },
75
+ navigation: configuredNavigation,
76
+ navigationRules: configuredNavigationRules,
77
+ mdx: config.mdx,
78
+ plugins: [
79
+ ...(configuredAuthProvider ? [configuredAuthProvider] : []),
80
+ ...(configuredDocsPlugin ? [configuredDocsPlugin] : []),
81
+ ...configuredApiPlugins,
82
+ ...(configuredSearchPlugin ? [configuredSearchPlugin] : []),
83
+ ...(configuredApiKeysPlugin ? [configuredApiKeysPlugin] : []),
84
+ ...(configuredCustomPagesPlugin ? [configuredCustomPagesPlugin] : []),
85
+ ...configuredModulesPlugins,
86
+ ...configuredApiCatalogPlugins,
87
+ ...(config.plugins ?? []),
88
+ ],
89
+ syntaxHighlighting: {
90
+ highlighterPromise: shikiReady,
91
+ themes: config.syntaxHighlighting?.themes,
92
+ },
93
+ };
94
+ };
95
+
96
+ /**
97
+ * @deprecated Use {@link convertApitogoConfigToOptions} instead.
98
+ */
99
+ export const convertZudokuConfigToOptions = convertApitogoConfigToOptions;
100
+
101
+ export const getRoutesByOptions = (
102
+ options: ZudokuContextOptions,
103
+ enableStatusPages = true,
104
+ ) => {
105
+ const allPlugins = [
106
+ ...(options.plugins ?? []),
107
+ ...(options.authentication ? [options.authentication] : []),
108
+ ];
109
+
110
+ const routes = allPlugins
111
+ .flatMap((plugin) => (isNavigationPlugin(plugin) ? plugin.getRoutes() : []))
112
+ .concat(
113
+ enableStatusPages
114
+ ? [400, 404, 500].map((statusCode) => ({
115
+ path: `/${statusCode}`,
116
+ element: <StatusPage statusCode={statusCode} />,
117
+ }))
118
+ : [],
119
+ )
120
+ .concat([{ path: "*", element: <StatusPage statusCode={404} /> }])
121
+ .map((route) => ({
122
+ ...route,
123
+ errorElement: <RouterError className="w-full m-0" />,
124
+ }));
125
+
126
+ // @TODO Detect conflicts in routes and log warning
127
+
128
+ return routes;
129
+ };
130
+
131
+ /**
132
+ * How the entry gets the resolved modules of a config. The server and the demo parse them from the config
133
+ * (`resolveModulesConfig`, which needs zod); the browser takes what the build already resolved, so the schema
134
+ * is not in the browser bundle.
135
+ */
136
+ export type ModulesResolver = (config: ApitogoConfig) => ResolvedModulesConfig;
137
+
138
+ export const getRoutesByConfig = (
139
+ config: ApitogoConfig,
140
+ resolveModules: ModulesResolver,
141
+ ): RouteObject[] => {
142
+ const resolvedModules = resolveModules(config);
143
+ const options = convertApitogoConfigToOptions(config);
144
+ const routes = getRoutesByOptions(
145
+ options,
146
+ import.meta.env.IS_ZUPLO || config.enableStatusPages,
147
+ );
148
+
149
+ return [
150
+ ...createRedirectRoutes(getEffectiveRedirects(config, resolvedModules)),
151
+ {
152
+ element: (
153
+ <Apitogo {...options} env={import.meta.env}>
154
+ <BuildCheck
155
+ buildId={import.meta.env.ZUPLO_BUILD_ID}
156
+ environmentType={import.meta.env.ZUPLO_ENVIRONMENT_TYPE}
157
+ />
158
+ <Outlet />
159
+ </Apitogo>
160
+ ),
161
+ hydrateFallbackElement: <div>Loading...</div>,
162
+ children: [
163
+ {
164
+ element: (
165
+ <Meta>
166
+ <RouteGuard />
167
+ </Meta>
168
+ ),
169
+ errorElement: <RouterError />,
170
+ children: processRoutes(routes),
171
+ },
172
+ ],
173
+ },
174
+ ];
175
+ };
@@ -1,60 +1,61 @@
1
- import { createRoot } from "react-dom/client";
2
- import { createBrowserRouter } from "react-router";
3
- import type { ZudokuConfig } from "../config/validators/ZudokuConfig.js";
4
- import { Bootstrap } from "../lib/components/Bootstrap.js";
5
- import { openApiPlugin } from "../lib/plugins/openapi/index.js";
6
- import "../lib/util/logInit.js";
7
- import "./main.css";
8
- import { getRoutesByConfig } from "./main.js";
9
-
10
- const root = document.querySelector("div[data-api-url]");
11
- if (!root) {
12
- throw new Error("No div found with attribute data-api-url");
13
- }
14
-
15
- const apiUrl = root.getAttribute("data-api-url");
16
-
17
- if (!apiUrl) {
18
- throw new Error("No api url found");
19
- }
20
-
21
- const title = document.getElementsByTagName("title")[0]?.innerText;
22
- const logoUrl = root.getAttribute("data-logo-url");
23
-
24
- // IMPORTANT: This component must not contain tailwind classes
25
- // This directory is not processed by the tailwind plugin
26
-
27
- const config = {
28
- site: {
29
- logo: logoUrl
30
- ? {
31
- src: {
32
- light: logoUrl,
33
- dark: logoUrl,
34
- },
35
- }
36
- : undefined,
37
- title,
38
- },
39
- navigation: [
40
- {
41
- type: "link",
42
- label: "API Reference",
43
- to: "/",
44
- },
45
- ],
46
- plugins: [
47
- // Using the plugin directly because there's no config file to load in the virtual plugins
48
- openApiPlugin({
49
- type: "url",
50
- input: apiUrl,
51
- path: "/",
52
- }),
53
- ],
54
- } satisfies ZudokuConfig;
55
-
56
- const routes = getRoutesByConfig(config);
57
- const router = createBrowserRouter(routes, {
58
- basename: window.location.pathname,
59
- });
60
- createRoot(root).render(<Bootstrap router={router} />);
1
+ import { createRoot } from "react-dom/client";
2
+ import { createBrowserRouter } from "react-router";
3
+ import { resolveModulesConfig } from "../config/resolve-modules.js";
4
+ import type { ZudokuConfig } from "../config/validators/ZudokuConfig.js";
5
+ import { Bootstrap } from "../lib/components/Bootstrap.js";
6
+ import "../lib/util/logInit.js";
7
+ import "./main.css";
8
+ import { openApiPlugin } from "../lib/plugins/openapi/index.js";
9
+ import { getRoutesByConfig } from "./main.js";
10
+
11
+ const root = document.querySelector("div[data-api-url]");
12
+ if (!root) {
13
+ throw new Error("No div found with attribute data-api-url");
14
+ }
15
+
16
+ const apiUrl = root.getAttribute("data-api-url");
17
+
18
+ if (!apiUrl) {
19
+ throw new Error("No api url found");
20
+ }
21
+
22
+ const title = document.getElementsByTagName("title")[0]?.innerText;
23
+ const logoUrl = root.getAttribute("data-logo-url");
24
+
25
+ // IMPORTANT: This component must not contain tailwind classes
26
+ // This directory is not processed by the tailwind plugin
27
+
28
+ const config = {
29
+ site: {
30
+ logo: logoUrl
31
+ ? {
32
+ src: {
33
+ light: logoUrl,
34
+ dark: logoUrl,
35
+ },
36
+ }
37
+ : undefined,
38
+ title,
39
+ },
40
+ navigation: [
41
+ {
42
+ type: "link",
43
+ label: "API Reference",
44
+ to: "/",
45
+ },
46
+ ],
47
+ plugins: [
48
+ // Using the plugin directly because there's no config file to load in the virtual plugins
49
+ openApiPlugin({
50
+ type: "url",
51
+ input: apiUrl,
52
+ path: "/",
53
+ }),
54
+ ],
55
+ } satisfies ZudokuConfig;
56
+
57
+ const routes = getRoutesByConfig(config, resolveModulesConfig);
58
+ const router = createBrowserRouter(routes, {
59
+ basename: window.location.pathname,
60
+ });
61
+ createRoot(root).render(<Bootstrap router={router} />);
@@ -0,0 +1,31 @@
1
+ import type { ResolvedModulesConfig } from "./validators/ModulesSchema.js";
2
+ import type { ZudokuConfig } from "./validators/ZudokuConfig.js";
3
+
4
+ /**
5
+ * The redirects of the config without the one that would shadow the landing page. Lives apart from
6
+ * `resolve-modules.ts` because the browser entry needs it and must not pull in the module schema (zod).
7
+ */
8
+ export const getEffectiveRedirects = (
9
+ config: ZudokuConfig,
10
+ resolved: ResolvedModulesConfig,
11
+ ) => {
12
+ const redirects = config.redirects ?? [];
13
+
14
+ if (!resolved.landing.enabled) {
15
+ return redirects;
16
+ }
17
+
18
+ const landingPath = normalizePath(resolved.landing.path);
19
+
20
+ return redirects.filter(
21
+ (redirect) => normalizePath(redirect.from) !== landingPath,
22
+ );
23
+ };
24
+
25
+ const normalizePath = (path: string) => {
26
+ if (path === "/") {
27
+ return "/";
28
+ }
29
+
30
+ return path.replace(/\/+$/, "") || "/";
31
+ };
@@ -0,0 +1,13 @@
1
+ import type {
2
+ HeaderNavGroup,
3
+ HeaderNavItem,
4
+ HeaderNavLinkItem,
5
+ } from "./validators/HeaderNavigationSchema.js";
6
+
7
+ /**
8
+ * Lives apart from `HeaderNavigationSchema.ts` because the header components need it in the browser, and that file
9
+ * holds the schema (zod) and the list of every icon name.
10
+ */
11
+ export const isHeaderNavGroup = (
12
+ item: HeaderNavItem | HeaderNavLinkItem | HeaderNavGroup,
13
+ ): item is HeaderNavGroup => "items" in item;