myaidev-method 0.2.8 → 0.2.10

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 (158) hide show
  1. package/.claude/agents/wordpress-admin.md +271 -0
  2. package/.env.example +0 -1
  3. package/PACKAGE_FIXES_SUMMARY.md +319 -0
  4. package/PAYLOADCMS_AUTH_UPDATE.md +248 -0
  5. package/USER_GUIDE.md +260 -0
  6. package/bin/cli.js +70 -0
  7. package/dist/server/.tsbuildinfo +1 -0
  8. package/dist/server/auth/controllers/AuthController.d.ts +34 -0
  9. package/dist/server/auth/controllers/AuthController.d.ts.map +1 -0
  10. package/dist/server/auth/controllers/AuthController.js +43 -0
  11. package/dist/server/auth/controllers/AuthController.js.map +1 -0
  12. package/dist/server/auth/example-usage.d.ts +53 -0
  13. package/dist/server/auth/example-usage.d.ts.map +1 -0
  14. package/dist/server/auth/example-usage.js +129 -0
  15. package/dist/server/auth/example-usage.js.map +1 -0
  16. package/dist/server/auth/index.d.ts +11 -0
  17. package/dist/server/auth/index.d.ts.map +1 -0
  18. package/dist/server/auth/index.js +15 -0
  19. package/dist/server/auth/index.js.map +1 -0
  20. package/dist/server/auth/layers.d.ts +19 -0
  21. package/dist/server/auth/layers.d.ts.map +1 -0
  22. package/dist/server/auth/layers.js +33 -0
  23. package/dist/server/auth/layers.js.map +1 -0
  24. package/dist/server/auth/middleware/authMiddleware.d.ts +24 -0
  25. package/dist/server/auth/middleware/authMiddleware.d.ts.map +1 -0
  26. package/dist/server/auth/middleware/authMiddleware.js +65 -0
  27. package/dist/server/auth/middleware/authMiddleware.js.map +1 -0
  28. package/dist/server/auth/routes/authRoutes.d.ts +11 -0
  29. package/dist/server/auth/routes/authRoutes.d.ts.map +1 -0
  30. package/dist/server/auth/routes/authRoutes.js +213 -0
  31. package/dist/server/auth/routes/authRoutes.js.map +1 -0
  32. package/dist/server/auth/services/AuditLogService.d.ts +21 -0
  33. package/dist/server/auth/services/AuditLogService.d.ts.map +1 -0
  34. package/dist/server/auth/services/AuditLogService.js +28 -0
  35. package/dist/server/auth/services/AuditLogService.js.map +1 -0
  36. package/dist/server/auth/services/AuthService.d.ts +27 -0
  37. package/dist/server/auth/services/AuthService.d.ts.map +1 -0
  38. package/dist/server/auth/services/AuthService.js +246 -0
  39. package/dist/server/auth/services/AuthService.js.map +1 -0
  40. package/dist/server/auth/services/PasswordService.d.ts +12 -0
  41. package/dist/server/auth/services/PasswordService.d.ts.map +1 -0
  42. package/dist/server/auth/services/PasswordService.js +31 -0
  43. package/dist/server/auth/services/PasswordService.js.map +1 -0
  44. package/dist/server/auth/services/SessionRepository.d.ts +24 -0
  45. package/dist/server/auth/services/SessionRepository.d.ts.map +1 -0
  46. package/dist/server/auth/services/SessionRepository.js +101 -0
  47. package/dist/server/auth/services/SessionRepository.js.map +1 -0
  48. package/dist/server/auth/services/TokenService.d.ts +12 -0
  49. package/dist/server/auth/services/TokenService.d.ts.map +1 -0
  50. package/dist/server/auth/services/TokenService.js +86 -0
  51. package/dist/server/auth/services/TokenService.js.map +1 -0
  52. package/dist/server/auth/services/UserRepository.d.ts +23 -0
  53. package/dist/server/auth/services/UserRepository.d.ts.map +1 -0
  54. package/dist/server/auth/services/UserRepository.js +168 -0
  55. package/dist/server/auth/services/UserRepository.js.map +1 -0
  56. package/dist/server/auth/services/example.d.ts +26 -0
  57. package/dist/server/auth/services/example.d.ts.map +1 -0
  58. package/dist/server/auth/services/example.js +221 -0
  59. package/dist/server/auth/services/example.js.map +1 -0
  60. package/dist/server/auth/services/index.d.ts +6 -0
  61. package/dist/server/auth/services/index.d.ts.map +1 -0
  62. package/dist/server/auth/services/index.js +7 -0
  63. package/dist/server/auth/services/index.js.map +1 -0
  64. package/dist/server/database/db.d.ts +28 -0
  65. package/dist/server/database/db.d.ts.map +1 -0
  66. package/dist/server/database/db.js +91 -0
  67. package/dist/server/database/db.js.map +1 -0
  68. package/dist/server/database/schema.sql +95 -0
  69. package/dist/server/hono/app.d.ts +10 -0
  70. package/dist/server/hono/app.d.ts.map +1 -0
  71. package/dist/server/hono/app.js +26 -0
  72. package/dist/server/hono/app.js.map +1 -0
  73. package/dist/server/hono/routes.d.ts +12 -0
  74. package/dist/server/hono/routes.d.ts.map +1 -0
  75. package/dist/server/hono/routes.js +40 -0
  76. package/dist/server/hono/routes.js.map +1 -0
  77. package/dist/server/main.d.ts +2 -0
  78. package/dist/server/main.d.ts.map +1 -0
  79. package/dist/server/main.js +94 -0
  80. package/dist/server/main.js.map +1 -0
  81. package/dist/server/user-management/DirectoryService.d.ts +62 -0
  82. package/dist/server/user-management/DirectoryService.d.ts.map +1 -0
  83. package/dist/server/user-management/DirectoryService.js +201 -0
  84. package/dist/server/user-management/DirectoryService.js.map +1 -0
  85. package/dist/server/user-management/LinuxUserService.d.ts +71 -0
  86. package/dist/server/user-management/LinuxUserService.d.ts.map +1 -0
  87. package/dist/server/user-management/LinuxUserService.js +192 -0
  88. package/dist/server/user-management/LinuxUserService.js.map +1 -0
  89. package/dist/server/user-management/QuotaService.d.ts +59 -0
  90. package/dist/server/user-management/QuotaService.d.ts.map +1 -0
  91. package/dist/server/user-management/QuotaService.js +148 -0
  92. package/dist/server/user-management/QuotaService.js.map +1 -0
  93. package/dist/server/user-management/UserManagementService.d.ts +74 -0
  94. package/dist/server/user-management/UserManagementService.d.ts.map +1 -0
  95. package/dist/server/user-management/UserManagementService.js +122 -0
  96. package/dist/server/user-management/UserManagementService.js.map +1 -0
  97. package/dist/server/user-management/index.d.ts +26 -0
  98. package/dist/server/user-management/index.d.ts.map +1 -0
  99. package/dist/server/user-management/index.js +26 -0
  100. package/dist/server/user-management/index.js.map +1 -0
  101. package/dist/server/user-management/layers.d.ts +27 -0
  102. package/dist/server/user-management/layers.d.ts.map +1 -0
  103. package/dist/server/user-management/layers.js +37 -0
  104. package/dist/server/user-management/layers.js.map +1 -0
  105. package/dist/shared/types.d.ts +94 -0
  106. package/dist/shared/types.d.ts.map +1 -0
  107. package/dist/shared/types.js +32 -0
  108. package/dist/shared/types.js.map +1 -0
  109. package/package.json +25 -5
  110. package/src/lib/payloadcms-utils.js +5 -12
  111. package/src/server/auth/ARCHITECTURE.md +575 -0
  112. package/src/server/auth/IMPLEMENTATION_SUMMARY.md +287 -0
  113. package/src/server/auth/QUICK_START.md +283 -0
  114. package/src/server/auth/README.md +290 -0
  115. package/src/server/auth/controllers/AuthController.ts +129 -0
  116. package/src/server/auth/example-usage.ts +159 -0
  117. package/src/server/auth/index.ts +19 -0
  118. package/src/server/auth/layers.ts +57 -0
  119. package/src/server/auth/middleware/authMiddleware.ts +118 -0
  120. package/src/server/auth/routes/authRoutes.ts +319 -0
  121. package/src/server/auth/services/AuditLogService.ts +81 -0
  122. package/src/server/auth/services/AuthService.ts +408 -0
  123. package/src/server/auth/services/IMPLEMENTATION_SUMMARY.md +404 -0
  124. package/src/server/auth/services/PasswordService.ts +85 -0
  125. package/src/server/auth/services/README.md +361 -0
  126. package/src/server/auth/services/SessionRepository.ts +227 -0
  127. package/src/server/auth/services/TokenService.ts +174 -0
  128. package/src/server/auth/services/UserRepository.ts +318 -0
  129. package/src/server/auth/services/example.ts +346 -0
  130. package/src/server/auth/services/index.ts +6 -0
  131. package/src/server/database/db.ts +161 -0
  132. package/src/server/database/schema.sql +95 -0
  133. package/src/server/hono/app.ts +41 -0
  134. package/src/server/main.ts +115 -0
  135. package/src/server/user-management/DirectoryService.ts +348 -0
  136. package/src/server/user-management/LinuxUserService.ts +338 -0
  137. package/src/server/user-management/QuotaService.ts +256 -0
  138. package/src/server/user-management/README.md +333 -0
  139. package/src/server/user-management/UserManagementService.ts +335 -0
  140. package/src/server/user-management/index.ts +26 -0
  141. package/src/server/user-management/layers.ts +51 -0
  142. package/src/shared/types.ts +111 -0
  143. package/src/templates/claude/agents/coolify-deploy.md +50 -50
  144. package/src/templates/claude/agents/payloadcms-publish.md +46 -18
  145. package/src/templates/codex/commands/myai-astro-publish.md +8 -2
  146. package/src/templates/codex/commands/myai-content-writer.md +8 -2
  147. package/src/templates/codex/commands/myai-coolify-deploy.md +8 -2
  148. package/src/templates/codex/commands/myai-dev-architect.md +8 -2
  149. package/src/templates/codex/commands/myai-dev-code.md +8 -2
  150. package/src/templates/codex/commands/myai-dev-docs.md +8 -2
  151. package/src/templates/codex/commands/myai-dev-review.md +8 -2
  152. package/src/templates/codex/commands/myai-dev-test.md +8 -2
  153. package/src/templates/codex/commands/myai-docusaurus-publish.md +8 -2
  154. package/src/templates/codex/commands/myai-mintlify-publish.md +8 -2
  155. package/src/templates/codex/commands/myai-payloadcms-publish.md +17 -3
  156. package/src/templates/codex/commands/myai-sparc-workflow.md +8 -2
  157. package/src/templates/codex/commands/myai-wordpress-admin.md +8 -2
  158. package/src/templates/codex/commands/myai-wordpress-publish.md +8 -2
@@ -0,0 +1,290 @@
1
+ # Authentication System
2
+
3
+ Effect-TS based authentication system for MyAIDev Method web server.
4
+
5
+ ## Architecture
6
+
7
+ ### Services Layer
8
+
9
+ **AuthService** - High-level authentication orchestration
10
+ - `register()` - User registration with validation
11
+ - `login()` - User authentication with session creation
12
+ - `logout()` - Session revocation
13
+ - `verifyToken()` - JWT verification and session validation
14
+
15
+ **PasswordService** - Password hashing and validation
16
+ - `hash()` - bcrypt password hashing (12 rounds)
17
+ - `verify()` - Password verification
18
+ - `validatePasswordStrength()` - Password strength requirements
19
+
20
+ **TokenService** - JWT token management
21
+ - `generateToken()` - Create signed JWT (RS256)
22
+ - `verifyToken()` - Verify and decode JWT
23
+ - `hashToken()` - SHA-256 token hashing
24
+
25
+ **UserRepository** - User data persistence
26
+ - `create()` - Create new user
27
+ - `findById()` - Find user by ID
28
+ - `findByEmail()` - Find user by email
29
+ - `findByUsername()` - Find user by username
30
+ - `update()` - Update user data
31
+ - `incrementFailedLogins()` - Track failed login attempts
32
+ - `resetFailedLogins()` - Reset failed login counter
33
+
34
+ **SessionRepository** - Session management
35
+ - `create()` - Create new session
36
+ - `findById()` - Find session by ID
37
+ - `findByTokenHash()` - Find session by token hash
38
+ - `revoke()` - Revoke single session
39
+ - `revokeAllForUser()` - Revoke all user sessions
40
+ - `deleteExpired()` - Clean up expired sessions
41
+
42
+ **AuditLogService** - Security audit logging
43
+ - `log()` - Record security events
44
+
45
+ ### Middleware
46
+
47
+ **authMiddleware** - Hono middleware for route protection
48
+ - Extracts token from `Authorization: Bearer <token>` or `auth_token` cookie
49
+ - Verifies token and session validity
50
+ - Injects `user` and `session` into Hono context
51
+ - Returns 401 for authentication failures
52
+
53
+ ### Routes
54
+
55
+ **POST /api/auth/register**
56
+ ```typescript
57
+ Request: { username: string; email: string; password: string }
58
+ Response: { user: { id, username, email, emailVerified } }
59
+ Status: 201 Created | 400 Validation Error | 500 Server Error
60
+ ```
61
+
62
+ **POST /api/auth/login**
63
+ ```typescript
64
+ Request: { email: string; password: string }
65
+ Response: { user: { id, username, email, emailVerified }, token: string }
66
+ Cookie: auth_token (httpOnly, secure, sameSite=strict)
67
+ Status: 200 OK | 401 Unauthorized | 500 Server Error
68
+ ```
69
+
70
+ **POST /api/auth/logout** (requires auth)
71
+ ```typescript
72
+ Response: { message: "Logged out successfully" }
73
+ Status: 200 OK | 401 Unauthorized | 500 Server Error
74
+ ```
75
+
76
+ **GET /api/auth/me** (requires auth)
77
+ ```typescript
78
+ Response: { user: { id, username, email, emailVerified, createdAt, lastLoginAt } }
79
+ Status: 200 OK | 401 Unauthorized | 500 Server Error
80
+ ```
81
+
82
+ ## Security Features
83
+
84
+ ### Password Requirements
85
+ - Minimum 8 characters
86
+ - At least 1 uppercase letter
87
+ - At least 1 lowercase letter
88
+ - At least 1 number
89
+ - Hashed with bcrypt (12 rounds)
90
+
91
+ ### Account Lockout
92
+ - 5 failed login attempts triggers lockout
93
+ - 15 minute lockout duration
94
+ - Automatic unlock after duration expires
95
+ - Failed attempts reset on successful login
96
+
97
+ ### Session Management
98
+ - JWT tokens with RS256 signing
99
+ - 7 day token expiration
100
+ - Session stored with token hash (SHA-256)
101
+ - Session validation on every request
102
+ - Revocable sessions
103
+
104
+ ### Cookie Configuration
105
+ ```typescript
106
+ {
107
+ httpOnly: true,
108
+ secure: process.env.NODE_ENV === "production",
109
+ sameSite: "strict",
110
+ maxAge: 7 * 24 * 60 * 60, // 7 days
111
+ path: "/"
112
+ }
113
+ ```
114
+
115
+ ### Linux Username Generation
116
+ - Sanitized from user's username
117
+ - Lowercase alphanumeric + underscores
118
+ - Must start with letter
119
+ - Max 32 characters
120
+ - Guaranteed unique with counter suffix if needed
121
+
122
+ ## Usage Example
123
+
124
+ ### Integration with Hono
125
+
126
+ ```typescript
127
+ import { Hono } from "hono";
128
+ import { authRouter, authMiddleware } from "./auth/index.js";
129
+
130
+ const app = new Hono();
131
+
132
+ // Public routes
133
+ app.route("/api/auth", authRouter);
134
+
135
+ // Protected routes
136
+ app.get("/api/protected", authMiddleware, (c) => {
137
+ const user = c.get("user");
138
+ const session = c.get("session");
139
+ return c.json({ message: `Hello ${user.username}` });
140
+ });
141
+
142
+ export default app;
143
+ ```
144
+
145
+ ### Direct Service Usage
146
+
147
+ ```typescript
148
+ import { Effect } from "effect";
149
+ import { AppLayer } from "./auth/middleware/authMiddleware.js";
150
+ import { AuthService } from "./auth/services/AuthService.js";
151
+
152
+ const registerUser = Effect.gen(function* () {
153
+ const authService = yield* AuthService;
154
+ const user = yield* authService.register(
155
+ "testuser",
156
+ "test@example.com",
157
+ "SecurePass123",
158
+ "127.0.0.1",
159
+ "Mozilla/5.0"
160
+ );
161
+ return user;
162
+ });
163
+
164
+ const user = await Effect.runPromise(
165
+ Effect.provide(registerUser, AppLayer)
166
+ );
167
+ ```
168
+
169
+ ## Error Handling
170
+
171
+ All services use typed Effect errors:
172
+
173
+ - **AuthError** - Authentication failures (401)
174
+ - `INVALID_CREDENTIALS` - Wrong email/password
175
+ - `ACCOUNT_LOCKED` - Too many failed attempts
176
+ - `TOKEN_EXPIRED` - Session expired
177
+ - `SESSION_REVOKED` - Session invalidated
178
+ - `USER_INACTIVE` - Account disabled
179
+
180
+ - **ValidationError** - Input validation failures (400)
181
+ - Field-specific error messages
182
+ - Password strength requirements
183
+ - Email format validation
184
+
185
+ - **DatabaseError** - Database operation failures (500)
186
+ - Generic database errors
187
+ - Connection issues
188
+
189
+ ## Audit Logging
190
+
191
+ All authentication events are logged:
192
+ - `USER_REGISTERED` - New user registration
193
+ - `USER_LOGIN` - Successful login
194
+ - `USER_LOGOUT` - User logout
195
+ - `LOGIN_FAILED` - Failed login attempt
196
+ - `ACCOUNT_LOCKED` - Account locked notification
197
+
198
+ Audit logs include:
199
+ - User ID
200
+ - Action type
201
+ - Resource type and ID
202
+ - IP address
203
+ - User agent
204
+ - Timestamp
205
+ - Additional details
206
+
207
+ ## Testing
208
+
209
+ ```typescript
210
+ import { describe, it, expect } from "vitest";
211
+ import { Effect } from "effect";
212
+ import { AppLayer } from "./middleware/authMiddleware.js";
213
+ import { AuthService } from "./services/AuthService.js";
214
+
215
+ describe("AuthService", () => {
216
+ it("should register a new user", async () => {
217
+ const registerEffect = Effect.gen(function* () {
218
+ const authService = yield* AuthService;
219
+ return yield* authService.register(
220
+ "testuser",
221
+ "test@example.com",
222
+ "SecurePass123"
223
+ );
224
+ });
225
+
226
+ const user = await Effect.runPromise(
227
+ Effect.provide(registerEffect, AppLayer)
228
+ );
229
+
230
+ expect(user.username).toBe("testuser");
231
+ expect(user.email).toBe("test@example.com");
232
+ expect(user.passwordHash).toBeTruthy();
233
+ });
234
+ });
235
+ ```
236
+
237
+ ## Dependencies
238
+
239
+ - `effect` - Effect-TS for composable error handling
240
+ - `hono` - Web framework
241
+ - `bcrypt` - Password hashing
242
+ - `jose` - JWT handling (RS256)
243
+ - `node:crypto` - Token hashing and UUID generation
244
+
245
+ ## Design Patterns
246
+
247
+ ### Effect-TS Context.Tag Pattern
248
+ All services use `Context.Tag` for dependency injection:
249
+ ```typescript
250
+ export class ServiceName extends Context.Tag("ServiceName")<
251
+ ServiceName,
252
+ ServiceInterface
253
+ >() {
254
+ static Live = Layer.effect(this, Effect.gen(function* () {
255
+ // Dependencies
256
+ const dep = yield* DependencyService;
257
+
258
+ // Implementation
259
+ return { method: () => Effect.succeed(result) };
260
+ }));
261
+ }
262
+ ```
263
+
264
+ ### Layer Composition
265
+ Dependencies are composed into a single `AppLayer`:
266
+ ```typescript
267
+ export const AppLayer = Layer.mergeAll(
268
+ DatabaseService.Live,
269
+ PasswordService.Live,
270
+ TokenService.Live
271
+ ).pipe(
272
+ Layer.provideMerge(UserRepository.Live),
273
+ Layer.provideMerge(SessionRepository.Live),
274
+ Layer.provideMerge(AuditLogService.Live),
275
+ Layer.provideMerge(AuthService.Live)
276
+ );
277
+ ```
278
+
279
+ ### Effect.gen for Composition
280
+ All business logic uses `Effect.gen` with `yield*`:
281
+ ```typescript
282
+ const operation = Effect.gen(function* () {
283
+ const service = yield* Service;
284
+ const result = yield* service.method();
285
+ return result;
286
+ });
287
+ ```
288
+
289
+ ### No Type Casting
290
+ All type conversions are explicit and safe - no `as` type assertions.
@@ -0,0 +1,129 @@
1
+ import { Context, Effect, Layer } from "effect";
2
+ import { AuthService } from "../services/AuthService.js";
3
+ import {
4
+ AuthError,
5
+ AuthResponse,
6
+ DatabaseError,
7
+ LoginRequest,
8
+ RegisterRequest,
9
+ User,
10
+ ValidationError,
11
+ } from "../../../shared/types.js";
12
+
13
+ export interface RegisterResult {
14
+ user: {
15
+ id: string;
16
+ username: string;
17
+ email: string;
18
+ emailVerified: boolean;
19
+ };
20
+ }
21
+
22
+ export interface LoginResult extends AuthResponse {}
23
+
24
+ export interface MeResult {
25
+ user: {
26
+ id: string;
27
+ username: string;
28
+ email: string;
29
+ emailVerified: boolean;
30
+ createdAt: number;
31
+ lastLoginAt: number | null;
32
+ };
33
+ }
34
+
35
+ export class AuthController extends Context.Tag("AuthController")<
36
+ AuthController,
37
+ {
38
+ readonly register: (
39
+ data: RegisterRequest,
40
+ ipAddress?: string | null,
41
+ userAgent?: string | null
42
+ ) => Effect.Effect<RegisterResult, AuthError | ValidationError | DatabaseError>;
43
+ readonly login: (
44
+ data: LoginRequest,
45
+ ipAddress?: string | null,
46
+ userAgent?: string | null
47
+ ) => Effect.Effect<LoginResult, AuthError | DatabaseError>;
48
+ readonly logout: (
49
+ sessionId: string,
50
+ userId: string
51
+ ) => Effect.Effect<void, DatabaseError>;
52
+ readonly me: (user: User) => Effect.Effect<MeResult, never>;
53
+ }
54
+ >() {
55
+ static Live = Layer.effect(
56
+ this,
57
+ Effect.gen(function* () {
58
+ const authService = yield* AuthService;
59
+
60
+ const register = (
61
+ data: RegisterRequest,
62
+ ipAddress?: string | null,
63
+ userAgent?: string | null
64
+ ): Effect.Effect<RegisterResult, AuthError | ValidationError | DatabaseError> =>
65
+ Effect.gen(function* () {
66
+ const user = yield* authService.register(
67
+ data.username,
68
+ data.email,
69
+ data.password,
70
+ ipAddress,
71
+ userAgent
72
+ );
73
+
74
+ return {
75
+ user: {
76
+ id: user.id,
77
+ username: user.username,
78
+ email: user.email,
79
+ emailVerified: user.emailVerified,
80
+ },
81
+ };
82
+ });
83
+
84
+ const login = (
85
+ data: LoginRequest,
86
+ ipAddress?: string | null,
87
+ userAgent?: string | null
88
+ ): Effect.Effect<LoginResult, AuthError | DatabaseError> =>
89
+ Effect.gen(function* () {
90
+ const result = yield* authService.login(
91
+ data.email,
92
+ data.password,
93
+ ipAddress,
94
+ userAgent
95
+ );
96
+
97
+ return {
98
+ user: {
99
+ id: result.user.id,
100
+ username: result.user.username,
101
+ email: result.user.email,
102
+ emailVerified: result.user.emailVerified,
103
+ },
104
+ token: result.token,
105
+ };
106
+ });
107
+
108
+ const logout = (
109
+ sessionId: string,
110
+ userId: string
111
+ ): Effect.Effect<void, DatabaseError> =>
112
+ authService.logout(sessionId, userId);
113
+
114
+ const me = (user: User): Effect.Effect<MeResult, never> =>
115
+ Effect.succeed({
116
+ user: {
117
+ id: user.id,
118
+ username: user.username,
119
+ email: user.email,
120
+ emailVerified: user.emailVerified,
121
+ createdAt: user.createdAt,
122
+ lastLoginAt: user.lastLoginAt,
123
+ },
124
+ });
125
+
126
+ return { register, login, logout, me };
127
+ })
128
+ );
129
+ }
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Example usage of the authentication system
3
+ * This file demonstrates how to integrate the auth system with Hono
4
+ */
5
+
6
+ import { Hono } from "hono";
7
+ import { Layer } from "effect";
8
+ import { createAuthRoutes, createAuthMiddleware } from "./index.js";
9
+ import { PasswordService } from "./services/PasswordService.js";
10
+ import { TokenService } from "./services/TokenService.js";
11
+ import { UserRepository } from "./services/UserRepository.js";
12
+ import { SessionRepository } from "./services/SessionRepository.js";
13
+ import { AuditLogService } from "./services/AuditLogService.js";
14
+ import { AuthService } from "./services/AuthService.js";
15
+ import { DatabaseService } from "../database/db.js";
16
+
17
+ // Build the complete application layer with all services
18
+ const DbLayer = DatabaseService.Live({
19
+ path: process.env["DB_PATH"] || "./auth.db",
20
+ timeout: 5000,
21
+ verbose: process.env["NODE_ENV"] === "development",
22
+ });
23
+
24
+ const IndependentServices = Layer.mergeAll(
25
+ PasswordService.Live,
26
+ TokenService.Live,
27
+ AuditLogService.Live
28
+ );
29
+
30
+ const Repositories = Layer.mergeAll(
31
+ UserRepository.Live,
32
+ SessionRepository.Live
33
+ );
34
+
35
+ const Auth = AuthService.Live;
36
+
37
+ const AppLayer = Layer.mergeAll(
38
+ IndependentServices,
39
+ Repositories,
40
+ Auth
41
+ ).pipe(Layer.provide(DbLayer));
42
+
43
+ // Create main app
44
+ const app = new Hono();
45
+
46
+ // Create middleware and routes with AppLayer
47
+ const authMiddleware = createAuthMiddleware(AppLayer);
48
+ const authRouter = createAuthRoutes(AppLayer, authMiddleware);
49
+
50
+ // Mount authentication routes (public)
51
+ app.route("/api/auth", authRouter);
52
+
53
+ // Protected route example - requires authentication
54
+ app.get("/api/protected/profile", authMiddleware, (c) => {
55
+ const user = c.get("user");
56
+ const session = c.get("session");
57
+
58
+ return c.json({
59
+ message: "This is a protected endpoint",
60
+ user: {
61
+ id: user.id,
62
+ username: user.username,
63
+ email: user.email,
64
+ },
65
+ session: {
66
+ id: session.id,
67
+ createdAt: session.createdAt,
68
+ expiresAt: session.expiresAt,
69
+ },
70
+ });
71
+ });
72
+
73
+ // Protected route example - user data
74
+ app.get("/api/protected/data", authMiddleware, (c) => {
75
+ const user = c.get("user");
76
+
77
+ return c.json({
78
+ data: {
79
+ userId: user.id,
80
+ username: user.username,
81
+ linuxUsername: user.linuxUsername,
82
+ isActive: user.isActive,
83
+ emailVerified: user.emailVerified,
84
+ },
85
+ });
86
+ });
87
+
88
+ // Admin-only route example
89
+ app.get("/api/protected/admin", authMiddleware, (c) => {
90
+ const user = c.get("user");
91
+
92
+ // Add your own admin check logic here
93
+ // For example, check if user has admin role
94
+ if (user.email !== "admin@example.com") {
95
+ return c.json({ error: "FORBIDDEN", message: "Admin access required" }, 403);
96
+ }
97
+
98
+ return c.json({
99
+ message: "Welcome to admin panel",
100
+ adminData: "Sensitive information",
101
+ });
102
+ });
103
+
104
+ // Health check endpoint (public)
105
+ app.get("/health", (c) => {
106
+ return c.json({ status: "ok", timestamp: Date.now() });
107
+ });
108
+
109
+ // Start server
110
+ const port = process.env["PORT"] || 3000;
111
+ console.log(`Server starting on port ${port}`);
112
+
113
+ export default app;
114
+
115
+ /**
116
+ * To run this example:
117
+ *
118
+ * 1. Install dependencies:
119
+ * npm install hono effect bcrypt jose
120
+ *
121
+ * 2. Set up environment:
122
+ * export NODE_ENV=development
123
+ * export PORT=3000
124
+ *
125
+ * 3. Initialize database:
126
+ * node --import tsx/esm src/server/database/init-db.ts
127
+ *
128
+ * 4. Run the server:
129
+ * node --import tsx/esm src/server/auth/example-usage.ts
130
+ *
131
+ * API Usage Examples:
132
+ *
133
+ * Register:
134
+ * curl -X POST http://localhost:3000/api/auth/register \
135
+ * -H "Content-Type: application/json" \
136
+ * -d '{"username":"testuser","email":"test@example.com","password":"SecurePass123"}'
137
+ *
138
+ * Login:
139
+ * curl -X POST http://localhost:3000/api/auth/login \
140
+ * -H "Content-Type: application/json" \
141
+ * -d '{"email":"test@example.com","password":"SecurePass123"}' \
142
+ * -c cookies.txt
143
+ *
144
+ * Access protected endpoint (with cookie):
145
+ * curl http://localhost:3000/api/protected/profile \
146
+ * -b cookies.txt
147
+ *
148
+ * Access protected endpoint (with Bearer token):
149
+ * curl http://localhost:3000/api/protected/profile \
150
+ * -H "Authorization: Bearer <token>"
151
+ *
152
+ * Get current user:
153
+ * curl http://localhost:3000/api/auth/me \
154
+ * -b cookies.txt
155
+ *
156
+ * Logout:
157
+ * curl -X POST http://localhost:3000/api/auth/logout \
158
+ * -b cookies.txt
159
+ */
@@ -0,0 +1,19 @@
1
+ // Authentication module exports
2
+
3
+ // Services
4
+ export { AuthService } from "./services/AuthService.js";
5
+ export { PasswordService } from "./services/PasswordService.js";
6
+ export { TokenService } from "./services/TokenService.js";
7
+ export { UserRepository } from "./services/UserRepository.js";
8
+ export { SessionRepository } from "./services/SessionRepository.js";
9
+ export { AuditLogService } from "./services/AuditLogService.js";
10
+
11
+ // Controllers
12
+ export { AuthController } from "./controllers/AuthController.js";
13
+
14
+ // Middleware
15
+ export { createAuthMiddleware } from "./middleware/authMiddleware.js";
16
+ export type { AppRuntimeContext } from "./middleware/authMiddleware.js";
17
+
18
+ // Routes
19
+ export { createAuthRoutes } from "./routes/authRoutes.js";
@@ -0,0 +1,57 @@
1
+ import { Layer } from "effect";
2
+ import { PasswordService } from "./services/PasswordService.js";
3
+ import { TokenService } from "./services/TokenService.js";
4
+ import { UserRepository } from "./services/UserRepository.js";
5
+ import { SessionRepository } from "./services/SessionRepository.js";
6
+ import { AuditLogService } from "./services/AuditLogService.js";
7
+ import { AuthService } from "./services/AuthService.js";
8
+ import { DatabaseService } from "../database/db.js";
9
+ import { UserManagementLayer } from "../user-management/layers.js";
10
+
11
+ /**
12
+ * Creates the complete application layer with all auth services
13
+ * @param dbConfig Database configuration
14
+ * @returns Complete layer with all services including DatabaseService
15
+ */
16
+ export const createAppLayer = (dbConfig: { path: string; timeout?: number; verbose?: boolean }) => {
17
+ // Base database layer
18
+ const DbLayer = DatabaseService.Live(dbConfig);
19
+
20
+ // Service layers that don't require DatabaseService
21
+ const IndependentServices = Layer.mergeAll(
22
+ PasswordService.Live,
23
+ TokenService.Live
24
+ );
25
+
26
+ // Services and repositories that require DatabaseService
27
+ const DbDependentServices = Layer.mergeAll(
28
+ AuditLogService.Live,
29
+ UserRepository.Live,
30
+ SessionRepository.Live
31
+ );
32
+
33
+ // Provide DatabaseService to dependent services
34
+ const DbDependentWithDb = Layer.provide(DbDependentServices, DbLayer);
35
+
36
+ // Merge all services and database
37
+ const BaseServices = Layer.mergeAll(
38
+ IndependentServices,
39
+ DbDependentWithDb,
40
+ DbLayer
41
+ );
42
+
43
+ // Add user management layer
44
+ const ServicesWithUserManagement = Layer.mergeAll(
45
+ BaseServices,
46
+ UserManagementLayer
47
+ );
48
+
49
+ // Provide all dependencies to AuthService
50
+ const AuthWithDeps = Layer.provide(AuthService.Live, ServicesWithUserManagement);
51
+
52
+ // Complete application layer - merge everything
53
+ return Layer.mergeAll(
54
+ ServicesWithUserManagement,
55
+ AuthWithDeps
56
+ );
57
+ };