@fydemy/cms 1.0.4 → 1.0.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/README.md CHANGED
@@ -70,24 +70,7 @@ GITHUB_BRANCH=main
70
70
 
71
71
  > **Security Note**: Use strong passwords and keep `CMS_SESSION_SECRET` at least 32 characters long.
72
72
 
73
- ### 3. Update Middleware
74
-
75
- The init command will guide you to update `middleware.ts` to protect admin routes:
76
-
77
- ```typescript
78
- import { createAuthMiddleware } from "@fydemy/cms";
79
- import { NextRequest } from "next/server";
80
-
81
- export function middleware(request: NextRequest) {
82
- return createAuthMiddleware()(request);
83
- }
84
-
85
- export const config = {
86
- matcher: ["/admin/:path*"],
87
- };
88
- ```
89
-
90
- ### 4. Read Content in Your App
73
+ ### 3. Read Content in Your App
91
74
 
92
75
  ```typescript
93
76
  import { getMarkdownContent } from "@fydemy/cms";
package/dist/bin.js CHANGED
@@ -277,20 +277,48 @@ export const config = {
277
277
  );
278
278
  console.log("\u2705 Created middleware.ts");
279
279
  }
280
- const envExamplePath = import_path.default.join(process.cwd(), ".env.local.example");
281
- await import_promises.default.writeFile(
282
- envExamplePath,
283
- `CMS_ADMIN_USERNAME=admin
280
+ console.log("\n\u2699\uFE0F Configuration");
281
+ const rl = await import("readline");
282
+ const askQuestion = (query) => {
283
+ const interface_ = rl.createInterface({
284
+ input: process.stdin,
285
+ output: process.stdout
286
+ });
287
+ return new Promise((resolve) => {
288
+ interface_.question(query, (ans) => {
289
+ interface_.close();
290
+ resolve(ans);
291
+ });
292
+ });
293
+ };
294
+ const storageChoice = await askQuestion(
295
+ "Select production storage provider:\n 1. GitHub (default)\n 2. S3 / Cloudflare R2 / Vercel Blob\nEnter choice [1]: "
296
+ );
297
+ const isS3 = storageChoice.trim() === "2";
298
+ let envContent = `CMS_ADMIN_USERNAME=admin
284
299
  CMS_ADMIN_PASSWORD=password
285
300
  CMS_SESSION_SECRET=ensure_this_is_at_least_32_chars_long_random_string
286
301
 
287
- # GitHub Storage (Production)
302
+ `;
303
+ if (isS3) {
304
+ envContent += `# S3 / Cloudflare R2 / Vercel Blob Storage
305
+ STORAGE_BUCKET=my-bucket
306
+ STORAGE_ENDPOINT=https://<accountid>.r2.cloudflarestorage.com
307
+ STORAGE_ACCESS_KEY_ID=
308
+ STORAGE_SECRET_ACCESS_KEY=
309
+ STORAGE_REGION=auto
310
+ STORAGE_PUBLIC_URL=https://pub-<id>.r2.dev
311
+ `;
312
+ } else {
313
+ envContent += `# GitHub Storage (Production)
314
+ # Generate at https://github.com/settings/tokens (Needs 'repo' or 'contents:write' scope)
288
315
  GITHUB_TOKEN=
289
316
  GITHUB_REPO=owner/repo
290
317
  GITHUB_BRANCH=main
291
- `,
292
- "utf-8"
293
- );
318
+ `;
319
+ }
320
+ const envExamplePath = import_path.default.join(process.cwd(), ".env.local.example");
321
+ await import_promises.default.writeFile(envExamplePath, envContent, "utf-8");
294
322
  console.log("");
295
323
  console.log("\u{1F389} CMS initialized successfully!");
296
324
  console.log(
package/dist/bin.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/init/setup.ts","../src/bin.ts"],"sourcesContent":["import fs from \"fs/promises\";\nimport path from \"path\";\nimport { exec } from \"child_process\";\nimport { promisify } from \"util\";\n\nconst execAsync = promisify(exec);\n\nexport interface InitCMSConfig {\n /** Directory where content is stored (default: \"public/content\") */\n contentDir?: string;\n}\n\n/**\n * Initialize CMS in a Next.js project\n * Creates the content directory and an example markdown file.\n * @param config - Configuration options\n */\nexport async function initCMS(config: InitCMSConfig = {}) {\n const contentDir = config.contentDir || \"public/content\";\n const fullPath = path.join(process.cwd(), contentDir);\n const appDir = path.join(process.cwd(), \"app\");\n\n // Check if we are in a Next.js App Router project\n try {\n await fs.access(appDir);\n } catch {\n console.error(\n 'āŒ Error: \"app\" directory not found. This init script requires Next.js App Router.'\n );\n return;\n }\n\n console.log(\"šŸš€ Initializing @fydemy/cms...\");\n\n // 0. Install Dependencies\n console.log(\"šŸ“¦ Checking dependencies...\");\n try {\n const packageJsonPath = path.join(process.cwd(), \"package.json\");\n const packageJson = JSON.parse(await fs.readFile(packageJsonPath, \"utf-8\"));\n const dependencies = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n const missingDeps = [];\n if (!dependencies[\"@fydemy/cms\"]) missingDeps.push(\"@fydemy/cms\");\n if (!dependencies[\"tailwindcss\"]) missingDeps.push(\"tailwindcss\");\n\n // shadcn dependencies\n if (!dependencies[\"class-variance-authority\"])\n missingDeps.push(\"class-variance-authority\");\n if (!dependencies[\"clsx\"]) missingDeps.push(\"clsx\");\n if (!dependencies[\"tailwind-merge\"]) missingDeps.push(\"tailwind-merge\");\n if (!dependencies[\"@radix-ui/react-slot\"])\n missingDeps.push(\"@radix-ui/react-slot\");\n if (!dependencies[\"@radix-ui/react-label\"])\n missingDeps.push(\"@radix-ui/react-label\");\n\n if (missingDeps.length > 0) {\n console.log(\n `šŸ”§ Installing missing dependencies: ${missingDeps.join(\", \")}...`\n );\n // Detect package manager (default to npm if locking file not found)\n let installCmd = \"npm install\";\n try {\n await fs.access(\"pnpm-lock.yaml\");\n installCmd = \"pnpm add\";\n } catch {\n try {\n await fs.access(\"yarn.lock\");\n installCmd = \"yarn add\";\n } catch {\n // npm\n }\n }\n\n await execAsync(`${installCmd} ${missingDeps.join(\" \")}`);\n console.log(\"āœ… Dependencies installed\");\n }\n } catch (error) {\n console.warn(\n \"āš ļø Could not check/install dependencies automatically. Please ensure all dependencies are installed.\"\n );\n }\n\n // 1. Create content directory and example file\n await fs.mkdir(fullPath, { recursive: true });\n\n const exampleContent = `---\ntitle: Example Post\ndescription: This is an example markdown file\ndate: ${new Date().toISOString()}\n---\n\n# Welcome to your CMS!\n\nThis is an example markdown file. You can edit or delete it from the admin dashboard.\n\n## Features\n\n- File-based content storage\n- Markdown with frontmatter\n- GitHub integration for production\n- Simple authentication\n- No database required\n`;\n\n const examplePath = path.join(fullPath, \"example.md\");\n await fs.writeFile(examplePath, exampleContent, \"utf-8\");\n console.log(\"āœ… Created content directory and example file\");\n\n // 2. Scaffold Admin Pages (Ejected Code)\n const adminDir = path.join(appDir, \"admin\");\n const loginDir = path.join(adminDir, \"login\");\n\n await fs.mkdir(loginDir, { recursive: true });\n\n // Read template files from the dist directory (publicDir copied them there)\n const loginTemplate = await fs.readFile(\n path.join(__dirname, \"login.template.tsx\"),\n \"utf-8\"\n );\n const adminTemplate = await fs.readFile(\n path.join(__dirname, \"admin.template.tsx\"),\n \"utf-8\"\n );\n\n await fs.writeFile(path.join(adminDir, \"page.tsx\"), adminTemplate, \"utf-8\");\n\n await fs.writeFile(path.join(loginDir, \"page.tsx\"), loginTemplate, \"utf-8\");\n console.log(\"āœ… Scaffolded Admin UI (shadcn/ui components)\");\n\n // 2.5. Scaffold shadcn/ui Components and Utilities\n const componentsDir = path.join(process.cwd(), \"components\", \"ui\");\n const libDir = path.join(process.cwd(), \"lib\");\n\n await fs.mkdir(componentsDir, { recursive: true });\n await fs.mkdir(libDir, { recursive: true });\n\n // Copy utils.ts\n const utilsTemplate = await fs.readFile(\n path.join(__dirname, \"lib\", \"utils.ts\"),\n \"utf-8\"\n );\n await fs.writeFile(path.join(libDir, \"utils.ts\"), utilsTemplate, \"utf-8\");\n\n // Copy shadcn components\n const componentFiles = [\n \"button.tsx\",\n \"input.tsx\",\n \"card.tsx\",\n \"label.tsx\",\n \"textarea.tsx\",\n \"badge.tsx\",\n ];\n\n for (const componentFile of componentFiles) {\n const componentTemplate = await fs.readFile(\n path.join(__dirname, \"components\", \"ui\", componentFile),\n \"utf-8\"\n );\n await fs.writeFile(\n path.join(componentsDir, componentFile),\n componentTemplate,\n \"utf-8\"\n );\n }\n\n // Copy components.json\n const componentsJsonTemplate = await fs.readFile(\n path.join(__dirname, \"components.json\"),\n \"utf-8\"\n );\n await fs.writeFile(\n path.join(process.cwd(), \"components.json\"),\n componentsJsonTemplate,\n \"utf-8\"\n );\n\n console.log(\"āœ… Scaffolded shadcn/ui components\");\n\n // 3. Scaffold API Routes\n const apiCmsDir = path.join(appDir, \"api\", \"cms\");\n\n // Login\n await fs.mkdir(path.join(apiCmsDir, \"login\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"login\", \"route.ts\"),\n `import { handleLogin } from '@fydemy/cms';\\nexport { handleLogin as POST };\\n`,\n \"utf-8\"\n );\n\n // Logout\n await fs.mkdir(path.join(apiCmsDir, \"logout\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"logout\", \"route.ts\"),\n `import { handleLogout } from '@fydemy/cms';\\nexport { handleLogout as POST };\\n`,\n \"utf-8\"\n );\n\n // Upload\n await fs.mkdir(path.join(apiCmsDir, \"upload\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"upload\", \"route.ts\"),\n `import { handleUpload } from '@fydemy/cms';\\nexport { handleUpload as POST };\\n`,\n \"utf-8\"\n );\n\n // List\n await fs.mkdir(path.join(apiCmsDir, \"list\", \"[[...path]]\"), {\n recursive: true,\n });\n await fs.writeFile(\n path.join(apiCmsDir, \"list\", \"[[...path]]\", \"route.ts\"),\n `import { createListApiHandlers } from '@fydemy/cms';\nimport { NextRequest } from 'next/server';\n\nconst handlers = createListApiHandlers();\n\nexport async function GET(\n request: NextRequest,\n context: { params: Promise<{ path?: string[] }> }\n) {\n const params = await context.params;\n return handlers.GET(request, { params });\n}\n`,\n \"utf-8\"\n );\n\n // Content\n await fs.mkdir(path.join(apiCmsDir, \"content\", \"[...path]\"), {\n recursive: true,\n });\n await fs.writeFile(\n path.join(apiCmsDir, \"content\", \"[...path]\", \"route.ts\"),\n `import { createContentApiHandlers } from '@fydemy/cms';\nimport { NextRequest } from 'next/server';\n\nconst handlers = createContentApiHandlers();\n\nexport async function GET(\n request: NextRequest,\n context: { params: Promise<{ path: string[] }> }\n) {\n const params = await context.params;\n return handlers.GET(request, { params });\n}\n\nexport async function POST(\n request: NextRequest,\n context: { params: Promise<{ path: string[] }> }\n) {\n const params = await context.params;\n return handlers.POST(request, { params });\n}\n\nexport async function DELETE(\n request: NextRequest,\n context: { params: Promise<{ path: string[] }> }\n) {\n const params = await context.params;\n return handlers.DELETE(request, { params });\n}\n`,\n \"utf-8\"\n );\n console.log(\"āœ… Created API routes\");\n\n // 4. Middleware\n const middlewarePath = path.join(process.cwd(), \"middleware.ts\");\n try {\n await fs.access(middlewarePath);\n console.log(\n \"āš ļø middleware.ts already exists. Please manually add the CMS auth middleware:\"\n );\n console.log(`\nimport { createAuthMiddleware } from '@fydemy/cms';\n// ... existing imports\n\nexport function middleware(request: NextRequest) {\n // Add this:\n const authResponse = createAuthMiddleware()(request);\n if (authResponse) return authResponse;\n \n // ... existing middleware logic\n}\n`);\n } catch {\n await fs.writeFile(\n middlewarePath,\n `import { createAuthMiddleware } from '@fydemy/cms';\\nimport { NextRequest } from 'next/server';\\n\\nexport function middleware(request: NextRequest) {\\n return createAuthMiddleware()(request);\\n}\\n\\nexport const config = {\\n matcher: ['/admin/:path*'],\\n runtime: 'nodejs',\\n};\\n`,\n \"utf-8\"\n );\n console.log(\"āœ… Created middleware.ts\");\n }\n\n // 5. Env example\n const envExamplePath = path.join(process.cwd(), \".env.local.example\");\n await fs.writeFile(\n envExamplePath,\n `CMS_ADMIN_USERNAME=admin\\nCMS_ADMIN_PASSWORD=password\\nCMS_SESSION_SECRET=ensure_this_is_at_least_32_chars_long_random_string\\n\\n# GitHub Storage (Production)\\nGITHUB_TOKEN=\\nGITHUB_REPO=owner/repo\\nGITHUB_BRANCH=main\\n`,\n \"utf-8\"\n );\n\n console.log(\"\");\n console.log(\"šŸŽ‰ CMS initialized successfully!\");\n console.log(\n \"1. Copy .env.local.example to .env.local and set your credentials\"\n );\n console.log(\"2. Run your dev server and visit /admin\");\n}\n","#!/usr/bin/env node\n\nimport { initCMS } from \"./init/setup\";\n\ninitCMS().catch((err: unknown) => {\n console.error(\"Error initializing CMS:\", err);\n process.exit(1);\n});\n"],"mappings":"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","names":["path","fs"]}
1
+ {"version":3,"sources":["../src/init/setup.ts","../src/bin.ts"],"sourcesContent":["import fs from \"fs/promises\";\nimport path from \"path\";\nimport { exec } from \"child_process\";\nimport { promisify } from \"util\";\n\nconst execAsync = promisify(exec);\n\nexport interface InitCMSConfig {\n /** Directory where content is stored (default: \"public/content\") */\n contentDir?: string;\n}\n\n/**\n * Initialize CMS in a Next.js project\n * Creates the content directory and an example markdown file.\n * @param config - Configuration options\n */\nexport async function initCMS(config: InitCMSConfig = {}) {\n const contentDir = config.contentDir || \"public/content\";\n const fullPath = path.join(process.cwd(), contentDir);\n const appDir = path.join(process.cwd(), \"app\");\n\n // Check if we are in a Next.js App Router project\n try {\n await fs.access(appDir);\n } catch {\n console.error(\n 'āŒ Error: \"app\" directory not found. This init script requires Next.js App Router.'\n );\n return;\n }\n\n console.log(\"šŸš€ Initializing @fydemy/cms...\");\n\n // 0. Install Dependencies\n console.log(\"šŸ“¦ Checking dependencies...\");\n try {\n const packageJsonPath = path.join(process.cwd(), \"package.json\");\n const packageJson = JSON.parse(await fs.readFile(packageJsonPath, \"utf-8\"));\n const dependencies = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n const missingDeps = [];\n if (!dependencies[\"@fydemy/cms\"]) missingDeps.push(\"@fydemy/cms\");\n if (!dependencies[\"tailwindcss\"]) missingDeps.push(\"tailwindcss\");\n\n // shadcn dependencies\n if (!dependencies[\"class-variance-authority\"])\n missingDeps.push(\"class-variance-authority\");\n if (!dependencies[\"clsx\"]) missingDeps.push(\"clsx\");\n if (!dependencies[\"tailwind-merge\"]) missingDeps.push(\"tailwind-merge\");\n if (!dependencies[\"@radix-ui/react-slot\"])\n missingDeps.push(\"@radix-ui/react-slot\");\n if (!dependencies[\"@radix-ui/react-label\"])\n missingDeps.push(\"@radix-ui/react-label\");\n\n if (missingDeps.length > 0) {\n console.log(\n `šŸ”§ Installing missing dependencies: ${missingDeps.join(\", \")}...`\n );\n // Detect package manager (default to npm if locking file not found)\n let installCmd = \"npm install\";\n try {\n await fs.access(\"pnpm-lock.yaml\");\n installCmd = \"pnpm add\";\n } catch {\n try {\n await fs.access(\"yarn.lock\");\n installCmd = \"yarn add\";\n } catch {\n // npm\n }\n }\n\n await execAsync(`${installCmd} ${missingDeps.join(\" \")}`);\n console.log(\"āœ… Dependencies installed\");\n }\n } catch (error) {\n console.warn(\n \"āš ļø Could not check/install dependencies automatically. Please ensure all dependencies are installed.\"\n );\n }\n\n // 1. Create content directory and example file\n await fs.mkdir(fullPath, { recursive: true });\n\n const exampleContent = `---\ntitle: Example Post\ndescription: This is an example markdown file\ndate: ${new Date().toISOString()}\n---\n\n# Welcome to your CMS!\n\nThis is an example markdown file. You can edit or delete it from the admin dashboard.\n\n## Features\n\n- File-based content storage\n- Markdown with frontmatter\n- GitHub integration for production\n- Simple authentication\n- No database required\n`;\n\n const examplePath = path.join(fullPath, \"example.md\");\n await fs.writeFile(examplePath, exampleContent, \"utf-8\");\n console.log(\"āœ… Created content directory and example file\");\n\n // 2. Scaffold Admin Pages (Ejected Code)\n const adminDir = path.join(appDir, \"admin\");\n const loginDir = path.join(adminDir, \"login\");\n\n await fs.mkdir(loginDir, { recursive: true });\n\n // Read template files from the dist directory (publicDir copied them there)\n const loginTemplate = await fs.readFile(\n path.join(__dirname, \"login.template.tsx\"),\n \"utf-8\"\n );\n const adminTemplate = await fs.readFile(\n path.join(__dirname, \"admin.template.tsx\"),\n \"utf-8\"\n );\n\n await fs.writeFile(path.join(adminDir, \"page.tsx\"), adminTemplate, \"utf-8\");\n\n await fs.writeFile(path.join(loginDir, \"page.tsx\"), loginTemplate, \"utf-8\");\n console.log(\"āœ… Scaffolded Admin UI (shadcn/ui components)\");\n\n // 2.5. Scaffold shadcn/ui Components and Utilities\n const componentsDir = path.join(process.cwd(), \"components\", \"ui\");\n const libDir = path.join(process.cwd(), \"lib\");\n\n await fs.mkdir(componentsDir, { recursive: true });\n await fs.mkdir(libDir, { recursive: true });\n\n // Copy utils.ts\n const utilsTemplate = await fs.readFile(\n path.join(__dirname, \"lib\", \"utils.ts\"),\n \"utf-8\"\n );\n await fs.writeFile(path.join(libDir, \"utils.ts\"), utilsTemplate, \"utf-8\");\n\n // Copy shadcn components\n const componentFiles = [\n \"button.tsx\",\n \"input.tsx\",\n \"card.tsx\",\n \"label.tsx\",\n \"textarea.tsx\",\n \"badge.tsx\",\n ];\n\n for (const componentFile of componentFiles) {\n const componentTemplate = await fs.readFile(\n path.join(__dirname, \"components\", \"ui\", componentFile),\n \"utf-8\"\n );\n await fs.writeFile(\n path.join(componentsDir, componentFile),\n componentTemplate,\n \"utf-8\"\n );\n }\n\n // Copy components.json\n const componentsJsonTemplate = await fs.readFile(\n path.join(__dirname, \"components.json\"),\n \"utf-8\"\n );\n await fs.writeFile(\n path.join(process.cwd(), \"components.json\"),\n componentsJsonTemplate,\n \"utf-8\"\n );\n\n console.log(\"āœ… Scaffolded shadcn/ui components\");\n\n // 3. Scaffold API Routes\n const apiCmsDir = path.join(appDir, \"api\", \"cms\");\n\n // Login\n await fs.mkdir(path.join(apiCmsDir, \"login\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"login\", \"route.ts\"),\n `import { handleLogin } from '@fydemy/cms';\\nexport { handleLogin as POST };\\n`,\n \"utf-8\"\n );\n\n // Logout\n await fs.mkdir(path.join(apiCmsDir, \"logout\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"logout\", \"route.ts\"),\n `import { handleLogout } from '@fydemy/cms';\\nexport { handleLogout as POST };\\n`,\n \"utf-8\"\n );\n\n // Upload\n await fs.mkdir(path.join(apiCmsDir, \"upload\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"upload\", \"route.ts\"),\n `import { handleUpload } from '@fydemy/cms';\\nexport { handleUpload as POST };\\n`,\n \"utf-8\"\n );\n\n // List\n await fs.mkdir(path.join(apiCmsDir, \"list\", \"[[...path]]\"), {\n recursive: true,\n });\n await fs.writeFile(\n path.join(apiCmsDir, \"list\", \"[[...path]]\", \"route.ts\"),\n `import { createListApiHandlers } from '@fydemy/cms';\nimport { NextRequest } from 'next/server';\n\nconst handlers = createListApiHandlers();\n\nexport async function GET(\n request: NextRequest,\n context: { params: Promise<{ path?: string[] }> }\n) {\n const params = await context.params;\n return handlers.GET(request, { params });\n}\n`,\n \"utf-8\"\n );\n\n // Content\n await fs.mkdir(path.join(apiCmsDir, \"content\", \"[...path]\"), {\n recursive: true,\n });\n await fs.writeFile(\n path.join(apiCmsDir, \"content\", \"[...path]\", \"route.ts\"),\n `import { createContentApiHandlers } from '@fydemy/cms';\nimport { NextRequest } from 'next/server';\n\nconst handlers = createContentApiHandlers();\n\nexport async function GET(\n request: NextRequest,\n context: { params: Promise<{ path: string[] }> }\n) {\n const params = await context.params;\n return handlers.GET(request, { params });\n}\n\nexport async function POST(\n request: NextRequest,\n context: { params: Promise<{ path: string[] }> }\n) {\n const params = await context.params;\n return handlers.POST(request, { params });\n}\n\nexport async function DELETE(\n request: NextRequest,\n context: { params: Promise<{ path: string[] }> }\n) {\n const params = await context.params;\n return handlers.DELETE(request, { params });\n}\n`,\n \"utf-8\"\n );\n console.log(\"āœ… Created API routes\");\n\n // 4. Middleware\n const middlewarePath = path.join(process.cwd(), \"middleware.ts\");\n try {\n await fs.access(middlewarePath);\n console.log(\n \"āš ļø middleware.ts already exists. Please manually add the CMS auth middleware:\"\n );\n console.log(`\nimport { createAuthMiddleware } from '@fydemy/cms';\n// ... existing imports\n\nexport function middleware(request: NextRequest) {\n // Add this:\n const authResponse = createAuthMiddleware()(request);\n if (authResponse) return authResponse;\n \n // ... existing middleware logic\n}\n`);\n } catch {\n await fs.writeFile(\n middlewarePath,\n `import { createAuthMiddleware } from '@fydemy/cms';\\nimport { NextRequest } from 'next/server';\\n\\nexport function middleware(request: NextRequest) {\\n return createAuthMiddleware()(request);\\n}\\n\\nexport const config = {\\n matcher: ['/admin/:path*'],\\n runtime: 'nodejs',\\n};\\n`,\n \"utf-8\"\n );\n console.log(\"āœ… Created middleware.ts\");\n }\n\n // 5. Env example & Storage Selection\n console.log(\"\\nāš™ļø Configuration\");\n\n // Interactive storage selection\n const rl = await import(\"readline\");\n const askQuestion = (query: string): Promise<string> => {\n const interface_ = rl.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n return new Promise((resolve) => {\n interface_.question(query, (ans) => {\n interface_.close();\n resolve(ans);\n });\n });\n };\n\n const storageChoice = await askQuestion(\n \"Select production storage provider:\\n 1. GitHub (default)\\n 2. S3 / Cloudflare R2 / Vercel Blob\\nEnter choice [1]: \"\n );\n\n const isS3 = storageChoice.trim() === \"2\";\n\n let envContent = `CMS_ADMIN_USERNAME=admin\nCMS_ADMIN_PASSWORD=password\nCMS_SESSION_SECRET=ensure_this_is_at_least_32_chars_long_random_string\n\n`;\n\n if (isS3) {\n envContent += `# S3 / Cloudflare R2 / Vercel Blob Storage\nSTORAGE_BUCKET=my-bucket\nSTORAGE_ENDPOINT=https://<accountid>.r2.cloudflarestorage.com\nSTORAGE_ACCESS_KEY_ID=\nSTORAGE_SECRET_ACCESS_KEY=\nSTORAGE_REGION=auto\nSTORAGE_PUBLIC_URL=https://pub-<id>.r2.dev\n`;\n } else {\n envContent += `# GitHub Storage (Production)\n# Generate at https://github.com/settings/tokens (Needs 'repo' or 'contents:write' scope)\nGITHUB_TOKEN=\nGITHUB_REPO=owner/repo\nGITHUB_BRANCH=main\n`;\n }\n\n const envExamplePath = path.join(process.cwd(), \".env.local.example\");\n await fs.writeFile(envExamplePath, envContent, \"utf-8\");\n\n console.log(\"\");\n console.log(\"šŸŽ‰ CMS initialized successfully!\");\n console.log(\n \"1. Copy .env.local.example to .env.local and set your credentials\"\n );\n console.log(\"2. Run your dev server and visit /admin\");\n}\n","#!/usr/bin/env node\n\nimport { initCMS } from \"./init/setup\";\n\ninitCMS().catch((err: unknown) => {\n console.error(\"Error initializing CMS:\", err);\n process.exit(1);\n});\n"],"mappings":"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","names":["path","fs"]}
package/dist/bin.mjs CHANGED
@@ -254,20 +254,48 @@ export const config = {
254
254
  );
255
255
  console.log("\u2705 Created middleware.ts");
256
256
  }
257
- const envExamplePath = path.join(process.cwd(), ".env.local.example");
258
- await fs.writeFile(
259
- envExamplePath,
260
- `CMS_ADMIN_USERNAME=admin
257
+ console.log("\n\u2699\uFE0F Configuration");
258
+ const rl = await import("readline");
259
+ const askQuestion = (query) => {
260
+ const interface_ = rl.createInterface({
261
+ input: process.stdin,
262
+ output: process.stdout
263
+ });
264
+ return new Promise((resolve) => {
265
+ interface_.question(query, (ans) => {
266
+ interface_.close();
267
+ resolve(ans);
268
+ });
269
+ });
270
+ };
271
+ const storageChoice = await askQuestion(
272
+ "Select production storage provider:\n 1. GitHub (default)\n 2. S3 / Cloudflare R2 / Vercel Blob\nEnter choice [1]: "
273
+ );
274
+ const isS3 = storageChoice.trim() === "2";
275
+ let envContent = `CMS_ADMIN_USERNAME=admin
261
276
  CMS_ADMIN_PASSWORD=password
262
277
  CMS_SESSION_SECRET=ensure_this_is_at_least_32_chars_long_random_string
263
278
 
264
- # GitHub Storage (Production)
279
+ `;
280
+ if (isS3) {
281
+ envContent += `# S3 / Cloudflare R2 / Vercel Blob Storage
282
+ STORAGE_BUCKET=my-bucket
283
+ STORAGE_ENDPOINT=https://<accountid>.r2.cloudflarestorage.com
284
+ STORAGE_ACCESS_KEY_ID=
285
+ STORAGE_SECRET_ACCESS_KEY=
286
+ STORAGE_REGION=auto
287
+ STORAGE_PUBLIC_URL=https://pub-<id>.r2.dev
288
+ `;
289
+ } else {
290
+ envContent += `# GitHub Storage (Production)
291
+ # Generate at https://github.com/settings/tokens (Needs 'repo' or 'contents:write' scope)
265
292
  GITHUB_TOKEN=
266
293
  GITHUB_REPO=owner/repo
267
294
  GITHUB_BRANCH=main
268
- `,
269
- "utf-8"
270
- );
295
+ `;
296
+ }
297
+ const envExamplePath = path.join(process.cwd(), ".env.local.example");
298
+ await fs.writeFile(envExamplePath, envContent, "utf-8");
271
299
  console.log("");
272
300
  console.log("\u{1F389} CMS initialized successfully!");
273
301
  console.log(
package/dist/bin.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/init/setup.ts","../src/bin.ts"],"sourcesContent":["import fs from \"fs/promises\";\nimport path from \"path\";\nimport { exec } from \"child_process\";\nimport { promisify } from \"util\";\n\nconst execAsync = promisify(exec);\n\nexport interface InitCMSConfig {\n /** Directory where content is stored (default: \"public/content\") */\n contentDir?: string;\n}\n\n/**\n * Initialize CMS in a Next.js project\n * Creates the content directory and an example markdown file.\n * @param config - Configuration options\n */\nexport async function initCMS(config: InitCMSConfig = {}) {\n const contentDir = config.contentDir || \"public/content\";\n const fullPath = path.join(process.cwd(), contentDir);\n const appDir = path.join(process.cwd(), \"app\");\n\n // Check if we are in a Next.js App Router project\n try {\n await fs.access(appDir);\n } catch {\n console.error(\n 'āŒ Error: \"app\" directory not found. This init script requires Next.js App Router.'\n );\n return;\n }\n\n console.log(\"šŸš€ Initializing @fydemy/cms...\");\n\n // 0. Install Dependencies\n console.log(\"šŸ“¦ Checking dependencies...\");\n try {\n const packageJsonPath = path.join(process.cwd(), \"package.json\");\n const packageJson = JSON.parse(await fs.readFile(packageJsonPath, \"utf-8\"));\n const dependencies = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n const missingDeps = [];\n if (!dependencies[\"@fydemy/cms\"]) missingDeps.push(\"@fydemy/cms\");\n if (!dependencies[\"tailwindcss\"]) missingDeps.push(\"tailwindcss\");\n\n // shadcn dependencies\n if (!dependencies[\"class-variance-authority\"])\n missingDeps.push(\"class-variance-authority\");\n if (!dependencies[\"clsx\"]) missingDeps.push(\"clsx\");\n if (!dependencies[\"tailwind-merge\"]) missingDeps.push(\"tailwind-merge\");\n if (!dependencies[\"@radix-ui/react-slot\"])\n missingDeps.push(\"@radix-ui/react-slot\");\n if (!dependencies[\"@radix-ui/react-label\"])\n missingDeps.push(\"@radix-ui/react-label\");\n\n if (missingDeps.length > 0) {\n console.log(\n `šŸ”§ Installing missing dependencies: ${missingDeps.join(\", \")}...`\n );\n // Detect package manager (default to npm if locking file not found)\n let installCmd = \"npm install\";\n try {\n await fs.access(\"pnpm-lock.yaml\");\n installCmd = \"pnpm add\";\n } catch {\n try {\n await fs.access(\"yarn.lock\");\n installCmd = \"yarn add\";\n } catch {\n // npm\n }\n }\n\n await execAsync(`${installCmd} ${missingDeps.join(\" \")}`);\n console.log(\"āœ… Dependencies installed\");\n }\n } catch (error) {\n console.warn(\n \"āš ļø Could not check/install dependencies automatically. Please ensure all dependencies are installed.\"\n );\n }\n\n // 1. Create content directory and example file\n await fs.mkdir(fullPath, { recursive: true });\n\n const exampleContent = `---\ntitle: Example Post\ndescription: This is an example markdown file\ndate: ${new Date().toISOString()}\n---\n\n# Welcome to your CMS!\n\nThis is an example markdown file. You can edit or delete it from the admin dashboard.\n\n## Features\n\n- File-based content storage\n- Markdown with frontmatter\n- GitHub integration for production\n- Simple authentication\n- No database required\n`;\n\n const examplePath = path.join(fullPath, \"example.md\");\n await fs.writeFile(examplePath, exampleContent, \"utf-8\");\n console.log(\"āœ… Created content directory and example file\");\n\n // 2. Scaffold Admin Pages (Ejected Code)\n const adminDir = path.join(appDir, \"admin\");\n const loginDir = path.join(adminDir, \"login\");\n\n await fs.mkdir(loginDir, { recursive: true });\n\n // Read template files from the dist directory (publicDir copied them there)\n const loginTemplate = await fs.readFile(\n path.join(__dirname, \"login.template.tsx\"),\n \"utf-8\"\n );\n const adminTemplate = await fs.readFile(\n path.join(__dirname, \"admin.template.tsx\"),\n \"utf-8\"\n );\n\n await fs.writeFile(path.join(adminDir, \"page.tsx\"), adminTemplate, \"utf-8\");\n\n await fs.writeFile(path.join(loginDir, \"page.tsx\"), loginTemplate, \"utf-8\");\n console.log(\"āœ… Scaffolded Admin UI (shadcn/ui components)\");\n\n // 2.5. Scaffold shadcn/ui Components and Utilities\n const componentsDir = path.join(process.cwd(), \"components\", \"ui\");\n const libDir = path.join(process.cwd(), \"lib\");\n\n await fs.mkdir(componentsDir, { recursive: true });\n await fs.mkdir(libDir, { recursive: true });\n\n // Copy utils.ts\n const utilsTemplate = await fs.readFile(\n path.join(__dirname, \"lib\", \"utils.ts\"),\n \"utf-8\"\n );\n await fs.writeFile(path.join(libDir, \"utils.ts\"), utilsTemplate, \"utf-8\");\n\n // Copy shadcn components\n const componentFiles = [\n \"button.tsx\",\n \"input.tsx\",\n \"card.tsx\",\n \"label.tsx\",\n \"textarea.tsx\",\n \"badge.tsx\",\n ];\n\n for (const componentFile of componentFiles) {\n const componentTemplate = await fs.readFile(\n path.join(__dirname, \"components\", \"ui\", componentFile),\n \"utf-8\"\n );\n await fs.writeFile(\n path.join(componentsDir, componentFile),\n componentTemplate,\n \"utf-8\"\n );\n }\n\n // Copy components.json\n const componentsJsonTemplate = await fs.readFile(\n path.join(__dirname, \"components.json\"),\n \"utf-8\"\n );\n await fs.writeFile(\n path.join(process.cwd(), \"components.json\"),\n componentsJsonTemplate,\n \"utf-8\"\n );\n\n console.log(\"āœ… Scaffolded shadcn/ui components\");\n\n // 3. Scaffold API Routes\n const apiCmsDir = path.join(appDir, \"api\", \"cms\");\n\n // Login\n await fs.mkdir(path.join(apiCmsDir, \"login\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"login\", \"route.ts\"),\n `import { handleLogin } from '@fydemy/cms';\\nexport { handleLogin as POST };\\n`,\n \"utf-8\"\n );\n\n // Logout\n await fs.mkdir(path.join(apiCmsDir, \"logout\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"logout\", \"route.ts\"),\n `import { handleLogout } from '@fydemy/cms';\\nexport { handleLogout as POST };\\n`,\n \"utf-8\"\n );\n\n // Upload\n await fs.mkdir(path.join(apiCmsDir, \"upload\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"upload\", \"route.ts\"),\n `import { handleUpload } from '@fydemy/cms';\\nexport { handleUpload as POST };\\n`,\n \"utf-8\"\n );\n\n // List\n await fs.mkdir(path.join(apiCmsDir, \"list\", \"[[...path]]\"), {\n recursive: true,\n });\n await fs.writeFile(\n path.join(apiCmsDir, \"list\", \"[[...path]]\", \"route.ts\"),\n `import { createListApiHandlers } from '@fydemy/cms';\nimport { NextRequest } from 'next/server';\n\nconst handlers = createListApiHandlers();\n\nexport async function GET(\n request: NextRequest,\n context: { params: Promise<{ path?: string[] }> }\n) {\n const params = await context.params;\n return handlers.GET(request, { params });\n}\n`,\n \"utf-8\"\n );\n\n // Content\n await fs.mkdir(path.join(apiCmsDir, \"content\", \"[...path]\"), {\n recursive: true,\n });\n await fs.writeFile(\n path.join(apiCmsDir, \"content\", \"[...path]\", \"route.ts\"),\n `import { createContentApiHandlers } from '@fydemy/cms';\nimport { NextRequest } from 'next/server';\n\nconst handlers = createContentApiHandlers();\n\nexport async function GET(\n request: NextRequest,\n context: { params: Promise<{ path: string[] }> }\n) {\n const params = await context.params;\n return handlers.GET(request, { params });\n}\n\nexport async function POST(\n request: NextRequest,\n context: { params: Promise<{ path: string[] }> }\n) {\n const params = await context.params;\n return handlers.POST(request, { params });\n}\n\nexport async function DELETE(\n request: NextRequest,\n context: { params: Promise<{ path: string[] }> }\n) {\n const params = await context.params;\n return handlers.DELETE(request, { params });\n}\n`,\n \"utf-8\"\n );\n console.log(\"āœ… Created API routes\");\n\n // 4. Middleware\n const middlewarePath = path.join(process.cwd(), \"middleware.ts\");\n try {\n await fs.access(middlewarePath);\n console.log(\n \"āš ļø middleware.ts already exists. Please manually add the CMS auth middleware:\"\n );\n console.log(`\nimport { createAuthMiddleware } from '@fydemy/cms';\n// ... existing imports\n\nexport function middleware(request: NextRequest) {\n // Add this:\n const authResponse = createAuthMiddleware()(request);\n if (authResponse) return authResponse;\n \n // ... existing middleware logic\n}\n`);\n } catch {\n await fs.writeFile(\n middlewarePath,\n `import { createAuthMiddleware } from '@fydemy/cms';\\nimport { NextRequest } from 'next/server';\\n\\nexport function middleware(request: NextRequest) {\\n return createAuthMiddleware()(request);\\n}\\n\\nexport const config = {\\n matcher: ['/admin/:path*'],\\n runtime: 'nodejs',\\n};\\n`,\n \"utf-8\"\n );\n console.log(\"āœ… Created middleware.ts\");\n }\n\n // 5. Env example\n const envExamplePath = path.join(process.cwd(), \".env.local.example\");\n await fs.writeFile(\n envExamplePath,\n `CMS_ADMIN_USERNAME=admin\\nCMS_ADMIN_PASSWORD=password\\nCMS_SESSION_SECRET=ensure_this_is_at_least_32_chars_long_random_string\\n\\n# GitHub Storage (Production)\\nGITHUB_TOKEN=\\nGITHUB_REPO=owner/repo\\nGITHUB_BRANCH=main\\n`,\n \"utf-8\"\n );\n\n console.log(\"\");\n console.log(\"šŸŽ‰ CMS initialized successfully!\");\n console.log(\n \"1. Copy .env.local.example to .env.local and set your credentials\"\n );\n console.log(\"2. Run your dev server and visit /admin\");\n}\n","#!/usr/bin/env node\n\nimport { initCMS } from \"./init/setup\";\n\ninitCMS().catch((err: unknown) => {\n console.error(\"Error initializing CMS:\", err);\n process.exit(1);\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/init/setup.ts","../src/bin.ts"],"sourcesContent":["import fs from \"fs/promises\";\nimport path from \"path\";\nimport { exec } from \"child_process\";\nimport { promisify } from \"util\";\n\nconst execAsync = promisify(exec);\n\nexport interface InitCMSConfig {\n /** Directory where content is stored (default: \"public/content\") */\n contentDir?: string;\n}\n\n/**\n * Initialize CMS in a Next.js project\n * Creates the content directory and an example markdown file.\n * @param config - Configuration options\n */\nexport async function initCMS(config: InitCMSConfig = {}) {\n const contentDir = config.contentDir || \"public/content\";\n const fullPath = path.join(process.cwd(), contentDir);\n const appDir = path.join(process.cwd(), \"app\");\n\n // Check if we are in a Next.js App Router project\n try {\n await fs.access(appDir);\n } catch {\n console.error(\n 'āŒ Error: \"app\" directory not found. This init script requires Next.js App Router.'\n );\n return;\n }\n\n console.log(\"šŸš€ Initializing @fydemy/cms...\");\n\n // 0. Install Dependencies\n console.log(\"šŸ“¦ Checking dependencies...\");\n try {\n const packageJsonPath = path.join(process.cwd(), \"package.json\");\n const packageJson = JSON.parse(await fs.readFile(packageJsonPath, \"utf-8\"));\n const dependencies = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n const missingDeps = [];\n if (!dependencies[\"@fydemy/cms\"]) missingDeps.push(\"@fydemy/cms\");\n if (!dependencies[\"tailwindcss\"]) missingDeps.push(\"tailwindcss\");\n\n // shadcn dependencies\n if (!dependencies[\"class-variance-authority\"])\n missingDeps.push(\"class-variance-authority\");\n if (!dependencies[\"clsx\"]) missingDeps.push(\"clsx\");\n if (!dependencies[\"tailwind-merge\"]) missingDeps.push(\"tailwind-merge\");\n if (!dependencies[\"@radix-ui/react-slot\"])\n missingDeps.push(\"@radix-ui/react-slot\");\n if (!dependencies[\"@radix-ui/react-label\"])\n missingDeps.push(\"@radix-ui/react-label\");\n\n if (missingDeps.length > 0) {\n console.log(\n `šŸ”§ Installing missing dependencies: ${missingDeps.join(\", \")}...`\n );\n // Detect package manager (default to npm if locking file not found)\n let installCmd = \"npm install\";\n try {\n await fs.access(\"pnpm-lock.yaml\");\n installCmd = \"pnpm add\";\n } catch {\n try {\n await fs.access(\"yarn.lock\");\n installCmd = \"yarn add\";\n } catch {\n // npm\n }\n }\n\n await execAsync(`${installCmd} ${missingDeps.join(\" \")}`);\n console.log(\"āœ… Dependencies installed\");\n }\n } catch (error) {\n console.warn(\n \"āš ļø Could not check/install dependencies automatically. Please ensure all dependencies are installed.\"\n );\n }\n\n // 1. Create content directory and example file\n await fs.mkdir(fullPath, { recursive: true });\n\n const exampleContent = `---\ntitle: Example Post\ndescription: This is an example markdown file\ndate: ${new Date().toISOString()}\n---\n\n# Welcome to your CMS!\n\nThis is an example markdown file. You can edit or delete it from the admin dashboard.\n\n## Features\n\n- File-based content storage\n- Markdown with frontmatter\n- GitHub integration for production\n- Simple authentication\n- No database required\n`;\n\n const examplePath = path.join(fullPath, \"example.md\");\n await fs.writeFile(examplePath, exampleContent, \"utf-8\");\n console.log(\"āœ… Created content directory and example file\");\n\n // 2. Scaffold Admin Pages (Ejected Code)\n const adminDir = path.join(appDir, \"admin\");\n const loginDir = path.join(adminDir, \"login\");\n\n await fs.mkdir(loginDir, { recursive: true });\n\n // Read template files from the dist directory (publicDir copied them there)\n const loginTemplate = await fs.readFile(\n path.join(__dirname, \"login.template.tsx\"),\n \"utf-8\"\n );\n const adminTemplate = await fs.readFile(\n path.join(__dirname, \"admin.template.tsx\"),\n \"utf-8\"\n );\n\n await fs.writeFile(path.join(adminDir, \"page.tsx\"), adminTemplate, \"utf-8\");\n\n await fs.writeFile(path.join(loginDir, \"page.tsx\"), loginTemplate, \"utf-8\");\n console.log(\"āœ… Scaffolded Admin UI (shadcn/ui components)\");\n\n // 2.5. Scaffold shadcn/ui Components and Utilities\n const componentsDir = path.join(process.cwd(), \"components\", \"ui\");\n const libDir = path.join(process.cwd(), \"lib\");\n\n await fs.mkdir(componentsDir, { recursive: true });\n await fs.mkdir(libDir, { recursive: true });\n\n // Copy utils.ts\n const utilsTemplate = await fs.readFile(\n path.join(__dirname, \"lib\", \"utils.ts\"),\n \"utf-8\"\n );\n await fs.writeFile(path.join(libDir, \"utils.ts\"), utilsTemplate, \"utf-8\");\n\n // Copy shadcn components\n const componentFiles = [\n \"button.tsx\",\n \"input.tsx\",\n \"card.tsx\",\n \"label.tsx\",\n \"textarea.tsx\",\n \"badge.tsx\",\n ];\n\n for (const componentFile of componentFiles) {\n const componentTemplate = await fs.readFile(\n path.join(__dirname, \"components\", \"ui\", componentFile),\n \"utf-8\"\n );\n await fs.writeFile(\n path.join(componentsDir, componentFile),\n componentTemplate,\n \"utf-8\"\n );\n }\n\n // Copy components.json\n const componentsJsonTemplate = await fs.readFile(\n path.join(__dirname, \"components.json\"),\n \"utf-8\"\n );\n await fs.writeFile(\n path.join(process.cwd(), \"components.json\"),\n componentsJsonTemplate,\n \"utf-8\"\n );\n\n console.log(\"āœ… Scaffolded shadcn/ui components\");\n\n // 3. Scaffold API Routes\n const apiCmsDir = path.join(appDir, \"api\", \"cms\");\n\n // Login\n await fs.mkdir(path.join(apiCmsDir, \"login\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"login\", \"route.ts\"),\n `import { handleLogin } from '@fydemy/cms';\\nexport { handleLogin as POST };\\n`,\n \"utf-8\"\n );\n\n // Logout\n await fs.mkdir(path.join(apiCmsDir, \"logout\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"logout\", \"route.ts\"),\n `import { handleLogout } from '@fydemy/cms';\\nexport { handleLogout as POST };\\n`,\n \"utf-8\"\n );\n\n // Upload\n await fs.mkdir(path.join(apiCmsDir, \"upload\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"upload\", \"route.ts\"),\n `import { handleUpload } from '@fydemy/cms';\\nexport { handleUpload as POST };\\n`,\n \"utf-8\"\n );\n\n // List\n await fs.mkdir(path.join(apiCmsDir, \"list\", \"[[...path]]\"), {\n recursive: true,\n });\n await fs.writeFile(\n path.join(apiCmsDir, \"list\", \"[[...path]]\", \"route.ts\"),\n `import { createListApiHandlers } from '@fydemy/cms';\nimport { NextRequest } from 'next/server';\n\nconst handlers = createListApiHandlers();\n\nexport async function GET(\n request: NextRequest,\n context: { params: Promise<{ path?: string[] }> }\n) {\n const params = await context.params;\n return handlers.GET(request, { params });\n}\n`,\n \"utf-8\"\n );\n\n // Content\n await fs.mkdir(path.join(apiCmsDir, \"content\", \"[...path]\"), {\n recursive: true,\n });\n await fs.writeFile(\n path.join(apiCmsDir, \"content\", \"[...path]\", \"route.ts\"),\n `import { createContentApiHandlers } from '@fydemy/cms';\nimport { NextRequest } from 'next/server';\n\nconst handlers = createContentApiHandlers();\n\nexport async function GET(\n request: NextRequest,\n context: { params: Promise<{ path: string[] }> }\n) {\n const params = await context.params;\n return handlers.GET(request, { params });\n}\n\nexport async function POST(\n request: NextRequest,\n context: { params: Promise<{ path: string[] }> }\n) {\n const params = await context.params;\n return handlers.POST(request, { params });\n}\n\nexport async function DELETE(\n request: NextRequest,\n context: { params: Promise<{ path: string[] }> }\n) {\n const params = await context.params;\n return handlers.DELETE(request, { params });\n}\n`,\n \"utf-8\"\n );\n console.log(\"āœ… Created API routes\");\n\n // 4. Middleware\n const middlewarePath = path.join(process.cwd(), \"middleware.ts\");\n try {\n await fs.access(middlewarePath);\n console.log(\n \"āš ļø middleware.ts already exists. Please manually add the CMS auth middleware:\"\n );\n console.log(`\nimport { createAuthMiddleware } from '@fydemy/cms';\n// ... existing imports\n\nexport function middleware(request: NextRequest) {\n // Add this:\n const authResponse = createAuthMiddleware()(request);\n if (authResponse) return authResponse;\n \n // ... existing middleware logic\n}\n`);\n } catch {\n await fs.writeFile(\n middlewarePath,\n `import { createAuthMiddleware } from '@fydemy/cms';\\nimport { NextRequest } from 'next/server';\\n\\nexport function middleware(request: NextRequest) {\\n return createAuthMiddleware()(request);\\n}\\n\\nexport const config = {\\n matcher: ['/admin/:path*'],\\n runtime: 'nodejs',\\n};\\n`,\n \"utf-8\"\n );\n console.log(\"āœ… Created middleware.ts\");\n }\n\n // 5. Env example & Storage Selection\n console.log(\"\\nāš™ļø Configuration\");\n\n // Interactive storage selection\n const rl = await import(\"readline\");\n const askQuestion = (query: string): Promise<string> => {\n const interface_ = rl.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n return new Promise((resolve) => {\n interface_.question(query, (ans) => {\n interface_.close();\n resolve(ans);\n });\n });\n };\n\n const storageChoice = await askQuestion(\n \"Select production storage provider:\\n 1. GitHub (default)\\n 2. S3 / Cloudflare R2 / Vercel Blob\\nEnter choice [1]: \"\n );\n\n const isS3 = storageChoice.trim() === \"2\";\n\n let envContent = `CMS_ADMIN_USERNAME=admin\nCMS_ADMIN_PASSWORD=password\nCMS_SESSION_SECRET=ensure_this_is_at_least_32_chars_long_random_string\n\n`;\n\n if (isS3) {\n envContent += `# S3 / Cloudflare R2 / Vercel Blob Storage\nSTORAGE_BUCKET=my-bucket\nSTORAGE_ENDPOINT=https://<accountid>.r2.cloudflarestorage.com\nSTORAGE_ACCESS_KEY_ID=\nSTORAGE_SECRET_ACCESS_KEY=\nSTORAGE_REGION=auto\nSTORAGE_PUBLIC_URL=https://pub-<id>.r2.dev\n`;\n } else {\n envContent += `# GitHub Storage (Production)\n# Generate at https://github.com/settings/tokens (Needs 'repo' or 'contents:write' scope)\nGITHUB_TOKEN=\nGITHUB_REPO=owner/repo\nGITHUB_BRANCH=main\n`;\n }\n\n const envExamplePath = path.join(process.cwd(), \".env.local.example\");\n await fs.writeFile(envExamplePath, envContent, \"utf-8\");\n\n console.log(\"\");\n console.log(\"šŸŽ‰ CMS initialized successfully!\");\n console.log(\n \"1. Copy .env.local.example to .env.local and set your credentials\"\n );\n console.log(\"2. Run your dev server and visit /admin\");\n}\n","#!/usr/bin/env node\n\nimport { initCMS } from \"./init/setup\";\n\ninitCMS().catch((err: unknown) => {\n console.error(\"Error initializing CMS:\", err);\n process.exit(1);\n});\n"],"mappings":"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","names":[]}