create-specra 0.1.4 → 0.1.6
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/package.json +1 -1
- package/templates/minimal/app/api/mdx-watch/route.ts +5 -79
- package/templates/minimal/app/docs/[version]/[...slug]/page.tsx +25 -45
- package/templates/minimal/app/layout.tsx +8 -41
- package/templates/minimal/app/not-found.tsx +10 -0
- package/templates/minimal/app/page.tsx +3 -9
- package/templates/minimal/next.config.mjs +1 -18
- package/templates/minimal/package-lock.json +90 -0
- package/templates/minimal/package.json +1 -1
- package/templates/minimal/{middleware.ts → proxy_.ts} +6 -7
- package/templates/minimal/yarn.lock +359 -85
- package/templates/minimal/next.config.default.mjs +0 -38
- package/templates/minimal/next.config.export.mjs +0 -64
package/package.json
CHANGED
|
@@ -1,80 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
// Next.js requires dynamic to be statically analyzable, so we can't re-export it
|
|
2
|
+
export const dynamic = 'error'
|
|
3
|
+
export const runtime = 'nodejs'
|
|
4
4
|
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
export async function GET(request: NextRequest) {
|
|
8
|
-
// Only allow in development mode
|
|
9
|
-
if (process.env.NODE_ENV !== 'development') {
|
|
10
|
-
return new Response('Not available in production', { status: 404 })
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const encoder = new TextEncoder()
|
|
14
|
-
|
|
15
|
-
const stream = new ReadableStream({
|
|
16
|
-
start(controller) {
|
|
17
|
-
// Send initial connection message
|
|
18
|
-
const connectMsg = `data: ${JSON.stringify({ type: 'connected' })}\n\n`
|
|
19
|
-
controller.enqueue(encoder.encode(connectMsg))
|
|
20
|
-
|
|
21
|
-
const docsPath = join(process.cwd(), 'docs')
|
|
22
|
-
|
|
23
|
-
// Watch the docs directory recursively
|
|
24
|
-
const watcher = watch(
|
|
25
|
-
docsPath,
|
|
26
|
-
{ recursive: true },
|
|
27
|
-
(eventType, filename) => {
|
|
28
|
-
if (!filename) return
|
|
29
|
-
|
|
30
|
-
// Only watch for .mdx and .json files (MDX files and category configs)
|
|
31
|
-
if (filename.endsWith('.mdx') || filename.endsWith('.json')) {
|
|
32
|
-
console.log(`[MDX Watch] ${eventType}: ${filename}`)
|
|
33
|
-
|
|
34
|
-
const message = `data: ${JSON.stringify({
|
|
35
|
-
type: 'change',
|
|
36
|
-
file: filename,
|
|
37
|
-
eventType
|
|
38
|
-
})}\n\n`
|
|
39
|
-
|
|
40
|
-
try {
|
|
41
|
-
controller.enqueue(encoder.encode(message))
|
|
42
|
-
} catch (error) {
|
|
43
|
-
console.error('[MDX Watch] Error sending message:', error)
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
// Handle client disconnect
|
|
50
|
-
request.signal.addEventListener('abort', () => {
|
|
51
|
-
console.log('[MDX Watch] Client disconnected')
|
|
52
|
-
watcher.close()
|
|
53
|
-
try {
|
|
54
|
-
controller.close()
|
|
55
|
-
} catch (error) {
|
|
56
|
-
// Controller might already be closed
|
|
57
|
-
}
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
// Handle errors
|
|
61
|
-
watcher.on('error', (error) => {
|
|
62
|
-
console.error('[MDX Watch] Watcher error:', error)
|
|
63
|
-
watcher.close()
|
|
64
|
-
try {
|
|
65
|
-
controller.close()
|
|
66
|
-
} catch (e) {
|
|
67
|
-
// Controller might already be closed
|
|
68
|
-
}
|
|
69
|
-
})
|
|
70
|
-
}
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
return new Response(stream, {
|
|
74
|
-
headers: {
|
|
75
|
-
'Content-Type': 'text/event-stream',
|
|
76
|
-
'Cache-Control': 'no-cache, no-transform',
|
|
77
|
-
'Connection': 'keep-alive',
|
|
78
|
-
},
|
|
79
|
-
})
|
|
80
|
-
}
|
|
5
|
+
// Re-export the GET handler from SDK
|
|
6
|
+
export { GET } from "specra/app/api/mdx-watch"
|
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
getCachedAllDocs,
|
|
9
9
|
getCachedDocBySlug,
|
|
10
10
|
getConfig,
|
|
11
|
-
SpecraConfig,
|
|
12
11
|
} from "specra/lib"
|
|
13
12
|
import {
|
|
14
13
|
DocLayout,
|
|
@@ -23,8 +22,6 @@ import {
|
|
|
23
22
|
DocLoading,
|
|
24
23
|
} from "specra/components"
|
|
25
24
|
|
|
26
|
-
import specraConfig from "./../../../../specra.config.json"
|
|
27
|
-
|
|
28
25
|
interface PageProps {
|
|
29
26
|
params: Promise<{
|
|
30
27
|
version: string
|
|
@@ -35,7 +32,6 @@ interface PageProps {
|
|
|
35
32
|
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
|
|
36
33
|
const { version, slug: slugArray } = await params
|
|
37
34
|
const slug = slugArray.join("/")
|
|
38
|
-
|
|
39
35
|
const doc = await getCachedDocBySlug(slug, version)
|
|
40
36
|
|
|
41
37
|
if (!doc) {
|
|
@@ -78,7 +74,6 @@ export async function generateStaticParams() {
|
|
|
78
74
|
for (const version of versions) {
|
|
79
75
|
const docs = await getCachedAllDocs(version)
|
|
80
76
|
for (const doc of docs) {
|
|
81
|
-
// Add the custom slug path
|
|
82
77
|
params.push({
|
|
83
78
|
version,
|
|
84
79
|
slug: doc.slug.split("/").filter(Boolean),
|
|
@@ -97,13 +92,9 @@ export default async function DocPage({ params }: PageProps) {
|
|
|
97
92
|
const versions = getCachedVersions()
|
|
98
93
|
const config = getConfig()
|
|
99
94
|
const isCategory = isCategoryPage(slug, allDocs)
|
|
100
|
-
|
|
101
|
-
// Try to get the doc (might be index.mdx or regular .mdx)
|
|
102
95
|
const doc = await getCachedDocBySlug(slug, version)
|
|
103
96
|
|
|
104
|
-
// If no doc found and it's a category, show category index
|
|
105
97
|
if (!doc && isCategory) {
|
|
106
|
-
// Find a doc in this category to get the tab group
|
|
107
98
|
const categoryDoc = allDocs.find((d) => d.slug.startsWith(slug + "/"))
|
|
108
99
|
const categoryTabGroup = categoryDoc?.meta?.tab_group || categoryDoc?.categoryTabGroup
|
|
109
100
|
|
|
@@ -113,7 +104,7 @@ export default async function DocPage({ params }: PageProps) {
|
|
|
113
104
|
header={<Header currentVersion={version} versions={versions} config={config} />}
|
|
114
105
|
docs={allDocs}
|
|
115
106
|
version={version}
|
|
116
|
-
|
|
107
|
+
children={
|
|
117
108
|
<CategoryIndex
|
|
118
109
|
categoryPath={slug}
|
|
119
110
|
version={version}
|
|
@@ -134,7 +125,6 @@ export default async function DocPage({ params }: PageProps) {
|
|
|
134
125
|
)
|
|
135
126
|
}
|
|
136
127
|
|
|
137
|
-
// If no doc found, render 404 content within the layout (keeps sidebar visible)
|
|
138
128
|
if (!doc) {
|
|
139
129
|
return (
|
|
140
130
|
<>
|
|
@@ -143,7 +133,7 @@ export default async function DocPage({ params }: PageProps) {
|
|
|
143
133
|
header={<Header currentVersion={version} versions={versions} config={config} />}
|
|
144
134
|
docs={allDocs}
|
|
145
135
|
version={version}
|
|
146
|
-
|
|
136
|
+
children={<NotFoundContent version={version} />}
|
|
147
137
|
toc={<div />}
|
|
148
138
|
config={config}
|
|
149
139
|
currentPageTabGroup={undefined}
|
|
@@ -158,15 +148,7 @@ export default async function DocPage({ params }: PageProps) {
|
|
|
158
148
|
|
|
159
149
|
const toc = extractTableOfContents(doc.content)
|
|
160
150
|
const { previous, next } = getAdjacentDocs(slug, allDocs)
|
|
161
|
-
|
|
162
|
-
// console.log("[v0] Extracted ToC:", toc)
|
|
163
|
-
|
|
164
|
-
// If doc exists but is also a category, show both content and children
|
|
165
151
|
const showCategoryIndex = isCategory && doc
|
|
166
|
-
|
|
167
|
-
// console.log("showCategoryIndex: ", showCategoryIndex)
|
|
168
|
-
|
|
169
|
-
// Get current page's tab group from doc metadata or category
|
|
170
152
|
const currentPageTabGroup = doc.meta?.tab_group || doc.categoryTabGroup
|
|
171
153
|
|
|
172
154
|
return (
|
|
@@ -176,36 +158,34 @@ export default async function DocPage({ params }: PageProps) {
|
|
|
176
158
|
header={<Header currentVersion={version} versions={versions} config={config} />}
|
|
177
159
|
docs={allDocs}
|
|
178
160
|
version={version}
|
|
179
|
-
content={
|
|
180
|
-
showCategoryIndex ? (
|
|
181
|
-
<CategoryIndex
|
|
182
|
-
categoryPath={slug}
|
|
183
|
-
version={version}
|
|
184
|
-
allDocs={allDocs}
|
|
185
|
-
title={doc.meta.title}
|
|
186
|
-
description={doc.meta.description}
|
|
187
|
-
content={doc.content}
|
|
188
|
-
config={config}
|
|
189
|
-
/>
|
|
190
|
-
) : (
|
|
191
|
-
<DocLayout
|
|
192
|
-
meta={doc.meta}
|
|
193
|
-
content={doc.content}
|
|
194
|
-
previousDoc={previous ? { title: previous.meta.title, slug: previous.slug } : undefined}
|
|
195
|
-
nextDoc={next ? { title: next.meta.title, slug: next.slug } : undefined}
|
|
196
|
-
version={version}
|
|
197
|
-
slug={slug}
|
|
198
|
-
config={config}
|
|
199
|
-
/>
|
|
200
|
-
)
|
|
201
|
-
}
|
|
202
161
|
toc={showCategoryIndex ? <div /> : <TableOfContents items={toc} config={config} />}
|
|
203
162
|
config={config}
|
|
204
163
|
currentPageTabGroup={currentPageTabGroup}
|
|
205
|
-
|
|
164
|
+
>
|
|
165
|
+
{showCategoryIndex ? (
|
|
166
|
+
<CategoryIndex
|
|
167
|
+
categoryPath={slug}
|
|
168
|
+
version={version}
|
|
169
|
+
allDocs={allDocs}
|
|
170
|
+
title={doc.meta.title}
|
|
171
|
+
description={doc.meta.description}
|
|
172
|
+
content={doc.content}
|
|
173
|
+
config={config}
|
|
174
|
+
/>
|
|
175
|
+
) : (
|
|
176
|
+
<DocLayout
|
|
177
|
+
meta={doc.meta}
|
|
178
|
+
content={doc.content}
|
|
179
|
+
previousDoc={previous ? { title: previous.meta.title, slug: previous.slug } : undefined}
|
|
180
|
+
nextDoc={next ? { title: next.meta.title, slug: next.slug } : undefined}
|
|
181
|
+
version={version}
|
|
182
|
+
slug={slug}
|
|
183
|
+
config={config}
|
|
184
|
+
/>
|
|
185
|
+
)}
|
|
186
|
+
</DocLayoutWrapper>
|
|
206
187
|
<MdxHotReload />
|
|
207
188
|
<HotReloadIndicator />
|
|
208
|
-
<DevModeBadge />
|
|
209
189
|
</Suspense>
|
|
210
190
|
</>
|
|
211
191
|
)
|
|
@@ -1,33 +1,15 @@
|
|
|
1
|
-
import "server-only"
|
|
2
|
-
|
|
3
|
-
import type React from "react"
|
|
4
1
|
import type { Metadata } from "next"
|
|
5
|
-
import { Geist
|
|
6
|
-
|
|
2
|
+
import { Geist } from "next/font/google"
|
|
7
3
|
import { getConfig, getAssetPath, SpecraConfig, initConfig } from "specra/lib"
|
|
8
|
-
import {
|
|
9
|
-
|
|
4
|
+
import { ConfigProvider, TabProvider } from "specra/components"
|
|
10
5
|
import specraConfig from "../specra.config.json"
|
|
11
6
|
import "./globals.css"
|
|
12
7
|
|
|
13
|
-
/* -----------------------------
|
|
14
|
-
Fonts
|
|
15
|
-
------------------------------ */
|
|
16
8
|
const geist = Geist({ subsets: ["latin"] })
|
|
17
|
-
const geistMono = Geist_Mono({ subsets: ["latin"] })
|
|
18
|
-
|
|
19
|
-
// const sans = Geist({ subsets: ["latin"] })
|
|
20
|
-
// const geistMono = Geist_Mono({ subsets: ["latin"] })
|
|
21
9
|
|
|
22
|
-
|
|
23
|
-
Initialize Specra config ONCE
|
|
24
|
-
(module scope, server-only)
|
|
25
|
-
------------------------------ */
|
|
10
|
+
// Initialize Specra config
|
|
26
11
|
initConfig(specraConfig as unknown as Partial<SpecraConfig>)
|
|
27
12
|
|
|
28
|
-
/* -----------------------------
|
|
29
|
-
Runtime Metadata (REQUIRED)
|
|
30
|
-
------------------------------ */
|
|
31
13
|
export async function generateMetadata(): Promise<Metadata> {
|
|
32
14
|
const config = getConfig()
|
|
33
15
|
|
|
@@ -37,13 +19,9 @@ export async function generateMetadata(): Promise<Metadata> {
|
|
|
37
19
|
template: `%s | ${config.site.title}`,
|
|
38
20
|
},
|
|
39
21
|
description: config.site.description || "Modern documentation platform",
|
|
40
|
-
metadataBase: config.site.url
|
|
41
|
-
? new URL(config.site.url)
|
|
42
|
-
: undefined,
|
|
22
|
+
metadataBase: config.site.url ? new URL(config.site.url) : undefined,
|
|
43
23
|
icons: {
|
|
44
|
-
icon: config.site.favicon
|
|
45
|
-
? [{ url: getAssetPath(config.site.favicon) }]
|
|
46
|
-
: [],
|
|
24
|
+
icon: config.site.favicon ? [{ url: getAssetPath(config.site.favicon) }] : [],
|
|
47
25
|
apple: getAssetPath("/apple-icon.png"),
|
|
48
26
|
},
|
|
49
27
|
openGraph: {
|
|
@@ -62,24 +40,13 @@ export async function generateMetadata(): Promise<Metadata> {
|
|
|
62
40
|
}
|
|
63
41
|
}
|
|
64
42
|
|
|
65
|
-
|
|
66
|
-
Root Layout
|
|
67
|
-
------------------------------ */
|
|
68
|
-
export default function RootLayout({
|
|
69
|
-
children,
|
|
70
|
-
}: {
|
|
71
|
-
children: React.ReactNode
|
|
72
|
-
}) {
|
|
43
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
73
44
|
const config = getConfig()
|
|
74
|
-
const defaultTab =
|
|
75
|
-
config.navigation?.tabGroups?.[0]?.id ?? ""
|
|
45
|
+
const defaultTab = config.navigation?.tabGroups?.[0]?.id ?? ""
|
|
76
46
|
|
|
77
47
|
return (
|
|
78
48
|
<html lang={config.site.language || "en"}>
|
|
79
|
-
<body
|
|
80
|
-
// className={`${geist.className} ${geistMono.className} antialiased`}
|
|
81
|
-
className={`font-sans antialiased`}
|
|
82
|
-
>
|
|
49
|
+
<body className={`${geist.className} font-sans antialiased`}>
|
|
83
50
|
<ConfigProvider config={config}>
|
|
84
51
|
<TabProvider defaultTab={defaultTab}>
|
|
85
52
|
{children}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Link from "next/link"
|
|
2
2
|
import { ArrowRight, BookOpen, Zap, Code, Github, Twitter, Linkedin } from "lucide-react"
|
|
3
|
-
import { getConfig
|
|
4
|
-
import { Button, SiteBanner } from "specra/components"
|
|
3
|
+
import { getConfig } from "specra/lib"
|
|
4
|
+
import { Button, SiteBanner, Logo } from "specra/components"
|
|
5
5
|
|
|
6
6
|
export default function HomePage() {
|
|
7
7
|
// Server component - can use getConfig directly
|
|
@@ -16,13 +16,7 @@ export default function HomePage() {
|
|
|
16
16
|
<header className="border-b border-border">
|
|
17
17
|
<div className="container flex h-16 items-center justify-between px-6 mx-auto">
|
|
18
18
|
<Link href="/" className="flex items-center gap-2">
|
|
19
|
-
{config.site.logo
|
|
20
|
-
<img src={getAssetPath(config.site.logo ?? "")} alt={config.site.title} className="h-8 w-auto" />
|
|
21
|
-
) : (
|
|
22
|
-
<div className="h-8 w-8 rounded-xl bg-primary flex items-center justify-center">
|
|
23
|
-
<span className="text-primary-foreground font-bold text-lg">S</span>
|
|
24
|
-
</div>
|
|
25
|
-
)}
|
|
19
|
+
<Logo logo={config.site.logo} alt={config.site.title} className="w-18 object-contain" />
|
|
26
20
|
<span className="font-semibold text-lg text-foreground">Specra</span>
|
|
27
21
|
</Link>
|
|
28
22
|
<div className="flex items-center gap-6">
|
|
@@ -1,18 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
let config;
|
|
4
|
-
let target = ""
|
|
5
|
-
|
|
6
|
-
switch (mode) {
|
|
7
|
-
case "export":
|
|
8
|
-
config = await import("./next.config.export.mjs");
|
|
9
|
-
target = "export"
|
|
10
|
-
break;
|
|
11
|
-
default:
|
|
12
|
-
config = await import("./next.config.default.mjs");
|
|
13
|
-
target = "server"
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
console.log(`Building for target: ${target}`)
|
|
17
|
-
|
|
18
|
-
export default config.default ?? config;
|
|
1
|
+
export { default } from "specra/next-config"
|
|
@@ -6408,6 +6408,96 @@
|
|
|
6408
6408
|
"type": "github",
|
|
6409
6409
|
"url": "https://github.com/sponsors/wooorm"
|
|
6410
6410
|
}
|
|
6411
|
+
},
|
|
6412
|
+
"node_modules/@next/swc-darwin-arm64": {
|
|
6413
|
+
"version": "16.1.0",
|
|
6414
|
+
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.0.tgz",
|
|
6415
|
+
"integrity": "sha512-onHq8dl8KjDb8taANQdzs3XmIqQWV3fYdslkGENuvVInFQzZnuBYYOG2HGHqqtvgmEU7xWzhgndXXxnhk4Z3fQ==",
|
|
6416
|
+
"cpu": [
|
|
6417
|
+
"arm64"
|
|
6418
|
+
],
|
|
6419
|
+
"optional": true,
|
|
6420
|
+
"os": [
|
|
6421
|
+
"darwin"
|
|
6422
|
+
],
|
|
6423
|
+
"engines": {
|
|
6424
|
+
"node": ">= 10"
|
|
6425
|
+
}
|
|
6426
|
+
},
|
|
6427
|
+
"node_modules/@next/swc-darwin-x64": {
|
|
6428
|
+
"version": "16.1.0",
|
|
6429
|
+
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.0.tgz",
|
|
6430
|
+
"integrity": "sha512-Am6VJTp8KhLuAH13tPrAoVIXzuComlZlMwGr++o2KDjWiKPe3VwpxYhgV6I4gKls2EnsIMggL4y7GdXyDdJcFA==",
|
|
6431
|
+
"cpu": [
|
|
6432
|
+
"x64"
|
|
6433
|
+
],
|
|
6434
|
+
"optional": true,
|
|
6435
|
+
"os": [
|
|
6436
|
+
"darwin"
|
|
6437
|
+
],
|
|
6438
|
+
"engines": {
|
|
6439
|
+
"node": ">= 10"
|
|
6440
|
+
}
|
|
6441
|
+
},
|
|
6442
|
+
"node_modules/@next/swc-linux-arm64-gnu": {
|
|
6443
|
+
"version": "16.1.0",
|
|
6444
|
+
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.0.tgz",
|
|
6445
|
+
"integrity": "sha512-fVicfaJT6QfghNyg8JErZ+EMNQ812IS0lmKfbmC01LF1nFBcKfcs4Q75Yy8IqnsCqH/hZwGhqzj3IGVfWV6vpA==",
|
|
6446
|
+
"cpu": [
|
|
6447
|
+
"arm64"
|
|
6448
|
+
],
|
|
6449
|
+
"optional": true,
|
|
6450
|
+
"os": [
|
|
6451
|
+
"linux"
|
|
6452
|
+
],
|
|
6453
|
+
"engines": {
|
|
6454
|
+
"node": ">= 10"
|
|
6455
|
+
}
|
|
6456
|
+
},
|
|
6457
|
+
"node_modules/@next/swc-linux-arm64-musl": {
|
|
6458
|
+
"version": "16.1.0",
|
|
6459
|
+
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.0.tgz",
|
|
6460
|
+
"integrity": "sha512-TojQnDRoX7wJWXEEwdfuJtakMDW64Q7NrxQPviUnfYJvAx5/5wcGE+1vZzQ9F17m+SdpFeeXuOr6v3jbyusYMQ==",
|
|
6461
|
+
"cpu": [
|
|
6462
|
+
"arm64"
|
|
6463
|
+
],
|
|
6464
|
+
"optional": true,
|
|
6465
|
+
"os": [
|
|
6466
|
+
"linux"
|
|
6467
|
+
],
|
|
6468
|
+
"engines": {
|
|
6469
|
+
"node": ">= 10"
|
|
6470
|
+
}
|
|
6471
|
+
},
|
|
6472
|
+
"node_modules/@next/swc-win32-arm64-msvc": {
|
|
6473
|
+
"version": "16.1.0",
|
|
6474
|
+
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.0.tgz",
|
|
6475
|
+
"integrity": "sha512-+DK/akkAvvXn5RdYN84IOmLkSy87SCmpofJPdB8vbLmf01BzntPBSYXnMvnEEv/Vcf3HYJwt24QZ/s6sWAwOMQ==",
|
|
6476
|
+
"cpu": [
|
|
6477
|
+
"arm64"
|
|
6478
|
+
],
|
|
6479
|
+
"optional": true,
|
|
6480
|
+
"os": [
|
|
6481
|
+
"win32"
|
|
6482
|
+
],
|
|
6483
|
+
"engines": {
|
|
6484
|
+
"node": ">= 10"
|
|
6485
|
+
}
|
|
6486
|
+
},
|
|
6487
|
+
"node_modules/@next/swc-win32-x64-msvc": {
|
|
6488
|
+
"version": "16.1.0",
|
|
6489
|
+
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.0.tgz",
|
|
6490
|
+
"integrity": "sha512-Tr0j94MphimCCks+1rtYPzQFK+faJuhHWCegU9S9gDlgyOk8Y3kPmO64UcjyzZAlligeBtYZ/2bEyrKq0d2wqQ==",
|
|
6491
|
+
"cpu": [
|
|
6492
|
+
"x64"
|
|
6493
|
+
],
|
|
6494
|
+
"optional": true,
|
|
6495
|
+
"os": [
|
|
6496
|
+
"win32"
|
|
6497
|
+
],
|
|
6498
|
+
"engines": {
|
|
6499
|
+
"node": ">= 10"
|
|
6500
|
+
}
|
|
6411
6501
|
}
|
|
6412
6502
|
}
|
|
6413
6503
|
}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { NextRequest } from "next/server"
|
|
1
|
+
import { createSecurityProxy } from "specra/middleware/security"
|
|
3
2
|
|
|
4
3
|
// Note: Redirects from frontmatter are handled at build time via next.config.js
|
|
5
|
-
// This
|
|
4
|
+
// This proxy handles runtime security headers, path validation, and dynamic logic
|
|
6
5
|
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
6
|
+
export const proxy = createSecurityProxy({
|
|
7
|
+
production: process.env.NODE_ENV === "production",
|
|
8
|
+
strictPathValidation: true,
|
|
9
|
+
})
|
|
11
10
|
|
|
12
11
|
export const config = {
|
|
13
12
|
matcher: [
|