free-framework 4.5.3 → 4.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/commands/build.js +5 -0
- package/package.json +1 -1
- package/templates/app-template/resources/views/counter.free +19 -0
- package/templates/app-template/resources/views/header.free +18 -0
- package/templates/app-template/app/controllers/AuthController.free +0 -42
- package/templates/app-template/app/middleware/auth.js +0 -25
- package/templates/app-template/app/views/counter.free +0 -23
- package/templates/app-template/app/views/header.free +0 -13
package/cli/commands/build.js
CHANGED
|
@@ -46,7 +46,12 @@ module.exports = function () {
|
|
|
46
46
|
let combinedAST = [];
|
|
47
47
|
|
|
48
48
|
console.log(`🔍 Found ${freeFiles.length} files to process.`);
|
|
49
|
+
const processedFiles = new Set();
|
|
49
50
|
freeFiles.forEach(filePath => {
|
|
51
|
+
const absolutePath = path.resolve(filePath);
|
|
52
|
+
if (processedFiles.has(absolutePath)) return;
|
|
53
|
+
processedFiles.add(absolutePath);
|
|
54
|
+
|
|
50
55
|
const file = path.basename(filePath);
|
|
51
56
|
console.log(` 📄 Processing ${file}...`);
|
|
52
57
|
const code = fs.readFileSync(filePath, "utf-8");
|
package/package.json
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
component Counter {
|
|
2
|
+
state {
|
|
3
|
+
count: 0
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
div {
|
|
7
|
+
class "p-4 bg-gray-800 rounded-lg text-center"
|
|
8
|
+
h2 { text "Reactive Counter" }
|
|
9
|
+
p {
|
|
10
|
+
class "text-4xl font-black text-primary my-4"
|
|
11
|
+
text "{count}"
|
|
12
|
+
}
|
|
13
|
+
button {
|
|
14
|
+
class "px-6 py-2 bg-primary text-dark font-bold rounded-full hover:scale-105 transition-transform"
|
|
15
|
+
text "Increment"
|
|
16
|
+
on-click { state.count++ }
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
component Header {
|
|
2
|
+
header {
|
|
3
|
+
class "fixed top-0 left-0 w-full p-6 flex justify-between items-center backdrop-blur-md bg-black/50 z-50 border-b border-white/10"
|
|
4
|
+
|
|
5
|
+
div {
|
|
6
|
+
class "text-2xl font-black italic tracking-tighter"
|
|
7
|
+
span { class "text-primary"; text "FREE" }
|
|
8
|
+
text " APP"
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
nav {
|
|
12
|
+
class "flex gap-8 font-medium text-sm letter-spacing-1"
|
|
13
|
+
a { href "/"; text "HOME" }
|
|
14
|
+
a { href "/dashboard"; text "DASHBOARD" }
|
|
15
|
+
a { href "/login"; text "LOGIN"; class "text-primary" }
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AuthController.free
|
|
3
|
-
* Default Authentication Logic (Login, Register).
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
action register {
|
|
7
|
-
const { name, email, password } = body;
|
|
8
|
-
if (!name || !email || !password) throw new Error("Missing credentials");
|
|
9
|
-
|
|
10
|
-
const bcrypt = require('bcryptjs');
|
|
11
|
-
const hashedPassword = await bcrypt.hash(password, 10);
|
|
12
|
-
|
|
13
|
-
const user = await User.create( { name, email, password: hashedPassword });
|
|
14
|
-
|
|
15
|
-
// Generate JWT
|
|
16
|
-
const jwt = require('jsonwebtoken');
|
|
17
|
-
const secret = process.env.JWT_SECRET || 'super_secret_jwt_key_that_should_be_long_and_random';
|
|
18
|
-
const token = jwt.sign( { id: user.id, email: user.email, role: user.role }, secret, { expiresIn: '7d' });
|
|
19
|
-
|
|
20
|
-
return { success: true, token, user: { id: user.id, name: user.name, email: user.email } };
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
action login {
|
|
24
|
-
const { email, password } = body;
|
|
25
|
-
if (!email || !password) throw new Error("Missing credentials");
|
|
26
|
-
|
|
27
|
-
const userQuery = await User.query().where( { email }).get();
|
|
28
|
-
const user = userQuery[0];
|
|
29
|
-
|
|
30
|
-
if (!user) throw new Error("Invalid credentials");
|
|
31
|
-
|
|
32
|
-
const bcrypt = require('bcryptjs');
|
|
33
|
-
const isMatch = await bcrypt.compare(password, user.password);
|
|
34
|
-
if (!isMatch) throw new Error("Invalid credentials");
|
|
35
|
-
|
|
36
|
-
// Generate JWT
|
|
37
|
-
const jwt = require('jsonwebtoken');
|
|
38
|
-
const secret = process.env.JWT_SECRET || 'super_secret_jwt_key_that_should_be_long_and_random';
|
|
39
|
-
const token = jwt.sign( { id: user.id, email: user.email, role: user.role }, secret, { expiresIn: '7d' });
|
|
40
|
-
|
|
41
|
-
return { success: true, token, user: { id: user.id, name: user.name, email: user.email } };
|
|
42
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* app/middleware/auth.js
|
|
3
|
-
* Default JWT Authentication Guard
|
|
4
|
-
*/
|
|
5
|
-
const jwt = require('jsonwebtoken');
|
|
6
|
-
|
|
7
|
-
module.exports = async function authGuard(req, res, next) {
|
|
8
|
-
const authHeader = req.headers['authorization'];
|
|
9
|
-
const token = authHeader && authHeader.split(' ')[1];
|
|
10
|
-
|
|
11
|
-
if (!token) {
|
|
12
|
-
res.writeHead(401, { 'Content-Type': 'application/json' });
|
|
13
|
-
res.end(JSON.stringify({ error: 'Unauthorized: No token provided' }));
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
try {
|
|
18
|
-
const decoded = jwt.verify(token, process.env.JWT_SECRET || 'super_secret_jwt_key_that_should_be_long_and_random');
|
|
19
|
-
req.user = decoded; // Attach user payload to request
|
|
20
|
-
next();
|
|
21
|
-
} catch (err) {
|
|
22
|
-
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
23
|
-
res.end(JSON.stringify({ error: 'Forbidden: Invalid or expired token' }));
|
|
24
|
-
}
|
|
25
|
-
};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
component Counter {
|
|
2
|
-
state count = 0
|
|
3
|
-
|
|
4
|
-
div class="glass p-8 flex flex-col items-center gap-6 max-w-sm mx-auto mt-20" {
|
|
5
|
-
h2 class="text-2xl font-bold" {
|
|
6
|
-
text "Interactive Island"
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
div class="text-6xl font-black text-glow" {
|
|
10
|
-
span class="state-bind" data-bind="count" { text "{count}" }
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
div class="flex gap-4" {
|
|
14
|
-
button class="btn-premium" onclick="count++" {
|
|
15
|
-
text "Increment"
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
button class="px-6 py-3 bg-white/10 hover:bg-white/20 rounded-xl transition-all" onclick="Free.call('addTask', { title: 'Count is ' + state.count }).then(() => alert('Saved!'))" {
|
|
19
|
-
text "Save Task to DB"
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
component Header {
|
|
2
|
-
nav class="fixed top-0 left-0 right-0 z-50 px-8 py-4 glass flex justify-between items-center m-4" {
|
|
3
|
-
h1 class="text-xl font-black text-glow" {
|
|
4
|
-
text "Free Ultra"
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
div class="flex gap-6 text-sm font-medium opacity-70" {
|
|
8
|
-
link "Docs" "/docs" class="hover:text-primary transition-colors"
|
|
9
|
-
link "Benchmarks" "/benchmarks" class="hover:text-primary transition-colors"
|
|
10
|
-
link "Community" "/community" class="hover:text-primary transition-colors"
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
}
|