@programinglive/dev-workflow-mcp-server 1.7.13 → 1.7.14

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/CHANGELOG.md CHANGED
@@ -2,6 +2,47 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [1.7.14](https://github.com/programinglive/dev-workflow-mcp-server/compare/v1.7.13...v1.7.14) (2025-12-19)
6
+
7
+
8
+ ### ✨ Features
9
+
10
+ * add API dependencies and update login to use API client ([94bb42f](https://github.com/programinglive/dev-workflow-mcp-server/commit/94bb42f27b4bd225bb3813b81d5f2bff973edb16))
11
+ * add REST API server for frontend database access ([cdb347c](https://github.com/programinglive/dev-workflow-mcp-server/commit/cdb347cf204ce423b94db7e72980783e986a124d))
12
+ * implement JWT authentication and update client ([8efbe80](https://github.com/programinglive/dev-workflow-mcp-server/commit/8efbe80c3a69046f716b247fc359158dc8fec3e2))
13
+
14
+
15
+ ### ♻️ Refactors
16
+
17
+ * remove session cookies, enforce JWT only ([bacd83a](https://github.com/programinglive/dev-workflow-mcp-server/commit/bacd83a16510499667143f4906d0cc8de0127d61))
18
+
19
+
20
+ ### 🐛 Bug Fixes
21
+
22
+ * add credentials:include to getCurrentUser to persist session ([b8f2df5](https://github.com/programinglive/dev-workflow-mcp-server/commit/b8f2df531a2d2bae78ad3c3ea2c7dcda62e5e835))
23
+ * add root netlify.toml for monorepo support ([54c5ed3](https://github.com/programinglive/dev-workflow-mcp-server/commit/54c5ed3960aafd5a814773efa487efe9197d4385))
24
+ * enable trust proxy and force secure cookies for cross-domain session ([2c5d6e8](https://github.com/programinglive/dev-workflow-mcp-server/commit/2c5d6e858d05de06304d88286b931b1f12a95bf1))
25
+ * ensure getMe uses full API URL ([b3bd0da](https://github.com/programinglive/dev-workflow-mcp-server/commit/b3bd0da097de57b42d9253615f791677011486af))
26
+ * force API URL to tunnel address to resolve cached old IP ([1883731](https://github.com/programinglive/dev-workflow-mcp-server/commit/18837313a7b96395f1cf04b56d7fe1a74e13b1ed))
27
+ * inline auth functions in API server ([eefd73c](https://github.com/programinglive/dev-workflow-mcp-server/commit/eefd73c82dcf47d419662eaeb8854f6047e6464a))
28
+ * remove duplicate variable declarations in API server ([31d3621](https://github.com/programinglive/dev-workflow-mcp-server/commit/31d3621213ddb3560ee0570fdf6411d9acf7018f))
29
+ * remove dynamic API route for static export ([05a4dd0](https://github.com/programinglive/dev-workflow-mcp-server/commit/05a4dd0e4901e5ac329e50ebe392839d1242de4e))
30
+ * remove explicit publish path to fix netlify build ([cd64bcf](https://github.com/programinglive/dev-workflow-mcp-server/commit/cd64bcf0b4effb71be090235357d665d1f26b567))
31
+ * remove incorrect netlify publish dir for dynamic build ([ea34cf4](https://github.com/programinglive/dev-workflow-mcp-server/commit/ea34cf464466b4ddc8eaa6432434d1fbabb3583e))
32
+ * remove incorrect publish dir from netlify config ([010236f](https://github.com/programinglive/dev-workflow-mcp-server/commit/010236fd0eb1419f7cae4429159f4aac1a988174))
33
+ * restore static export for netlify deployment ([685d841](https://github.com/programinglive/dev-workflow-mcp-server/commit/685d84178b239b5cd681b4d479456e69519a8af8))
34
+ * update API URL to use Cloudflare Tunnel for HTTPS ([ab72f6c](https://github.com/programinglive/dev-workflow-mcp-server/commit/ab72f6c0b8acc6974aba7c8df8418e35da6f2a51))
35
+ * use apiClient in history page and add version indicator ([4889669](https://github.com/programinglive/dev-workflow-mcp-server/commit/48896694166cd5d42ab4134d4dbfdb0df8ca0d44))
36
+ * use npm install instead of ci to avoid lockfile issues ([e5fae26](https://github.com/programinglive/dev-workflow-mcp-server/commit/e5fae26f767c5f0e4aba2593df321c700ac14a38))
37
+
38
+
39
+ ### 🧹 Chores
40
+
41
+ * bump version to 1.7.14 to ensure fresh build ([f7d8886](https://github.com/programinglive/dev-workflow-mcp-server/commit/f7d88861ceb111c57e3b34bf4b5a5cc25a19805b))
42
+ * bump version to 1.7.15 for JWT frontend deploy ([7850268](https://github.com/programinglive/dev-workflow-mcp-server/commit/7850268d019251619d60a0a841db2bab8061be04))
43
+ * cleanup post-release and update website version to 1.7.13 ([7341d44](https://github.com/programinglive/dev-workflow-mcp-server/commit/7341d446bbddcb9232e70606acaf950fde7ff5c2))
44
+ * save pending changes before release ([4d4b1c9](https://github.com/programinglive/dev-workflow-mcp-server/commit/4d4b1c9e6122baed3cc6782a572fe3700dabf19b))
45
+
5
46
  ### [1.7.13](https://github.com/programinglive/dev-workflow-mcp-server/compare/v1.7.12...v1.7.13) (2025-12-18)
6
47
 
7
48
 
@@ -0,0 +1,3 @@
1
+ url: http://localhost:8080
2
+ tunnel: api-devworkflow
3
+ credentials-file: /home/dhika/.cloudflared/credentials.json
@@ -19,6 +19,23 @@ services:
19
19
  timeout: 5s
20
20
  retries: 5
21
21
 
22
+ api:
23
+ build:
24
+ context: ./web
25
+ dockerfile: Dockerfile.api
26
+ container_name: dev-workflow-api
27
+ ports:
28
+ - "8080:8080"
29
+ environment:
30
+ - DEV_WORKFLOW_DB_URL=${DEV_WORKFLOW_DB_URL}
31
+ - SESSION_SECRET=${SESSION_SECRET:-dev-workflow-secret-change-in-production}
32
+ - NODE_ENV=${NODE_ENV:-production}
33
+ - API_PORT=8080
34
+ depends_on:
35
+ postgres:
36
+ condition: service_healthy
37
+ restart: unless-stopped
38
+
22
39
  volumes:
23
40
  postgres_data:
24
41
  driver: local
@@ -4,6 +4,8 @@ Authoritative history of user-visible changes for the Development Workflow MCP S
4
4
 
5
5
  | Version | Date | Notes |
6
6
  |---------|------|-------|
7
+ | 1.7.14 | 2025-12-19 | add API dependencies and update login to use API client (94bb42f) |
8
+ | 1.7.13 | 2025-12-18 | remote db connection, history api 500 errors, and windows startup (ce559a6) |
7
9
  | 1.7.12 | 2025-12-17 | post-release cleanup v1.7.11 (c2ee733) |
8
10
  | 1.7.11 | 2025-12-17 | test: comprehensive DB adapter tests, env support, and warning fixes (64b029a) |
9
11
  | 1.7.10 | 2025-12-16 | update release notes and finalize ci config (92ac78a) |
@@ -37,6 +39,42 @@ Authoritative history of user-visible changes for the Development Workflow MCP S
37
39
 
38
40
 
39
41
 
42
+
43
+
44
+ ## 1.7.14 – ✨ Features
45
+
46
+ Released on **2025-12-19**.
47
+
48
+ - add API dependencies and update login to use API client (94bb42f)
49
+ - add REST API server for frontend database access (cdb347c)
50
+ - implement JWT authentication and update client (8efbe80)
51
+ - remove session cookies, enforce JWT only (bacd83a)
52
+ - add credentials:include to getCurrentUser to persist session (b8f2df5)
53
+ - add root netlify.toml for monorepo support (54c5ed3)
54
+ - enable trust proxy and force secure cookies for cross-domain session (2c5d6e8)
55
+ - ensure getMe uses full API URL (b3bd0da)
56
+ - force API URL to tunnel address to resolve cached old IP (1883731)
57
+ - inline auth functions in API server (eefd73c)
58
+ - remove duplicate variable declarations in API server (31d3621)
59
+ - remove dynamic API route for static export (05a4dd0)
60
+ - remove explicit publish path to fix netlify build (cd64bcf)
61
+ - remove incorrect netlify publish dir for dynamic build (ea34cf4)
62
+ - remove incorrect publish dir from netlify config (010236f)
63
+ - restore static export for netlify deployment (685d841)
64
+ - update API URL to use Cloudflare Tunnel for HTTPS (ab72f6c)
65
+ - use apiClient in history page and add version indicator (4889669)
66
+ - use npm install instead of ci to avoid lockfile issues (e5fae26)
67
+ - bump version to 1.7.14 to ensure fresh build (f7d8886)
68
+ - bump version to 1.7.15 for JWT frontend deploy (7850268)
69
+ - cleanup post-release and update website version to 1.7.13 (7341d44)
70
+ - save pending changes before release (4d4b1c9)
71
+
72
+ ## 1.7.13 – 🐛 Bug Fixes
73
+
74
+ Released on **2025-12-18**.
75
+
76
+ - remote db connection, history api 500 errors, and windows startup (ce559a6)
77
+
40
78
  ## 1.7.12 – 📝 Documentation
41
79
 
42
80
  Released on **2025-12-17**.
package/netlify.toml ADDED
@@ -0,0 +1,7 @@
1
+ [build]
2
+ base = "web"
3
+ command = "npm run build"
4
+ # publish = ".next" (Removed to allow auto-detection)
5
+
6
+ [[plugins]]
7
+ package = "@netlify/plugin-nextjs"
package/nginx-api.conf ADDED
@@ -0,0 +1,27 @@
1
+ server {
2
+ listen 80;
3
+ server_name api.devworkflow.programinglive.com;
4
+
5
+ location / {
6
+ proxy_pass http://localhost:8080;
7
+ proxy_http_version 1.1;
8
+ proxy_set_header Upgrade $http_upgrade;
9
+ proxy_set_header Connection 'upgrade';
10
+ proxy_set_header Host $host;
11
+ proxy_set_header X-Real-IP $remote_addr;
12
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
13
+ proxy_set_header X-Forwarded-Proto $scheme;
14
+ proxy_cache_bypass $http_upgrade;
15
+
16
+ # CORS headers (backup in case API doesn't set them)
17
+ add_header 'Access-Control-Allow-Origin' 'https://devworkflow.programinglive.com' always;
18
+ add_header 'Access-Control-Allow-Credentials' 'true' always;
19
+ add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
20
+ add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization' always;
21
+
22
+ # Handle preflight requests
23
+ if ($request_method = 'OPTIONS') {
24
+ return 204;
25
+ }
26
+ }
27
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@programinglive/dev-workflow-mcp-server",
3
- "version": "1.7.13",
3
+ "version": "1.7.14",
4
4
  "description": "MCP server to enforce development workflow discipline",
5
5
  "homepage": "https://devworkflow.programinglive.com/",
6
6
  "mcpName": "io.github.programinglive/dev-workflow-mcp-server",
@@ -0,0 +1,75 @@
1
+ import fetch from 'node-fetch';
2
+
3
+ const API_BASE_URL = 'https://hollywood-andrew-cycle-genre.trycloudflare.com';
4
+ const USERNAME = 'programinglive';
5
+ const PASSWORD = 'mcpdevserver';
6
+
7
+ async function testAuthFlow() {
8
+ console.log('🚀 Starting Auth Flow Test...');
9
+ console.log(`Target: ${API_BASE_URL}\n`);
10
+
11
+ try {
12
+ // 1. Login
13
+ console.log('1️⃣ Attempting Login...');
14
+ const loginRes = await fetch(`${API_BASE_URL}/api/auth/login`, {
15
+ method: 'POST',
16
+ headers: { 'Content-Type': 'application/json' },
17
+ body: JSON.stringify({ username: USERNAME, password: PASSWORD }),
18
+ });
19
+
20
+ console.log(` Status: ${loginRes.status}`);
21
+ if (!loginRes.ok) {
22
+ throw new Error(`Login failed: ${loginRes.statusText}`);
23
+ }
24
+
25
+ const loginData = await loginRes.json();
26
+ const token = loginData.token;
27
+
28
+ if (token) {
29
+ console.log(' ✅ Login Successful! JWT Token received.');
30
+ console.log(` Token: ${token.substring(0, 20)}...`);
31
+ } else {
32
+ console.log(' ⚠️ Login successful but NO TOKEN returned (Legacy Session mode?)');
33
+ }
34
+
35
+ // 2. Access Protected Route (GET /me)
36
+ console.log('\n2️⃣ Verifying Session/Token (GET /api/auth/me)...');
37
+ const headers = {};
38
+ if (token) {
39
+ headers['Authorization'] = `Bearer ${token}`;
40
+ console.log(' Using Authorization: Bearer header');
41
+ } else {
42
+ console.log(' Using Cookies (if any)');
43
+ }
44
+
45
+ const meRes = await fetch(`${API_BASE_URL}/api/auth/me`, {
46
+ headers,
47
+ });
48
+
49
+ console.log(` Status: ${meRes.status}`);
50
+ if (meRes.ok) {
51
+ const meData = await meRes.json();
52
+ console.log(` ✅ Authorized! User: ${meData.username} (${meData.email})`);
53
+ } else {
54
+ console.error(' ❌ Authorization Failed!');
55
+ console.error(await meRes.text());
56
+ }
57
+
58
+ // 3. Access History (GET /api/history)
59
+ console.log('\n3️⃣ Fetching History...');
60
+ const historyRes = await fetch(`${API_BASE_URL}/api/history`, { headers });
61
+ console.log(` Status: ${historyRes.status}`);
62
+
63
+ if (historyRes.ok) {
64
+ const historyData = await historyRes.json();
65
+ console.log(` ✅ History fetched! Count: ${historyData.history ? historyData.history.length : 0}`);
66
+ } else {
67
+ console.log(' ❌ History fetch failed.');
68
+ }
69
+
70
+ } catch (error) {
71
+ console.error('\n❌ Test Failed:', error.message);
72
+ }
73
+ }
74
+
75
+ testAuthFlow();
@@ -0,0 +1,25 @@
1
+ FROM node:20-alpine
2
+
3
+ # Install dependencies for native modules
4
+ RUN apk add --no-cache python3 make g++ postgresql-client
5
+
6
+ WORKDIR /app
7
+
8
+ # Copy package files
9
+ COPY package*.json ./
10
+
11
+ # Install dependencies
12
+ RUN npm install --only=production
13
+
14
+ # Copy application code
15
+ COPY . .
16
+
17
+ # Expose API port
18
+ EXPOSE 8080
19
+
20
+ # Set environment
21
+ ENV NODE_ENV=production
22
+ ENV API_PORT=8080
23
+
24
+ # Run API server
25
+ CMD ["node", "api-server.js"]
@@ -0,0 +1,211 @@
1
+ import express from 'express';
2
+ import cors from 'cors';
3
+ import pg from 'pg';
4
+ import dotenv from 'dotenv';
5
+ import bcrypt from 'bcrypt';
6
+ import jwt from 'jsonwebtoken';
7
+
8
+ dotenv.config({ path: '../.env' });
9
+
10
+ const app = express();
11
+ const { Pool } = pg;
12
+
13
+ const PORT = process.env.API_PORT || 8080;
14
+ const dbUrl = process.env.DEV_WORKFLOW_DB_URL;
15
+ const JWT_SECRET = process.env.JWT_SECRET || 'dev-workflow-jwt-secret-change-me';
16
+
17
+ if (!dbUrl) {
18
+ console.error('❌ DEV_WORKFLOW_DB_URL is not set');
19
+ process.exit(1);
20
+ }
21
+
22
+ const pool = new Pool({ connectionString: dbUrl });
23
+
24
+ // Authentication helper functions
25
+ async function authenticateUser(pool, username, password) {
26
+ const result = await pool.query(
27
+ 'SELECT * FROM users WHERE username = $1',
28
+ [username]
29
+ );
30
+
31
+ if (result.rows.length === 0) {
32
+ return null;
33
+ }
34
+
35
+ const user = result.rows[0];
36
+ const isValid = await bcrypt.compare(password, user.password_hash);
37
+
38
+ if (!isValid) {
39
+ return null;
40
+ }
41
+
42
+ return {
43
+ id: user.id,
44
+ username: user.username,
45
+ email: user.email,
46
+ };
47
+ }
48
+
49
+ async function getUserById(pool, userId) {
50
+ const result = await pool.query(
51
+ 'SELECT id, username, email FROM users WHERE id = $1',
52
+ [userId]
53
+ );
54
+
55
+ return result.rows[0] || null;
56
+ }
57
+
58
+ // CORS configuration - allow Netlify domain
59
+ const corsOptions = {
60
+ origin: [
61
+ 'https://devworkflow.programinglive.com',
62
+ 'http://localhost:3000',
63
+ ],
64
+ credentials: true,
65
+ methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
66
+ allowedHeaders: ['Content-Type', 'Authorization'],
67
+ };
68
+
69
+ app.use(cors(corsOptions));
70
+ app.use(express.json());
71
+ app.use(express.urlencoded({ extended: true }));
72
+ app.set('trust proxy', 1);
73
+
74
+ // Middleware to verify JWT
75
+ const requireAuth = (req, res, next) => {
76
+ const authHeader = req.headers.authorization;
77
+
78
+ if (authHeader && authHeader.startsWith('Bearer ')) {
79
+ const token = authHeader.split(' ')[1];
80
+ try {
81
+ const decoded = jwt.verify(token, JWT_SECRET);
82
+ req.user = decoded;
83
+ return next();
84
+ } catch (err) {
85
+ return res.status(401).json({ error: 'Invalid token' });
86
+ }
87
+ }
88
+
89
+ return res.status(401).json({ error: 'Authentication required' });
90
+ };
91
+
92
+ // Health check endpoint
93
+ app.get('/api/health', (req, res) => {
94
+ res.json({ status: 'ok', timestamp: new Date().toISOString() });
95
+ });
96
+
97
+ // Authentication endpoints
98
+ app.post('/api/auth/login', async (req, res) => {
99
+ try {
100
+ const { username, password } = req.body;
101
+
102
+ if (!username || !password) {
103
+ return res.status(400).json({ error: 'Username and password are required' });
104
+ }
105
+
106
+ const user = await authenticateUser(pool, username, password);
107
+
108
+ if (!user) {
109
+ return res.status(401).json({ error: 'Invalid credentials' });
110
+ }
111
+
112
+ // Generate JWT Token
113
+ const token = jwt.sign(
114
+ { userId: user.id, username: user.username },
115
+ JWT_SECRET,
116
+ { expiresIn: '30d' }
117
+ );
118
+
119
+ res.json({
120
+ success: true,
121
+ token,
122
+ user: {
123
+ id: user.id,
124
+ username: user.username,
125
+ email: user.email,
126
+ },
127
+ });
128
+ } catch (error) {
129
+ console.error('Login error:', error);
130
+ res.status(500).json({ error: 'Internal server error' });
131
+ }
132
+ });
133
+
134
+ app.post('/api/auth/logout', (req, res) => {
135
+ // Client-side only action for JWT
136
+ res.json({ success: true });
137
+ });
138
+
139
+ app.get('/api/auth/me', requireAuth, async (req, res) => {
140
+ try {
141
+ const user = await getUserById(pool, req.user.userId);
142
+
143
+ if (!user) {
144
+ return res.status(404).json({ error: 'User not found' });
145
+ }
146
+
147
+ res.json({
148
+ id: user.id,
149
+ username: user.username,
150
+ email: user.email,
151
+ });
152
+ } catch (error) {
153
+ console.error('Get user error:', error);
154
+ res.status(500).json({ error: 'Internal server error' });
155
+ }
156
+ });
157
+
158
+ // Workflow history endpoints
159
+ app.get('/api/history', requireAuth, async (req, res) => {
160
+ try {
161
+ const result = await pool.query(
162
+ `SELECT id, task_type, description, commit_message, completed_at, tests_passed, documentation_type
163
+ FROM workflow_history
164
+ WHERE user_id = $1
165
+ ORDER BY completed_at DESC
166
+ LIMIT 100`,
167
+ [req.user.userId]
168
+ );
169
+
170
+ res.json({
171
+ history: result.rows,
172
+ });
173
+ } catch (error) {
174
+ console.error('Get history error:', error);
175
+ res.status(500).json({ error: 'Failed to fetch history' });
176
+ }
177
+ });
178
+
179
+ app.post('/api/history', requireAuth, async (req, res) => {
180
+ try {
181
+ const { task_type, description, commit_message, tests_passed, documentation_type } = req.body;
182
+
183
+ const result = await pool.query(
184
+ `INSERT INTO workflow_history (user_id, task_type, description, commit_message, tests_passed, documentation_type, completed_at)
185
+ VALUES ($1, $2, $3, $4, $5, $6, NOW())
186
+ RETURNING *`,
187
+ [req.user.userId, task_type, description, commit_message, tests_passed, documentation_type]
188
+ );
189
+
190
+ res.json({
191
+ success: true,
192
+ history: result.rows[0],
193
+ });
194
+ } catch (error) {
195
+ console.error('Create history error:', error);
196
+ res.status(500).json({ error: 'Failed to create history entry' });
197
+ }
198
+ });
199
+
200
+ // Error handling middleware
201
+ app.use((err, req, res, next) => {
202
+ console.error('Unhandled error:', err);
203
+ res.status(500).json({ error: 'Internal server error' });
204
+ });
205
+
206
+ // Start server
207
+ app.listen(PORT, '0.0.0.0', () => {
208
+ console.log(`✅ API server running on port ${PORT}`);
209
+ console.log(`📊 Database: ${dbUrl.replace(/:[^:]*@/, ':****@')}`);
210
+ console.log(`🌐 CORS enabled for: ${corsOptions.origin.join(', ')}`);
211
+ });
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { useEffect, useState, useMemo } from 'react';
4
4
  import { useRouter } from 'next/navigation';
5
+ import { apiClient } from '@/lib/api-client';
5
6
  import {
6
7
  CheckCircle,
7
8
  XCircle,
@@ -34,27 +35,33 @@ export default function HistoryPage() {
34
35
  const router = useRouter();
35
36
 
36
37
  useEffect(() => {
37
- fetch('/api/auth/me')
38
- .then(res => {
39
- if (res.ok) {
40
- setIsAuthenticated(true);
41
- // Sync auth state with Navbar
42
- localStorage.setItem('isLoggedIn', 'true');
43
- window.dispatchEvent(new Event('authUpdate'));
44
- return fetch('/api/history-fallback');
45
- } else {
46
- router.push('/login');
38
+ const loadData = async () => {
39
+ try {
40
+ // Verify auth
41
+ const user = await apiClient.getCurrentUser();
42
+ if (!user) {
47
43
  throw new Error('Not authenticated');
48
44
  }
49
- })
50
- .then(res => res?.json())
51
- .then(data => {
52
- if (data?.history) {
53
- setHistory(data.history);
45
+
46
+ setIsAuthenticated(true);
47
+ // Sync auth state
48
+ localStorage.setItem('isLoggedIn', 'true');
49
+ window.dispatchEvent(new Event('authUpdate'));
50
+
51
+ // Fetch history
52
+ const result = await apiClient.getHistory();
53
+ if (result?.history) {
54
+ setHistory(result.history);
54
55
  }
55
- })
56
- .catch(() => { })
57
- .finally(() => setLoading(false));
56
+ } catch (error) {
57
+ console.error('History load error:', error);
58
+ router.push('/login');
59
+ } finally {
60
+ setLoading(false);
61
+ }
62
+ };
63
+
64
+ loadData();
58
65
  }, [router]);
59
66
 
60
67
  const stats = useMemo(() => {
@@ -4,6 +4,7 @@ import { useState, useEffect } from 'react';
4
4
  import { useRouter } from 'next/navigation';
5
5
  import Image from 'next/image';
6
6
  import { Lock, User } from 'lucide-react';
7
+ import { apiClient } from '@/lib/api-client';
7
8
 
8
9
  export default function LoginPage() {
9
10
  const [username, setUsername] = useState('');
@@ -21,9 +22,9 @@ export default function LoginPage() {
21
22
  return;
22
23
  }
23
24
 
24
- fetch('/api/auth/me')
25
- .then(res => {
26
- if (res.ok) {
25
+ apiClient.getCurrentUser()
26
+ .then(user => {
27
+ if (user) {
27
28
  router.push('/history');
28
29
  }
29
30
  })
@@ -37,23 +38,17 @@ export default function LoginPage() {
37
38
  setLoading(true);
38
39
 
39
40
  try {
40
- const response = await fetch('/api/auth/login', {
41
- method: 'POST',
42
- headers: { 'Content-Type': 'application/json' },
43
- body: JSON.stringify({ username, password }),
44
- });
41
+ const data = await apiClient.login(username, password);
45
42
 
46
- const data = await response.json();
47
-
48
- if (response.ok) {
43
+ if (data.success) {
49
44
  localStorage.setItem('isLoggedIn', 'true');
50
45
  window.dispatchEvent(new Event('authUpdate'));
51
46
  router.push('/history');
52
47
  } else {
53
- setError(data.error || 'Login failed');
48
+ setError('Login failed');
54
49
  }
55
- } catch (err) {
56
- setError('Network error. Please try again.');
50
+ } catch (err: any) {
51
+ setError(err.message || 'Network error. Please try again.');
57
52
  } finally {
58
53
  setLoading(false);
59
54
  }
@@ -77,6 +72,9 @@ export default function LoginPage() {
77
72
  <p className="mt-2 text-sm text-gray-500 dark:text-gray-400">
78
73
  Sign in to access your workflow history
79
74
  </p>
75
+ <p className="mt-1 text-xs text-gray-400 font-mono">
76
+ v1.7.18 (JWT Fix)
77
+ </p>
80
78
  </div>
81
79
 
82
80
  <form className="mt-8 space-y-6" onSubmit={handleSubmit}>
@@ -17,7 +17,7 @@ export default function Hero() {
17
17
  .catch(() => setDownloads(null));
18
18
 
19
19
  // Version is hardcoded for static export
20
- setVersion("1.7.11");
20
+ setVersion("1.7.13");
21
21
  }, []);
22
22
 
23
23
  const formatDownloads = (num: number) => {
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import { useState, useEffect } from "react";
4
+ import { apiClient } from "@/lib/api-client";
4
5
 
5
6
  type HistoryItem = {
6
7
  id: number;
@@ -31,11 +32,10 @@ export default function History() {
31
32
 
32
33
  const loadData = async () => {
33
34
  try {
34
- // Fetch workflow history from API
35
- const response = await fetch('/api/workflow/history');
35
+ // Fetch workflow history from API via apiClient
36
+ const data = await apiClient.getHistory();
36
37
 
37
- if (response.ok) {
38
- const data = await response.json();
38
+ if (data?.history) {
39
39
  setHistory(data.history || []);
40
40
  setTotalPages(Math.ceil((data.history?.length || 0) / 10));
41
41
  setSummary({