apikeyscreator 1.0.0
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/BUN.md +263 -0
- package/IMPLEMENTATION.md +298 -0
- package/LIBRARY.md +425 -0
- package/PROJECT-SUMMARY.md +297 -0
- package/QUICK-REF.md +277 -0
- package/README.md +228 -0
- package/examples/client.js +162 -0
- package/package.json +25 -0
- package/src/middleware/auth.js +17 -0
- package/src/routes/apiKeys.js +143 -0
- package/src/routes/auth.js +96 -0
- package/src/server.js +41 -0
- package/src/utils/db.js +137 -0
- package/src/utils/jwt.js +24 -0
- package/test.js +118 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import { db } from '../utils/db.js';
|
|
3
|
+
|
|
4
|
+
export const apiKeysRoutes = express.Router();
|
|
5
|
+
|
|
6
|
+
// List all API keys for user
|
|
7
|
+
apiKeysRoutes.get('/', (req, res) => {
|
|
8
|
+
const keys = db.keys.findByUserId(req.user.userId);
|
|
9
|
+
|
|
10
|
+
return res.json({
|
|
11
|
+
message: 'API keys retrieved successfully',
|
|
12
|
+
count: keys.length,
|
|
13
|
+
keys: keys.map(k => ({
|
|
14
|
+
id: k.id,
|
|
15
|
+
name: k.name,
|
|
16
|
+
key: k.key.substring(0, 10) + '...' + k.key.substring(k.key.length - 4),
|
|
17
|
+
fullKey: k.key,
|
|
18
|
+
active: k.active,
|
|
19
|
+
createdAt: k.createdAt,
|
|
20
|
+
lastUsed: k.lastUsed,
|
|
21
|
+
})),
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Get single API key
|
|
26
|
+
apiKeysRoutes.get('/:id', (req, res) => {
|
|
27
|
+
const keyId = req.params.id;
|
|
28
|
+
|
|
29
|
+
const key = db.keys.findById(req.user.userId, keyId);
|
|
30
|
+
if (!key) {
|
|
31
|
+
return res.status(404).json({ error: 'API key not found' });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return res.json({
|
|
35
|
+
message: 'API key retrieved successfully',
|
|
36
|
+
key: {
|
|
37
|
+
id: key.id,
|
|
38
|
+
name: key.name,
|
|
39
|
+
key: key.key.substring(0, 10) + '...' + key.key.substring(key.key.length - 4),
|
|
40
|
+
fullKey: key.key,
|
|
41
|
+
active: key.active,
|
|
42
|
+
createdAt: key.createdAt,
|
|
43
|
+
lastUsed: key.lastUsed,
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Create new API key
|
|
49
|
+
apiKeysRoutes.post('/', async (req, res) => {
|
|
50
|
+
try {
|
|
51
|
+
const { name } = req.body;
|
|
52
|
+
|
|
53
|
+
if (!name) {
|
|
54
|
+
return res.status(400).json({
|
|
55
|
+
error: 'Key name is required'
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const newKey = db.keys.create(req.user.userId, name);
|
|
60
|
+
|
|
61
|
+
return res.status(201).json({
|
|
62
|
+
message: 'API key created successfully',
|
|
63
|
+
key: {
|
|
64
|
+
id: newKey.id,
|
|
65
|
+
name: newKey.name,
|
|
66
|
+
key: newKey.key,
|
|
67
|
+
active: newKey.active,
|
|
68
|
+
createdAt: newKey.createdAt,
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
} catch (error) {
|
|
72
|
+
return res.status(500).json({
|
|
73
|
+
error: error.message
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Update API key (name, status)
|
|
79
|
+
apiKeysRoutes.put('/:id', async (req, res) => {
|
|
80
|
+
try {
|
|
81
|
+
const keyId = req.params.id;
|
|
82
|
+
const { name, active } = req.body;
|
|
83
|
+
|
|
84
|
+
const key = db.keys.findById(req.user.userId, keyId);
|
|
85
|
+
if (!key) {
|
|
86
|
+
return res.status(404).json({ error: 'API key not found' });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const updates = {};
|
|
90
|
+
if (name !== undefined) updates.name = name;
|
|
91
|
+
if (active !== undefined) updates.active = active;
|
|
92
|
+
|
|
93
|
+
const updatedKey = db.keys.update(req.user.userId, keyId, updates);
|
|
94
|
+
|
|
95
|
+
return res.json({
|
|
96
|
+
message: 'API key updated successfully',
|
|
97
|
+
key: {
|
|
98
|
+
id: updatedKey.id,
|
|
99
|
+
name: updatedKey.name,
|
|
100
|
+
key: updatedKey.key.substring(0, 10) + '...' + updatedKey.key.substring(updatedKey.key.length - 4),
|
|
101
|
+
active: updatedKey.active,
|
|
102
|
+
createdAt: updatedKey.createdAt,
|
|
103
|
+
lastUsed: updatedKey.lastUsed,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
} catch (error) {
|
|
107
|
+
return res.status(500).json({
|
|
108
|
+
error: error.message
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Delete API key
|
|
114
|
+
apiKeysRoutes.delete('/:id', (req, res) => {
|
|
115
|
+
const keyId = req.params.id;
|
|
116
|
+
|
|
117
|
+
const key = db.keys.findById(req.user.userId, keyId);
|
|
118
|
+
if (!key) {
|
|
119
|
+
return res.status(404).json({ error: 'API key not found' });
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
db.keys.delete(req.user.userId, keyId);
|
|
123
|
+
|
|
124
|
+
return res.json({
|
|
125
|
+
message: 'API key deleted successfully',
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Record key usage
|
|
130
|
+
apiKeysRoutes.post('/:id/usage', (req, res) => {
|
|
131
|
+
const keyId = req.params.id;
|
|
132
|
+
|
|
133
|
+
const key = db.keys.findById(req.user.userId, keyId);
|
|
134
|
+
if (!key) {
|
|
135
|
+
return res.status(404).json({ error: 'API key not found' });
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
db.keys.recordUsage(req.user.userId, keyId);
|
|
139
|
+
|
|
140
|
+
return res.json({
|
|
141
|
+
message: 'API key usage recorded',
|
|
142
|
+
});
|
|
143
|
+
});
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import bcrypt from 'bcryptjs';
|
|
3
|
+
import { db } from '../utils/db.js';
|
|
4
|
+
import { generateToken } from '../utils/jwt.js';
|
|
5
|
+
|
|
6
|
+
export const authRoutes = express.Router();
|
|
7
|
+
|
|
8
|
+
// Register
|
|
9
|
+
authRoutes.post('/register', async (req, res) => {
|
|
10
|
+
try {
|
|
11
|
+
const { email, password } = req.body;
|
|
12
|
+
|
|
13
|
+
if (!email || !password) {
|
|
14
|
+
return res.status(400).json({
|
|
15
|
+
error: 'Email and password are required'
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const existingUser = db.users.findByEmail(email);
|
|
20
|
+
if (existingUser) {
|
|
21
|
+
return res.status(409).json({
|
|
22
|
+
error: 'User already exists'
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const hashedPassword = await bcrypt.hash(password, 10);
|
|
27
|
+
const user = db.users.create(email, hashedPassword);
|
|
28
|
+
|
|
29
|
+
const token = generateToken(user.id, user.email);
|
|
30
|
+
|
|
31
|
+
return res.status(201).json({
|
|
32
|
+
message: 'User registered successfully',
|
|
33
|
+
user: { id: user.id, email: user.email },
|
|
34
|
+
token,
|
|
35
|
+
});
|
|
36
|
+
} catch (error) {
|
|
37
|
+
return res.status(500).json({
|
|
38
|
+
error: error.message
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Login
|
|
44
|
+
authRoutes.post('/login', async (req, res) => {
|
|
45
|
+
try {
|
|
46
|
+
const { email, password } = req.body;
|
|
47
|
+
|
|
48
|
+
if (!email || !password) {
|
|
49
|
+
return res.status(400).json({
|
|
50
|
+
error: 'Email and password are required'
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const user = db.users.findByEmail(email);
|
|
55
|
+
if (!user) {
|
|
56
|
+
return res.status(401).json({
|
|
57
|
+
error: 'Invalid email or password'
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const isPasswordValid = await bcrypt.compare(password, user.password);
|
|
62
|
+
if (!isPasswordValid) {
|
|
63
|
+
return res.status(401).json({
|
|
64
|
+
error: 'Invalid email or password'
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const token = generateToken(user.id, user.email);
|
|
69
|
+
|
|
70
|
+
return res.json({
|
|
71
|
+
message: 'Login successful',
|
|
72
|
+
user: { id: user.id, email: user.email },
|
|
73
|
+
token,
|
|
74
|
+
});
|
|
75
|
+
} catch (error) {
|
|
76
|
+
return res.status(500).json({
|
|
77
|
+
error: error.message
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Get current user
|
|
83
|
+
authRoutes.get('/me', (req, res) => {
|
|
84
|
+
const token = req.headers['authorization']?.split(' ')[1];
|
|
85
|
+
|
|
86
|
+
if (!token) {
|
|
87
|
+
return res.status(401).json({ error: 'Missing authorization token' });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const user = db.users.findByEmail(req.query.email);
|
|
91
|
+
|
|
92
|
+
return res.json({
|
|
93
|
+
message: 'User retrieved successfully',
|
|
94
|
+
user: user ? { id: user.id, email: user.email } : null,
|
|
95
|
+
});
|
|
96
|
+
});
|
package/src/server.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import cors from 'cors';
|
|
3
|
+
import { authMiddleware } from './middleware/auth.js';
|
|
4
|
+
import { apiKeysRoutes } from './routes/apiKeys.js';
|
|
5
|
+
import { authRoutes } from './routes/auth.js';
|
|
6
|
+
|
|
7
|
+
const app = express();
|
|
8
|
+
|
|
9
|
+
app.use(express.json());
|
|
10
|
+
app.use(cors());
|
|
11
|
+
|
|
12
|
+
// Health check
|
|
13
|
+
app.get('/', (req, res) => {
|
|
14
|
+
res.json({ message: 'API Keys Creator System running' });
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
// Public auth routes
|
|
18
|
+
app.use('/auth', authRoutes);
|
|
19
|
+
|
|
20
|
+
// Protected API routes
|
|
21
|
+
app.use('/api/keys', authMiddleware, apiKeysRoutes);
|
|
22
|
+
|
|
23
|
+
// Error handling
|
|
24
|
+
app.use((err, req, res, next) => {
|
|
25
|
+
console.error('Error:', err);
|
|
26
|
+
res.status(err.status || 500).json({
|
|
27
|
+
error: err.message || 'Internal Server Error',
|
|
28
|
+
code: err.code || 'INTERNAL_ERROR'
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// 404 handler
|
|
33
|
+
app.use((req, res) => {
|
|
34
|
+
res.status(404).json({ error: 'Not Found' });
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const PORT = process.env.PORT || 3000;
|
|
38
|
+
|
|
39
|
+
app.listen(PORT, () => {
|
|
40
|
+
console.log(`โ API Keys Creator System running on http://localhost:${PORT}`);
|
|
41
|
+
});
|
package/src/utils/db.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
|
|
5
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const USERS_DB = path.join(__dirname, '../data/users.json');
|
|
7
|
+
const KEYS_DB = path.join(__dirname, '../data/keys.json');
|
|
8
|
+
|
|
9
|
+
const ensureDir = () => {
|
|
10
|
+
const dir = path.dirname(USERS_DB);
|
|
11
|
+
if (!fs.existsSync(dir)) {
|
|
12
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const ensureFile = (filepath, defaultContent = {}) => {
|
|
17
|
+
ensureDir();
|
|
18
|
+
if (!fs.existsSync(filepath)) {
|
|
19
|
+
fs.writeFileSync(filepath, JSON.stringify(defaultContent, null, 2));
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const db = {
|
|
24
|
+
users: {
|
|
25
|
+
readAll: () => {
|
|
26
|
+
ensureFile(USERS_DB, {});
|
|
27
|
+
const data = fs.readFileSync(USERS_DB, 'utf-8');
|
|
28
|
+
return JSON.parse(data);
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
write: (users) => {
|
|
32
|
+
ensureFile(USERS_DB, {});
|
|
33
|
+
fs.writeFileSync(USERS_DB, JSON.stringify(users, null, 2));
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
findByEmail: (email) => {
|
|
37
|
+
const users = db.users.readAll();
|
|
38
|
+
return users[email];
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
create: (email, hashedPassword) => {
|
|
42
|
+
const users = db.users.readAll();
|
|
43
|
+
const userId = Date.now().toString();
|
|
44
|
+
users[email] = {
|
|
45
|
+
id: userId,
|
|
46
|
+
email,
|
|
47
|
+
password: hashedPassword,
|
|
48
|
+
createdAt: new Date().toISOString(),
|
|
49
|
+
};
|
|
50
|
+
db.users.write(users);
|
|
51
|
+
return users[email];
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
keys: {
|
|
56
|
+
readAll: () => {
|
|
57
|
+
ensureFile(KEYS_DB, {});
|
|
58
|
+
const data = fs.readFileSync(KEYS_DB, 'utf-8');
|
|
59
|
+
return JSON.parse(data);
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
write: (keys) => {
|
|
63
|
+
ensureFile(KEYS_DB, {});
|
|
64
|
+
fs.writeFileSync(KEYS_DB, JSON.stringify(keys, null, 2));
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
create: (userId, keyName) => {
|
|
68
|
+
const keys = db.keys.readAll();
|
|
69
|
+
const keyId = Date.now().toString();
|
|
70
|
+
|
|
71
|
+
if (!keys[userId]) {
|
|
72
|
+
keys[userId] = [];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const newKey = {
|
|
76
|
+
id: keyId,
|
|
77
|
+
name: keyName,
|
|
78
|
+
key: `sk_${Math.random().toString(36).substr(2, 32)}`,
|
|
79
|
+
createdAt: new Date().toISOString(),
|
|
80
|
+
lastUsed: null,
|
|
81
|
+
active: true,
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
keys[userId].push(newKey);
|
|
85
|
+
db.keys.write(keys);
|
|
86
|
+
|
|
87
|
+
return newKey;
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
findByUserId: (userId) => {
|
|
91
|
+
const keys = db.keys.readAll();
|
|
92
|
+
return keys[userId] || [];
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
findById: (userId, keyId) => {
|
|
96
|
+
const userKeys = db.keys.findByUserId(userId);
|
|
97
|
+
return userKeys.find(k => k.id === keyId);
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
update: (userId, keyId, updates) => {
|
|
101
|
+
const keys = db.keys.readAll();
|
|
102
|
+
if (!keys[userId]) return null;
|
|
103
|
+
|
|
104
|
+
const keyIndex = keys[userId].findIndex(k => k.id === keyId);
|
|
105
|
+
if (keyIndex === -1) return null;
|
|
106
|
+
|
|
107
|
+
keys[userId][keyIndex] = {
|
|
108
|
+
...keys[userId][keyIndex],
|
|
109
|
+
...updates,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
db.keys.write(keys);
|
|
113
|
+
return keys[userId][keyIndex];
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
delete: (userId, keyId) => {
|
|
117
|
+
const keys = db.keys.readAll();
|
|
118
|
+
if (!keys[userId]) return false;
|
|
119
|
+
|
|
120
|
+
const initialLength = keys[userId].length;
|
|
121
|
+
keys[userId] = keys[userId].filter(k => k.id !== keyId);
|
|
122
|
+
|
|
123
|
+
if (keys[userId].length < initialLength) {
|
|
124
|
+
db.keys.write(keys);
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return false;
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
recordUsage: (userId, keyId) => {
|
|
132
|
+
return db.keys.update(userId, keyId, {
|
|
133
|
+
lastUsed: new Date().toISOString(),
|
|
134
|
+
});
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
};
|
package/src/utils/jwt.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import jwt from 'jsonwebtoken';
|
|
2
|
+
|
|
3
|
+
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key-change-in-production';
|
|
4
|
+
const TOKEN_EXPIRY = '24h';
|
|
5
|
+
|
|
6
|
+
export const generateToken = (userId, email) => {
|
|
7
|
+
return jwt.sign(
|
|
8
|
+
{ userId, email },
|
|
9
|
+
JWT_SECRET,
|
|
10
|
+
{ expiresIn: TOKEN_EXPIRY }
|
|
11
|
+
);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const verifyToken = (token) => {
|
|
15
|
+
try {
|
|
16
|
+
return jwt.verify(token, JWT_SECRET);
|
|
17
|
+
} catch (error) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const generateApiKey = () => {
|
|
23
|
+
return `sk_${Math.random().toString(36).substr(2, 48)}`;
|
|
24
|
+
};
|
package/test.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const BASE_URL = 'http://localhost:3000';
|
|
4
|
+
|
|
5
|
+
async function test() {
|
|
6
|
+
try {
|
|
7
|
+
console.log('๐งช Testing API Keys Creator System\n');
|
|
8
|
+
|
|
9
|
+
// Test 1: Health check
|
|
10
|
+
console.log('1. Testing health check...');
|
|
11
|
+
let res = await fetch(`${BASE_URL}/`);
|
|
12
|
+
let data = await res.json();
|
|
13
|
+
console.log(` โ ${data.message}\n`);
|
|
14
|
+
|
|
15
|
+
// Test 2: Register
|
|
16
|
+
console.log('2. Testing registration...');
|
|
17
|
+
res = await fetch(`${BASE_URL}/auth/register`, {
|
|
18
|
+
method: 'POST',
|
|
19
|
+
headers: { 'Content-Type': 'application/json' },
|
|
20
|
+
body: JSON.stringify({
|
|
21
|
+
email: 'test@example.com',
|
|
22
|
+
password: 'testpass123'
|
|
23
|
+
})
|
|
24
|
+
});
|
|
25
|
+
data = await res.json();
|
|
26
|
+
if (!res.ok) {
|
|
27
|
+
console.log(` โ Registration (second attempt) - ${data.error}\n`);
|
|
28
|
+
} else {
|
|
29
|
+
console.log(` โ User registered: ${data.user.email}`);
|
|
30
|
+
console.log(` โ Token: ${data.token.substring(0, 30)}...\n`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Test 3: Login
|
|
34
|
+
console.log('3. Testing login...');
|
|
35
|
+
res = await fetch(`${BASE_URL}/auth/login`, {
|
|
36
|
+
method: 'POST',
|
|
37
|
+
headers: { 'Content-Type': 'application/json' },
|
|
38
|
+
body: JSON.stringify({
|
|
39
|
+
email: 'test@example.com',
|
|
40
|
+
password: 'testpass123'
|
|
41
|
+
})
|
|
42
|
+
});
|
|
43
|
+
data = await res.json();
|
|
44
|
+
const token = data.token;
|
|
45
|
+
console.log(` โ Login successful`);
|
|
46
|
+
console.log(` โ Token: ${token.substring(0, 30)}...\n`);
|
|
47
|
+
|
|
48
|
+
// Test 4: Create API Key
|
|
49
|
+
console.log('4. Testing API key creation...');
|
|
50
|
+
res = await fetch(`${BASE_URL}/api/keys`, {
|
|
51
|
+
method: 'POST',
|
|
52
|
+
headers: {
|
|
53
|
+
'Content-Type': 'application/json',
|
|
54
|
+
'Authorization': `Bearer ${token}`
|
|
55
|
+
},
|
|
56
|
+
body: JSON.stringify({ name: 'Test Key' })
|
|
57
|
+
});
|
|
58
|
+
data = await res.json();
|
|
59
|
+
const keyId = data.key.id;
|
|
60
|
+
console.log(` โ API Key created: ${data.key.name}`);
|
|
61
|
+
console.log(` โ Key: ${data.key.key}\n`);
|
|
62
|
+
|
|
63
|
+
// Test 5: List API Keys
|
|
64
|
+
console.log('5. Testing list API keys...');
|
|
65
|
+
res = await fetch(`${BASE_URL}/api/keys`, {
|
|
66
|
+
headers: { 'Authorization': `Bearer ${token}` }
|
|
67
|
+
});
|
|
68
|
+
data = await res.json();
|
|
69
|
+
console.log(` โ Found ${data.count} key(s)\n`);
|
|
70
|
+
|
|
71
|
+
// Test 6: Get single key
|
|
72
|
+
console.log('6. Testing get single key...');
|
|
73
|
+
res = await fetch(`${BASE_URL}/api/keys/${keyId}`, {
|
|
74
|
+
headers: { 'Authorization': `Bearer ${token}` }
|
|
75
|
+
});
|
|
76
|
+
data = await res.json();
|
|
77
|
+
console.log(` โ Retrieved: ${data.key.name}\n`);
|
|
78
|
+
|
|
79
|
+
// Test 7: Update key
|
|
80
|
+
console.log('7. Testing update key...');
|
|
81
|
+
res = await fetch(`${BASE_URL}/api/keys/${keyId}`, {
|
|
82
|
+
method: 'PUT',
|
|
83
|
+
headers: {
|
|
84
|
+
'Content-Type': 'application/json',
|
|
85
|
+
'Authorization': `Bearer ${token}`
|
|
86
|
+
},
|
|
87
|
+
body: JSON.stringify({ name: 'Updated Test Key', active: false })
|
|
88
|
+
});
|
|
89
|
+
data = await res.json();
|
|
90
|
+
console.log(` โ Updated: ${data.key.name} (active: ${data.key.active})\n`);
|
|
91
|
+
|
|
92
|
+
// Test 8: Record usage
|
|
93
|
+
console.log('8. Testing record usage...');
|
|
94
|
+
res = await fetch(`${BASE_URL}/api/keys/${keyId}/usage`, {
|
|
95
|
+
method: 'POST',
|
|
96
|
+
headers: { 'Authorization': `Bearer ${token}` }
|
|
97
|
+
});
|
|
98
|
+
data = await res.json();
|
|
99
|
+
console.log(` โ ${data.message}\n`);
|
|
100
|
+
|
|
101
|
+
// Test 9: Delete key
|
|
102
|
+
console.log('9. Testing delete key...');
|
|
103
|
+
res = await fetch(`${BASE_URL}/api/keys/${keyId}`, {
|
|
104
|
+
method: 'DELETE',
|
|
105
|
+
headers: { 'Authorization': `Bearer ${token}` }
|
|
106
|
+
});
|
|
107
|
+
data = await res.json();
|
|
108
|
+
console.log(` โ ${data.message}\n`);
|
|
109
|
+
|
|
110
|
+
console.log('โ
All tests passed!');
|
|
111
|
+
process.exit(0);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error('โ Test failed:', error.message);
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
test();
|