create-aphex 0.1.1 → 0.2.0
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/dist/index.js +9 -88
- package/package.json +4 -4
- package/templates/base/.dockerignore +0 -44
- package/templates/base/.env.example +0 -38
- package/templates/base/CHANGELOG.md +0 -119
- package/templates/base/Dockerfile +0 -69
- package/templates/base/README.md +0 -147
- package/templates/base/aphex.config.ts +0 -45
- package/templates/base/docker-compose.yml +0 -31
- package/templates/base/drizzle/0000_tiny_redwing.sql +0 -226
- package/templates/base/drizzle/meta/0000_snapshot.json +0 -1379
- package/templates/base/drizzle/meta/_journal.json +0 -13
- package/templates/base/drizzle.config.ts +0 -17
- package/templates/base/package.json +0 -81
- package/templates/base/prod.docker-compose.yml +0 -61
- package/templates/base/src/app.css +0 -32
- package/templates/base/src/app.d.ts +0 -26
- package/templates/base/src/app.html +0 -11
- package/templates/base/src/hooks.server.ts +0 -52
- package/templates/base/src/lib/assets/favicon.svg +0 -5
- package/templates/base/src/lib/auth-client.ts +0 -19
- package/templates/base/src/lib/index.ts +0 -1
- package/templates/base/src/lib/schemaTypes/index.ts +0 -11
- package/templates/base/src/lib/schemaTypes/post.ts +0 -47
- package/templates/base/src/lib/server/auth/better-auth/instance.ts +0 -165
- package/templates/base/src/lib/server/auth/index.ts +0 -25
- package/templates/base/src/lib/server/auth/instance.ts +0 -7
- package/templates/base/src/lib/server/auth/service.ts +0 -486
- package/templates/base/src/lib/server/cache/index.ts +0 -10
- package/templates/base/src/lib/server/db/auth-schema.ts +0 -86
- package/templates/base/src/lib/server/db/cms-schema.ts +0 -23
- package/templates/base/src/lib/server/db/index.ts +0 -55
- package/templates/base/src/lib/server/db/schema.ts +0 -3
- package/templates/base/src/lib/server/email/components/EmailLayout.svelte +0 -24
- package/templates/base/src/lib/server/email/components/EmailVerification.svelte +0 -26
- package/templates/base/src/lib/server/email/components/Invitation.svelte +0 -30
- package/templates/base/src/lib/server/email/components/PasswordReset.svelte +0 -28
- package/templates/base/src/lib/server/email/index.ts +0 -28
- package/templates/base/src/lib/server/email/invitation-hook.ts +0 -56
- package/templates/base/src/lib/server/email/renderer.ts +0 -13
- package/templates/base/src/lib/server/email/templates/email-verification.ts +0 -8
- package/templates/base/src/lib/server/email/templates/invitation.ts +0 -8
- package/templates/base/src/lib/server/email/templates/password-reset.ts +0 -7
- package/templates/base/src/lib/server/services/organization.ts +0 -68
- package/templates/base/src/lib/server/storage/index.ts +0 -28
- package/templates/base/src/lib/stores/activeTab.svelte.ts +0 -14
- package/templates/base/src/lib/utils/imageBuilder.ts +0 -3
- package/templates/base/src/lib/utils/slug.ts +0 -33
- package/templates/base/src/routes/(protected)/admin/+layout.server.ts +0 -86
- package/templates/base/src/routes/(protected)/admin/+layout.svelte +0 -78
- package/templates/base/src/routes/(protected)/admin/+page.server.ts +0 -60
- package/templates/base/src/routes/(protected)/admin/+page.svelte +0 -34
- package/templates/base/src/routes/(protected)/admin/organizations/+page.server.ts +0 -39
- package/templates/base/src/routes/(protected)/admin/organizations/+page.svelte +0 -31
- package/templates/base/src/routes/(protected)/admin/organizations/_components/CreateOrganization.svelte +0 -141
- package/templates/base/src/routes/(protected)/admin/organizations/_components/OrganizationsList.svelte +0 -102
- package/templates/base/src/routes/(protected)/admin/settings/+layout.server.ts +0 -42
- package/templates/base/src/routes/(protected)/admin/settings/+layout.svelte +0 -116
- package/templates/base/src/routes/(protected)/admin/settings/+page.server.ts +0 -16
- package/templates/base/src/routes/(protected)/admin/settings/+page.svelte +0 -32
- package/templates/base/src/routes/(protected)/admin/settings/_components/AccountSettings.svelte +0 -177
- package/templates/base/src/routes/(protected)/admin/settings/_components/ApiKeysSettings.svelte +0 -472
- package/templates/base/src/routes/(protected)/admin/settings/_components/OrganizationsSettings.svelte +0 -182
- package/templates/base/src/routes/(protected)/admin/settings/account/+page.server.ts +0 -25
- package/templates/base/src/routes/(protected)/admin/settings/account/+page.svelte +0 -23
- package/templates/base/src/routes/(protected)/admin/settings/api-keys/+page.server.ts +0 -54
- package/templates/base/src/routes/(protected)/admin/settings/api-keys/+page.svelte +0 -14
- package/templates/base/src/routes/(protected)/admin/settings/members/+page.server.ts +0 -31
- package/templates/base/src/routes/(protected)/admin/settings/members/+page.svelte +0 -338
- package/templates/base/src/routes/(protected)/admin/settings/roles/+page.server.ts +0 -17
- package/templates/base/src/routes/(protected)/admin/settings/roles/+page.svelte +0 -339
- package/templates/base/src/routes/+layout.svelte +0 -12
- package/templates/base/src/routes/+page.svelte +0 -2
- package/templates/base/src/routes/api/[...slug]/+server.ts +0 -35
- package/templates/base/src/routes/api/instance-settings/+server.ts +0 -70
- package/templates/base/src/routes/api/invitations/+server.ts +0 -54
- package/templates/base/src/routes/api/invitations/[id]/accept/+server.ts +0 -54
- package/templates/base/src/routes/api/invitations/[id]/reject/+server.ts +0 -49
- package/templates/base/src/routes/api/settings/api-keys/+server.ts +0 -57
- package/templates/base/src/routes/api/settings/api-keys/[id]/+server.ts +0 -53
- package/templates/base/src/routes/god-mode/+layout.server.ts +0 -32
- package/templates/base/src/routes/god-mode/+layout.svelte +0 -155
- package/templates/base/src/routes/god-mode/+page.server.ts +0 -10
- package/templates/base/src/routes/god-mode/+page.svelte +0 -32
- package/templates/base/src/routes/god-mode/_components/CreateOrganization.svelte +0 -141
- package/templates/base/src/routes/god-mode/_components/OrganizationsList.svelte +0 -169
- package/templates/base/src/routes/god-mode/organizations/+page.server.ts +0 -43
- package/templates/base/src/routes/god-mode/organizations/+page.svelte +0 -74
- package/templates/base/src/routes/invitations/+page.server.ts +0 -48
- package/templates/base/src/routes/invitations/+page.svelte +0 -264
- package/templates/base/src/routes/invite/[token]/+page.server.ts +0 -59
- package/templates/base/src/routes/invite/[token]/+page.svelte +0 -109
- package/templates/base/src/routes/login/+page.server.ts +0 -14
- package/templates/base/src/routes/login/+page.svelte +0 -332
- package/templates/base/src/routes/media/[id]/[filename]/+server.ts +0 -3
- package/templates/base/src/routes/reset-password/[token]/+page.server.ts +0 -15
- package/templates/base/src/routes/reset-password/[token]/+page.svelte +0 -179
- package/templates/base/src/routes/verify-email/+page.svelte +0 -41
- package/templates/base/static/images/aphex-darkmode.png +0 -0
- package/templates/base/static/images/aphex-lightmode.png +0 -0
- package/templates/base/static/robots.txt +0 -3
- package/templates/base/svelte.config.js +0 -19
- package/templates/base/tsconfig.json +0 -20
- package/templates/base/vite.config.ts +0 -138
|
@@ -1,332 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { authClient } from '$lib/auth-client';
|
|
3
|
-
import { goto } from '$app/navigation';
|
|
4
|
-
import { page } from '$app/state';
|
|
5
|
-
import { Button } from '@aphexcms/ui/shadcn/button';
|
|
6
|
-
import { Input } from '@aphexcms/ui/shadcn/input';
|
|
7
|
-
import { Label } from '@aphexcms/ui/shadcn/label';
|
|
8
|
-
import * as Card from '@aphexcms/ui/shadcn/card';
|
|
9
|
-
import { resolve } from '$app/paths';
|
|
10
|
-
|
|
11
|
-
type Mode = 'signin' | 'signup' | 'reset-password';
|
|
12
|
-
|
|
13
|
-
// Read initial mode + prefilled email from URL (used by invite flow)
|
|
14
|
-
const initialMode: Mode = page.url.searchParams.get('mode') === 'signup' ? 'signup' : 'signin';
|
|
15
|
-
const prefilledEmail = page.url.searchParams.get('email') ?? '';
|
|
16
|
-
// When the email came from an invite link, lock the field so users can't
|
|
17
|
-
// sign up with an address that won't match the invitation.
|
|
18
|
-
const emailLocked = prefilledEmail.length > 0 && initialMode === 'signup';
|
|
19
|
-
|
|
20
|
-
let email = $state(prefilledEmail);
|
|
21
|
-
let password = $state('');
|
|
22
|
-
let error = $state('');
|
|
23
|
-
let loading = $state(false);
|
|
24
|
-
let mode: Mode = $state(initialMode);
|
|
25
|
-
let resetSuccess = $state('');
|
|
26
|
-
let signupSuccess = $state(false);
|
|
27
|
-
|
|
28
|
-
// Get callback URL for post-login redirect (used by invite flow)
|
|
29
|
-
let callbackUrl = $derived(page.url.searchParams.get('callbackUrl'));
|
|
30
|
-
|
|
31
|
-
// Error messages mapping
|
|
32
|
-
const errorMessages: Record<string, string> = {
|
|
33
|
-
session_expired: 'Your session has expired. Please log in again.',
|
|
34
|
-
no_organization:
|
|
35
|
-
'No organization found. Please contact an administrator to be invited to an organization.',
|
|
36
|
-
unauthorized: 'You do not have permission to access this resource.',
|
|
37
|
-
kicked_from_org:
|
|
38
|
-
'Your access to the organization has been revoked. Please contact your administrator.',
|
|
39
|
-
no_session: 'Please log in to continue.'
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
// Read error from URL reactively (Svelte 5)
|
|
43
|
-
$effect(() => {
|
|
44
|
-
const errorCode = page.url.searchParams.get('error');
|
|
45
|
-
if (errorCode && errorMessages[errorCode]) {
|
|
46
|
-
error = errorMessages[errorCode];
|
|
47
|
-
// Clear error from URL
|
|
48
|
-
const url = new URL(window.location.href);
|
|
49
|
-
url.searchParams.delete('error');
|
|
50
|
-
window.history.replaceState({}, '', url);
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
async function handleSubmit(e: SubmitEvent) {
|
|
55
|
-
e.preventDefault();
|
|
56
|
-
error = '';
|
|
57
|
-
resetSuccess = '';
|
|
58
|
-
loading = true;
|
|
59
|
-
|
|
60
|
-
try {
|
|
61
|
-
if (mode === 'reset-password') {
|
|
62
|
-
const response = await fetch('/api/user/request-password-reset', {
|
|
63
|
-
method: 'POST',
|
|
64
|
-
headers: {
|
|
65
|
-
'Content-Type': 'application/json'
|
|
66
|
-
},
|
|
67
|
-
body: JSON.stringify({
|
|
68
|
-
email,
|
|
69
|
-
redirectTo: `${window.location.origin}/reset-password`
|
|
70
|
-
})
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
const result = await response.json();
|
|
74
|
-
|
|
75
|
-
if (!response.ok || result.error) {
|
|
76
|
-
error = result.message || 'Failed to send reset email';
|
|
77
|
-
} else {
|
|
78
|
-
resetSuccess = 'Check your email for the password reset link';
|
|
79
|
-
}
|
|
80
|
-
} else if (mode === 'signin') {
|
|
81
|
-
const result = await authClient.signIn.email({
|
|
82
|
-
email,
|
|
83
|
-
password
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
if (result.error) {
|
|
87
|
-
if (result.error.code === 'EMAIL_NOT_VERIFIED') {
|
|
88
|
-
error =
|
|
89
|
-
'Please verify your email address before signing in. Check your inbox for a verification link.';
|
|
90
|
-
} else {
|
|
91
|
-
error = result.error.message || 'Failed to sign in';
|
|
92
|
-
}
|
|
93
|
-
} else {
|
|
94
|
-
goto(callbackUrl || '/admin');
|
|
95
|
-
}
|
|
96
|
-
} else {
|
|
97
|
-
// mode === 'signup'
|
|
98
|
-
const result = await authClient.signUp.email({
|
|
99
|
-
email,
|
|
100
|
-
password,
|
|
101
|
-
name: email.split('@')[0] // Use email username as name
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
if (result.error) {
|
|
105
|
-
error = result.error.message || 'Failed to sign up';
|
|
106
|
-
} else {
|
|
107
|
-
// Email verification is enabled — show confirmation instead of redirecting
|
|
108
|
-
signupSuccess = true;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
} catch (err) {
|
|
112
|
-
error = err instanceof Error ? err.message : 'An error occurred';
|
|
113
|
-
} finally {
|
|
114
|
-
loading = false;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function setMode(newMode: Mode) {
|
|
119
|
-
mode = newMode;
|
|
120
|
-
error = '';
|
|
121
|
-
resetSuccess = '';
|
|
122
|
-
}
|
|
123
|
-
</script>
|
|
124
|
-
|
|
125
|
-
<svelte:head>
|
|
126
|
-
<title>{mode === 'signin' ? 'Aphex CMS - Sign In' : 'Aphex CMS - Sign Up'}</title>
|
|
127
|
-
<meta
|
|
128
|
-
name="description"
|
|
129
|
-
content={mode === 'signin'
|
|
130
|
-
? 'Sign in to your Aphex CMS dashboard to manage your content and organizations.'
|
|
131
|
-
: 'Create a new account to get started with Aphex CMS and manage your content.'}
|
|
132
|
-
/>
|
|
133
|
-
</svelte:head>
|
|
134
|
-
|
|
135
|
-
<div class="bg-muted/40 flex min-h-screen items-center justify-center px-4 py-12">
|
|
136
|
-
<div class="w-full max-w-md">
|
|
137
|
-
<Card.Root class="shadow-lg">
|
|
138
|
-
<Card.Header class="space-y-1">
|
|
139
|
-
<Card.Title class="text-center text-2xl font-bold">
|
|
140
|
-
{mode === 'reset-password'
|
|
141
|
-
? 'Reset Password'
|
|
142
|
-
: mode === 'signin'
|
|
143
|
-
? 'Sign In'
|
|
144
|
-
: 'Create Account'}
|
|
145
|
-
</Card.Title>
|
|
146
|
-
<Card.Description class="text-center">
|
|
147
|
-
{mode === 'reset-password'
|
|
148
|
-
? 'Enter your email to receive a reset link'
|
|
149
|
-
: mode === 'signin'
|
|
150
|
-
? 'Access your CMS dashboard'
|
|
151
|
-
: 'Get started with Aphex CMS'}
|
|
152
|
-
</Card.Description>
|
|
153
|
-
</Card.Header>
|
|
154
|
-
|
|
155
|
-
<Card.Content>
|
|
156
|
-
{#if signupSuccess}
|
|
157
|
-
<div class="space-y-4">
|
|
158
|
-
<div class="rounded-lg border border-green-500/50 bg-green-500/10 p-4 text-center">
|
|
159
|
-
<p class="font-medium text-green-700 dark:text-green-400">
|
|
160
|
-
Account created! Check your email to verify your address.
|
|
161
|
-
</p>
|
|
162
|
-
<p class="text-muted-foreground mt-2 text-sm">
|
|
163
|
-
We sent a verification link to <strong>{email}</strong>
|
|
164
|
-
</p>
|
|
165
|
-
</div>
|
|
166
|
-
<Button
|
|
167
|
-
variant="outline"
|
|
168
|
-
class="w-full"
|
|
169
|
-
onclick={() => {
|
|
170
|
-
signupSuccess = false;
|
|
171
|
-
setMode('signin');
|
|
172
|
-
}}
|
|
173
|
-
>
|
|
174
|
-
Back to Sign In
|
|
175
|
-
</Button>
|
|
176
|
-
</div>
|
|
177
|
-
{:else}
|
|
178
|
-
<form onsubmit={handleSubmit} class="space-y-4">
|
|
179
|
-
<!-- Success Alert -->
|
|
180
|
-
{#if resetSuccess}
|
|
181
|
-
<div class="rounded-lg border border-green-500/50 bg-green-500/10 p-3">
|
|
182
|
-
<p class="text-sm font-medium text-green-700 dark:text-green-400">{resetSuccess}</p>
|
|
183
|
-
</div>
|
|
184
|
-
{/if}
|
|
185
|
-
|
|
186
|
-
<!-- Error Alert -->
|
|
187
|
-
{#if error}
|
|
188
|
-
<div class="border-destructive/50 bg-destructive/10 rounded-lg border p-3">
|
|
189
|
-
<p class="text-destructive text-sm font-medium">{error}</p>
|
|
190
|
-
</div>
|
|
191
|
-
{/if}
|
|
192
|
-
|
|
193
|
-
<!-- Email Field -->
|
|
194
|
-
<div class="space-y-2">
|
|
195
|
-
<Label for="email">Email</Label>
|
|
196
|
-
<Input
|
|
197
|
-
id="email"
|
|
198
|
-
type="email"
|
|
199
|
-
placeholder="you@example.com"
|
|
200
|
-
bind:value={email}
|
|
201
|
-
required
|
|
202
|
-
autocomplete="email"
|
|
203
|
-
readonly={emailLocked}
|
|
204
|
-
/>
|
|
205
|
-
{#if emailLocked}
|
|
206
|
-
<p class="text-muted-foreground text-xs">Locked to match your invitation.</p>
|
|
207
|
-
{/if}
|
|
208
|
-
</div>
|
|
209
|
-
|
|
210
|
-
<!-- Password Field (hidden in reset mode) -->
|
|
211
|
-
{#if mode !== 'reset-password'}
|
|
212
|
-
<div class="space-y-2">
|
|
213
|
-
<div class="flex items-center justify-between">
|
|
214
|
-
<Label for="password">Password</Label>
|
|
215
|
-
{#if mode === 'signin'}
|
|
216
|
-
<button
|
|
217
|
-
type="button"
|
|
218
|
-
class="text-primary text-xs hover:underline"
|
|
219
|
-
onclick={() => setMode('reset-password')}
|
|
220
|
-
>
|
|
221
|
-
Forgot password?
|
|
222
|
-
</button>
|
|
223
|
-
{/if}
|
|
224
|
-
</div>
|
|
225
|
-
<Input
|
|
226
|
-
id="password"
|
|
227
|
-
type="password"
|
|
228
|
-
placeholder="••••••••"
|
|
229
|
-
bind:value={password}
|
|
230
|
-
required
|
|
231
|
-
autocomplete={mode === 'signin' ? 'current-password' : 'new-password'}
|
|
232
|
-
/>
|
|
233
|
-
{#if mode === 'signup'}
|
|
234
|
-
<p class="text-muted-foreground text-xs">Must be at least 8 characters long</p>
|
|
235
|
-
{/if}
|
|
236
|
-
</div>
|
|
237
|
-
{/if}
|
|
238
|
-
|
|
239
|
-
<!-- Submit Button -->
|
|
240
|
-
<Button type="submit" class="w-full" disabled={loading}>
|
|
241
|
-
{#if loading}
|
|
242
|
-
<svg
|
|
243
|
-
class="mr-2 h-4 w-4 animate-spin"
|
|
244
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
245
|
-
fill="none"
|
|
246
|
-
viewBox="0 0 24 24"
|
|
247
|
-
>
|
|
248
|
-
<circle
|
|
249
|
-
class="opacity-25"
|
|
250
|
-
cx="12"
|
|
251
|
-
cy="12"
|
|
252
|
-
r="10"
|
|
253
|
-
stroke="currentColor"
|
|
254
|
-
stroke-width="4"
|
|
255
|
-
></circle>
|
|
256
|
-
<path
|
|
257
|
-
class="opacity-75"
|
|
258
|
-
fill="currentColor"
|
|
259
|
-
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
260
|
-
></path>
|
|
261
|
-
</svg>
|
|
262
|
-
{/if}
|
|
263
|
-
{mode === 'reset-password'
|
|
264
|
-
? 'Send Reset Link'
|
|
265
|
-
: mode === 'signin'
|
|
266
|
-
? 'Sign In'
|
|
267
|
-
: 'Sign Up'}
|
|
268
|
-
</Button>
|
|
269
|
-
|
|
270
|
-
<!-- Back to Sign In (in reset mode) -->
|
|
271
|
-
{#if mode === 'reset-password'}
|
|
272
|
-
<Button
|
|
273
|
-
type="button"
|
|
274
|
-
variant="ghost"
|
|
275
|
-
class="w-full"
|
|
276
|
-
onclick={() => setMode('signin')}
|
|
277
|
-
>
|
|
278
|
-
← Back to Sign In
|
|
279
|
-
</Button>
|
|
280
|
-
{/if}
|
|
281
|
-
</form>
|
|
282
|
-
{/if}
|
|
283
|
-
</Card.Content>
|
|
284
|
-
|
|
285
|
-
<Card.Footer class="flex flex-col space-y-4">
|
|
286
|
-
{#if !signupSuccess && mode !== 'reset-password'}
|
|
287
|
-
<div class="relative">
|
|
288
|
-
<div class="absolute inset-0 flex items-center">
|
|
289
|
-
<span class="w-full border-t"></span>
|
|
290
|
-
</div>
|
|
291
|
-
<div class="relative flex justify-center text-xs uppercase">
|
|
292
|
-
<span class="bg-card text-muted-foreground px-2">
|
|
293
|
-
{mode === 'signin' ? 'New to Aphex?' : 'Already have an account?'}
|
|
294
|
-
</span>
|
|
295
|
-
</div>
|
|
296
|
-
</div>
|
|
297
|
-
|
|
298
|
-
<Button
|
|
299
|
-
type="button"
|
|
300
|
-
variant="outline"
|
|
301
|
-
class="w-full"
|
|
302
|
-
onclick={() => setMode(mode === 'signin' ? 'signup' : 'signin')}
|
|
303
|
-
>
|
|
304
|
-
{mode === 'signin' ? 'Create an account' : 'Sign in instead'}
|
|
305
|
-
</Button>
|
|
306
|
-
{/if}
|
|
307
|
-
</Card.Footer>
|
|
308
|
-
</Card.Root>
|
|
309
|
-
|
|
310
|
-
<!-- Footer -->
|
|
311
|
-
<p class="text-muted-foreground mt-6 text-center text-xs">Aphex CMS - Built with SvelteKit</p>
|
|
312
|
-
|
|
313
|
-
<!-- Footer Logo -->
|
|
314
|
-
<div class="mt-2 flex justify-center opacity-20">
|
|
315
|
-
<svg
|
|
316
|
-
class="h-8 w-8 fill-black dark:fill-white"
|
|
317
|
-
version="1.1"
|
|
318
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
319
|
-
viewBox="0 0 512 512"
|
|
320
|
-
>
|
|
321
|
-
<path
|
|
322
|
-
d="M0 0 C17.1474496 14.16905616 25.92496627 35.45820085 34.56640625 55.4140625 C35.34334316 57.19720923 36.12053079 58.98024674 36.89794922 60.76318359 C51.78722595 94.97195072 66.32335778 129.32882671 80.31640625 163.9140625 C80.6444928 164.72450012 80.97257935 165.53493774 81.31060791 166.36993408 C99.98913061 212.53216334 117.78569191 259.01293728 134.00390625 306.1015625 C134.36190811 307.13669983 134.36190811 307.13669983 134.72714233 308.19274902 C137.32766526 315.72906515 139.80262285 323.3004011 142.1171875 330.9296875 C142.43800545 331.95940926 142.43800545 331.95940926 142.76530457 333.00993347 C145.2565569 341.39135358 146.09964488 351.05219488 142.44140625 359.23046875 C139.92789443 362.992009 136.34564423 365.89944351 132.31640625 367.9140625 C124.8558052 368.61421121 118.36839373 368.62364314 112.31640625 363.9140625 C105.53664487 356.69699976 100.652558 348.68983785 95.94140625 340.0390625 C90.47619491 330.29913602 84.93335438 322.05287151 77.31640625 313.9140625 C75.27331056 311.57880549 73.26394666 309.2152832 71.25390625 306.8515625 C70.24519648 305.67152884 69.23608749 304.49183631 68.2265625 303.3125 C67.73816895 302.74112305 67.24977539 302.16974609 66.74658203 301.58105469 C65.40017275 300.01169952 64.04454028 298.45078423 62.6875 296.890625 C48.81582552 280.69615056 38.44623629 261.89870442 27.89111328 243.45849609 C-8.42360388 178.69858879 -8.42360388 178.69858879 -68.08203125 137.78515625 C-79.11186673 135.11741947 -89.899608 136.09230489 -99.68359375 141.9140625 C-115.46806791 152.47947666 -122.3076261 172.13261849 -126.43359375 189.7890625 C-126.73185059 191.06136719 -126.73185059 191.06136719 -127.03613281 192.359375 C-130.16760015 206.71148601 -131.06828893 221.08194412 -130.99609375 235.7265625 C-130.9939386 236.51966827 -130.99178345 237.31277405 -130.98956299 238.12991333 C-131.31394288 266.6844263 -131.31394288 266.6844263 -123.23828125 293.5859375 C-112.95312656 315.60340432 -111.26097095 345.34400812 -119.5 368.0390625 C-124.86779615 381.07766965 -132.78250397 390.79435644 -145.68359375 396.9140625 C-155.27731384 400.41943083 -164.20346687 401.56551213 -174.37109375 401.4140625 C-176.32958252 401.39702271 -176.32958252 401.39702271 -178.32763672 401.37963867 C-197.70054192 400.99323331 -215.16231823 397.0095896 -230.68359375 384.9140625 C-231.37066406 384.41519531 -232.05773437 383.91632813 -232.765625 383.40234375 C-244.80767188 373.97296976 -251.15090869 358.63090674 -253.68359375 343.9140625 C-253.9270261 339.66653687 -253.91464574 335.41789154 -253.93359375 331.1640625 C-253.96453125 329.45089844 -253.96453125 329.45089844 -253.99609375 327.703125 C-254.00125 326.58164062 -254.00640625 325.46015625 -254.01171875 324.3046875 C-254.02106445 323.29438477 -254.03041016 322.28408203 -254.04003906 321.24316406 C-253.25260131 313.88871121 -250.02140677 307.08532381 -247.0859375 300.359375 C-246.73986954 299.55749252 -246.39380157 298.75561005 -246.0372467 297.9294281 C-245.29136983 296.20150738 -244.54396437 294.47424582 -243.79516602 292.74758911 C-241.75797546 288.04789133 -239.73451175 283.34229198 -237.7109375 278.63671875 C-237.0834108 277.17808662 -237.0834108 277.17808662 -236.44320679 275.68998718 C-232.12759637 265.64489937 -227.89599701 255.56528394 -223.68359375 245.4765625 C-223.31303864 244.58933502 -222.94248352 243.70210754 -222.56069946 242.78799438 C-221.05624911 239.1852842 -219.55230259 235.58236459 -218.04930115 231.97904968 C-215.45620988 225.7624217 -212.85713855 219.54832537 -210.25390625 213.3359375 C-199.87599396 188.56875674 -189.53860671 163.78483086 -179.21582031 138.99462891 C-176.70326253 132.96093438 -174.18966694 126.92767262 -171.67578125 120.89453125 C-171.2632309 119.90436005 -170.85068054 118.91418884 -170.42562866 117.89401245 C-168.35461551 112.92351005 -166.28304289 107.95324201 -164.21044922 102.98339844 C-160.33953189 93.69973915 -156.47385511 84.41400336 -152.62658691 75.12051392 C-150.82992691 70.78139762 -149.03030349 66.44351312 -147.23046875 62.10571289 C-146.38199036 60.05847127 -145.53492768 58.01064218 -144.68945312 55.9621582 C-140.72547669 46.35880091 -136.72273166 36.78723512 -132.3203125 27.375 C-132.00310242 26.69433975 -131.68589233 26.0136795 -131.35906982 25.31239319 C-123.25124472 8.26154126 -109.39227096 -6.16254505 -91.68359375 -13.0859375 C-59.99340229 -22.6620319 -26.67593546 -20.59334511 0 0 Z "
|
|
323
|
-
transform="translate(308.68359375,64.0859375)"
|
|
324
|
-
/>
|
|
325
|
-
<path
|
|
326
|
-
d="M0 0 C18.24717952 9.79342293 31.4582424 26.28742033 37.6171875 45.97265625 C39.90862161 58.10790422 38.62948747 76.77026254 32.3125 87.5625 C31.23887442 89.06398132 30.13305826 90.54284625 29 92 C28.04867187 93.39798828 28.04867187 93.39798828 27.078125 94.82421875 C22.05477616 102.1158627 16.59613089 108.96607145 8 112 C-4.55244493 113.74100692 -12.66496084 107.03937869 -22.140625 99.87890625 C-25.14482573 97.61370274 -28.2068393 95.46853473 -31.33056641 93.37231445 C-44.35072813 84.61921656 -53.55106508 73.69367426 -57 58 C-59.27762162 41.63399726 -53.36243485 19.43955677 -44.1875 5.9375 C-32.8352893 -8.66127096 -15.43371672 -7.37348527 0 0 Z "
|
|
327
|
-
transform="translate(254,240)"
|
|
328
|
-
/>
|
|
329
|
-
</svg>
|
|
330
|
-
</div>
|
|
331
|
-
</div>
|
|
332
|
-
</div>
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { redirect } from '@sveltejs/kit';
|
|
2
|
-
import type { PageServerLoad } from '../../(protected)/admin/$types';
|
|
3
|
-
|
|
4
|
-
export const load: PageServerLoad = async ({ locals, request }) => {
|
|
5
|
-
const { aphexCMS } = locals;
|
|
6
|
-
|
|
7
|
-
const session = await aphexCMS.auth?.getSession(request, aphexCMS.databaseAdapter);
|
|
8
|
-
|
|
9
|
-
// If user is already authenticated, redirect to admin
|
|
10
|
-
if (session?.session) {
|
|
11
|
-
throw redirect(302, '/admin');
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
return {};
|
|
15
|
-
};
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { authClient } from '$lib/auth-client';
|
|
3
|
-
import { goto } from '$app/navigation';
|
|
4
|
-
import { page } from '$app/state';
|
|
5
|
-
import { Button } from '@aphexcms/ui/shadcn/button';
|
|
6
|
-
import { Input } from '@aphexcms/ui/shadcn/input';
|
|
7
|
-
import { Label } from '@aphexcms/ui/shadcn/label';
|
|
8
|
-
import * as Card from '@aphexcms/ui/shadcn/card';
|
|
9
|
-
import { resolve } from '$app/paths';
|
|
10
|
-
|
|
11
|
-
let newPassword = $state('');
|
|
12
|
-
let confirmPassword = $state('');
|
|
13
|
-
let error = $state('');
|
|
14
|
-
let success = $state(false);
|
|
15
|
-
let loading = $state(false);
|
|
16
|
-
let token = $state('');
|
|
17
|
-
|
|
18
|
-
// Get token from SvelteKit route params
|
|
19
|
-
$effect(() => {
|
|
20
|
-
const errorParam = page.url.searchParams.get('error');
|
|
21
|
-
|
|
22
|
-
if (errorParam === 'INVALID_TOKEN') {
|
|
23
|
-
error = 'Invalid or expired reset link. Please request a new password reset.';
|
|
24
|
-
} else if (page.params.token) {
|
|
25
|
-
// Token from dynamic route parameter
|
|
26
|
-
token = page.params.token;
|
|
27
|
-
} else {
|
|
28
|
-
error = 'No reset token provided. Please request a new password reset.';
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
async function handleSubmit(e: SubmitEvent) {
|
|
33
|
-
e.preventDefault();
|
|
34
|
-
error = '';
|
|
35
|
-
loading = true;
|
|
36
|
-
|
|
37
|
-
if (newPassword !== confirmPassword) {
|
|
38
|
-
error = 'Passwords do not match';
|
|
39
|
-
loading = false;
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (newPassword.length < 8) {
|
|
44
|
-
error = 'Password must be at least 8 characters long';
|
|
45
|
-
loading = false;
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
try {
|
|
50
|
-
const result = await authClient.resetPassword({
|
|
51
|
-
newPassword,
|
|
52
|
-
token
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
if (result.error) {
|
|
56
|
-
error = result.error.message || 'Failed to reset password';
|
|
57
|
-
} else {
|
|
58
|
-
success = true;
|
|
59
|
-
setTimeout(() => {
|
|
60
|
-
goto(resolve('/login'));
|
|
61
|
-
}, 2000);
|
|
62
|
-
}
|
|
63
|
-
} catch (err) {
|
|
64
|
-
error = err instanceof Error ? err.message : 'An error occurred';
|
|
65
|
-
} finally {
|
|
66
|
-
loading = false;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
</script>
|
|
70
|
-
|
|
71
|
-
<svelte:head>
|
|
72
|
-
<title>Aphex CMS - Reset Password</title>
|
|
73
|
-
<meta name="description" content="Reset your Aphex CMS account password securely." />
|
|
74
|
-
</svelte:head>
|
|
75
|
-
|
|
76
|
-
<div class="bg-muted/40 flex min-h-screen items-center justify-center px-4 py-12">
|
|
77
|
-
<div class="w-full max-w-md">
|
|
78
|
-
<Card.Root class="shadow-lg">
|
|
79
|
-
<Card.Header class="space-y-1">
|
|
80
|
-
<Card.Title class="text-center text-2xl font-bold">
|
|
81
|
-
{success ? 'Password Reset!' : 'Reset Your Password'}
|
|
82
|
-
</Card.Title>
|
|
83
|
-
<Card.Description class="text-center">
|
|
84
|
-
{success ? 'Redirecting to login...' : 'Enter your new password'}
|
|
85
|
-
</Card.Description>
|
|
86
|
-
</Card.Header>
|
|
87
|
-
|
|
88
|
-
<Card.Content>
|
|
89
|
-
{#if success}
|
|
90
|
-
<div class="rounded-lg border border-green-500/50 bg-green-500/10 p-4 text-center">
|
|
91
|
-
<p class="font-medium text-green-700 dark:text-green-400">
|
|
92
|
-
Your password has been reset successfully!
|
|
93
|
-
</p>
|
|
94
|
-
</div>
|
|
95
|
-
{:else}
|
|
96
|
-
<form onsubmit={handleSubmit} class="space-y-4">
|
|
97
|
-
<!-- Error Alert -->
|
|
98
|
-
{#if error}
|
|
99
|
-
<div class="border-destructive/50 bg-destructive/10 rounded-lg border p-3">
|
|
100
|
-
<p class="text-destructive text-sm font-medium">{error}</p>
|
|
101
|
-
</div>
|
|
102
|
-
{/if}
|
|
103
|
-
|
|
104
|
-
<!-- New Password Field -->
|
|
105
|
-
<div class="space-y-2">
|
|
106
|
-
<Label for="newPassword">New Password</Label>
|
|
107
|
-
<Input
|
|
108
|
-
id="newPassword"
|
|
109
|
-
type="password"
|
|
110
|
-
placeholder="••••••••"
|
|
111
|
-
bind:value={newPassword}
|
|
112
|
-
required
|
|
113
|
-
autocomplete="new-password"
|
|
114
|
-
disabled={!token || loading}
|
|
115
|
-
/>
|
|
116
|
-
<p class="text-muted-foreground text-xs">Must be at least 8 characters long</p>
|
|
117
|
-
</div>
|
|
118
|
-
|
|
119
|
-
<!-- Confirm Password Field -->
|
|
120
|
-
<div class="space-y-2">
|
|
121
|
-
<Label for="confirmPassword">Confirm Password</Label>
|
|
122
|
-
<Input
|
|
123
|
-
id="confirmPassword"
|
|
124
|
-
type="password"
|
|
125
|
-
placeholder="••••••••"
|
|
126
|
-
bind:value={confirmPassword}
|
|
127
|
-
required
|
|
128
|
-
autocomplete="new-password"
|
|
129
|
-
disabled={!token || loading}
|
|
130
|
-
/>
|
|
131
|
-
</div>
|
|
132
|
-
|
|
133
|
-
<!-- Submit Button -->
|
|
134
|
-
<Button type="submit" class="w-full" disabled={!token || loading}>
|
|
135
|
-
{#if loading}
|
|
136
|
-
<svg
|
|
137
|
-
class="mr-2 h-4 w-4 animate-spin"
|
|
138
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
139
|
-
fill="none"
|
|
140
|
-
viewBox="0 0 24 24"
|
|
141
|
-
>
|
|
142
|
-
<circle
|
|
143
|
-
class="opacity-25"
|
|
144
|
-
cx="12"
|
|
145
|
-
cy="12"
|
|
146
|
-
r="10"
|
|
147
|
-
stroke="currentColor"
|
|
148
|
-
stroke-width="4"
|
|
149
|
-
></circle>
|
|
150
|
-
<path
|
|
151
|
-
class="opacity-75"
|
|
152
|
-
fill="currentColor"
|
|
153
|
-
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
154
|
-
></path>
|
|
155
|
-
</svg>
|
|
156
|
-
{/if}
|
|
157
|
-
Reset Password
|
|
158
|
-
</Button>
|
|
159
|
-
|
|
160
|
-
<!-- Back to Login -->
|
|
161
|
-
<Button
|
|
162
|
-
type="button"
|
|
163
|
-
variant="ghost"
|
|
164
|
-
class="w-full"
|
|
165
|
-
onclick={() => goto(resolve('/login'))}
|
|
166
|
-
>
|
|
167
|
-
← Back to Login
|
|
168
|
-
</Button>
|
|
169
|
-
</form>
|
|
170
|
-
{/if}
|
|
171
|
-
</Card.Content>
|
|
172
|
-
</Card.Root>
|
|
173
|
-
|
|
174
|
-
<!-- Footer -->
|
|
175
|
-
<p class="text-muted-foreground mt-6 text-center text-xs">
|
|
176
|
-
Aphex CMS - Built with SvelteKit & Better Auth
|
|
177
|
-
</p>
|
|
178
|
-
</div>
|
|
179
|
-
</div>
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { goto } from '$app/navigation';
|
|
3
|
-
import { page } from '$app/state';
|
|
4
|
-
import { Button } from '@aphexcms/ui/shadcn/button';
|
|
5
|
-
import * as Card from '@aphexcms/ui/shadcn/card';
|
|
6
|
-
|
|
7
|
-
// Better Auth redirects here after successful verification
|
|
8
|
-
// with autoSignInAfterVerification, user may already be signed in
|
|
9
|
-
let callbackUrl = $derived(page.url.searchParams.get('callbackUrl'));
|
|
10
|
-
</script>
|
|
11
|
-
|
|
12
|
-
<svelte:head>
|
|
13
|
-
<title>Aphex CMS - Email Verified</title>
|
|
14
|
-
</svelte:head>
|
|
15
|
-
|
|
16
|
-
<div class="bg-muted/40 flex min-h-screen items-center justify-center px-4 py-12">
|
|
17
|
-
<div class="w-full max-w-md">
|
|
18
|
-
<Card.Root class="shadow-lg">
|
|
19
|
-
<Card.Header class="space-y-1">
|
|
20
|
-
<Card.Title class="text-center text-2xl font-bold">Email Verified</Card.Title>
|
|
21
|
-
<Card.Description class="text-center">
|
|
22
|
-
Your email has been verified successfully
|
|
23
|
-
</Card.Description>
|
|
24
|
-
</Card.Header>
|
|
25
|
-
|
|
26
|
-
<Card.Content>
|
|
27
|
-
<div class="rounded-lg border border-green-500/50 bg-green-500/10 p-4 text-center">
|
|
28
|
-
<p class="font-medium text-green-700 dark:text-green-400">
|
|
29
|
-
Your email address has been verified. You can now sign in.
|
|
30
|
-
</p>
|
|
31
|
-
</div>
|
|
32
|
-
|
|
33
|
-
<Button class="mt-6 w-full" onclick={() => goto(callbackUrl || '/login')}>
|
|
34
|
-
Continue to Sign In
|
|
35
|
-
</Button>
|
|
36
|
-
</Card.Content>
|
|
37
|
-
</Card.Root>
|
|
38
|
-
|
|
39
|
-
<p class="text-muted-foreground mt-6 text-center text-xs">Aphex CMS - Built with SvelteKit</p>
|
|
40
|
-
</div>
|
|
41
|
-
</div>
|
|
Binary file
|
|
Binary file
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { mdsvex } from 'mdsvex';
|
|
2
|
-
import adapterAuto from '@sveltejs/adapter-auto';
|
|
3
|
-
import adapterNode from '@sveltejs/adapter-node';
|
|
4
|
-
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
|
5
|
-
|
|
6
|
-
/** @type {import('@sveltejs/kit').Config} */
|
|
7
|
-
const config = {
|
|
8
|
-
preprocess: [vitePreprocess(), mdsvex()],
|
|
9
|
-
kit: {
|
|
10
|
-
adapter: process.env.ADAPTER === 'node' ? adapterNode() : adapterAuto(),
|
|
11
|
-
alias: {
|
|
12
|
-
'@lib': '../../packages/ui/src/lib',
|
|
13
|
-
'@lib/*': '../../packages/ui/src/lib/*'
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
extensions: ['.svelte', '.svx']
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export default config;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "./.svelte-kit/tsconfig.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"allowJs": true,
|
|
5
|
-
"checkJs": true,
|
|
6
|
-
"esModuleInterop": true,
|
|
7
|
-
"forceConsistentCasingInFileNames": true,
|
|
8
|
-
"resolveJsonModule": true,
|
|
9
|
-
"skipLibCheck": true,
|
|
10
|
-
"sourceMap": true,
|
|
11
|
-
"strict": true,
|
|
12
|
-
"moduleResolution": "bundler",
|
|
13
|
-
"allowImportingTsExtensions": true
|
|
14
|
-
}
|
|
15
|
-
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
|
16
|
-
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
|
|
17
|
-
//
|
|
18
|
-
// To make changes to top-level options such as include and exclude, we recommend extending
|
|
19
|
-
// the generated config; see https://svelte.dev/docs/kit/configuration#typescript
|
|
20
|
-
}
|