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