@fydemy/cms 1.0.1 → 1.0.2

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
@@ -32,24 +32,29 @@ yarn add @fydemy/cms
32
32
 
33
33
  ### 1. Initialize the CMS
34
34
 
35
- Create a script to initialize your content directory:
35
+ Run the initialization command in your Next.js App Router project:
36
36
 
37
- ```typescript
38
- // scripts/init-cms.ts
39
- import { initCMS } from "@fydemy/cms";
40
-
41
- initCMS();
37
+ ```bash
38
+ npx fydemy-cms init
42
39
  ```
43
40
 
44
- Run it:
41
+ This command will automatically:
42
+
43
+ - Create the content directory
44
+ - Scaffold Admin UI pages (`/app/admin`)
45
+ - Create API routes (`/app/api/cms`)
46
+ - Create a `.env.local.example` file
47
+ - Provide instructions for updating `middleware.ts`
48
+
49
+ ### 2. Configure Environment
50
+
51
+ Copy `.env.local.example` to `.env.local` and set your credentials:
45
52
 
46
53
  ```bash
47
- npx tsx scripts/init-cms.ts
54
+ cp .env.local.example .env.local
48
55
  ```
49
56
 
50
- ### 2. Set Environment Variables
51
-
52
- Create `.env.local`:
57
+ Update variables in `.env.local`:
53
58
 
54
59
  ```env
55
60
  # Required for authentication
@@ -65,62 +70,24 @@ GITHUB_BRANCH=main
65
70
 
66
71
  > **Security Note**: Use strong passwords and keep `CMS_SESSION_SECRET` at least 32 characters long.
67
72
 
68
- ### 3. Set Up API Routes
69
-
70
- Create the following API routes in your Next.js app:
71
-
72
- **`app/api/cms/login/route.ts`**
73
-
74
- ```typescript
75
- import { handleLogin } from "@fydemy/cms";
76
- export { handleLogin as POST };
77
- ```
78
-
79
- **`app/api/cms/logout/route.ts`**
80
-
81
- ```typescript
82
- import { handleLogout } from "@fydemy/cms";
83
- export { handleLogout as POST };
84
- ```
85
-
86
- **`app/api/cms/content/[...path]/route.ts`**
87
-
88
- ```typescript
89
- import { createContentApiHandlers } from "@fydemy/cms";
90
-
91
- const handlers = createContentApiHandlers();
92
- export const GET = handlers.GET;
93
- export const POST = handlers.POST;
94
- export const DELETE = handlers.DELETE;
95
- ```
73
+ ### 3. Update Middleware
96
74
 
97
- **`app/api/cms/list/[[...path]]/route.ts`**
98
-
99
- ```typescript
100
- import { createListApiHandlers } from "@fydemy/cms";
101
-
102
- const handlers = createListApiHandlers();
103
- export const GET = handlers.GET;
104
- ```
105
-
106
- ### 4. Add Middleware
107
-
108
- **`middleware.ts`** (root of your project)
75
+ The init command will guide you to update `middleware.ts` to protect admin routes:
109
76
 
110
77
  ```typescript
111
78
  import { createAuthMiddleware } from "@fydemy/cms";
79
+ import { NextRequest } from "next/server";
112
80
 
113
- export const middleware = createAuthMiddleware({
114
- loginPath: "/admin/login",
115
- protectedPaths: ["/admin"],
116
- });
81
+ export function middleware(request: NextRequest) {
82
+ return createAuthMiddleware()(request);
83
+ }
117
84
 
118
85
  export const config = {
119
86
  matcher: ["/admin/:path*"],
120
87
  };
121
88
  ```
122
89
 
123
- ### 5. Read Content in Your App
90
+ ### 4. Read Content in Your App
124
91
 
125
92
  ```typescript
126
93
  import { getMarkdownContent } from "@fydemy/cms";
package/dist/bin.d.mts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/bin.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/bin.js ADDED
@@ -0,0 +1,199 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
+ // If the importer is in node compatibility mode or this is not an ESM
19
+ // file that has been converted to a CommonJS file using a Babel-
20
+ // compatible transform (i.e. "__esModule" has not been set), then set
21
+ // "default" to the CommonJS "module.exports" for node compatibility.
22
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
+ mod
24
+ ));
25
+
26
+ // src/init/setup.ts
27
+ var import_promises = __toESM(require("fs/promises"));
28
+ var import_path = __toESM(require("path"));
29
+ async function initCMS(config = {}) {
30
+ const contentDir = config.contentDir || "public/content";
31
+ const fullPath = import_path.default.join(process.cwd(), contentDir);
32
+ const appDir = import_path.default.join(process.cwd(), "app");
33
+ try {
34
+ await import_promises.default.access(appDir);
35
+ } catch {
36
+ console.error(
37
+ '\u274C Error: "app" directory not found. This init script requires Next.js App Router.'
38
+ );
39
+ return;
40
+ }
41
+ console.log("\u{1F680} Initializing @fydemy/cms...");
42
+ await import_promises.default.mkdir(fullPath, { recursive: true });
43
+ const exampleContent = `---
44
+ title: Example Post
45
+ description: This is an example markdown file
46
+ date: ${(/* @__PURE__ */ new Date()).toISOString()}
47
+ ---
48
+
49
+ # Welcome to your CMS!
50
+
51
+ This is an example markdown file. You can edit or delete it from the admin dashboard.
52
+
53
+ ## Features
54
+
55
+ - File-based content storage
56
+ - Markdown with frontmatter
57
+ - GitHub integration for production
58
+ - Simple authentication
59
+ - No database required
60
+ `;
61
+ const examplePath = import_path.default.join(fullPath, "example.md");
62
+ await import_promises.default.writeFile(examplePath, exampleContent, "utf-8");
63
+ console.log("\u2705 Created content directory and example file");
64
+ const adminDir = import_path.default.join(appDir, "admin");
65
+ const loginDir = import_path.default.join(adminDir, "login");
66
+ await import_promises.default.mkdir(loginDir, { recursive: true });
67
+ await import_promises.default.writeFile(
68
+ import_path.default.join(adminDir, "page.tsx"),
69
+ `import { AdminDashboard } from '@fydemy/cms';
70
+
71
+ export default AdminDashboard;
72
+ `,
73
+ "utf-8"
74
+ );
75
+ await import_promises.default.writeFile(
76
+ import_path.default.join(loginDir, "page.tsx"),
77
+ `import { Login } from '@fydemy/cms';
78
+
79
+ export default Login;
80
+ `,
81
+ "utf-8"
82
+ );
83
+ console.log("\u2705 Created Admin UI pages");
84
+ const apiCmsDir = import_path.default.join(appDir, "api", "cms");
85
+ await import_promises.default.mkdir(import_path.default.join(apiCmsDir, "login"), { recursive: true });
86
+ await import_promises.default.writeFile(
87
+ import_path.default.join(apiCmsDir, "login", "route.ts"),
88
+ `import { handleLogin } from '@fydemy/cms';
89
+ export { handleLogin as POST };
90
+ `,
91
+ "utf-8"
92
+ );
93
+ await import_promises.default.mkdir(import_path.default.join(apiCmsDir, "logout"), { recursive: true });
94
+ await import_promises.default.writeFile(
95
+ import_path.default.join(apiCmsDir, "logout", "route.ts"),
96
+ `import { handleLogout } from '@fydemy/cms';
97
+ export { handleLogout as POST };
98
+ `,
99
+ "utf-8"
100
+ );
101
+ await import_promises.default.mkdir(import_path.default.join(apiCmsDir, "upload"), { recursive: true });
102
+ await import_promises.default.writeFile(
103
+ import_path.default.join(apiCmsDir, "upload", "route.ts"),
104
+ `import { handleUpload } from '@fydemy/cms';
105
+ export { handleUpload as POST };
106
+ `,
107
+ "utf-8"
108
+ );
109
+ await import_promises.default.mkdir(import_path.default.join(apiCmsDir, "list", "[[...path]]"), {
110
+ recursive: true
111
+ });
112
+ await import_promises.default.writeFile(
113
+ import_path.default.join(apiCmsDir, "list", "[[...path]]", "route.ts"),
114
+ `import { createListApiHandlers } from '@fydemy/cms';
115
+
116
+ const handlers = createListApiHandlers();
117
+ export const GET = handlers.GET;
118
+ `,
119
+ "utf-8"
120
+ );
121
+ await import_promises.default.mkdir(import_path.default.join(apiCmsDir, "content", "[...path]"), {
122
+ recursive: true
123
+ });
124
+ await import_promises.default.writeFile(
125
+ import_path.default.join(apiCmsDir, "content", "[...path]", "route.ts"),
126
+ `import { createContentApiHandlers } from '@fydemy/cms';
127
+
128
+ const handlers = createContentApiHandlers();
129
+ export const GET = handlers.GET;
130
+ export const POST = handlers.POST;
131
+ export const DELETE = handlers.DELETE;
132
+ `,
133
+ "utf-8"
134
+ );
135
+ console.log("\u2705 Created API routes");
136
+ const middlewarePath = import_path.default.join(process.cwd(), "middleware.ts");
137
+ try {
138
+ await import_promises.default.access(middlewarePath);
139
+ console.log(
140
+ "\u26A0\uFE0F middleware.ts already exists. Please manually add the CMS auth middleware:"
141
+ );
142
+ console.log(`
143
+ import { createAuthMiddleware } from '@fydemy/cms';
144
+ // ... existing imports
145
+
146
+ export function middleware(request: NextRequest) {
147
+ // Add this:
148
+ const authResponse = createAuthMiddleware()(request);
149
+ if (authResponse) return authResponse;
150
+
151
+ // ... existing middleware logic
152
+ }
153
+ `);
154
+ } catch {
155
+ await import_promises.default.writeFile(
156
+ middlewarePath,
157
+ `import { createAuthMiddleware } from '@fydemy/cms';
158
+ import { NextRequest } from 'next/server';
159
+
160
+ export function middleware(request: NextRequest) {
161
+ return createAuthMiddleware()(request);
162
+ }
163
+
164
+ export const config = {
165
+ matcher: ['/admin/:path*'],
166
+ };
167
+ `,
168
+ "utf-8"
169
+ );
170
+ console.log("\u2705 Created middleware.ts");
171
+ }
172
+ const envExamplePath = import_path.default.join(process.cwd(), ".env.local.example");
173
+ await import_promises.default.writeFile(
174
+ envExamplePath,
175
+ `CMS_ADMIN_USERNAME=admin
176
+ CMS_ADMIN_PASSWORD=password
177
+ CMS_SESSION_SECRET=ensure_this_is_at_least_32_chars_long_random_string
178
+
179
+ # GitHub Storage (Production)
180
+ GITHUB_TOKEN=
181
+ GITHUB_REPO=owner/repo
182
+ GITHUB_BRANCH=main
183
+ `,
184
+ "utf-8"
185
+ );
186
+ console.log("");
187
+ console.log("\u{1F389} CMS initialized successfully!");
188
+ console.log(
189
+ "1. Copy .env.local.example to .env.local and set your credentials"
190
+ );
191
+ console.log("2. Run your dev server and visit /admin");
192
+ }
193
+
194
+ // src/bin.ts
195
+ initCMS().catch((err) => {
196
+ console.error("Error initializing CMS:", err);
197
+ process.exit(1);
198
+ });
199
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/init/setup.ts","../src/bin.ts"],"sourcesContent":["import fs from \"fs/promises\";\nimport path from \"path\";\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 // 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\n const adminDir = path.join(appDir, \"admin\");\n const loginDir = path.join(adminDir, \"login\");\n\n await fs.mkdir(loginDir, { recursive: true });\n\n await fs.writeFile(\n path.join(adminDir, \"page.tsx\"),\n `import { AdminDashboard } from '@fydemy/cms';\\n\\nexport default AdminDashboard;\\n`,\n \"utf-8\"\n );\n\n await fs.writeFile(\n path.join(loginDir, \"page.tsx\"),\n `import { Login } from '@fydemy/cms';\\n\\nexport default Login;\\n`,\n \"utf-8\"\n );\n console.log(\"✅ Created Admin UI pages\");\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';\\n\\nconst handlers = createListApiHandlers();\\nexport const GET = handlers.GET;\\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';\\n\\nconst handlers = createContentApiHandlers();\\nexport const GET = handlers.GET;\\nexport const POST = handlers.POST;\\nexport const DELETE = handlers.DELETE;\\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};\\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"]}
package/dist/bin.mjs ADDED
@@ -0,0 +1,176 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/init/setup.ts
4
+ import fs from "fs/promises";
5
+ import path from "path";
6
+ async function initCMS(config = {}) {
7
+ const contentDir = config.contentDir || "public/content";
8
+ const fullPath = path.join(process.cwd(), contentDir);
9
+ const appDir = path.join(process.cwd(), "app");
10
+ try {
11
+ await fs.access(appDir);
12
+ } catch {
13
+ console.error(
14
+ '\u274C Error: "app" directory not found. This init script requires Next.js App Router.'
15
+ );
16
+ return;
17
+ }
18
+ console.log("\u{1F680} Initializing @fydemy/cms...");
19
+ await fs.mkdir(fullPath, { recursive: true });
20
+ const exampleContent = `---
21
+ title: Example Post
22
+ description: This is an example markdown file
23
+ date: ${(/* @__PURE__ */ new Date()).toISOString()}
24
+ ---
25
+
26
+ # Welcome to your CMS!
27
+
28
+ This is an example markdown file. You can edit or delete it from the admin dashboard.
29
+
30
+ ## Features
31
+
32
+ - File-based content storage
33
+ - Markdown with frontmatter
34
+ - GitHub integration for production
35
+ - Simple authentication
36
+ - No database required
37
+ `;
38
+ const examplePath = path.join(fullPath, "example.md");
39
+ await fs.writeFile(examplePath, exampleContent, "utf-8");
40
+ console.log("\u2705 Created content directory and example file");
41
+ const adminDir = path.join(appDir, "admin");
42
+ const loginDir = path.join(adminDir, "login");
43
+ await fs.mkdir(loginDir, { recursive: true });
44
+ await fs.writeFile(
45
+ path.join(adminDir, "page.tsx"),
46
+ `import { AdminDashboard } from '@fydemy/cms';
47
+
48
+ export default AdminDashboard;
49
+ `,
50
+ "utf-8"
51
+ );
52
+ await fs.writeFile(
53
+ path.join(loginDir, "page.tsx"),
54
+ `import { Login } from '@fydemy/cms';
55
+
56
+ export default Login;
57
+ `,
58
+ "utf-8"
59
+ );
60
+ console.log("\u2705 Created Admin UI pages");
61
+ const apiCmsDir = path.join(appDir, "api", "cms");
62
+ await fs.mkdir(path.join(apiCmsDir, "login"), { recursive: true });
63
+ await fs.writeFile(
64
+ path.join(apiCmsDir, "login", "route.ts"),
65
+ `import { handleLogin } from '@fydemy/cms';
66
+ export { handleLogin as POST };
67
+ `,
68
+ "utf-8"
69
+ );
70
+ await fs.mkdir(path.join(apiCmsDir, "logout"), { recursive: true });
71
+ await fs.writeFile(
72
+ path.join(apiCmsDir, "logout", "route.ts"),
73
+ `import { handleLogout } from '@fydemy/cms';
74
+ export { handleLogout as POST };
75
+ `,
76
+ "utf-8"
77
+ );
78
+ await fs.mkdir(path.join(apiCmsDir, "upload"), { recursive: true });
79
+ await fs.writeFile(
80
+ path.join(apiCmsDir, "upload", "route.ts"),
81
+ `import { handleUpload } from '@fydemy/cms';
82
+ export { handleUpload as POST };
83
+ `,
84
+ "utf-8"
85
+ );
86
+ await fs.mkdir(path.join(apiCmsDir, "list", "[[...path]]"), {
87
+ recursive: true
88
+ });
89
+ await fs.writeFile(
90
+ path.join(apiCmsDir, "list", "[[...path]]", "route.ts"),
91
+ `import { createListApiHandlers } from '@fydemy/cms';
92
+
93
+ const handlers = createListApiHandlers();
94
+ export const GET = handlers.GET;
95
+ `,
96
+ "utf-8"
97
+ );
98
+ await fs.mkdir(path.join(apiCmsDir, "content", "[...path]"), {
99
+ recursive: true
100
+ });
101
+ await fs.writeFile(
102
+ path.join(apiCmsDir, "content", "[...path]", "route.ts"),
103
+ `import { createContentApiHandlers } from '@fydemy/cms';
104
+
105
+ const handlers = createContentApiHandlers();
106
+ export const GET = handlers.GET;
107
+ export const POST = handlers.POST;
108
+ export const DELETE = handlers.DELETE;
109
+ `,
110
+ "utf-8"
111
+ );
112
+ console.log("\u2705 Created API routes");
113
+ const middlewarePath = path.join(process.cwd(), "middleware.ts");
114
+ try {
115
+ await fs.access(middlewarePath);
116
+ console.log(
117
+ "\u26A0\uFE0F middleware.ts already exists. Please manually add the CMS auth middleware:"
118
+ );
119
+ console.log(`
120
+ import { createAuthMiddleware } from '@fydemy/cms';
121
+ // ... existing imports
122
+
123
+ export function middleware(request: NextRequest) {
124
+ // Add this:
125
+ const authResponse = createAuthMiddleware()(request);
126
+ if (authResponse) return authResponse;
127
+
128
+ // ... existing middleware logic
129
+ }
130
+ `);
131
+ } catch {
132
+ await fs.writeFile(
133
+ middlewarePath,
134
+ `import { createAuthMiddleware } from '@fydemy/cms';
135
+ import { NextRequest } from 'next/server';
136
+
137
+ export function middleware(request: NextRequest) {
138
+ return createAuthMiddleware()(request);
139
+ }
140
+
141
+ export const config = {
142
+ matcher: ['/admin/:path*'],
143
+ };
144
+ `,
145
+ "utf-8"
146
+ );
147
+ console.log("\u2705 Created middleware.ts");
148
+ }
149
+ const envExamplePath = path.join(process.cwd(), ".env.local.example");
150
+ await fs.writeFile(
151
+ envExamplePath,
152
+ `CMS_ADMIN_USERNAME=admin
153
+ CMS_ADMIN_PASSWORD=password
154
+ CMS_SESSION_SECRET=ensure_this_is_at_least_32_chars_long_random_string
155
+
156
+ # GitHub Storage (Production)
157
+ GITHUB_TOKEN=
158
+ GITHUB_REPO=owner/repo
159
+ GITHUB_BRANCH=main
160
+ `,
161
+ "utf-8"
162
+ );
163
+ console.log("");
164
+ console.log("\u{1F389} CMS initialized successfully!");
165
+ console.log(
166
+ "1. Copy .env.local.example to .env.local and set your credentials"
167
+ );
168
+ console.log("2. Run your dev server and visit /admin");
169
+ }
170
+
171
+ // src/bin.ts
172
+ initCMS().catch((err) => {
173
+ console.error("Error initializing CMS:", err);
174
+ process.exit(1);
175
+ });
176
+ //# sourceMappingURL=bin.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/init/setup.ts","../src/bin.ts"],"sourcesContent":["import fs from \"fs/promises\";\nimport path from \"path\";\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 // 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\n const adminDir = path.join(appDir, \"admin\");\n const loginDir = path.join(adminDir, \"login\");\n\n await fs.mkdir(loginDir, { recursive: true });\n\n await fs.writeFile(\n path.join(adminDir, \"page.tsx\"),\n `import { AdminDashboard } from '@fydemy/cms';\\n\\nexport default AdminDashboard;\\n`,\n \"utf-8\"\n );\n\n await fs.writeFile(\n path.join(loginDir, \"page.tsx\"),\n `import { Login } from '@fydemy/cms';\\n\\nexport default Login;\\n`,\n \"utf-8\"\n );\n console.log(\"✅ Created Admin UI pages\");\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';\\n\\nconst handlers = createListApiHandlers();\\nexport const GET = handlers.GET;\\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';\\n\\nconst handlers = createContentApiHandlers();\\nexport const GET = handlers.GET;\\nexport const POST = handlers.POST;\\nexport const DELETE = handlers.DELETE;\\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};\\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":[]}
package/dist/index.d.mts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
3
 
3
4
  interface MarkdownData {
4
5
  content: string;
@@ -338,6 +339,10 @@ declare function handleUpload(request: NextRequest): Promise<NextResponse<{
338
339
  filename: string;
339
340
  }>>;
340
341
 
342
+ declare function AdminDashboard(): react_jsx_runtime.JSX.Element;
343
+
344
+ declare function Login(): react_jsx_runtime.JSX.Element;
345
+
341
346
  /**
342
347
  * Create middleware to protect admin routes
343
348
  */
@@ -428,4 +433,4 @@ declare function incrementRateLimit(identifier: string): void;
428
433
  */
429
434
  declare function resetRateLimit(identifier: string): void;
430
435
 
431
- export { type CollectionItem, type FileEntry, GitHubStorage, type InitCMSConfig, LocalStorage, MAX_FILE_SIZE, MAX_PASSWORD_LENGTH, MAX_USERNAME_LENGTH, type MarkdownData, type StorageProvider, checkRateLimit, clearSessionCookie, createAuthMiddleware, createContentApiHandlers, createListApiHandlers, createSession, deleteMarkdownContent, getCollectionItem, getCollectionItems, getCollections, getMarkdownContent, getSessionFromCookies, getStorageProvider, handleDeleteContent, handleGetContent, handleListFiles, handleLogin, handleLogout, handleSaveContent, handleUpload, incrementRateLimit, initCMS, listDirectory, listMarkdownFiles, markdownFileExists, parseMarkdown, resetRateLimit, sanitizeFrontmatter, saveMarkdownContent, setSessionCookie, stringifyMarkdown, uploadFile, validateCredentials, validateFilePath, validateFileSize, validatePassword, validateUsername, verifySession };
436
+ export { AdminDashboard, type CollectionItem, type FileEntry, GitHubStorage, type InitCMSConfig, LocalStorage, Login, MAX_FILE_SIZE, MAX_PASSWORD_LENGTH, MAX_USERNAME_LENGTH, type MarkdownData, type StorageProvider, checkRateLimit, clearSessionCookie, createAuthMiddleware, createContentApiHandlers, createListApiHandlers, createSession, deleteMarkdownContent, getCollectionItem, getCollectionItems, getCollections, getMarkdownContent, getSessionFromCookies, getStorageProvider, handleDeleteContent, handleGetContent, handleListFiles, handleLogin, handleLogout, handleSaveContent, handleUpload, incrementRateLimit, initCMS, listDirectory, listMarkdownFiles, markdownFileExists, parseMarkdown, resetRateLimit, sanitizeFrontmatter, saveMarkdownContent, setSessionCookie, stringifyMarkdown, uploadFile, validateCredentials, validateFilePath, validateFileSize, validatePassword, validateUsername, verifySession };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
3
 
3
4
  interface MarkdownData {
4
5
  content: string;
@@ -338,6 +339,10 @@ declare function handleUpload(request: NextRequest): Promise<NextResponse<{
338
339
  filename: string;
339
340
  }>>;
340
341
 
342
+ declare function AdminDashboard(): react_jsx_runtime.JSX.Element;
343
+
344
+ declare function Login(): react_jsx_runtime.JSX.Element;
345
+
341
346
  /**
342
347
  * Create middleware to protect admin routes
343
348
  */
@@ -428,4 +433,4 @@ declare function incrementRateLimit(identifier: string): void;
428
433
  */
429
434
  declare function resetRateLimit(identifier: string): void;
430
435
 
431
- export { type CollectionItem, type FileEntry, GitHubStorage, type InitCMSConfig, LocalStorage, MAX_FILE_SIZE, MAX_PASSWORD_LENGTH, MAX_USERNAME_LENGTH, type MarkdownData, type StorageProvider, checkRateLimit, clearSessionCookie, createAuthMiddleware, createContentApiHandlers, createListApiHandlers, createSession, deleteMarkdownContent, getCollectionItem, getCollectionItems, getCollections, getMarkdownContent, getSessionFromCookies, getStorageProvider, handleDeleteContent, handleGetContent, handleListFiles, handleLogin, handleLogout, handleSaveContent, handleUpload, incrementRateLimit, initCMS, listDirectory, listMarkdownFiles, markdownFileExists, parseMarkdown, resetRateLimit, sanitizeFrontmatter, saveMarkdownContent, setSessionCookie, stringifyMarkdown, uploadFile, validateCredentials, validateFilePath, validateFileSize, validatePassword, validateUsername, verifySession };
436
+ export { AdminDashboard, type CollectionItem, type FileEntry, GitHubStorage, type InitCMSConfig, LocalStorage, Login, MAX_FILE_SIZE, MAX_PASSWORD_LENGTH, MAX_USERNAME_LENGTH, type MarkdownData, type StorageProvider, checkRateLimit, clearSessionCookie, createAuthMiddleware, createContentApiHandlers, createListApiHandlers, createSession, deleteMarkdownContent, getCollectionItem, getCollectionItems, getCollections, getMarkdownContent, getSessionFromCookies, getStorageProvider, handleDeleteContent, handleGetContent, handleListFiles, handleLogin, handleLogout, handleSaveContent, handleUpload, incrementRateLimit, initCMS, listDirectory, listMarkdownFiles, markdownFileExists, parseMarkdown, resetRateLimit, sanitizeFrontmatter, saveMarkdownContent, setSessionCookie, stringifyMarkdown, uploadFile, validateCredentials, validateFilePath, validateFileSize, validatePassword, validateUsername, verifySession };