@raybase/docs 0.0.1 → 0.1.2

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 (88) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cli.d.ts +8 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +9 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/index.d.ts +10 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +14 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/install.d.ts +35 -0
  11. package/dist/install.d.ts.map +1 -0
  12. package/dist/install.js +29 -0
  13. package/dist/install.js.map +1 -0
  14. package/package.json +38 -8
  15. package/templates/astro-emdash/content/docs/getting-started.mdx +13 -0
  16. package/templates/astro-emdash/content/docs/index.mdx +13 -0
  17. package/templates/astro-emdash/content/docs/mcp.mdx +11 -0
  18. package/templates/astro-emdash/content/docs/meta.json +4 -0
  19. package/templates/astro-emdash/site/content/docs/getting-started.mdx +12 -0
  20. package/templates/astro-emdash/site/content/docs/index.mdx +12 -0
  21. package/templates/astro-emdash/site/content/docs/mcp.mdx +10 -0
  22. package/templates/astro-emdash/site/content/docs/meta.json +4 -0
  23. package/templates/astro-emdash/site/source.config.ts +10 -0
  24. package/templates/astro-emdash/site/src/docs/docs-assets.ts +1 -0
  25. package/templates/astro-emdash/site/src/docs/docs-client.tsx +22 -0
  26. package/templates/astro-emdash/site/src/docs/docs-data.ts +24 -0
  27. package/templates/astro-emdash/site/src/docs/docs-handler.tsx +105 -0
  28. package/templates/astro-emdash/site/src/docs/docs-layout.tsx +56 -0
  29. package/templates/astro-emdash/site/src/docs/docs-mdx.tsx +79 -0
  30. package/templates/astro-emdash/site/src/docs/docs-page-actions.tsx +146 -0
  31. package/templates/astro-emdash/site/src/docs/docs-page.tsx +70 -0
  32. package/templates/astro-emdash/site/src/docs/llm-text.ts +61 -0
  33. package/templates/astro-emdash/site/src/docs/source.ts +7 -0
  34. package/templates/astro-emdash/site/src/pages/docs/[...slug].ts +6 -0
  35. package/templates/astro-emdash/site/src/pages/docs/api/markdown.ts +4 -0
  36. package/templates/astro-emdash/site/src/pages/docs/api/search.ts +4 -0
  37. package/templates/astro-emdash/site/src/pages/llms.txt.ts +8 -0
  38. package/templates/astro-emdash/site/src/styles-docs.css +3 -0
  39. package/templates/astro-emdash/source.config.ts +10 -0
  40. package/templates/astro-emdash/src/docs/docs-assets.ts +1 -0
  41. package/templates/astro-emdash/src/docs/docs-client.tsx +22 -0
  42. package/templates/astro-emdash/src/docs/docs-data.ts +24 -0
  43. package/templates/astro-emdash/src/docs/docs-handler.tsx +105 -0
  44. package/templates/astro-emdash/src/docs/docs-layout.tsx +56 -0
  45. package/templates/astro-emdash/src/docs/docs-mdx.tsx +79 -0
  46. package/templates/astro-emdash/src/docs/docs-page-actions.tsx +146 -0
  47. package/templates/astro-emdash/src/docs/docs-page.tsx +70 -0
  48. package/templates/astro-emdash/src/docs/llm-text.ts +61 -0
  49. package/templates/astro-emdash/src/docs/source.ts +7 -0
  50. package/templates/astro-emdash/src/routes/docs/$.tsx +22 -0
  51. package/templates/astro-emdash/src/routes/docs/api/markdown.ts +12 -0
  52. package/templates/astro-emdash/src/routes/docs/api/search.ts +12 -0
  53. package/templates/astro-emdash/src/routes/docs.index.tsx +22 -0
  54. package/templates/astro-emdash/src/routes/docs.tsx +22 -0
  55. package/templates/astro-emdash/src/styles-docs.css +3 -0
  56. package/templates/react-router/app/components/mdx.tsx +79 -0
  57. package/templates/react-router/app/lib/layout.shared.tsx +54 -0
  58. package/templates/react-router/app/lib/source.ts +7 -0
  59. package/templates/react-router/app/routes/docs.$.tsx +49 -0
  60. package/templates/react-router/app/routes/docs.api.search.ts +10 -0
  61. package/templates/react-router/app/routes/docs.tsx +13 -0
  62. package/templates/react-router/content/docs/getting-started.mdx +8 -0
  63. package/templates/react-router/content/docs/index.mdx +8 -0
  64. package/templates/react-router/content/docs/mcp.mdx +121 -0
  65. package/templates/react-router/content/docs/meta.json +4 -0
  66. package/templates/react-router/source.config.ts +5 -0
  67. package/templates/tanstack-start/content/docs/getting-started.mdx +10 -0
  68. package/templates/tanstack-start/content/docs/index.mdx +8 -0
  69. package/templates/tanstack-start/content/docs/mcp.mdx +121 -0
  70. package/templates/tanstack-start/content/docs/meta.json +4 -0
  71. package/templates/tanstack-start/source.config.ts +10 -0
  72. package/templates/tanstack-start/src/docs/docs-assets.ts +1 -0
  73. package/templates/tanstack-start/src/docs/docs-client.tsx +22 -0
  74. package/templates/tanstack-start/src/docs/docs-data.ts +24 -0
  75. package/templates/tanstack-start/src/docs/docs-handler.tsx +105 -0
  76. package/templates/tanstack-start/src/docs/docs-layout.tsx +56 -0
  77. package/templates/tanstack-start/src/docs/docs-mdx.tsx +79 -0
  78. package/templates/tanstack-start/src/docs/docs-page-actions.tsx +146 -0
  79. package/templates/tanstack-start/src/docs/docs-page.tsx +70 -0
  80. package/templates/tanstack-start/src/docs/llm-text.ts +61 -0
  81. package/templates/tanstack-start/src/docs/source.ts +7 -0
  82. package/templates/tanstack-start/src/routes/docs/$.tsx +22 -0
  83. package/templates/tanstack-start/src/routes/docs/api/markdown.ts +12 -0
  84. package/templates/tanstack-start/src/routes/docs/api/search.ts +12 -0
  85. package/templates/tanstack-start/src/routes/docs.index.tsx +22 -0
  86. package/templates/tanstack-start/src/routes/docs.tsx +22 -0
  87. package/templates/tanstack-start/src/styles-docs.css +3 -0
  88. package/README.md +0 -3
@@ -0,0 +1,121 @@
1
+ ---
2
+ title: Connecting to this app with AI
3
+ description: Add this app's MCP server to ChatGPT, Claude, Codex CLI, Claude Code, or another AI agent.
4
+ ---
5
+
6
+ Use this page when you want an AI Agent to work with this app through its MCP server.
7
+
8
+ Server URL:
9
+
10
+ <McpServerUrlBlock />
11
+
12
+ Use the deployed HTTPS URL for ChatGPT and Claude web/desktop connectors. If you are testing from Codex CLI or Claude Code on your own machine, `http://localhost:3000/mcp` can work. For ChatGPT, Claude web, and Claude Desktop remote connectors, expose local development through a secure HTTPS tunnel or deploy first; those products connect from provider infrastructure, not from your laptop.
13
+
14
+ ## ChatGPT web
15
+
16
+ ChatGPT custom MCP apps are configured from ChatGPT web.
17
+
18
+ 1. Open ChatGPT web and go to **Settings -> Apps & Connectors** or **Settings -> Apps**, depending on the current UI.
19
+ 2. Open **Advanced settings** and turn on **Developer mode** if it is available for your account or workspace.
20
+ 3. Return to **Apps & Connectors** or **Apps** and click **Create**.
21
+ 4. Enter an app name, a short description, and the server URL above.
22
+ 5. Choose the authentication option this app uses. For OAuth, complete the authorization prompt when ChatGPT scans tools.
23
+ 6. Click **Create** after the tool scan succeeds and the expected tools appear.
24
+ 7. In a new chat, click **+** by the composer, choose **More**, select this app, and ask ChatGPT to use it.
25
+
26
+ For Business, Enterprise, or Edu workspaces, an admin or owner may need to create, enable, publish, or allow this app from **Workspace settings -> Apps** before other members can connect it.
27
+
28
+ ChatGPT may ask for confirmation before actions that change data, depending on your workspace settings and the action being requested.
29
+
30
+ ## ChatGPT desktop
31
+
32
+ Create and manage the custom MCP app in ChatGPT web first. There is no separate documented desktop creation flow for custom MCP apps. If this app appears in the desktop app's composer tools menu after web setup, select it there; otherwise use ChatGPT web for MCP conversations with this app.
33
+
34
+ ## Claude web and desktop
35
+
36
+ Claude custom connectors are remote MCP connectors. The setup is the same in Claude web and Claude Desktop, and the connection to this app comes from Anthropic's cloud. Use the deployed HTTPS URL or an internet-reachable tunnel; `localhost` is only for separate local Claude Desktop or Claude Code configuration.
37
+
38
+ For individual plans, including Free, Pro, and Max:
39
+
40
+ 1. Open **Customize -> Connectors**.
41
+ 2. Click **+**, then **Add custom connector**.
42
+ 3. Enter a name and the server URL above.
43
+ 4. Open **Advanced settings** only if this app requires a fixed OAuth Client ID or Client Secret.
44
+ 5. Click **Add**, then **Connect** and complete authentication.
45
+ 6. In a chat, click **+**, choose **Connectors**, and toggle this connector on for the conversation.
46
+
47
+ For Team or Enterprise plans:
48
+
49
+ 1. An Owner opens **Organization settings -> Connectors**.
50
+ 2. Clicks **Add**, hovers **Custom**, selects **Web**, enters the server URL, and clicks **Add**.
51
+ 3. Each member opens **Customize -> Connectors**, finds the custom connector, clicks **Connect**, and authenticates before enabling it in a conversation.
52
+
53
+ ## Codex CLI
54
+
55
+ Codex supports streamable HTTP MCP servers. Add this app:
56
+
57
+ <CodexMcpAddCommand />
58
+
59
+ For local development:
60
+
61
+ ```bash
62
+ codex mcp add this-app-local --url http://localhost:3000/mcp
63
+ ```
64
+
65
+ If the server requires OAuth, authenticate after adding it:
66
+
67
+ ```bash
68
+ codex mcp login this-app
69
+ ```
70
+
71
+ Start `codex`, then type `/mcp` at the Codex prompt to confirm the server and tools loaded. Codex CLI and the Codex IDE extension share the same MCP configuration.
72
+
73
+ ## Claude Code CLI
74
+
75
+ Claude Code's CLI supports remote HTTP MCP servers. Add this app:
76
+
77
+ <ClaudeMcpAddCommand />
78
+
79
+ For local development:
80
+
81
+ ```bash
82
+ claude mcp add --transport http this-app-local http://localhost:3000/mcp
83
+ ```
84
+
85
+ Add `--scope user` if every Claude Code project should see the server. Otherwise Claude Code stores it in the current local scope. Then start Claude Code and type `/mcp` at the Claude Code prompt; if the server needs OAuth, select it there and complete the browser authorization flow. Use `claude mcp list`, `claude mcp get this-app`, or `claude mcp remove this-app` to manage the configuration.
86
+
87
+ ## Connect from another AI agent
88
+
89
+ 1. Choose **Add MCP server** or the closest equivalent in your agent.
90
+ 2. Use **HTTP** or **Streamable HTTP** transport.
91
+ 3. Name the server after this app.
92
+ 4. Enter the server URL above.
93
+ 5. Complete the sign-in and authorization flow.
94
+ 6. Ask the agent to list available tools so you can confirm what it can access.
95
+
96
+ ## What the AI can do
97
+
98
+ Replace this section before shipping the app.
99
+
100
+ - **Read access** (`mcp:read`): describe the records, search results, summaries, or workflow context the AI can read for the signed-in member.
101
+ - **Write access** (`mcp:write`): describe the specific actions the AI can perform, such as creating records, updating statuses, or running workflow steps.
102
+ - **Tool-specific access**: note any important per-tool permissions that users may see during authorization.
103
+ - **Not available through AI**: list important boundaries, such as account management, billing, security settings, or destructive workflows that are not exposed.
104
+
105
+ The detailed tool names and input fields are discoverable by the AI client after connection, so keep this page focused on the scope of access and the workflows a person should expect.
106
+
107
+ ## Headless use: CLIs, CI, and agents without a browser
108
+
109
+ When the client cannot complete the browser sign-in above, sign in to this app yourself and register a machine credential for it:
110
+
111
+ ```bash
112
+ curl -X POST https://your-app.example/api/auth/oauth/register \
113
+ -H "content-type: application/json" -b "<your session cookie>" \
114
+ -d '{"client_name":"CI runner","grant_types":["client_credentials"],"scope":"mcp:read"}'
115
+ ```
116
+
117
+ The response includes a `client_id` and a one-time `client_secret`. Give both to the client; it requests access tokens with `grant_type=client_credentials` and HTTP Basic authentication, and the tokens act as you with only the scope you registered. Revoke the credential at any time with `DELETE /api/auth/oauth/clients/<client_id>` while signed in.
118
+
119
+ ## Disconnect access
120
+
121
+ Disconnect the app from your AI client when you no longer want it to use these tools. If this app includes a connected AI clients page or integrations settings page, revoke access there as well. Otherwise, contact the app owner to revoke the connection.
@@ -0,0 +1,4 @@
1
+ {
2
+ "title": "Docs",
3
+ "pages": ["index", "getting-started", "mcp"]
4
+ }
@@ -0,0 +1,5 @@
1
+ import { defineDocs } from "fumadocs-mdx/config";
2
+
3
+ export const docs = defineDocs({
4
+ dir: "content/docs"
5
+ });
@@ -0,0 +1,10 @@
1
+ ---
2
+ title: Getting started
3
+ description: Replace this page with the first real workflow guide.
4
+ ---
5
+
6
+ Replace this placeholder with the first workflow a real user or operator needs.
7
+
8
+ Document behavior only after it exists in the app. Avoid promising screens, APIs, permissions, or automations that have not been implemented.
9
+
10
+ Only invited people can sign in. If extra sign-in buttons are configured for this app, they still require an approved setup or invite link before a new account can be created.
@@ -0,0 +1,8 @@
1
+ ---
2
+ title: Welcome to the docs
3
+ description: Start here when replacing the placeholder documentation.
4
+ ---
5
+
6
+ Use this space for product, operator, and API documentation once those workflows exist.
7
+
8
+ Keep docs in `content/docs`, and update the page tree as the documentation grows.
@@ -0,0 +1,121 @@
1
+ ---
2
+ title: Connecting to this app with AI
3
+ description: Add this app's MCP server to ChatGPT, Claude, Codex CLI, Claude Code, or another AI agent.
4
+ ---
5
+
6
+ Use this page when you want an AI Agent to work with this app through its MCP server.
7
+
8
+ Server URL:
9
+
10
+ <McpServerUrlBlock />
11
+
12
+ Use the deployed HTTPS URL for ChatGPT and Claude web/desktop connectors. If you are testing from Codex CLI or Claude Code on your own machine, `http://localhost:3000/mcp` can work. For ChatGPT, Claude web, and Claude Desktop remote connectors, expose local development through a secure HTTPS tunnel or deploy first; those products connect from provider infrastructure, not from your laptop.
13
+
14
+ ## ChatGPT web
15
+
16
+ ChatGPT custom MCP apps are configured from ChatGPT web.
17
+
18
+ 1. Open ChatGPT web and go to **Settings -> Apps & Connectors** or **Settings -> Apps**, depending on the current UI.
19
+ 2. Open **Advanced settings** and turn on **Developer mode** if it is available for your account or workspace.
20
+ 3. Return to **Apps & Connectors** or **Apps** and click **Create**.
21
+ 4. Enter an app name, a short description, and the server URL above.
22
+ 5. Choose the authentication option this app uses. For OAuth, complete the authorization prompt when ChatGPT scans tools.
23
+ 6. Click **Create** after the tool scan succeeds and the expected tools appear.
24
+ 7. In a new chat, click **+** by the composer, choose **More**, select this app, and ask ChatGPT to use it.
25
+
26
+ For Business, Enterprise, or Edu workspaces, an admin or owner may need to create, enable, publish, or allow this app from **Workspace settings -> Apps** before other members can connect it.
27
+
28
+ ChatGPT may ask for confirmation before actions that change data, depending on your workspace settings and the action being requested.
29
+
30
+ ## ChatGPT desktop
31
+
32
+ Create and manage the custom MCP app in ChatGPT web first. There is no separate documented desktop creation flow for custom MCP apps. If this app appears in the desktop app's composer tools menu after web setup, select it there; otherwise use ChatGPT web for MCP conversations with this app.
33
+
34
+ ## Claude web and desktop
35
+
36
+ Claude custom connectors are remote MCP connectors. The setup is the same in Claude web and Claude Desktop, and the connection to this app comes from Anthropic's cloud. Use the deployed HTTPS URL or an internet-reachable tunnel; `localhost` is only for separate local Claude Desktop or Claude Code configuration.
37
+
38
+ For individual plans, including Free, Pro, and Max:
39
+
40
+ 1. Open **Customize -> Connectors**.
41
+ 2. Click **+**, then **Add custom connector**.
42
+ 3. Enter a name and the server URL above.
43
+ 4. Open **Advanced settings** only if this app requires a fixed OAuth Client ID or Client Secret.
44
+ 5. Click **Add**, then **Connect** and complete authentication.
45
+ 6. In a chat, click **+**, choose **Connectors**, and toggle this connector on for the conversation.
46
+
47
+ For Team or Enterprise plans:
48
+
49
+ 1. An Owner opens **Organization settings -> Connectors**.
50
+ 2. Clicks **Add**, hovers **Custom**, selects **Web**, enters the server URL, and clicks **Add**.
51
+ 3. Each member opens **Customize -> Connectors**, finds the custom connector, clicks **Connect**, and authenticates before enabling it in a conversation.
52
+
53
+ ## Codex CLI
54
+
55
+ Codex supports streamable HTTP MCP servers. Add this app:
56
+
57
+ <CodexMcpAddCommand />
58
+
59
+ For local development:
60
+
61
+ ```bash
62
+ codex mcp add this-app-local --url http://localhost:3000/mcp
63
+ ```
64
+
65
+ If the server requires OAuth, authenticate after adding it:
66
+
67
+ ```bash
68
+ codex mcp login this-app
69
+ ```
70
+
71
+ Start `codex`, then type `/mcp` at the Codex prompt to confirm the server and tools loaded. Codex CLI and the Codex IDE extension share the same MCP configuration.
72
+
73
+ ## Claude Code CLI
74
+
75
+ Claude Code's CLI supports remote HTTP MCP servers. Add this app:
76
+
77
+ <ClaudeMcpAddCommand />
78
+
79
+ For local development:
80
+
81
+ ```bash
82
+ claude mcp add --transport http this-app-local http://localhost:3000/mcp
83
+ ```
84
+
85
+ Add `--scope user` if every Claude Code project should see the server. Otherwise Claude Code stores it in the current local scope. Then start Claude Code and type `/mcp` at the Claude Code prompt; if the server needs OAuth, select it there and complete the browser authorization flow. Use `claude mcp list`, `claude mcp get this-app`, or `claude mcp remove this-app` to manage the configuration.
86
+
87
+ ## Connect from another AI agent
88
+
89
+ 1. Choose **Add MCP server** or the closest equivalent in your agent.
90
+ 2. Use **HTTP** or **Streamable HTTP** transport.
91
+ 3. Name the server after this app.
92
+ 4. Enter the server URL above.
93
+ 5. Complete the sign-in and authorization flow.
94
+ 6. Ask the agent to list available tools so you can confirm what it can access.
95
+
96
+ ## What the AI can do
97
+
98
+ Replace this section before shipping the app.
99
+
100
+ - **Read access** (`mcp:read`): describe the records, search results, summaries, or workflow context the AI can read for the signed-in member.
101
+ - **Write access** (`mcp:write`): describe the specific actions the AI can perform, such as creating records, updating statuses, or running workflow steps.
102
+ - **Tool-specific access**: note any important per-tool permissions that users may see during authorization.
103
+ - **Not available through AI**: list important boundaries, such as account management, billing, security settings, or destructive workflows that are not exposed.
104
+
105
+ The detailed tool names and input fields are discoverable by the AI client after connection, so keep this page focused on the scope of access and the workflows a person should expect.
106
+
107
+ ## Headless use: CLIs, CI, and agents without a browser
108
+
109
+ When the client cannot complete the browser sign-in above, sign in to this app yourself and register a machine credential for it:
110
+
111
+ ```bash
112
+ curl -X POST https://your-app.example/api/auth/oauth/register \
113
+ -H "content-type: application/json" -b "<your session cookie>" \
114
+ -d '{"client_name":"CI runner","grant_types":["client_credentials"],"scope":"mcp:read"}'
115
+ ```
116
+
117
+ The response includes a `client_id` and a one-time `client_secret`. Give both to the client; it requests access tokens with `grant_type=client_credentials` and HTTP Basic authentication, and the tokens act as you with only the scope you registered. Revoke the credential at any time with `DELETE /api/auth/oauth/clients/<client_id>` while signed in.
118
+
119
+ ## Disconnect access
120
+
121
+ Disconnect the app from your AI client when you no longer want it to use these tools. If this app includes a connected AI clients page or integrations settings page, revoke access there as well. Otherwise, contact the app owner to revoke the connection.
@@ -0,0 +1,4 @@
1
+ {
2
+ "title": "Docs",
3
+ "pages": ["index", "getting-started", "mcp"]
4
+ }
@@ -0,0 +1,10 @@
1
+ import { defineDocs } from "fumadocs-mdx/config";
2
+
3
+ export const docs = defineDocs({
4
+ dir: "content/docs",
5
+ docs: {
6
+ postprocess: {
7
+ includeProcessedMarkdown: true
8
+ }
9
+ }
10
+ });
@@ -0,0 +1 @@
1
+ export const docsClientScriptSrc = import.meta.env.DEV ? "/src/docs/docs-client.tsx" : "/assets/raybase-docs-client.js";
@@ -0,0 +1,22 @@
1
+ import "@vitejs/plugin-react/preamble";
2
+ import { StrictMode, startTransition } from "react";
3
+ import { hydrateRoot } from "react-dom/client";
4
+ import { DocsRoot, preloadDocsContent, type DocsPageData } from "./docs-page";
5
+
6
+ const root = document.getElementById("raybase-docs-root");
7
+ const dataScript = document.getElementById("raybase-docs-page-data");
8
+
9
+ if (root && dataScript?.textContent) {
10
+ const data = JSON.parse(dataScript.textContent) as DocsPageData;
11
+
12
+ startTransition(() => {
13
+ void preloadDocsContent(data).then(() => {
14
+ hydrateRoot(
15
+ root,
16
+ <StrictMode>
17
+ <DocsRoot data={data} />
18
+ </StrictMode>
19
+ );
20
+ });
21
+ });
22
+ }
@@ -0,0 +1,24 @@
1
+ import type { SerializedPageTree } from "fumadocs-core/source/client";
2
+ import type { DocsPageData } from "./docs-page";
3
+ import { preloadDocsContent } from "./docs-page";
4
+ import { source } from "./source";
5
+
6
+ export async function loadDocsPageTree(): Promise<SerializedPageTree> {
7
+ return source.serializePageTree(source.getPageTree());
8
+ }
9
+
10
+ export async function loadDocsPageData(slugs: string[]): Promise<DocsPageData | null> {
11
+ const page = source.getPage(slugs);
12
+ if (!page) return null;
13
+
14
+ const data = {
15
+ path: page.path,
16
+ url: page.url,
17
+ title: page.data.title,
18
+ description: page.data.description,
19
+ pageTree: await loadDocsPageTree()
20
+ } satisfies DocsPageData;
21
+
22
+ await preloadDocsContent(data);
23
+ return data;
24
+ }
@@ -0,0 +1,105 @@
1
+ import { createFromSource } from "fumadocs-core/search/server";
2
+ import { renderToReadableStream } from "react-dom/server";
3
+ import docsCss from "../styles-docs.css?inline";
4
+ import { docsClientScriptSrc } from "./docs-assets";
5
+ import { loadDocsPageData, loadDocsPageTree } from "./docs-data";
6
+ import { DocsRoot, type DocsPageData } from "./docs-page";
7
+ import { getDocsMarkdownResponse, getDocsSlugs } from "./llm-text";
8
+ import { source } from "./source";
9
+
10
+ const docsThemeInitScript =
11
+ "(function(){try{var t=localStorage.getItem('theme');var d=t==='dark'||((!t||t==='system')&&matchMedia('(prefers-color-scheme: dark)').matches);document.documentElement.classList.toggle('dark',d);}catch(e){}})();";
12
+
13
+ const search = createFromSource(source, {
14
+ language: "english"
15
+ });
16
+
17
+ export async function handleDocsRequest(request: Request): Promise<Response> {
18
+ const url = new URL(request.url);
19
+
20
+ if (url.pathname === "/docs/api/search") {
21
+ return search.GET(request);
22
+ }
23
+
24
+ if (url.pathname === "/docs/api/markdown") {
25
+ const response = await getDocsMarkdownResponse(url.searchParams.get("path"));
26
+ return response ?? new Response("Not found", { status: 404 });
27
+ }
28
+
29
+ if (/\.mdx?$/.test(url.pathname)) {
30
+ const response = await getDocsMarkdownResponse(url.pathname);
31
+ return response ?? new Response("Not found", { status: 404 });
32
+ }
33
+
34
+ const data = await loadDocsPageData(getDocsSlugs(url.pathname));
35
+ if (!data) {
36
+ return docsHtmlResponse(
37
+ {
38
+ path: "",
39
+ url: url.pathname,
40
+ title: "Docs page not found",
41
+ pageTree: await loadDocsPageTree()
42
+ },
43
+ "<main class=\"mx-auto flex min-h-screen max-w-3xl flex-col justify-center px-6 py-16\"><p class=\"text-sm font-medium text-fd-muted-foreground\">404</p><h1 class=\"mt-3 text-3xl font-semibold text-fd-foreground\">Docs page not found</h1><p class=\"mt-3 text-fd-muted-foreground\">The requested documentation page does not exist.</p><a class=\"mt-6 inline-flex text-sm font-medium text-fd-primary underline-offset-4 hover:underline\" href=\"/docs\">Back to docs</a></main>",
44
+ 404
45
+ );
46
+ }
47
+
48
+ return docsHtmlResponse(data, await renderDocsBody(data));
49
+ }
50
+
51
+ async function renderDocsBody(data: DocsPageData): Promise<string> {
52
+ const stream = await renderToReadableStream(<DocsRoot data={cloneDocsPageData(data)} />);
53
+ await stream.allReady;
54
+ return new Response(stream).text();
55
+ }
56
+
57
+ function cloneDocsPageData(data: DocsPageData): DocsPageData {
58
+ return JSON.parse(JSON.stringify(data)) as DocsPageData;
59
+ }
60
+
61
+ function docsHtmlResponse(data: DocsPageData, body: string, status = 200): Response {
62
+ const html = `<!doctype html>
63
+ <html lang="en">
64
+ <head>
65
+ <meta charset="utf-8" />
66
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
67
+ <title>${escapeHtml(data.title)}</title>
68
+ <script>${docsThemeInitScript}</script>
69
+ <style id="raybase-docs-styles">${docsCss}</style>
70
+ </head>
71
+ <body>
72
+ <div id="raybase-docs-root">${body}</div>
73
+ <script type="application/json" id="raybase-docs-page-data">${escapeJson(data)}</script>
74
+ <script type="module" async src="${docsClientScriptSrc}"></script>
75
+ </body>
76
+ </html>`;
77
+
78
+ return new Response(html, {
79
+ status,
80
+ headers: {
81
+ "content-type": "text/html; charset=utf-8"
82
+ }
83
+ });
84
+ }
85
+
86
+ function escapeJson(value: unknown): string {
87
+ return JSON.stringify(value).replace(/</g, "\\u003c");
88
+ }
89
+
90
+ function escapeHtml(value: string) {
91
+ return value.replace(/[&<>"']/g, (char) => {
92
+ switch (char) {
93
+ case "&":
94
+ return "&amp;";
95
+ case "<":
96
+ return "&lt;";
97
+ case ">":
98
+ return "&gt;";
99
+ case "\"":
100
+ return "&quot;";
101
+ default:
102
+ return "&#39;";
103
+ }
104
+ });
105
+ }
@@ -0,0 +1,56 @@
1
+ import type { DocsLayoutProps } from "fumadocs-ui/layouts/docs";
2
+ import type { ComponentProps } from "react";
3
+ import { ThemeSwitch } from "fumadocs-ui/layouts/shared/slots/theme-switch";
4
+ import { ArrowLeft } from "lucide-react";
5
+ import { appConfig } from "../raybase.config";
6
+
7
+ const appHomeHref = "/";
8
+
9
+ export function baseOptions(): Omit<DocsLayoutProps, "children" | "tree"> {
10
+ return {
11
+ nav: {
12
+ title: DocsNavTitle,
13
+ url: appHomeHref
14
+ },
15
+ sidebar: {
16
+ footer: <DocsSidebarFooter />
17
+ },
18
+ themeSwitch: {
19
+ enabled: false
20
+ }
21
+ };
22
+ }
23
+
24
+ function DocsNavTitle({ className, href = appHomeHref, ...props }: ComponentProps<"a">) {
25
+ return (
26
+ <div className={className}>
27
+ <div className="inline-flex min-w-0 flex-col items-start gap-0.5 leading-none">
28
+ <a
29
+ {...props}
30
+ href={href}
31
+ title={`Back to ${appConfig.appName}`}
32
+ className="max-w-44 truncate rounded-sm text-[0.9375rem] font-semibold leading-none text-fd-foreground underline-offset-4 transition-colors hover:text-fd-primary hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fd-ring"
33
+ >
34
+ {appConfig.appName}
35
+ </a>
36
+ <span className="text-[0.6875rem] font-medium leading-none text-fd-muted-foreground">Docs</span>
37
+ </div>
38
+ </div>
39
+ );
40
+ }
41
+
42
+ function DocsSidebarFooter() {
43
+ return (
44
+ <div className="mt-2 flex min-w-0 items-center justify-between gap-3 border-t pt-3">
45
+ <a
46
+ href={appHomeHref}
47
+ title={`Back to ${appConfig.appName}`}
48
+ className="inline-flex min-w-0 items-center gap-1.5 rounded-md px-1 py-1 text-xs font-medium text-fd-muted-foreground transition-colors hover:text-fd-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fd-ring"
49
+ >
50
+ <ArrowLeft className="size-3.5 shrink-0" aria-hidden="true" />
51
+ <span className="truncate">Back to app</span>
52
+ </a>
53
+ <ThemeSwitch className="shrink-0 p-0" />
54
+ </div>
55
+ );
56
+ }
@@ -0,0 +1,79 @@
1
+ import { CodeBlock, Pre } from "fumadocs-ui/components/codeblock";
2
+ import defaultMdxComponents from "fumadocs-ui/mdx";
3
+ import type { MDXComponents } from "mdx/types";
4
+
5
+ interface McpServerUrlProps {
6
+ path?: string;
7
+ }
8
+
9
+ interface ClaudeMcpAddCommandProps extends McpServerUrlProps {
10
+ name?: string;
11
+ }
12
+
13
+ interface CodexMcpAddCommandProps extends McpServerUrlProps {
14
+ name?: string;
15
+ }
16
+
17
+ function browserOrigin() {
18
+ return typeof window === "undefined" ? "" : window.location.origin;
19
+ }
20
+
21
+ function currentUrl(path = "/mcp") {
22
+ const origin = browserOrigin();
23
+ return origin ? new URL(path, origin).toString() : path;
24
+ }
25
+
26
+ function McpServerUrl(props: McpServerUrlProps) {
27
+ return <code suppressHydrationWarning>{currentUrl(props.path)}</code>;
28
+ }
29
+
30
+ function McpServerUrlBlock(props: McpServerUrlProps) {
31
+ return (
32
+ <CodeBlock>
33
+ <Pre>
34
+ <code suppressHydrationWarning>{currentUrl(props.path)}</code>
35
+ </Pre>
36
+ </CodeBlock>
37
+ );
38
+ }
39
+
40
+ function ClaudeMcpAddCommand(props: ClaudeMcpAddCommandProps) {
41
+ const command = `claude mcp add --transport http ${props.name ?? "this-app"} "${currentUrl(props.path)}"`;
42
+
43
+ return (
44
+ <CodeBlock>
45
+ <Pre>
46
+ <code suppressHydrationWarning>{command}</code>
47
+ </Pre>
48
+ </CodeBlock>
49
+ );
50
+ }
51
+
52
+ function CodexMcpAddCommand(props: CodexMcpAddCommandProps) {
53
+ const command = `codex mcp add ${props.name ?? "this-app"} --url "${currentUrl(props.path)}"`;
54
+
55
+ return (
56
+ <CodeBlock>
57
+ <Pre>
58
+ <code suppressHydrationWarning>{command}</code>
59
+ </Pre>
60
+ </CodeBlock>
61
+ );
62
+ }
63
+
64
+ export function getMDXComponents(components?: MDXComponents) {
65
+ return {
66
+ ...defaultMdxComponents,
67
+ McpServerUrl,
68
+ McpServerUrlBlock,
69
+ ClaudeMcpAddCommand,
70
+ CodexMcpAddCommand,
71
+ ...components
72
+ } satisfies MDXComponents;
73
+ }
74
+
75
+ export const useMDXComponents = getMDXComponents;
76
+
77
+ declare global {
78
+ type MDXProvidedComponents = ReturnType<typeof getMDXComponents>;
79
+ }