@gravito/satellite-membership 0.1.1

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 (50) hide show
  1. package/.dockerignore +8 -0
  2. package/.env.example +19 -0
  3. package/ARCHITECTURE.md +14 -0
  4. package/CHANGELOG.md +14 -0
  5. package/Dockerfile +25 -0
  6. package/README.md +112 -0
  7. package/WHITEPAPER.md +20 -0
  8. package/dist/index.d.ts +26 -0
  9. package/dist/index.js +1121 -0
  10. package/docs/EXTENDING.md +99 -0
  11. package/docs/PASSKEYS.md +78 -0
  12. package/locales/en.json +30 -0
  13. package/locales/zh-TW.json +30 -0
  14. package/package.json +35 -0
  15. package/src/Application/DTOs/MemberDTO.ts +34 -0
  16. package/src/Application/Mail/ForgotPasswordMail.ts +42 -0
  17. package/src/Application/Mail/MemberLevelChangedMail.ts +41 -0
  18. package/src/Application/Mail/WelcomeMail.ts +45 -0
  19. package/src/Application/Services/PasskeysService.ts +198 -0
  20. package/src/Application/UseCases/ForgotPassword.ts +34 -0
  21. package/src/Application/UseCases/LoginMember.ts +64 -0
  22. package/src/Application/UseCases/RegisterMember.ts +65 -0
  23. package/src/Application/UseCases/ResetPassword.ts +30 -0
  24. package/src/Application/UseCases/UpdateMemberLevel.ts +47 -0
  25. package/src/Application/UseCases/UpdateSettings.ts +81 -0
  26. package/src/Application/UseCases/VerifyEmail.ts +23 -0
  27. package/src/Domain/Contracts/IMemberPasskeyRepository.ts +8 -0
  28. package/src/Domain/Contracts/IMemberRepository.ts +11 -0
  29. package/src/Domain/Entities/Member.ts +219 -0
  30. package/src/Domain/Entities/MemberPasskey.ts +97 -0
  31. package/src/Infrastructure/Auth/SentinelMemberProvider.ts +52 -0
  32. package/src/Infrastructure/Persistence/AtlasMemberPasskeyRepository.ts +63 -0
  33. package/src/Infrastructure/Persistence/AtlasMemberRepository.ts +91 -0
  34. package/src/Infrastructure/Persistence/Migrations/20250101_create_members_table.ts +30 -0
  35. package/src/Infrastructure/Persistence/Migrations/20250102_create_member_passkeys_table.ts +25 -0
  36. package/src/Interface/Http/Controllers/PasskeyController.ts +98 -0
  37. package/src/Interface/Http/Middleware/VerifySingleDevice.ts +51 -0
  38. package/src/index.ts +234 -0
  39. package/src/manifest.json +15 -0
  40. package/tests/PasskeysService.test.ts +113 -0
  41. package/tests/email-integration.test.ts +161 -0
  42. package/tests/grand-review.ts +176 -0
  43. package/tests/integration.test.ts +75 -0
  44. package/tests/member.test.ts +47 -0
  45. package/tests/unit.test.ts +7 -0
  46. package/tests/update-settings.test.ts +101 -0
  47. package/tsconfig.json +26 -0
  48. package/views/emails/level_changed.html +35 -0
  49. package/views/emails/reset_password.html +34 -0
  50. package/views/emails/welcome.html +31 -0
package/tsconfig.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "baseUrl": ".",
6
+ "paths": {
7
+ "@gravito/core": [
8
+ "../../packages/core/src/index.ts"
9
+ ],
10
+ "@gravito/*": [
11
+ "../../packages/*/src/index.ts"
12
+ ]
13
+ },
14
+ "types": [
15
+ "bun-types"
16
+ ]
17
+ },
18
+ "include": [
19
+ "src/**/*"
20
+ ],
21
+ "exclude": [
22
+ "node_modules",
23
+ "dist",
24
+ "**/*.test.ts"
25
+ ]
26
+ }
@@ -0,0 +1,35 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-TW">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <style>
7
+ body { font-family: 'Inter', system-ui, -apple-system, sans-serif; line-height: 1.6; color: #1a1a1a; margin: 0; padding: 0; background-color: #f9fafb; }
8
+ .container { max-width: 600px; margin: 40px auto; padding: 32px; background: #ffffff; border-radius: 12px; box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); border-top: 8px solid {{ branding.color }}; }
9
+ .logo { font-size: 24px; font-weight: 800; color: {{ branding.color }}; margin-bottom: 24px; text-align: center; }
10
+ .badge { display: inline-block; padding: 4px 12px; background: #fef3c7; color: #92400e; border-radius: 9999px; font-size: 14px; font-weight: 600; margin-bottom: 16px; }
11
+ h1 { font-size: 24px; font-weight: 700; color: #111827; margin-bottom: 16px; text-align: center; }
12
+ p { margin-bottom: 24px; color: #4b5563; text-align: center; }
13
+ .level-up { font-size: 32px; margin: 24px 0; text-align: center; }
14
+ .footer { margin-top: 32px; font-size: 14px; color: #9ca3af; text-align: center; }
15
+ </style>
16
+ </head>
17
+ <body>
18
+ <div class="container">
19
+ <div class="logo">{{ branding.name }}</div>
20
+ <div style="text-align: center;"><span class="badge">{{ lang.badge_text }}</span></div>
21
+ <h1>{{ lang.title }}</h1>
22
+ <p>{{ lang.body }}</p>
23
+
24
+ <div class="level-up">
25
+ <span style="color: #9ca3af; text-decoration: line-through; font-size: 20px;">{{ oldLevel }}</span>
26
+ <span style="margin: 0 16px;">→</span>
27
+ <span style="color: {{ branding.color }}; font-weight: 800;">{{ newLevel }}</span>
28
+ </div>
29
+
30
+ <div class="footer">
31
+ &copy; {{ currentYear }} {{ branding.name }}. All rights reserved.
32
+ </div>
33
+ </div>
34
+ </body>
35
+ </html>
@@ -0,0 +1,34 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-TW">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <style>
7
+ body { font-family: 'Inter', system-ui, -apple-system, sans-serif; line-height: 1.6; color: #1a1a1a; margin: 0; padding: 0; background-color: #f9fafb; }
8
+ .container { max-width: 600px; margin: 40px auto; padding: 32px; background: #ffffff; border-radius: 12px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); }
9
+ .logo { font-size: 24px; font-weight: 800; color: {{ branding.color }}; margin-bottom: 24px; text-align: center; }
10
+ h1 { font-size: 24px; font-weight: 700; color: #111827; margin-bottom: 16px; text-align: center; }
11
+ p { margin-bottom: 24px; color: #4b5563; text-align: center; }
12
+ .btn { display: block; width: fit-content; margin: 0 auto; padding: 12px 24px; background-color: {{ branding.color }}; color: #ffffff !important; text-decoration: none; border-radius: 8px; font-weight: 600; transition: background-color 0.2s; }
13
+ .footer { margin-top: 32px; font-size: 14px; color: #9ca3af; text-align: center; }
14
+ .warning { font-size: 12px; color: #9ca3af; margin-top: 24px; text-align: center; }
15
+ </style>
16
+ </head>
17
+ <body>
18
+ <div class="container">
19
+ <div class="logo">{{ branding.name }}</div>
20
+ <h1>{{ lang.reset_password_title }}</h1>
21
+ <p>{{ lang.reset_password_body }}</p>
22
+
23
+ <a href="{{ resetUrl }}" class="btn">
24
+ {{ lang.reset_password_button }}
25
+ </a>
26
+
27
+ <p class="warning">{{ lang.reset_password_warning }}</p>
28
+
29
+ <div class="footer">
30
+ &copy; {{ currentYear }} {{ branding.name }}. All rights reserved.
31
+ </div>
32
+ </div>
33
+ </body>
34
+ </html>
@@ -0,0 +1,31 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-TW">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <style>
7
+ body { font-family: 'Inter', system-ui, -apple-system, sans-serif; line-height: 1.6; color: #1a1a1a; margin: 0; padding: 0; background-color: #f9fafb; }
8
+ .container { max-width: 600px; margin: 40px auto; padding: 32px; background: #ffffff; border-radius: 12px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); }
9
+ .logo { font-size: 24px; font-weight: 800; color: {{ branding.color }}; margin-bottom: 24px; text-align: center; }
10
+ h1 { font-size: 24px; font-weight: 700; color: #111827; margin-bottom: 16px; text-align: center; }
11
+ p { margin-bottom: 24px; color: #4b5563; text-align: center; }
12
+ .btn { display: block; width: fit-content; margin: 0 auto; padding: 12px 24px; background-color: {{ branding.color }}; color: #ffffff !important; text-decoration: none; border-radius: 8px; font-weight: 600; transition: background-color 0.2s; }
13
+ .footer { margin-top: 32px; font-size: 14px; color: #9ca3af; text-align: center; }
14
+ </style>
15
+ </head>
16
+ <body>
17
+ <div class="container">
18
+ <div class="logo">{{ branding.name }}</div>
19
+ <h1>{{ lang.welcome_title }}</h1>
20
+ <p>{{ lang.welcome_body }}</p>
21
+
22
+ <a href="{{ verificationUrl }}" class="btn">
23
+ {{ lang.verify_button }}
24
+ </a>
25
+
26
+ <div class="footer">
27
+ &copy; {{ currentYear }} {{ branding.name }}. All rights reserved.
28
+ </div>
29
+ </div>
30
+ </body>
31
+ </html>