doccupine 0.0.93 → 0.0.94
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/README.md +19 -0
- package/dist/index.js +25 -10
- package/dist/lib/layout.d.ts +18 -1
- package/dist/lib/layout.js +140 -119
- package/dist/lib/structures.js +11 -1
- package/dist/templates/app/api/gate/route.d.ts +1 -0
- package/dist/templates/app/api/gate/route.js +56 -0
- package/dist/templates/app/gate/page.d.ts +1 -0
- package/dist/templates/app/gate/page.js +21 -0
- package/dist/templates/app/robots.js +21 -0
- package/dist/templates/app/sitemap.js +1 -7
- package/dist/templates/components/layout/Button.d.ts +1 -1
- package/dist/templates/components/layout/Button.js +20 -4
- package/dist/templates/components/layout/SiteGate.d.ts +1 -0
- package/dist/templates/components/layout/SiteGate.js +191 -0
- package/dist/templates/env.example.d.ts +1 -1
- package/dist/templates/env.example.js +7 -0
- package/dist/templates/lib/siteGate.d.ts +1 -0
- package/dist/templates/lib/siteGate.js +59 -0
- package/dist/templates/mdx/authentication.mdx.d.ts +1 -0
- package/dist/templates/mdx/authentication.mdx.js +72 -0
- package/dist/templates/package.js +14 -14
- package/dist/templates/pnpmWorkspace.d.ts +1 -1
- package/dist/templates/pnpmWorkspace.js +5 -19
- package/dist/templates/proxy.js +64 -16
- package/package.json +4 -4
package/dist/templates/proxy.js
CHANGED
|
@@ -3,6 +3,7 @@ export const proxyTemplate = (analyticsConfig = null) => {
|
|
|
3
3
|
const posthogImport = hasPostHog
|
|
4
4
|
? `import { getPostHogServerClient } from "@/lib/posthog";\n`
|
|
5
5
|
: "";
|
|
6
|
+
const gateImport = `import { GATE_COOKIE_NAME, isGateUnlocked } from "@/lib/siteGate";\n`;
|
|
6
7
|
const posthogPageviewFn = hasPostHog
|
|
7
8
|
? `
|
|
8
9
|
const SKIP_PAGEVIEW_PATTERN = /^\\/(api|ingest|_next)\\//;
|
|
@@ -55,27 +56,30 @@ function captureServerPageview(req: NextRequest, event: NextFetchEvent) {
|
|
|
55
56
|
? ` captureServerPageview(req, event);\n`
|
|
56
57
|
: "";
|
|
57
58
|
const fnSignature = hasPostHog
|
|
58
|
-
? `export function proxy(req: NextRequest, event: NextFetchEvent)`
|
|
59
|
-
: `export function proxy(req: NextRequest)`;
|
|
59
|
+
? `export async function proxy(req: NextRequest, event: NextFetchEvent)`
|
|
60
|
+
: `export async function proxy(req: NextRequest)`;
|
|
60
61
|
const eventImport = hasPostHog ? ", NextFetchEvent" : "";
|
|
61
|
-
// Matcher scope:
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
//
|
|
62
|
+
// Matcher scope: run on every path. The middleware handles MCP key auth,
|
|
63
|
+
// the SITE_PASSWORD gate for the content APIs, PostHog pageviews, and the
|
|
64
|
+
// X-Robots-Tag backstop while password protection is active — all of which
|
|
65
|
+
// need to see page and API requests alike. When SITE_PASSWORD is unset and
|
|
66
|
+
// PostHog is off the middleware just returns NextResponse.next() without
|
|
67
|
+
// mutating the response, so doc pages remain edge-cacheable.
|
|
67
68
|
//
|
|
68
69
|
// Theme detection happens client-side via the theme-init blocking script
|
|
69
|
-
// in the root layout (sets a "dark" class on <html>). Middleware
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
const matcher =
|
|
70
|
+
// in the root layout (sets a "dark" class on <html>). Middleware never sets
|
|
71
|
+
// Vary, Accept-CH, or a theme cookie, because doing so would mark every
|
|
72
|
+
// response as dynamic and disable caching at Vercel/Cloudflare.
|
|
73
|
+
const matcher = `["/:path*"]`;
|
|
73
74
|
return `import { NextResponse } from "next/server";
|
|
74
75
|
import type { NextRequest${eventImport} } from "next/server";
|
|
75
|
-
${posthogImport}${posthogPageviewFn}
|
|
76
|
+
${gateImport}${posthogImport}${posthogPageviewFn}
|
|
76
77
|
${fnSignature} {
|
|
77
|
-
${posthogCall}
|
|
78
|
-
|
|
78
|
+
${posthogCall} const pathname = req.nextUrl.pathname;
|
|
79
|
+
const sitePassword = process.env.SITE_PASSWORD;
|
|
80
|
+
|
|
81
|
+
// API key auth for /api/mcp when DOCS_API_KEY is configured
|
|
82
|
+
if (pathname.startsWith("/api/mcp")) {
|
|
79
83
|
const apiKey = process.env.DOCS_API_KEY;
|
|
80
84
|
if (apiKey) {
|
|
81
85
|
const authHeader = req.headers.get("authorization");
|
|
@@ -89,7 +93,51 @@ ${posthogCall} // API key auth for /api/mcp when DOCS_API_KEY is configured
|
|
|
89
93
|
}
|
|
90
94
|
}
|
|
91
95
|
|
|
92
|
-
|
|
96
|
+
// SITE_PASSWORD gate. Enforced here in the middleware (not the layout) so it
|
|
97
|
+
// works even though the doc pages render statically: pages can't read the
|
|
98
|
+
// request cookie, but the middleware always can. Skip Next internals so the
|
|
99
|
+
// gate screen's own assets keep loading.
|
|
100
|
+
if (sitePassword && !pathname.startsWith("/_next")) {
|
|
101
|
+
const unlocked = await isGateUnlocked(
|
|
102
|
+
req.cookies.get(GATE_COOKIE_NAME)?.value,
|
|
103
|
+
sitePassword,
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
// Content APIs (RAG chat + search) return 401 without a valid cookie so the
|
|
107
|
+
// docs can't be scraped around the login screen. /api/mcp keeps its own key
|
|
108
|
+
// auth above; /api/gate and /api/theme stay open so the gate can unlock and
|
|
109
|
+
// the theme can toggle.
|
|
110
|
+
if (
|
|
111
|
+
!unlocked &&
|
|
112
|
+
(pathname.startsWith("/api/rag") || pathname.startsWith("/api/search"))
|
|
113
|
+
) {
|
|
114
|
+
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Locked visitors see the gate screen. Rewrite (not redirect) so the URL is
|
|
118
|
+
// preserved — after unlocking, a reload lands them back on the page they
|
|
119
|
+
// asked for. API routes are never rewritten to HTML.
|
|
120
|
+
if (!unlocked && !pathname.startsWith("/api") && pathname !== "/gate") {
|
|
121
|
+
const res = NextResponse.rewrite(new URL("/gate", req.url));
|
|
122
|
+
res.headers.set("X-Robots-Tag", "noindex, nofollow");
|
|
123
|
+
return res;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Unlocked visitors never need the gate screen.
|
|
127
|
+
if (unlocked && pathname === "/gate") {
|
|
128
|
+
return NextResponse.redirect(new URL("/", req.url));
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const res = NextResponse.next();
|
|
133
|
+
|
|
134
|
+
// While password protection is active, keep the whole site out of search
|
|
135
|
+
// indexes as a header-level backstop to robots.txt's disallow rule.
|
|
136
|
+
if (sitePassword) {
|
|
137
|
+
res.headers.set("X-Robots-Tag", "noindex, nofollow");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return res;
|
|
93
141
|
}
|
|
94
142
|
|
|
95
143
|
export const config = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "doccupine",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.94",
|
|
4
4
|
"description": "Free and open-source documentation platform. Write MDX, get a production-ready site with AI chat, built-in components, and an MCP server - in one command.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"chalk": "^5.6.2",
|
|
38
38
|
"chokidar": "^5.0.0",
|
|
39
39
|
"commander": "^15.0.0",
|
|
40
|
-
"fs-extra": "^11.3.
|
|
40
|
+
"fs-extra": "^11.3.6",
|
|
41
41
|
"gray-matter": "^4.0.3",
|
|
42
42
|
"next": "^16.2.9",
|
|
43
43
|
"prompts": "^2.4.2",
|
|
@@ -46,9 +46,9 @@
|
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@types/fs-extra": "^11.0.4",
|
|
49
|
-
"@types/node": "^
|
|
49
|
+
"@types/node": "^26.1.0",
|
|
50
50
|
"@types/prompts": "^2.4.9",
|
|
51
|
-
"prettier": "^3.
|
|
51
|
+
"prettier": "^3.9.4",
|
|
52
52
|
"typescript": "^6.0.3",
|
|
53
53
|
"vitest": "^4.1.9"
|
|
54
54
|
},
|