arikajs 0.10.2 → 0.10.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.
Files changed (76) hide show
  1. package/dist/Application.d.ts +1 -1
  2. package/dist/Application.d.ts.map +1 -1
  3. package/dist/Application.js +15 -1
  4. package/dist/Application.js.map +1 -1
  5. package/dist/facades/Schedule.d.ts +8 -0
  6. package/dist/facades/Schedule.d.ts.map +1 -0
  7. package/dist/facades/Schedule.js +25 -0
  8. package/dist/facades/Schedule.js.map +1 -0
  9. package/dist/helpers.d.ts +17 -1
  10. package/dist/helpers.d.ts.map +1 -1
  11. package/dist/helpers.js +44 -2
  12. package/dist/helpers.js.map +1 -1
  13. package/dist/http/Handler.d.ts +4 -0
  14. package/dist/http/Handler.d.ts.map +1 -1
  15. package/dist/http/Handler.js +348 -1
  16. package/dist/http/Handler.js.map +1 -1
  17. package/dist/http/Kernel.d.ts.map +1 -1
  18. package/dist/http/Kernel.js +15 -13
  19. package/dist/http/Kernel.js.map +1 -1
  20. package/dist/http/Middleware/ViewMiddleware.d.ts.map +1 -1
  21. package/dist/http/Middleware/ViewMiddleware.js +31 -5
  22. package/dist/http/Middleware/ViewMiddleware.js.map +1 -1
  23. package/dist/index.d.ts +9 -3
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +19 -3
  26. package/dist/index.js.map +1 -1
  27. package/dist/providers/FrameworkServiceProvider.d.ts.map +1 -1
  28. package/dist/providers/FrameworkServiceProvider.js +2 -0
  29. package/dist/providers/FrameworkServiceProvider.js.map +1 -1
  30. package/dist/providers/QueueServiceProvider.d.ts.map +1 -1
  31. package/dist/providers/QueueServiceProvider.js +2 -7
  32. package/dist/providers/QueueServiceProvider.js.map +1 -1
  33. package/dist/providers/StorageServiceProvider.d.ts +12 -0
  34. package/dist/providers/StorageServiceProvider.d.ts.map +1 -0
  35. package/dist/providers/StorageServiceProvider.js +41 -0
  36. package/dist/providers/StorageServiceProvider.js.map +1 -0
  37. package/dist/providers/ViewServiceProvider.d.ts.map +1 -1
  38. package/dist/providers/ViewServiceProvider.js +4 -0
  39. package/dist/providers/ViewServiceProvider.js.map +1 -1
  40. package/package.json +27 -22
  41. package/CHANGELOG.md +0 -124
  42. package/src/Application.ts +0 -236
  43. package/src/Contracts/Application.ts +0 -24
  44. package/src/createApp.ts +0 -9
  45. package/src/helpers.ts +0 -106
  46. package/src/http/Handler.ts +0 -184
  47. package/src/http/Kernel.ts +0 -108
  48. package/src/http/Middleware/RequestLoggingMiddleware.ts +0 -17
  49. package/src/http/Middleware/ServeStaticMiddleware.ts +0 -34
  50. package/src/http/Middleware/ValidateRequestMiddleware.ts +0 -35
  51. package/src/http/Middleware/VerifyCsrfToken.ts +0 -101
  52. package/src/http/Middleware/ViewMiddleware.ts +0 -24
  53. package/src/http/views/errors/401.ark.html +0 -57
  54. package/src/http/views/errors/403.ark.html +0 -54
  55. package/src/http/views/errors/404.ark.html +0 -179
  56. package/src/http/views/errors/419.ark.html +0 -54
  57. package/src/http/views/errors/429.ark.html +0 -54
  58. package/src/http/views/errors/500.ark.html +0 -54
  59. package/src/http/views/errors/503.ark.html +0 -49
  60. package/src/index.ts +0 -75
  61. package/src/providers/AuthServiceProvider.ts +0 -28
  62. package/src/providers/CacheServiceProvider.ts +0 -29
  63. package/src/providers/DatabaseServiceProvider.ts +0 -46
  64. package/src/providers/EventsServiceProvider.ts +0 -19
  65. package/src/providers/FrameworkServiceProvider.ts +0 -44
  66. package/src/providers/HttpServiceProvider.ts +0 -37
  67. package/src/providers/LoggingServiceProvider.ts +0 -17
  68. package/src/providers/MailServiceProvider.ts +0 -33
  69. package/src/providers/QueueServiceProvider.ts +0 -36
  70. package/src/providers/SchedulerServiceProvider.ts +0 -18
  71. package/src/providers/SessionServiceProvider.ts +0 -68
  72. package/src/providers/TranslationServiceProvider.ts +0 -51
  73. package/src/providers/ValidationServiceProvider.ts +0 -24
  74. package/src/providers/ViewServiceProvider.ts +0 -46
  75. package/tests/Framework.test.ts +0 -140
  76. package/tsconfig.json +0 -25
@@ -1,108 +0,0 @@
1
- import { Application } from '../Contracts/Application';
2
- import { Request, Response, NotFoundHttpException } from '@arikajs/http';
3
- import { Pipeline } from '@arikajs/middleware';
4
- import { Dispatcher } from '@arikajs/dispatcher';
5
- import { RequestLoggingMiddleware } from './Middleware/RequestLoggingMiddleware';
6
- import { BodyParserMiddleware, CorsMiddleware, TrimStrings, ConvertEmptyStringsToNull, SecurityHeaders, Throttle } from '@arikajs/http';
7
- import { Handler } from './Handler';
8
- import { ViewMiddleware } from './Middleware/ViewMiddleware';
9
- import { VerifyCsrfToken } from './Middleware/VerifyCsrfToken';
10
- import { ServeStaticMiddleware } from './Middleware/ServeStaticMiddleware';
11
- import { StartSession } from '@arikajs/session';
12
- import { Authenticate, EnsureEmailIsVerified } from '@arikajs/auth';
13
-
14
-
15
- export class Kernel {
16
- /**
17
- * The application's global HTTP middleware stack.
18
- */
19
- protected middleware: any[] = [
20
- new CorsMiddleware(),
21
- new SecurityHeaders(),
22
- new RequestLoggingMiddleware(),
23
- new BodyParserMiddleware(),
24
- new TrimStrings(),
25
- new ConvertEmptyStringsToNull(),
26
- new ServeStaticMiddleware(),
27
- ];
28
-
29
- /**
30
- * The application's route middleware groups.
31
- */
32
- protected middlewareGroups: Record<string, any[]> = {
33
- web: [
34
- StartSession,
35
- ViewMiddleware,
36
- VerifyCsrfToken,
37
- ],
38
- api: [],
39
- };
40
-
41
- /**
42
- * The application's route middleware.
43
- */
44
- protected routeMiddleware: Record<string, any> = {
45
- 'auth': Authenticate,
46
- 'verified': EnsureEmailIsVerified,
47
- 'throttle': Throttle,
48
- };
49
-
50
- protected handler: Handler;
51
-
52
- constructor(protected app: Application) {
53
- try {
54
- this.handler = this.app.make(Handler);
55
- } catch (e) {
56
- this.handler = new Handler();
57
- }
58
-
59
- const router = this.app.getRouter();
60
- if ((router as any).setMiddlewareGroups) {
61
- (router as any).setMiddlewareGroups(this.middlewareGroups);
62
- }
63
- if ((router as any).setRouteMiddleware) {
64
- (router as any).setRouteMiddleware(this.routeMiddleware);
65
- }
66
- }
67
-
68
- /**
69
- * Handle an incoming HTTP request.
70
- */
71
- public async handle(request: Request, response: Response): Promise<Response> {
72
- try {
73
- const pipeline = new Pipeline<Request, Response>(this.app.getContainer());
74
- pipeline.setMiddlewareGroups(this.middlewareGroups);
75
- pipeline.setAliases(this.routeMiddleware);
76
-
77
- return await pipeline.pipe(this.middleware)
78
- .handle(request, async (req: Request) => {
79
- return this.dispatchToRouter(req, response);
80
- }, response);
81
- } catch (error: any) {
82
- this.handler.report(error);
83
- return await this.handler.render(request, error, response);
84
- }
85
- }
86
-
87
- /**
88
- * Dispatch the request to the router.
89
- */
90
- protected async dispatchToRouter(request: Request, response: Response): Promise<Response> {
91
- const router = this.app.getRouter();
92
-
93
- const result = await router.dispatch(request, response);
94
-
95
- if (result === null) {
96
- throw new NotFoundHttpException(`Route not found: [${request.method()}] ${request.path()}`);
97
- }
98
-
99
- return result as Response;
100
- }
101
-
102
- /**
103
- * Send the response back to the client.
104
- */
105
- public terminate(request: Request, response: Response): void {
106
- response.terminate();
107
- }
108
- }
@@ -1,17 +0,0 @@
1
-
2
- import { Log } from '@arikajs/logging';
3
-
4
- export class RequestLoggingMiddleware {
5
- public async handle(request: any, next: (request: any) => Promise<any>): Promise<any> {
6
- const start = Date.now();
7
- const method = request.method();
8
- const url = request.path();
9
-
10
- const response = await next(request);
11
-
12
- const duration = Date.now() - start;
13
- Log.info(`${method} ${url} - ${duration}ms`);
14
-
15
- return response;
16
- }
17
- }
@@ -1,34 +0,0 @@
1
- import { Request, Response } from '@arikajs/http';
2
- import serveStatic from 'serve-static';
3
- import path from 'path';
4
-
5
- export class ServeStaticMiddleware {
6
- private serve: ReturnType<typeof serveStatic>;
7
-
8
- constructor(publicPath: string = path.join(process.cwd(), 'public')) {
9
- this.serve = serveStatic(publicPath, {
10
- index: false,
11
- fallthrough: true,
12
- });
13
- }
14
-
15
- public async handle(request: Request, next: (req: Request) => Promise<Response>, response: Response): Promise<Response> {
16
- return new Promise((resolve, reject) => {
17
- const req = request.getIncomingMessage();
18
- const res = response.getOriginalResponse();
19
-
20
- this.serve(req as any, res as any, async (err: any) => {
21
- if (err) {
22
- return reject(err);
23
- }
24
-
25
- try {
26
- const result = await next(request);
27
- resolve(result);
28
- } catch (e) {
29
- reject(e);
30
- }
31
- });
32
- });
33
- }
34
- }
@@ -1,35 +0,0 @@
1
-
2
- import { Request, Response } from '@arikajs/http';
3
- import { Validator } from '@arikajs/validation';
4
-
5
- export class ValidateRequestMiddleware {
6
- protected rules: Record<string, any> = {};
7
-
8
- /**
9
- * Set the validation rules.
10
- */
11
- public using(rules: Record<string, any>): this {
12
- this.rules = rules;
13
- return this;
14
- }
15
-
16
- /**
17
- * Handle the incoming request.
18
- */
19
- public async handle(request: Request, next: (request: Request) => Promise<Response>, response: Response): Promise<Response> {
20
- if (Object.keys(this.rules).length === 0) {
21
- return next(request);
22
- }
23
-
24
- const validator = new Validator(request.all(), this.rules);
25
-
26
- if (await validator.fails()) {
27
- return response.status(422).json({
28
- message: 'The given data was invalid.',
29
- errors: validator.errors()
30
- });
31
- }
32
-
33
- return next(request);
34
- }
35
- }
@@ -1,101 +0,0 @@
1
-
2
- import { Request, Response, Middleware } from '@arikajs/http';
3
- import { HttpException } from '@arikajs/http';
4
- import crypto from 'node:crypto';
5
-
6
- export class VerifyCsrfToken implements Middleware {
7
- /**
8
- * The URIs that should be excluded from CSRF verification.
9
- */
10
- protected except: string[] = [];
11
-
12
- /**
13
- * Handle the incoming request.
14
- */
15
- public async handle(request: Request, next: (request: Request) => Promise<Response>): Promise<Response> {
16
- if (this.isReading(request) || this.runningUnitTests() || await this.inExceptArray(request)) {
17
- return await this.addCookieToResponse(request, await next(request));
18
- }
19
-
20
- if (await this.tokensMatch(request)) {
21
- return await this.addCookieToResponse(request, await next(request));
22
- }
23
-
24
- throw new HttpException(419, 'CSRF token mismatch.');
25
- }
26
-
27
- /**
28
- * Determine if the request has a URI that should pass through CSRF verification.
29
- */
30
- protected async inExceptArray(request: Request): Promise<boolean> {
31
- const path = request.path();
32
- for (const except of this.except) {
33
- if (except === '/') {
34
- if (path === '/') return true;
35
- continue;
36
- }
37
- if (path.startsWith(except)) {
38
- return true;
39
- }
40
- }
41
- return false;
42
- }
43
-
44
- /**
45
- * Determine if the session and input tokens match.
46
- */
47
- protected async tokensMatch(request: Request): Promise<boolean> {
48
- const token = await this.getTokenFromRequest(request);
49
- const sessionToken = await request.session.get('_token');
50
-
51
- if (!token || !sessionToken || token.length !== sessionToken.length) {
52
- return false;
53
- }
54
-
55
- return crypto.timingSafeEqual(Buffer.from(token), Buffer.from(sessionToken));
56
- }
57
-
58
- /**
59
- * Get the CSRF token from the request.
60
- */
61
- protected async getTokenFromRequest(request: Request): Promise<string | null> {
62
- const token = request.input('_token') || request.header('X-CSRF-TOKEN') || request.header('X-XSRF-TOKEN');
63
-
64
- if (!token) {
65
- return null;
66
- }
67
-
68
- return token;
69
- }
70
-
71
- /**
72
- * Determine if the HTTP request uses a read-only method.
73
- */
74
- protected isReading(request: Request): boolean {
75
- return ['GET', 'HEAD', 'OPTIONS'].includes(request.method());
76
- }
77
-
78
- /**
79
- * Determine if the application is running unit tests.
80
- */
81
- protected runningUnitTests(): boolean {
82
- return process.env.NODE_ENV === 'test';
83
- }
84
-
85
- /**
86
- * Add the CSRF token to the response cookies.
87
- */
88
- protected async addCookieToResponse(request: Request, response: Response): Promise<Response> {
89
- const token = await request.session.get('_token');
90
- if (token) {
91
- const config = (request as any).app.config();
92
- response.cookie('XSRF-TOKEN', token, {
93
- path: '/',
94
- httpOnly: false,
95
- sameSite: 'lax',
96
- secure: config.get('session.secure', false)
97
- });
98
- }
99
- return response;
100
- }
101
- }
@@ -1,24 +0,0 @@
1
-
2
- import { View } from '@arikajs/view';
3
- import crypto from 'node:crypto';
4
-
5
- export class ViewMiddleware {
6
- constructor(private view: View) { }
7
-
8
- public async handle(request: any, next: (request: any) => Promise<any>): Promise<any> {
9
- // Attach the view engine to the request object
10
- request.view = this.view;
11
-
12
- // Ensure CSRF token exists in session and share it with views
13
- if (request.session) {
14
- let token = await request.session.get('_token');
15
- if (!token) {
16
- token = crypto.randomBytes(40).toString('hex');
17
- await request.session.set('_token', token);
18
- }
19
- this.view.share('_csrf', token);
20
- }
21
-
22
- return await next(request);
23
- }
24
- }
@@ -1,57 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>401 - Unauthorized | {{app_name}}</title>
7
- <link rel="icon" type="image/png" href="/assets/img/favicon.png">
8
- <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;800&family=Plus+Jakarta+Sans:wght@300;400;600;800&display=swap" rel="stylesheet">
9
- <style>
10
- * { margin: 0; padding: 0; box-sizing: border-box; }
11
- body { font-family: 'Plus Jakarta Sans', sans-serif; background-color: #f8fafc; color: #0f172a; min-height: 100vh; display: flex; flex-direction: column; overflow-x: hidden; position: relative; }
12
- .aurora { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: -1; filter: blur(100px); opacity: 0.25; pointer-events: none; }
13
- .aurora-blur { position: absolute; border-radius: 50%; animation: move 20s infinite alternate; }
14
- .blur-1 { width: 50vw; height: 50vw; background: radial-gradient(circle, #8b5cf6 0%, transparent 70%); top: -10%; left: -10%; }
15
- .blur-2 { width: 40vw; height: 40vw; background: radial-gradient(circle, #f59e0b 0%, transparent 70%); bottom: -10%; right: -10%; animation-duration: 25s; }
16
- @keyframes move { from { transform: translate(0, 0) scale(1); } to { transform: translate(10%, 10%) scale(1.1); } }
17
- header { width: 100%; padding: 1.5rem 5%; display: flex; justify-content: space-between; align-items: center; backdrop-filter: blur(10px); border-bottom: 1px solid rgba(15, 23, 42, 0.08); }
18
- .logo { width: 120px; height: auto; filter: drop-shadow(0 4px 6px rgba(139, 92, 246, 0.2)); }
19
- .main-content { flex: 1; display: flex; align-items: center; justify-content: center; padding: 6rem 2rem 4rem; }
20
- .container { position: relative; z-index: 10; max-width: 700px; width: 100%; text-align: center; animation: fadeIn 0.8s ease-out; }
21
- @keyframes fadeIn { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: translateY(0); } }
22
- .badge { display: inline-block; padding: 0.45rem 1.1rem; background: rgba(245, 158, 11, 0.08); border: 1px solid #f59e0b; color: #d97706; border-radius: 999px; font-size: 0.8rem; font-weight: 700; margin-bottom: 1.75rem; text-transform: uppercase; letter-spacing: 0.1em; }
23
- h1 { font-family: 'Outfit', sans-serif; font-size: clamp(3rem, 10vw, 5.5rem); font-weight: 800; line-height: 1; margin-bottom: 1.5rem; letter-spacing: -0.04em; background: linear-gradient(135deg, #0f172a 30%, #334155 100%); background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
24
- .description { font-size: 1.15rem; color: #64748b; max-width: 520px; margin: 0 auto 2.5rem; line-height: 1.7; }
25
- .actions { display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap; }
26
- .btn { padding: 0.875rem 2rem; border-radius: 12px; font-weight: 600; text-decoration: none; transition: all 0.25s ease; font-size: 0.95rem; display: inline-flex; align-items: center; gap: 0.5rem; }
27
- .btn-primary { background: #8b5cf6; color: white; box-shadow: 0 4px 20px rgba(139, 92, 246, 0.35); }
28
- .btn-primary:hover { transform: translateY(-2px); box-shadow: 0 8px 30px rgba(139, 92, 246, 0.45); background: #7c3aed; }
29
- .btn-secondary { background: rgba(15, 23, 42, 0.05); color: #0f172a; border: 1px solid rgba(15, 23, 42, 0.1); }
30
- .btn-secondary:hover { background: rgba(15, 23, 42, 0.1); }
31
- .code-display { font-family: 'Outfit', sans-serif; font-size: clamp(6rem, 20vw, 12rem); font-weight: 800; line-height: 1; margin-bottom: 0.5rem; background: linear-gradient(135deg, rgba(245, 158, 11, 0.2) 0%, rgba(139, 92, 246, 0.1) 100%); background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent; letter-spacing: -0.04em; }
32
- .footer { padding: 2rem 0; color: #94a3b8; font-size: 0.8rem; text-align: center; border-top: 1px solid rgba(15, 23, 42, 0.06); }
33
- .footer a { color: #8b5cf6; text-decoration: none; font-weight: 600; }
34
- @media (max-width: 640px) { .actions { flex-direction: column; align-items: center; } }
35
- </style>
36
- </head>
37
- <body>
38
- <div class="aurora"><div class="aurora-blur blur-1"></div><div class="aurora-blur blur-2"></div></div>
39
- <header><a href="/"><img src="/assets/img/logo.png" alt="{{app_name}} Logo" class="logo"></a></header>
40
- <main class="main-content">
41
- <div class="container">
42
- <div class="code-display">401</div>
43
- <div class="badge">Unauthorized</div>
44
- <h1>Authentication Required</h1>
45
- <p class="description">You must be logged in to view this page. Please sign in to your account and try again.</p>
46
- <div class="actions">
47
- <a href="/auth/login" class="btn btn-primary">
48
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h4a2 2 0 012 2v14a2 2 0 01-2 2h-4"/><polyline points="10 17 15 12 10 7"/><line x1="15" y1="12" x2="3" y2="12"/></svg>
49
- Sign In
50
- </a>
51
- <a href="/" class="btn btn-secondary">Return Home</a>
52
- </div>
53
- </div>
54
- </main>
55
- <footer class="footer">&copy; {{app_name}} &mdash; Powered by <a href="https://github.com/arikajs/arikajs">ArikaJS Framework</a></footer>
56
- </body>
57
- </html>
@@ -1,54 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>403 - Access Denied | {{app_name}}</title>
7
- <link rel="icon" type="image/png" href="/assets/img/favicon.png">
8
- <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;800&family=Plus+Jakarta+Sans:wght@300;400;600;800&display=swap" rel="stylesheet">
9
- <style>
10
- * { margin: 0; padding: 0; box-sizing: border-box; }
11
- body { font-family: 'Plus Jakarta Sans', sans-serif; background-color: #f8fafc; color: #0f172a; min-height: 100vh; display: flex; flex-direction: column; overflow-x: hidden; position: relative; }
12
- .aurora { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: -1; filter: blur(100px); opacity: 0.25; pointer-events: none; }
13
- .aurora-blur { position: absolute; border-radius: 50%; animation: move 20s infinite alternate; }
14
- .blur-1 { width: 50vw; height: 50vw; background: radial-gradient(circle, #ef4444 0%, transparent 70%); top: -10%; left: -10%; }
15
- .blur-2 { width: 40vw; height: 40vw; background: radial-gradient(circle, #8b5cf6 0%, transparent 70%); bottom: -10%; right: -10%; animation-duration: 25s; }
16
- @keyframes move { from { transform: translate(0, 0) scale(1); } to { transform: translate(10%, 10%) scale(1.1); } }
17
- header { width: 100%; padding: 1.5rem 5%; display: flex; justify-content: space-between; align-items: center; backdrop-filter: blur(10px); border-bottom: 1px solid rgba(15, 23, 42, 0.08); }
18
- .logo { width: 120px; height: auto; filter: drop-shadow(0 4px 6px rgba(139, 92, 246, 0.2)); }
19
- .main-content { flex: 1; display: flex; align-items: center; justify-content: center; padding: 6rem 2rem 4rem; }
20
- .container { position: relative; z-index: 10; max-width: 700px; width: 100%; text-align: center; animation: fadeIn 0.8s ease-out; }
21
- @keyframes fadeIn { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: translateY(0); } }
22
- .badge { display: inline-block; padding: 0.45rem 1.1rem; background: rgba(239, 68, 68, 0.08); border: 1px solid #ef4444; color: #dc2626; border-radius: 999px; font-size: 0.8rem; font-weight: 700; margin-bottom: 1.75rem; text-transform: uppercase; letter-spacing: 0.1em; }
23
- h1 { font-family: 'Outfit', sans-serif; font-size: clamp(3rem, 10vw, 5.5rem); font-weight: 800; line-height: 1; margin-bottom: 1.5rem; letter-spacing: -0.04em; background: linear-gradient(135deg, #0f172a 30%, #334155 100%); background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
24
- .description { font-size: 1.15rem; color: #64748b; max-width: 520px; margin: 0 auto 2.5rem; line-height: 1.7; }
25
- .actions { display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap; }
26
- .btn { padding: 0.875rem 2rem; border-radius: 12px; font-weight: 600; text-decoration: none; transition: all 0.25s ease; font-size: 0.95rem; display: inline-flex; align-items: center; gap: 0.5rem; }
27
- .btn-primary { background: #8b5cf6; color: white; box-shadow: 0 4px 20px rgba(139, 92, 246, 0.35); }
28
- .btn-primary:hover { transform: translateY(-2px); box-shadow: 0 8px 30px rgba(139, 92, 246, 0.45); background: #7c3aed; }
29
- .code-display { font-family: 'Outfit', sans-serif; font-size: clamp(6rem, 20vw, 12rem); font-weight: 800; line-height: 1; margin-bottom: 0.5rem; background: linear-gradient(135deg, rgba(239, 68, 68, 0.2) 0%, rgba(139, 92, 246, 0.1) 100%); background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent; letter-spacing: -0.04em; }
30
- .footer { padding: 2rem 0; color: #94a3b8; font-size: 0.8rem; text-align: center; border-top: 1px solid rgba(15, 23, 42, 0.06); }
31
- .footer a { color: #8b5cf6; text-decoration: none; font-weight: 600; }
32
- @media (max-width: 640px) { .actions { flex-direction: column; align-items: center; } }
33
- </style>
34
- </head>
35
- <body>
36
- <div class="aurora"><div class="aurora-blur blur-1"></div><div class="aurora-blur blur-2"></div></div>
37
- <header><a href="/"><img src="/assets/img/logo.png" alt="{{app_name}} Logo" class="logo"></a></header>
38
- <main class="main-content">
39
- <div class="container">
40
- <div class="code-display">403</div>
41
- <div class="badge">Forbidden</div>
42
- <h1>Access Denied</h1>
43
- <p class="description">You don't have the necessary permissions to access this area. If you believe this is an error, please contact your administrator.</p>
44
- <div class="actions">
45
- <a href="/" class="btn btn-primary">
46
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12L12 3l9 9"/><path d="M9 21V12h6v9"/></svg>
47
- Return Home
48
- </a>
49
- </div>
50
- </div>
51
- </main>
52
- <footer class="footer">&copy; {{app_name}} &mdash; Powered by <a href="https://github.com/arikajs/arikajs">ArikaJS Framework</a></footer>
53
- </body>
54
- </html>
@@ -1,179 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>404 - Page Not Found | {{app_name}}</title>
7
- <link rel="icon" type="image/png" href="/assets/img/favicon.png">
8
- <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;800&family=Plus+Jakarta+Sans:wght@300;400;600;800&display=swap" rel="stylesheet">
9
- <style>
10
- * { margin: 0; padding: 0; box-sizing: border-box; }
11
-
12
- body {
13
- font-family: 'Plus Jakarta Sans', sans-serif;
14
- background-color: #f8fafc;
15
- color: #0f172a;
16
- min-height: 100vh;
17
- display: flex;
18
- flex-direction: column;
19
- overflow-x: hidden;
20
- position: relative;
21
- }
22
-
23
- .aurora {
24
- position: fixed;
25
- top: 0; left: 0;
26
- width: 100%; height: 100%;
27
- z-index: -1;
28
- filter: blur(100px);
29
- opacity: 0.25;
30
- pointer-events: none;
31
- }
32
- .aurora-blur { position: absolute; border-radius: 50%; animation: move 20s infinite alternate; }
33
- .blur-1 { width: 50vw; height: 50vw; background: radial-gradient(circle, #8b5cf6 0%, transparent 70%); top: -10%; left: -10%; }
34
- .blur-2 { width: 40vw; height: 40vw; background: radial-gradient(circle, #ec4899 0%, transparent 70%); bottom: -10%; right: -10%; animation-duration: 25s; }
35
- @keyframes move { from { transform: translate(0, 0) scale(1); } to { transform: translate(10%, 10%) scale(1.1); } }
36
-
37
- header {
38
- width: 100%;
39
- padding: 1.5rem 5%;
40
- display: flex;
41
- justify-content: space-between;
42
- align-items: center;
43
- backdrop-filter: blur(10px);
44
- border-bottom: 1px solid rgba(15, 23, 42, 0.08);
45
- }
46
- .logo { width: 120px; height: auto; filter: drop-shadow(0 4px 6px rgba(139, 92, 246, 0.2)); }
47
-
48
- .main-content {
49
- flex: 1;
50
- display: flex;
51
- align-items: center;
52
- justify-content: center;
53
- padding: 6rem 2rem 4rem;
54
- }
55
-
56
- .container {
57
- position: relative;
58
- z-index: 10;
59
- max-width: 700px;
60
- width: 100%;
61
- text-align: center;
62
- animation: fadeIn 0.8s ease-out;
63
- }
64
- @keyframes fadeIn { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: translateY(0); } }
65
-
66
- .badge {
67
- display: inline-block;
68
- padding: 0.45rem 1.1rem;
69
- background: rgba(139, 92, 246, 0.08);
70
- border: 1px solid #8b5cf6;
71
- color: #8b5cf6;
72
- border-radius: 999px;
73
- font-size: 0.8rem;
74
- font-weight: 700;
75
- margin-bottom: 1.75rem;
76
- text-transform: uppercase;
77
- letter-spacing: 0.1em;
78
- }
79
-
80
- h1 {
81
- font-family: 'Outfit', sans-serif;
82
- font-size: clamp(3rem, 10vw, 5.5rem);
83
- font-weight: 800;
84
- line-height: 1;
85
- margin-bottom: 1.5rem;
86
- letter-spacing: -0.04em;
87
- background: linear-gradient(135deg, #0f172a 30%, #334155 100%);
88
- background-clip: text;
89
- -webkit-background-clip: text;
90
- -webkit-text-fill-color: transparent;
91
- }
92
-
93
- .description {
94
- font-size: 1.15rem;
95
- color: #64748b;
96
- max-width: 520px;
97
- margin: 0 auto 2.5rem;
98
- line-height: 1.7;
99
- font-weight: 400;
100
- }
101
-
102
- .actions { display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap; }
103
-
104
- .btn {
105
- padding: 0.875rem 2rem;
106
- border-radius: 12px;
107
- font-weight: 600;
108
- text-decoration: none;
109
- transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
110
- font-size: 0.95rem;
111
- display: inline-flex;
112
- align-items: center;
113
- gap: 0.5rem;
114
- }
115
- .btn-primary {
116
- background: #8b5cf6;
117
- color: white;
118
- box-shadow: 0 4px 20px rgba(139, 92, 246, 0.35);
119
- }
120
- .btn-primary:hover { transform: translateY(-2px); box-shadow: 0 8px 30px rgba(139, 92, 246, 0.45); background: #7c3aed; }
121
-
122
- .code-display {
123
- font-family: 'Outfit', sans-serif;
124
- font-size: clamp(6rem, 20vw, 12rem);
125
- font-weight: 800;
126
- line-height: 1;
127
- margin-bottom: 0.5rem;
128
- background: linear-gradient(135deg, rgba(139, 92, 246, 0.15) 0%, rgba(236, 72, 153, 0.1) 100%);
129
- background-clip: text;
130
- -webkit-background-clip: text;
131
- -webkit-text-fill-color: transparent;
132
- letter-spacing: -0.04em;
133
- }
134
-
135
- .footer {
136
- padding: 2rem 0;
137
- color: #94a3b8;
138
- font-size: 0.8rem;
139
- text-align: center;
140
- border-top: 1px solid rgba(15, 23, 42, 0.06);
141
- }
142
- .footer a { color: #8b5cf6; text-decoration: none; font-weight: 600; }
143
- .footer a:hover { text-decoration: underline; }
144
-
145
- @media (max-width: 640px) { .actions { flex-direction: column; align-items: center; } }
146
- </style>
147
- </head>
148
- <body>
149
- <div class="aurora">
150
- <div class="aurora-blur blur-1"></div>
151
- <div class="aurora-blur blur-2"></div>
152
- </div>
153
-
154
- <header>
155
- <a href="/">
156
- <img src="/assets/img/logo.png" alt="{{app_name}} Logo" class="logo">
157
- </a>
158
- </header>
159
-
160
- <main class="main-content">
161
- <div class="container">
162
- <div class="code-display">404</div>
163
- <div class="badge">Page Not Found</div>
164
- <h1>Lost in Space?</h1>
165
- <p class="description">The page you're looking for doesn't exist or has been moved. Don't worry — you can always head back to the homepage and start again.</p>
166
- <div class="actions">
167
- <a href="/" class="btn btn-primary">
168
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12L12 3l9 9"/><path d="M9 21V12h6v9"/></svg>
169
- Return Home
170
- </a>
171
- </div>
172
- </div>
173
- </main>
174
-
175
- <footer class="footer">
176
- &copy; {{app_name}} &mdash; Powered by <a href="https://github.com/arikajs/arikajs">ArikaJS Framework</a>
177
- </footer>
178
- </body>
179
- </html>