create-next-rkk 2.0.2 → 2.0.3
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/index.d.ts +17 -0
- package/dist/index.js +310 -132
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -4,4 +4,21 @@ export declare function validateProjectName(name: string): {
|
|
|
4
4
|
reason?: string;
|
|
5
5
|
};
|
|
6
6
|
export declare function cleanupProjectDir(projectPath: string): void;
|
|
7
|
+
/**
|
|
8
|
+
* Detect which package manager is available, preferring pnpm → yarn → npm.
|
|
9
|
+
* Returns the binary name ('pnpm' | 'yarn' | 'npm').
|
|
10
|
+
*/
|
|
11
|
+
export declare function detectPackageManager(): 'pnpm' | 'yarn' | 'npm';
|
|
12
|
+
/**
|
|
13
|
+
* Build the `create-next-app` scaffold command for a given package manager.
|
|
14
|
+
* Matches the exact defaults that `pnpm create next-app@latest --yes` uses:
|
|
15
|
+
* - TypeScript
|
|
16
|
+
* - ESLint
|
|
17
|
+
* - No Tailwind
|
|
18
|
+
* - NO --src-dir (app/ lives at project root)
|
|
19
|
+
* - App Router or Pages Router based on user choice
|
|
20
|
+
* - import alias @/*
|
|
21
|
+
* - --yes skips all interactive prompts
|
|
22
|
+
*/
|
|
23
|
+
export declare function buildCreateCommand(pm: 'pnpm' | 'yarn' | 'npm', targetDir: string, typescript: boolean, router: 'app' | 'pages'): string;
|
|
7
24
|
export declare function runCli(argv?: string[]): Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -39,6 +39,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
39
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
40
|
exports.validateProjectName = validateProjectName;
|
|
41
41
|
exports.cleanupProjectDir = cleanupProjectDir;
|
|
42
|
+
exports.detectPackageManager = detectPackageManager;
|
|
43
|
+
exports.buildCreateCommand = buildCreateCommand;
|
|
42
44
|
exports.runCli = runCli;
|
|
43
45
|
const commander_1 = require("commander");
|
|
44
46
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
@@ -69,10 +71,91 @@ function cleanupProjectDir(projectPath) {
|
|
|
69
71
|
fs.rmSync(projectPath, { recursive: true, force: true });
|
|
70
72
|
}
|
|
71
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Detect which package manager is available, preferring pnpm → yarn → npm.
|
|
76
|
+
* Returns the binary name ('pnpm' | 'yarn' | 'npm').
|
|
77
|
+
*/
|
|
78
|
+
function detectPackageManager() {
|
|
79
|
+
for (const pm of ['pnpm', 'yarn']) {
|
|
80
|
+
const result = (0, child_process_1.spawnSync)(pm, ['--version'], { encoding: 'utf8', shell: true });
|
|
81
|
+
if (result.status === 0)
|
|
82
|
+
return pm;
|
|
83
|
+
}
|
|
84
|
+
return 'npm';
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Build the `create-next-app` scaffold command for a given package manager.
|
|
88
|
+
* Matches the exact defaults that `pnpm create next-app@latest --yes` uses:
|
|
89
|
+
* - TypeScript
|
|
90
|
+
* - ESLint
|
|
91
|
+
* - No Tailwind
|
|
92
|
+
* - NO --src-dir (app/ lives at project root)
|
|
93
|
+
* - App Router or Pages Router based on user choice
|
|
94
|
+
* - import alias @/*
|
|
95
|
+
* - --yes skips all interactive prompts
|
|
96
|
+
*/
|
|
97
|
+
function buildCreateCommand(pm, targetDir, typescript, router) {
|
|
98
|
+
const tsFlag = typescript ? '--typescript' : '--js';
|
|
99
|
+
const routerFlag = router === 'app' ? '--app' : '--no-app';
|
|
100
|
+
if (pm === 'pnpm') {
|
|
101
|
+
return [
|
|
102
|
+
'pnpm',
|
|
103
|
+
'create',
|
|
104
|
+
'next-app@latest',
|
|
105
|
+
targetDir,
|
|
106
|
+
'--yes',
|
|
107
|
+
tsFlag,
|
|
108
|
+
'--eslint',
|
|
109
|
+
'--no-tailwind',
|
|
110
|
+
routerFlag,
|
|
111
|
+
'--no-src-dir',
|
|
112
|
+
'--import-alias', '@/*',
|
|
113
|
+
].join(' ');
|
|
114
|
+
}
|
|
115
|
+
if (pm === 'yarn') {
|
|
116
|
+
return [
|
|
117
|
+
'yarn',
|
|
118
|
+
'create',
|
|
119
|
+
'next-app',
|
|
120
|
+
targetDir,
|
|
121
|
+
tsFlag,
|
|
122
|
+
'--eslint',
|
|
123
|
+
'--no-tailwind',
|
|
124
|
+
routerFlag,
|
|
125
|
+
'--no-src-dir',
|
|
126
|
+
'--import-alias', '@/*',
|
|
127
|
+
'--yes',
|
|
128
|
+
].join(' ');
|
|
129
|
+
}
|
|
130
|
+
// npm / npx
|
|
131
|
+
return [
|
|
132
|
+
'npx',
|
|
133
|
+
'--yes',
|
|
134
|
+
'create-next-app@latest',
|
|
135
|
+
targetDir,
|
|
136
|
+
'--yes',
|
|
137
|
+
tsFlag,
|
|
138
|
+
'--eslint',
|
|
139
|
+
'--no-tailwind',
|
|
140
|
+
routerFlag,
|
|
141
|
+
'--no-src-dir',
|
|
142
|
+
'--import-alias', '@/*',
|
|
143
|
+
].join(' ');
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Build the install command for rkk-next.
|
|
147
|
+
*/
|
|
148
|
+
function buildInstallCommand(pm) {
|
|
149
|
+
if (pm === 'pnpm')
|
|
150
|
+
return 'pnpm add rkk-next';
|
|
151
|
+
if (pm === 'yarn')
|
|
152
|
+
return 'yarn add rkk-next';
|
|
153
|
+
return 'npm install rkk-next --legacy-peer-deps';
|
|
154
|
+
}
|
|
72
155
|
program
|
|
73
156
|
.name('create-next-rkk')
|
|
74
157
|
.description('Create a new Next.js app with rkk-next pre-configured')
|
|
75
|
-
.version('2.0.
|
|
158
|
+
.version('2.0.3')
|
|
76
159
|
.argument('[project-name]', 'name of your project')
|
|
77
160
|
.action(async (projectName) => {
|
|
78
161
|
console.log(chalk_1.default.bold.cyan('\n🚀 Create RKK Next.js App\n'));
|
|
@@ -113,63 +196,48 @@ program
|
|
|
113
196
|
console.error(chalk_1.default.red(`\nInvalid project name: ${validation.reason}\n`));
|
|
114
197
|
process.exit(1);
|
|
115
198
|
}
|
|
199
|
+
const pm = detectPackageManager();
|
|
116
200
|
const projectPath = path.join(process.cwd(), targetDir);
|
|
117
201
|
let createdProject = false;
|
|
118
202
|
let activeStep = null;
|
|
119
|
-
// Step 1: Create Next.js app
|
|
120
203
|
const spinner = (0, ora_1.default)('Creating Next.js application...').start();
|
|
121
204
|
try {
|
|
122
|
-
//
|
|
123
|
-
|
|
124
|
-
const createNextAppCmd = [
|
|
125
|
-
'npx',
|
|
126
|
-
'--yes',
|
|
127
|
-
'create-next-app@latest',
|
|
128
|
-
targetDir,
|
|
129
|
-
answers.typescript ? '--typescript' : '--js',
|
|
130
|
-
'--eslint',
|
|
131
|
-
'--no-tailwind',
|
|
132
|
-
'--src-dir',
|
|
133
|
-
answers.router === 'app' ? '--app' : '--no-app',
|
|
134
|
-
'--import-alias', '@/*',
|
|
135
|
-
'--no-git',
|
|
136
|
-
].join(' ');
|
|
205
|
+
// ── Step 1: Scaffold with create-next-app ──────────────────────────────
|
|
206
|
+
const createCmd = buildCreateCommand(pm, targetDir, answers.typescript, answers.router);
|
|
137
207
|
activeStep = 'create-app';
|
|
138
|
-
(0, child_process_1.execSync)(
|
|
208
|
+
(0, child_process_1.execSync)(createCmd, {
|
|
139
209
|
stdio: 'inherit',
|
|
140
|
-
cwd: process.cwd()
|
|
210
|
+
cwd: process.cwd(),
|
|
141
211
|
});
|
|
142
212
|
spinner.succeed('Next.js application created!');
|
|
143
213
|
createdProject = true;
|
|
144
|
-
// Verify directory exists
|
|
145
214
|
if (!fs.existsSync(projectPath)) {
|
|
146
|
-
throw new Error(`Project directory ${targetDir} was not created`);
|
|
215
|
+
throw new Error(`Project directory "${targetDir}" was not created`);
|
|
147
216
|
}
|
|
148
|
-
// Step 2: Install rkk-next
|
|
217
|
+
// ── Step 2: Install rkk-next ───────────────────────────────────────────
|
|
149
218
|
if (answers.installDeps) {
|
|
150
219
|
activeStep = 'install-rkk';
|
|
151
|
-
spinner.start(
|
|
152
|
-
(0, child_process_1.execSync)(
|
|
220
|
+
spinner.start(`Installing rkk-next (via ${pm})...`);
|
|
221
|
+
(0, child_process_1.execSync)(buildInstallCommand(pm), {
|
|
153
222
|
stdio: 'inherit',
|
|
154
|
-
cwd: projectPath
|
|
223
|
+
cwd: projectPath,
|
|
155
224
|
});
|
|
156
225
|
spinner.succeed('rkk-next installed!');
|
|
157
226
|
}
|
|
158
|
-
// Step 3:
|
|
227
|
+
// ── Step 3: Inject rkk-next into generated files ───────────────────────
|
|
159
228
|
activeStep = 'setup-templates';
|
|
160
229
|
spinner.start('Setting up rkk-next configuration...');
|
|
161
230
|
setupTemplateFiles(projectPath, answers.router, answers.typescript);
|
|
162
231
|
spinner.succeed('Configuration complete!');
|
|
163
|
-
//
|
|
232
|
+
// ── Done ───────────────────────────────────────────────────────────────
|
|
164
233
|
console.log(chalk_1.default.green.bold('\n✨ Success! Created ' + targetDir));
|
|
165
|
-
console.log(chalk_1.default.cyan('\
|
|
234
|
+
console.log(chalk_1.default.cyan('\nGet started:\n'));
|
|
166
235
|
console.log(chalk_1.default.white(' cd ' + targetDir));
|
|
167
236
|
if (!answers.installDeps) {
|
|
168
|
-
console.log(chalk_1.default.white(
|
|
237
|
+
console.log(chalk_1.default.white(` ${pm} install`));
|
|
169
238
|
}
|
|
170
|
-
console.log(chalk_1.default.white('
|
|
171
|
-
console.log(chalk_1.default.cyan('\n📚
|
|
172
|
-
console.log(chalk_1.default.white(' https://github.com/ROHIT8759/rkk-next\n'));
|
|
239
|
+
console.log(chalk_1.default.white(` ${pm === 'npm' ? 'npm run' : pm} dev`));
|
|
240
|
+
console.log(chalk_1.default.cyan('\n📚 Docs: https://github.com/ROHIT8759/rkk-next\n'));
|
|
173
241
|
console.log(chalk_1.default.yellow('Happy coding! 🎉\n'));
|
|
174
242
|
}
|
|
175
243
|
catch (error) {
|
|
@@ -189,112 +257,222 @@ program
|
|
|
189
257
|
process.exit(1);
|
|
190
258
|
}
|
|
191
259
|
});
|
|
260
|
+
/**
|
|
261
|
+
* Inject rkk-next features into the scaffolded project.
|
|
262
|
+
*
|
|
263
|
+
* Final structure (App Router, matches pnpm create next-app@latest):
|
|
264
|
+
*
|
|
265
|
+
* app/
|
|
266
|
+
* layout.tsx
|
|
267
|
+
* page.tsx
|
|
268
|
+
* globals.css (kept from scaffold)
|
|
269
|
+
* api/
|
|
270
|
+
* health/
|
|
271
|
+
* route.ts ← simple health-check
|
|
272
|
+
* hello/
|
|
273
|
+
* route.ts ← demo JSON endpoint with rkk middleware
|
|
274
|
+
* public/ (kept from scaffold)
|
|
275
|
+
* next.config.ts
|
|
276
|
+
* tsconfig.json (kept from scaffold)
|
|
277
|
+
* package.json (kept from scaffold)
|
|
278
|
+
* eslint.config.mjs (kept from scaffold)
|
|
279
|
+
* postcss.config.mjs (kept from scaffold)
|
|
280
|
+
* pnpm-lock.yaml (kept from scaffold)
|
|
281
|
+
*/
|
|
192
282
|
function setupTemplateFiles(projectDir, router, typescript) {
|
|
193
283
|
const ext = typescript ? 'tsx' : 'jsx';
|
|
194
|
-
const
|
|
284
|
+
const routeExt = typescript ? 'ts' : 'js';
|
|
195
285
|
if (router === 'pages') {
|
|
196
|
-
//
|
|
197
|
-
|
|
198
|
-
//
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
export default function
|
|
213
|
-
return
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
286
|
+
// ── Pages Router ────────────────────────────────────────────────────────
|
|
287
|
+
// Structure:
|
|
288
|
+
// pages/
|
|
289
|
+
// _app.tsx
|
|
290
|
+
// index.tsx
|
|
291
|
+
// api/
|
|
292
|
+
// health.ts
|
|
293
|
+
// hello.ts
|
|
294
|
+
const pagesDir = path.join(projectDir, 'pages');
|
|
295
|
+
const pagesApiDir = path.join(pagesDir, 'api');
|
|
296
|
+
fs.mkdirSync(pagesApiDir, { recursive: true });
|
|
297
|
+
// pages/_app.tsx
|
|
298
|
+
fs.writeFileSync(path.join(pagesDir, `_app.${ext}`), `import type { AppProps } from 'next/app';
|
|
299
|
+
import { reportWebVitals } from 'rkk-next';
|
|
300
|
+
import '../styles/globals.css';
|
|
301
|
+
|
|
302
|
+
export default function App({ Component, pageProps }: AppProps) {
|
|
303
|
+
return <Component {...pageProps} />;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export { reportWebVitals };
|
|
307
|
+
`);
|
|
308
|
+
// pages/index.tsx
|
|
309
|
+
fs.writeFileSync(path.join(pagesDir, `index.${ext}`), `import { MetaManager, SmartLink } from 'rkk-next';
|
|
310
|
+
|
|
311
|
+
export default function Home() {
|
|
312
|
+
return (
|
|
313
|
+
<>
|
|
314
|
+
<MetaManager
|
|
315
|
+
title="Home | My App"
|
|
316
|
+
description="Built with rkk-next and Next.js"
|
|
317
|
+
keywords="nextjs, seo, performance"
|
|
318
|
+
/>
|
|
319
|
+
<main style={{ padding: '2rem', maxWidth: '1200px', margin: '0 auto' }}>
|
|
320
|
+
<h1>Welcome to Your RKK Next.js App!</h1>
|
|
321
|
+
<p>Pre-configured with rkk-next for SEO, performance, and routing.</p>
|
|
322
|
+
<SmartLink href="/about">Learn More →</SmartLink>
|
|
323
|
+
</main>
|
|
324
|
+
</>
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
`);
|
|
328
|
+
// pages/api/health.ts
|
|
329
|
+
fs.writeFileSync(path.join(pagesApiDir, `health.${routeExt}`), `import type { NextApiRequest, NextApiResponse } from 'next';
|
|
330
|
+
import { composeMiddleware, cors, logger } from 'rkk-next';
|
|
331
|
+
|
|
332
|
+
function handler(_req: NextApiRequest, res: NextApiResponse) {
|
|
333
|
+
res.status(200).json({ status: 'ok', timestamp: new Date().toISOString() });
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export default composeMiddleware(
|
|
337
|
+
cors(),
|
|
338
|
+
logger()
|
|
339
|
+
)(handler);
|
|
340
|
+
`);
|
|
341
|
+
// pages/api/hello.ts
|
|
342
|
+
fs.writeFileSync(path.join(pagesApiDir, `hello.${routeExt}`), `import type { NextApiRequest, NextApiResponse } from 'next';
|
|
343
|
+
import { composeMiddleware, cors, rateLimit, logger, jsonResponse } from 'rkk-next';
|
|
344
|
+
|
|
345
|
+
function handler(req: NextApiRequest, res: NextApiResponse) {
|
|
346
|
+
jsonResponse(res, 200, { message: 'Hello from rkk-next!', method: req.method });
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export default composeMiddleware(
|
|
350
|
+
cors(),
|
|
351
|
+
rateLimit({ windowMs: 60_000, max: 60 }),
|
|
352
|
+
logger()
|
|
353
|
+
)(handler);
|
|
354
|
+
`);
|
|
235
355
|
}
|
|
236
356
|
else {
|
|
237
|
-
//
|
|
238
|
-
|
|
239
|
-
//
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
})
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
export default function
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
357
|
+
// ── App Router ──────────────────────────────────────────────────────────
|
|
358
|
+
// Structure (app/ at project root — NO src/):
|
|
359
|
+
// app/
|
|
360
|
+
// layout.tsx
|
|
361
|
+
// page.tsx
|
|
362
|
+
// globals.css (kept from scaffold)
|
|
363
|
+
// api/
|
|
364
|
+
// health/
|
|
365
|
+
// route.ts
|
|
366
|
+
// hello/
|
|
367
|
+
// route.ts
|
|
368
|
+
const appDir = path.join(projectDir, 'app');
|
|
369
|
+
const apiDir = path.join(appDir, 'api');
|
|
370
|
+
const healthDir = path.join(apiDir, 'health');
|
|
371
|
+
const helloDir = path.join(apiDir, 'hello');
|
|
372
|
+
fs.mkdirSync(healthDir, { recursive: true });
|
|
373
|
+
fs.mkdirSync(helloDir, { recursive: true });
|
|
374
|
+
// app/layout.tsx
|
|
375
|
+
fs.writeFileSync(path.join(appDir, `layout.${ext}`), `import type { Metadata } from 'next';
|
|
376
|
+
import { generateAppMetadata } from 'rkk-next';
|
|
377
|
+
import './globals.css';
|
|
378
|
+
|
|
379
|
+
export const metadata: Metadata = generateAppMetadata({
|
|
380
|
+
title: 'My RKK App',
|
|
381
|
+
description: 'Built with rkk-next and Next.js',
|
|
382
|
+
image: '/og-image.png',
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
export default function RootLayout({
|
|
386
|
+
children,
|
|
387
|
+
}: {
|
|
388
|
+
children: React.ReactNode;
|
|
389
|
+
}) {
|
|
390
|
+
return (
|
|
391
|
+
<html lang="en">
|
|
392
|
+
<body>{children}</body>
|
|
393
|
+
</html>
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
`);
|
|
397
|
+
// app/page.tsx
|
|
398
|
+
fs.writeFileSync(path.join(appDir, `page.${ext}`), `import { JsonLd } from 'rkk-next';
|
|
399
|
+
import Link from 'next/link';
|
|
400
|
+
|
|
401
|
+
export default function HomePage() {
|
|
402
|
+
return (
|
|
403
|
+
<>
|
|
404
|
+
<JsonLd
|
|
405
|
+
type="WebSite"
|
|
406
|
+
data={{
|
|
407
|
+
name: 'My RKK App',
|
|
408
|
+
url: 'https://myapp.com',
|
|
409
|
+
}}
|
|
410
|
+
/>
|
|
411
|
+
<main style={{ padding: '2rem', maxWidth: '1200px', margin: '0 auto' }}>
|
|
412
|
+
<h1>Welcome to Your RKK Next.js App!</h1>
|
|
413
|
+
<p>Pre-configured with rkk-next for SEO, performance, and routing.</p>
|
|
414
|
+
<Link href="/about">Learn More →</Link>
|
|
415
|
+
</main>
|
|
416
|
+
</>
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
`);
|
|
420
|
+
// app/api/health/route.ts — GET /api/health
|
|
421
|
+
fs.writeFileSync(path.join(healthDir, `route.${routeExt}`), `import { NextResponse } from 'next/server';
|
|
422
|
+
|
|
423
|
+
export const dynamic = 'force-dynamic';
|
|
424
|
+
|
|
425
|
+
export function GET() {
|
|
426
|
+
return NextResponse.json(
|
|
427
|
+
{ status: 'ok', timestamp: new Date().toISOString() },
|
|
428
|
+
{ status: 200 }
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
`);
|
|
432
|
+
// app/api/hello/route.ts — GET + POST /api/hello (with rkk-next middleware)
|
|
433
|
+
fs.writeFileSync(path.join(helloDir, `route.${routeExt}`), `import { NextRequest, NextResponse } from 'next/server';
|
|
434
|
+
import { cacheHeaders, SHORT_TERM_CACHE } from 'rkk-next';
|
|
435
|
+
|
|
436
|
+
export const dynamic = 'force-dynamic';
|
|
437
|
+
|
|
438
|
+
export function GET(req: NextRequest) {
|
|
439
|
+
const { searchParams } = new URL(req.url);
|
|
440
|
+
const name = searchParams.get('name') ?? 'World';
|
|
441
|
+
|
|
442
|
+
return NextResponse.json(
|
|
443
|
+
{ message: \`Hello, \${name}! Powered by rkk-next.\` },
|
|
444
|
+
{
|
|
445
|
+
status: 200,
|
|
446
|
+
headers: {
|
|
447
|
+
// Apply rkk-next short-term cache headers
|
|
448
|
+
'Cache-Control': SHORT_TERM_CACHE[0].value,
|
|
449
|
+
},
|
|
288
450
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
export async function POST(req: NextRequest) {
|
|
455
|
+
const body = await req.json().catch(() => ({}));
|
|
456
|
+
return NextResponse.json(
|
|
457
|
+
{ received: body, timestamp: new Date().toISOString() },
|
|
458
|
+
{ status: 201 }
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
`);
|
|
462
|
+
}
|
|
463
|
+
// ── next.config.ts (TypeScript, matches pnpm scaffold) ───────────────────
|
|
464
|
+
const configTsPath = path.join(projectDir, 'next.config.ts');
|
|
465
|
+
const configJsPath = path.join(projectDir, 'next.config.js');
|
|
466
|
+
fs.writeFileSync(configTsPath, `import type { NextConfig } from 'next';
|
|
467
|
+
|
|
468
|
+
const nextConfig: NextConfig = {
|
|
469
|
+
reactStrictMode: true,
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
export default nextConfig;
|
|
473
|
+
`);
|
|
474
|
+
if (fs.existsSync(configJsPath))
|
|
475
|
+
fs.unlinkSync(configJsPath);
|
|
298
476
|
}
|
|
299
477
|
async function runCli(argv = process.argv) {
|
|
300
478
|
await program.parseAsync(argv);
|