@lukoweb/apitogo 0.2.54 → 0.2.57
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 +2196 -1352
- package/dist/declarations/cli/platform/client/platform-api.d.ts +29 -0
- package/dist/declarations/cli/platform/helpers/platform-plan-catalog.d.ts +6 -0
- package/dist/declarations/config/validators/ZudokuConfig.d.ts +2 -0
- package/dist/declarations/lib/authentication/providers/openid.d.ts +2 -1
- package/dist/declarations/lib/plugins/markdown/index.d.ts +2 -1
- package/dist/flat-config.d.ts +1 -0
- package/docs/cli/commands.md +50 -32
- package/docs/cli/go-live.md +66 -93
- package/docs/cli/overview.md +18 -17
- package/docs/cli/setup.md +130 -141
- package/docs/cli/shape.md +94 -11
- package/docs/cli/walkthrough.md +1 -1
- package/docs/components/slot.mdx +116 -119
- package/docs/configuration/api-reference.md +98 -397
- package/docs/configuration/authentication.md +118 -159
- package/docs/configuration/footer.mdx +89 -118
- package/docs/configuration/make-config.mdx +2 -2
- package/docs/configuration/overview.md +97 -166
- package/docs/configuration/plans.md +100 -110
- package/docs/configuration/portal.md +116 -0
- package/docs/customization/colors-theme.mdx +255 -278
- package/docs/customization/fonts.md +105 -110
- package/docs/customization/landing-page.md +189 -188
- package/docs/deploy/apitogo.md +13 -17
- package/docs/deployment.md +15 -9
- package/docs/guides/stripe-setup.mdx +123 -0
- package/docs/markdown/frontmatter.md +172 -173
- package/docs/mcp/go-live.md +100 -100
- package/docs/mcp/overview.md +76 -76
- package/docs/quickstart.md +88 -72
- package/docs/writing.mdx +68 -72
- package/package.json +1 -1
- package/src/config/v2/docs-navigation.ts +7 -2
- package/src/config/v2/index.ts +1 -0
- package/src/config/v2/resolve.ts +28 -0
- package/src/config/v2/rules.ts +32 -1
- package/src/config/v2/schema.ts +9 -0
- package/src/config/v2/services.ts +90 -15
- package/src/config/v2/starter-landing.ts +41 -0
- package/src/config/v2/wrapper.ts +141 -7
- package/src/config/validators/ZudokuConfig.ts +794 -792
- package/src/lib/authentication/providers/openid.tsx +6 -1
- package/src/lib/plugins/markdown/index.tsx +86 -82
- package/src/vite/dev-server.ts +9 -1
- package/src/vite/dev-ssr-config.ts +32 -0
- package/src/vite/plugin-config.ts +4 -2
- package/src/vite/plugin-docs.ts +213 -205
- package/docs/concepts/auth-provider-api-identities.md +0 -105
- package/docs/configuration/ai-assistants.md +0 -65
- package/docs/configuration/api-catalog.md +0 -109
- package/docs/configuration/authentication-auth0.md +0 -181
- package/docs/configuration/authentication-azure-ad.md +0 -245
- package/docs/configuration/authentication-clerk.md +0 -117
- package/docs/configuration/authentication-firebase.md +0 -69
- package/docs/configuration/authentication-pingfederate.md +0 -143
- package/docs/configuration/authentication-supabase.md +0 -233
- package/docs/configuration/build-configuration.mdx +0 -147
- package/docs/configuration/docs.md +0 -282
- package/docs/configuration/llms.md +0 -90
- package/docs/configuration/manifest.md +0 -129
- package/docs/configuration/navigation.mdx +0 -415
- package/docs/configuration/protected-routes.md +0 -150
- package/docs/configuration/search.md +0 -164
- package/docs/configuration/sentry.mdx +0 -44
- package/docs/configuration/site.md +0 -124
- package/docs/configuration/slots.mdx +0 -125
- package/docs/configuration/vite-config.md +0 -18
- package/docs/custom-plugins.md +0 -285
- package/docs/deploy/apache-nginx.md +0 -41
- package/docs/deploy/cloudflare-pages.md +0 -74
- package/docs/deploy/direct-upload.md +0 -17
- package/docs/deploy/github-pages.md +0 -49
- package/docs/deploy/vercel.md +0 -101
- package/docs/extending/events.md +0 -124
- package/docs/guides/environment-variables.md +0 -94
- package/docs/guides/managing-api-keys-and-identities.md +0 -89
- package/docs/guides/navigation-rules.mdx +0 -203
- package/docs/guides/processors.mdx +0 -234
- package/docs/guides/transforming-examples.md +0 -156
- package/docs/guides/using-multiple-apis.md +0 -87
- package/docs/plugins.md +0 -24
package/src/vite/plugin-docs.ts
CHANGED
|
@@ -1,205 +1,213 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { glob } from "glob";
|
|
3
|
-
import globParent from "glob-parent";
|
|
4
|
-
import type { Plugin } from "vite";
|
|
5
|
-
import { type ConfigWithMeta, getCurrentConfig } from "../config/loader.js";
|
|
6
|
-
import {
|
|
7
|
-
type NavigationItem,
|
|
8
|
-
NavigationResolver,
|
|
9
|
-
} from "../config/validators/NavigationSchema.js";
|
|
10
|
-
import { DocsConfigSchema } from "../config/validators/ZudokuConfig.js";
|
|
11
|
-
import { traverseNavigation } from "../lib/components/navigation/utils.js";
|
|
12
|
-
import { joinUrl } from "../lib/util/joinUrl.js";
|
|
13
|
-
import { readFrontmatter } from "../lib/util/readFrontmatter.js";
|
|
14
|
-
import { writePluginDebugCode } from "./debug.js";
|
|
15
|
-
|
|
16
|
-
const ensureLeadingSlash = joinUrl;
|
|
17
|
-
|
|
18
|
-
// Glob markdown files and returns a mapping of route paths to file paths.
|
|
19
|
-
export const globMarkdownFiles = async (
|
|
20
|
-
config: ConfigWithMeta,
|
|
21
|
-
options: { absolute: boolean } = { absolute: false },
|
|
22
|
-
): Promise<Record<string, string>> => {
|
|
23
|
-
const docsConfig = DocsConfigSchema.parse(config.docs ?? {});
|
|
24
|
-
const fileMapping: Record<string, string> = {};
|
|
25
|
-
|
|
26
|
-
for (const globPattern of docsConfig.files) {
|
|
27
|
-
const globbedFiles = await glob(globPattern, {
|
|
28
|
-
root: config.__meta.rootDir,
|
|
29
|
-
ignore: ["**/node_modules/**", "**/dist/**", "**/.git/**"],
|
|
30
|
-
// Always glob with relative paths to avoid issues on different OS
|
|
31
|
-
absolute: false,
|
|
32
|
-
posix: true,
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
// Normalize parent by removing leading `./` or `/`
|
|
36
|
-
const parent = globParent(globPattern).replace(/^\.?\//, "");
|
|
37
|
-
|
|
38
|
-
// Precompute draft status for all files in production mode to avoid serial I/O
|
|
39
|
-
let draftFiles = new Set<string>();
|
|
40
|
-
if (process.env.NODE_ENV !== "development") {
|
|
41
|
-
const draftStatuses = await Promise.all(
|
|
42
|
-
globbedFiles.map(async (file) => {
|
|
43
|
-
const absolutePath = path.resolve(config.__meta.rootDir, file);
|
|
44
|
-
const { data } = await readFrontmatter(absolutePath);
|
|
45
|
-
return { file, isDraft: data.draft === true };
|
|
46
|
-
}),
|
|
47
|
-
);
|
|
48
|
-
draftFiles = new Set(
|
|
49
|
-
draftStatuses
|
|
50
|
-
.filter((entry) => entry.isDraft)
|
|
51
|
-
.map((entry) => entry.file),
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
for (const file of globbedFiles) {
|
|
56
|
-
// Skip draft documents in production mode
|
|
57
|
-
if (draftFiles.has(file)) {
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const relativePath = path.posix.relative(parent, file);
|
|
62
|
-
const routePath = ensureLeadingSlash(relativePath.replace(/\.mdx?$/, ""));
|
|
63
|
-
// Resolve to absolute path if requested, using path.resolve to handle cross-platform paths
|
|
64
|
-
const filePath = options.absolute
|
|
65
|
-
? path.resolve(config.__meta.rootDir, file)
|
|
66
|
-
: file;
|
|
67
|
-
fileMapping[routePath] = filePath;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return fileMapping;
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Resolves custom navigation paths and returns an updated file mapping.
|
|
76
|
-
* Handles cases where navigation defines custom paths for documents.
|
|
77
|
-
*/
|
|
78
|
-
export const resolveCustomNavigationPaths = async (
|
|
79
|
-
config: ConfigWithMeta,
|
|
80
|
-
fileMapping: Record<string, string>,
|
|
81
|
-
): Promise<Record<string, string>> => {
|
|
82
|
-
if (!config.navigation && !config.navigationRules) return fileMapping;
|
|
83
|
-
|
|
84
|
-
const resolver = new NavigationResolver(config);
|
|
85
|
-
const mapping = { ...fileMapping };
|
|
86
|
-
|
|
87
|
-
const processItem = (item: NavigationItem) => {
|
|
88
|
-
const doc =
|
|
89
|
-
item.type === "doc"
|
|
90
|
-
? { file: item.file, path: item.path }
|
|
91
|
-
: item.type === "category" && item.link
|
|
92
|
-
? { file: item.link.file, path: item.link.path }
|
|
93
|
-
: undefined;
|
|
94
|
-
|
|
95
|
-
// Only continue if the doc has a custom path
|
|
96
|
-
if (!doc || doc.path === doc.file) return;
|
|
97
|
-
|
|
98
|
-
const fileRoutePath = ensureLeadingSlash(doc.file.replace(/\.mdx?$/, ""));
|
|
99
|
-
const filePath = mapping[fileRoutePath];
|
|
100
|
-
if (!filePath) return;
|
|
101
|
-
|
|
102
|
-
const customPath = ensureLeadingSlash(doc.path);
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
//
|
|
160
|
-
// -
|
|
161
|
-
//
|
|
162
|
-
//
|
|
163
|
-
//
|
|
164
|
-
//
|
|
165
|
-
//
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
`
|
|
193
|
-
`
|
|
194
|
-
`
|
|
195
|
-
`
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { glob } from "glob";
|
|
3
|
+
import globParent from "glob-parent";
|
|
4
|
+
import type { Plugin } from "vite";
|
|
5
|
+
import { type ConfigWithMeta, getCurrentConfig } from "../config/loader.js";
|
|
6
|
+
import {
|
|
7
|
+
type NavigationItem,
|
|
8
|
+
NavigationResolver,
|
|
9
|
+
} from "../config/validators/NavigationSchema.js";
|
|
10
|
+
import { DocsConfigSchema } from "../config/validators/ZudokuConfig.js";
|
|
11
|
+
import { traverseNavigation } from "../lib/components/navigation/utils.js";
|
|
12
|
+
import { joinUrl } from "../lib/util/joinUrl.js";
|
|
13
|
+
import { readFrontmatter } from "../lib/util/readFrontmatter.js";
|
|
14
|
+
import { writePluginDebugCode } from "./debug.js";
|
|
15
|
+
|
|
16
|
+
const ensureLeadingSlash = joinUrl;
|
|
17
|
+
|
|
18
|
+
// Glob markdown files and returns a mapping of route paths to file paths.
|
|
19
|
+
export const globMarkdownFiles = async (
|
|
20
|
+
config: ConfigWithMeta,
|
|
21
|
+
options: { absolute: boolean } = { absolute: false },
|
|
22
|
+
): Promise<Record<string, string>> => {
|
|
23
|
+
const docsConfig = DocsConfigSchema.parse(config.docs ?? {});
|
|
24
|
+
const fileMapping: Record<string, string> = {};
|
|
25
|
+
|
|
26
|
+
for (const globPattern of docsConfig.files) {
|
|
27
|
+
const globbedFiles = await glob(globPattern, {
|
|
28
|
+
root: config.__meta.rootDir,
|
|
29
|
+
ignore: ["**/node_modules/**", "**/dist/**", "**/.git/**"],
|
|
30
|
+
// Always glob with relative paths to avoid issues on different OS
|
|
31
|
+
absolute: false,
|
|
32
|
+
posix: true,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Normalize parent by removing leading `./` or `/`
|
|
36
|
+
const parent = globParent(globPattern).replace(/^\.?\//, "");
|
|
37
|
+
|
|
38
|
+
// Precompute draft status for all files in production mode to avoid serial I/O
|
|
39
|
+
let draftFiles = new Set<string>();
|
|
40
|
+
if (process.env.NODE_ENV !== "development") {
|
|
41
|
+
const draftStatuses = await Promise.all(
|
|
42
|
+
globbedFiles.map(async (file) => {
|
|
43
|
+
const absolutePath = path.resolve(config.__meta.rootDir, file);
|
|
44
|
+
const { data } = await readFrontmatter(absolutePath);
|
|
45
|
+
return { file, isDraft: data.draft === true };
|
|
46
|
+
}),
|
|
47
|
+
);
|
|
48
|
+
draftFiles = new Set(
|
|
49
|
+
draftStatuses
|
|
50
|
+
.filter((entry) => entry.isDraft)
|
|
51
|
+
.map((entry) => entry.file),
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
for (const file of globbedFiles) {
|
|
56
|
+
// Skip draft documents in production mode
|
|
57
|
+
if (draftFiles.has(file)) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const relativePath = path.posix.relative(parent, file);
|
|
62
|
+
const routePath = ensureLeadingSlash(relativePath.replace(/\.mdx?$/, ""));
|
|
63
|
+
// Resolve to absolute path if requested, using path.resolve to handle cross-platform paths
|
|
64
|
+
const filePath = options.absolute
|
|
65
|
+
? path.resolve(config.__meta.rootDir, file)
|
|
66
|
+
: file;
|
|
67
|
+
fileMapping[routePath] = filePath;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return fileMapping;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Resolves custom navigation paths and returns an updated file mapping.
|
|
76
|
+
* Handles cases where navigation defines custom paths for documents.
|
|
77
|
+
*/
|
|
78
|
+
export const resolveCustomNavigationPaths = async (
|
|
79
|
+
config: ConfigWithMeta,
|
|
80
|
+
fileMapping: Record<string, string>,
|
|
81
|
+
): Promise<Record<string, string>> => {
|
|
82
|
+
if (!config.navigation && !config.navigationRules) return fileMapping;
|
|
83
|
+
|
|
84
|
+
const resolver = new NavigationResolver(config);
|
|
85
|
+
const mapping = { ...fileMapping };
|
|
86
|
+
|
|
87
|
+
const processItem = (item: NavigationItem) => {
|
|
88
|
+
const doc =
|
|
89
|
+
item.type === "doc"
|
|
90
|
+
? { file: item.file, path: item.path }
|
|
91
|
+
: item.type === "category" && item.link
|
|
92
|
+
? { file: item.link.file, path: item.link.path }
|
|
93
|
+
: undefined;
|
|
94
|
+
|
|
95
|
+
// Only continue if the doc has a custom path
|
|
96
|
+
if (!doc || doc.path === doc.file) return;
|
|
97
|
+
|
|
98
|
+
const fileRoutePath = ensureLeadingSlash(doc.file.replace(/\.mdx?$/, ""));
|
|
99
|
+
const filePath = mapping[fileRoutePath];
|
|
100
|
+
if (!filePath) return;
|
|
101
|
+
|
|
102
|
+
const customPath = ensureLeadingSlash(doc.path);
|
|
103
|
+
// A path that is the file's own route changes nothing; moving it would delete the page (`index` at `/index`, API-129).
|
|
104
|
+
if (customPath === fileRoutePath) return;
|
|
105
|
+
mapping[customPath] = filePath;
|
|
106
|
+
delete mapping[fileRoutePath];
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
if (config.navigation) {
|
|
110
|
+
const resolvedNavigation = await resolver.resolve();
|
|
111
|
+
traverseNavigation(resolvedNavigation, processItem);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (config.navigationRules) {
|
|
115
|
+
const resolvedRules = await resolver.resolveRules(config.navigationRules);
|
|
116
|
+
for (const rule of resolvedRules) {
|
|
117
|
+
if (rule.type === "insert") {
|
|
118
|
+
traverseNavigation(rule.items, processItem);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return mapping;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const viteDocsPlugin = (): Plugin => {
|
|
127
|
+
const virtualModuleId = "virtual:zudoku-docs-plugin";
|
|
128
|
+
const resolvedVirtualModuleId = `\0${virtualModuleId}`;
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
name: "zudoku-docs-plugin",
|
|
132
|
+
resolveId(id) {
|
|
133
|
+
if (id === virtualModuleId) {
|
|
134
|
+
return resolvedVirtualModuleId;
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
async load(id) {
|
|
138
|
+
if (id !== resolvedVirtualModuleId) return;
|
|
139
|
+
|
|
140
|
+
const config = getCurrentConfig();
|
|
141
|
+
|
|
142
|
+
if (
|
|
143
|
+
config.__meta.mode === "standalone" ||
|
|
144
|
+
!config.__resolvedModules.docs.enabled
|
|
145
|
+
) {
|
|
146
|
+
return `export const configuredDocsPlugin = undefined;`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const code: string[] = [
|
|
150
|
+
// IMPORTANT! This path here is important, we MUST resolve
|
|
151
|
+
// files here as Typescript from the appDir
|
|
152
|
+
config.__meta.mode === "internal"
|
|
153
|
+
? `import { markdownPlugin } from "${config.__meta.moduleDir}/src/lib/plugins/markdown/index.tsx";`
|
|
154
|
+
: `import { markdownPlugin } from "@lukoweb/apitogo/plugins/markdown";`,
|
|
155
|
+
];
|
|
156
|
+
|
|
157
|
+
const docsConfig = DocsConfigSchema.parse(config.docs ?? {});
|
|
158
|
+
|
|
159
|
+
// This is a workaround for a bug(?) in Vite where `import.meta.glob` failed us:
|
|
160
|
+
// - Root dir is `/path/to/docs`
|
|
161
|
+
// - The Markdown docs config is `/docs/**/*.md`
|
|
162
|
+
// - The basePath config is set to `/docs`
|
|
163
|
+
// This results in:
|
|
164
|
+
// > `Internal server error: Failed to resolve import "/some.md" from "virtual:zudoku-docs-plugins". Does the file exist?`
|
|
165
|
+
// Mind that the `docs` part that should be prepended is not in there
|
|
166
|
+
//
|
|
167
|
+
// This does only happen in dev SSR environments, so for prod the `basePath` is not added
|
|
168
|
+
const globImportBasePath =
|
|
169
|
+
process.env.NODE_ENV === "development" ? (config.basePath ?? "") : "";
|
|
170
|
+
|
|
171
|
+
// Glob markdown files and resolve custom navigation paths
|
|
172
|
+
const fileMapping = await resolveCustomNavigationPaths(
|
|
173
|
+
config,
|
|
174
|
+
await globMarkdownFiles(config, { absolute: false }),
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
// Transform file paths to import paths
|
|
178
|
+
const globbedDocuments: Record<string, string> = {};
|
|
179
|
+
for (const [routePath, file] of Object.entries(fileMapping)) {
|
|
180
|
+
const importPath = ensureLeadingSlash(
|
|
181
|
+
path.posix.join(globImportBasePath, file),
|
|
182
|
+
);
|
|
183
|
+
globbedDocuments[routePath] = importPath;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
code.push(
|
|
187
|
+
`const fileImports = {`,
|
|
188
|
+
...Object.entries(globbedDocuments).map(
|
|
189
|
+
([routePath, importPath]) =>
|
|
190
|
+
` "${routePath}": () => import("${importPath}"),`,
|
|
191
|
+
),
|
|
192
|
+
`};`,
|
|
193
|
+
`export const configuredDocsPlugin = markdownPlugin({`,
|
|
194
|
+
` basePath: "${config.basePath ?? ""}",`,
|
|
195
|
+
` fileImports,`,
|
|
196
|
+
// The home page owns its path, so `pages/index.md` does not take it over (API-129).
|
|
197
|
+
...(config.__resolvedModules.landing.enabled
|
|
198
|
+
? [
|
|
199
|
+
` reservedPaths: ${JSON.stringify([config.__resolvedModules.landing.path])},`,
|
|
200
|
+
]
|
|
201
|
+
: []),
|
|
202
|
+
` defaultOptions: ${JSON.stringify(docsConfig.defaultOptions)},`,
|
|
203
|
+
`});`,
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
await writePluginDebugCode(config.__meta.rootDir, "docs-plugin", code);
|
|
207
|
+
|
|
208
|
+
return code.join("\n");
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
export default viteDocsPlugin;
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Authentication Providers & API Identities
|
|
3
|
-
sidebar_label: Authentication and Identities
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
When building an API documentation portal, you often need a way for users to authenticate API
|
|
7
|
-
requests — API keys and other identities — separately from how they sign in to the portal. APIToGo
|
|
8
|
-
splits **portal authentication** from **API identities**.
|
|
9
|
-
|
|
10
|
-
## Authentication Providers and API Identities
|
|
11
|
-
|
|
12
|
-
:::tip
|
|
13
|
-
|
|
14
|
-
**Authentication providers** allow your users to sign in to your documentation portal. **API
|
|
15
|
-
Identities** allow your users to authenticate their API requests.
|
|
16
|
-
|
|
17
|
-
:::
|
|
18
|
-
|
|
19
|
-
Before diving into API Identities, it's important to understand that APIToGo separates user
|
|
20
|
-
authentication from API authentication. Authentication providers handle how users sign in to your
|
|
21
|
-
documentation portal, while API Identities manage how these users interact with your APIs.
|
|
22
|
-
|
|
23
|
-
Portal products use [`dev-portal`](../configuration/authentication.md) auth (backend-delegated
|
|
24
|
-
OIDC). SPA providers (Auth0, Clerk, …) are advanced for standalone docs sites. Providers handle:
|
|
25
|
-
|
|
26
|
-
- User authentication for the documentation portal
|
|
27
|
-
- Session management
|
|
28
|
-
- User authorization and access control
|
|
29
|
-
|
|
30
|
-
This separation allows you to:
|
|
31
|
-
|
|
32
|
-
- Use different authentication methods for your portal and APIs
|
|
33
|
-
- Manage API access independently of user authentication
|
|
34
|
-
- Support multiple API authentication schemes simultaneously
|
|
35
|
-
|
|
36
|
-
[Learn more about authentication providers](../configuration/authentication)
|
|
37
|
-
|
|
38
|
-
## Understanding API Identities
|
|
39
|
-
|
|
40
|
-
API Identities in APIToGo represent different authentication contexts that can be used to make API
|
|
41
|
-
requests. These could be different environments (production, staging), different authentication
|
|
42
|
-
methods (API key, JWT), or different service accounts.
|
|
43
|
-
|
|
44
|
-
### The API Identity Interface
|
|
45
|
-
|
|
46
|
-
```typescript
|
|
47
|
-
interface ApiIdentity {
|
|
48
|
-
id: string;
|
|
49
|
-
label: string;
|
|
50
|
-
authorizeRequest: (request: Request) => Promise<Request> | Request;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
interface ApiIdentityPlugin {
|
|
54
|
-
getIdentities: () => Promise<ApiIdentity[]> | ApiIdentity[];
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
Each API Identity consists of:
|
|
59
|
-
|
|
60
|
-
- `id`: A unique identifier for the identity
|
|
61
|
-
- `label`: A human-readable name shown in the UI
|
|
62
|
-
- `authorizeRequest`: A function that modifies requests to include the necessary authentication
|
|
63
|
-
|
|
64
|
-
## Implementing API Identities
|
|
65
|
-
|
|
66
|
-
In this example, we'll use Auth0 as our authentication provider and implement an API Identity for a
|
|
67
|
-
demo API.
|
|
68
|
-
|
|
69
|
-
:::note
|
|
70
|
-
|
|
71
|
-
For APItoGo-hosted portals, subscription keys come from the platform after `dev-portal` sign-in.
|
|
72
|
-
Implement custom API Identities when the playground should attach your own keys or JWTs.
|
|
73
|
-
|
|
74
|
-
:::
|
|
75
|
-
|
|
76
|
-
To add API Identities, implement the `ApiIdentityPlugin` interface:
|
|
77
|
-
|
|
78
|
-
```typescript
|
|
79
|
-
import { createApiIdentityPlugin } from "@lukoweb/apitogo/plugins";
|
|
80
|
-
|
|
81
|
-
export default {
|
|
82
|
-
authentication: {
|
|
83
|
-
type: "auth0",
|
|
84
|
-
domain: "my-domain.auth0.com",
|
|
85
|
-
clientId: "my-client-id",
|
|
86
|
-
},
|
|
87
|
-
plugins: [
|
|
88
|
-
createApiIdentityPlugin({
|
|
89
|
-
getIdentities: async (context) => [
|
|
90
|
-
{
|
|
91
|
-
id: "api-key-one",
|
|
92
|
-
label: "My API Key",
|
|
93
|
-
authorizeRequest: (request) => {
|
|
94
|
-
// We get the access token from the
|
|
95
|
-
// authentication provider (Auth0) and add it to the request headers
|
|
96
|
-
return context.authentication?.signRequest(request);
|
|
97
|
-
},
|
|
98
|
-
},
|
|
99
|
-
],
|
|
100
|
-
}),
|
|
101
|
-
],
|
|
102
|
-
};
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
When implemented, this identity will appear in the APIToGo playground.
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: AI Assistants
|
|
3
|
-
sidebar_icon: bot
|
|
4
|
-
description:
|
|
5
|
-
Configure which AI assistant integrations appear in dropdown menus across your APIToGo
|
|
6
|
-
documentation site, including built-in presets and custom providers.
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
By default, APIToGo shows "Use in Claude" and "Use in ChatGPT" options in dropdown menus on both
|
|
10
|
-
[API reference](./api-reference.md) and [documentation](./docs.md) pages. You can customize this
|
|
11
|
-
behavior using the top-level `aiAssistants` configuration.
|
|
12
|
-
|
|
13
|
-
## Disable AI Assistants
|
|
14
|
-
|
|
15
|
-
To remove all AI assistant options:
|
|
16
|
-
|
|
17
|
-
```ts title=config
|
|
18
|
-
const config = {
|
|
19
|
-
aiAssistants: false,
|
|
20
|
-
// ...
|
|
21
|
-
};
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Use Only Specific Presets
|
|
25
|
-
|
|
26
|
-
```ts title=config
|
|
27
|
-
const config = {
|
|
28
|
-
aiAssistants: ["claude"], // Only show Claude
|
|
29
|
-
// ...
|
|
30
|
-
};
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Available presets: `"claude"`, `"chatgpt"`
|
|
34
|
-
|
|
35
|
-
## Add Custom AI Assistants
|
|
36
|
-
|
|
37
|
-
You can add custom entries with a label and URL. Use `{pageUrl}` as a placeholder in the URL string,
|
|
38
|
-
or provide a callback for full control:
|
|
39
|
-
|
|
40
|
-
```ts title=config
|
|
41
|
-
const config = {
|
|
42
|
-
aiAssistants: [
|
|
43
|
-
"claude", // built-in preset
|
|
44
|
-
{
|
|
45
|
-
label: "Open in MyAI",
|
|
46
|
-
// Simple string with placeholder
|
|
47
|
-
url: "https://myai.com/?context={pageUrl}",
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
label: "Open in CustomAI",
|
|
51
|
-
// Callback for full control
|
|
52
|
-
url: ({ pageUrl, type }) => {
|
|
53
|
-
if (type === "openapi") {
|
|
54
|
-
return `https://custom.ai/?q=${encodeURIComponent("Explain this API: " + pageUrl)}`;
|
|
55
|
-
}
|
|
56
|
-
return `https://custom.ai/?q=${encodeURIComponent("Explain this page: " + pageUrl)}`;
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
],
|
|
60
|
-
// ...
|
|
61
|
-
};
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
The callback receives `{ pageUrl: string, type: "docs" | "openapi" }` so you can customize behavior
|
|
65
|
-
per context.
|