@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.
- package/.dockerignore +8 -0
- package/.env.example +19 -0
- package/ARCHITECTURE.md +14 -0
- package/CHANGELOG.md +14 -0
- package/Dockerfile +25 -0
- package/README.md +112 -0
- package/WHITEPAPER.md +20 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +1121 -0
- package/docs/EXTENDING.md +99 -0
- package/docs/PASSKEYS.md +78 -0
- package/locales/en.json +30 -0
- package/locales/zh-TW.json +30 -0
- package/package.json +35 -0
- package/src/Application/DTOs/MemberDTO.ts +34 -0
- package/src/Application/Mail/ForgotPasswordMail.ts +42 -0
- package/src/Application/Mail/MemberLevelChangedMail.ts +41 -0
- package/src/Application/Mail/WelcomeMail.ts +45 -0
- package/src/Application/Services/PasskeysService.ts +198 -0
- package/src/Application/UseCases/ForgotPassword.ts +34 -0
- package/src/Application/UseCases/LoginMember.ts +64 -0
- package/src/Application/UseCases/RegisterMember.ts +65 -0
- package/src/Application/UseCases/ResetPassword.ts +30 -0
- package/src/Application/UseCases/UpdateMemberLevel.ts +47 -0
- package/src/Application/UseCases/UpdateSettings.ts +81 -0
- package/src/Application/UseCases/VerifyEmail.ts +23 -0
- package/src/Domain/Contracts/IMemberPasskeyRepository.ts +8 -0
- package/src/Domain/Contracts/IMemberRepository.ts +11 -0
- package/src/Domain/Entities/Member.ts +219 -0
- package/src/Domain/Entities/MemberPasskey.ts +97 -0
- package/src/Infrastructure/Auth/SentinelMemberProvider.ts +52 -0
- package/src/Infrastructure/Persistence/AtlasMemberPasskeyRepository.ts +63 -0
- package/src/Infrastructure/Persistence/AtlasMemberRepository.ts +91 -0
- package/src/Infrastructure/Persistence/Migrations/20250101_create_members_table.ts +30 -0
- package/src/Infrastructure/Persistence/Migrations/20250102_create_member_passkeys_table.ts +25 -0
- package/src/Interface/Http/Controllers/PasskeyController.ts +98 -0
- package/src/Interface/Http/Middleware/VerifySingleDevice.ts +51 -0
- package/src/index.ts +234 -0
- package/src/manifest.json +15 -0
- package/tests/PasskeysService.test.ts +113 -0
- package/tests/email-integration.test.ts +161 -0
- package/tests/grand-review.ts +176 -0
- package/tests/integration.test.ts +75 -0
- package/tests/member.test.ts +47 -0
- package/tests/unit.test.ts +7 -0
- package/tests/update-settings.test.ts +101 -0
- package/tsconfig.json +26 -0
- package/views/emails/level_changed.html +35 -0
- package/views/emails/reset_password.html +34 -0
- 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
|
+
© {{ 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
|
+
© {{ 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
|
+
© {{ currentYear }} {{ branding.name }}. All rights reserved.
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
</body>
|
|
31
|
+
</html>
|