sveltekit-auth-example 2.0.0 → 2.0.2

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 (38) hide show
  1. package/.eslintrc.cjs +19 -7
  2. package/.prettierignore +1 -0
  3. package/.yarn/install-state.gz +0 -0
  4. package/CHANGELOG.md +164 -98
  5. package/README.md +6 -1
  6. package/package.json +67 -66
  7. package/prettier.config.mjs +15 -0
  8. package/src/app.d.ts +31 -29
  9. package/src/app.html +8 -3
  10. package/src/hooks.server.ts +15 -15
  11. package/src/lib/focus.ts +6 -6
  12. package/src/lib/google.ts +48 -49
  13. package/src/lib/server/db.ts +7 -6
  14. package/src/lib/server/sendgrid.ts +11 -11
  15. package/src/routes/+error.svelte +1 -1
  16. package/src/routes/+layout.server.ts +5 -5
  17. package/src/routes/+layout.svelte +133 -100
  18. package/src/routes/admin/+page.server.ts +1 -1
  19. package/src/routes/admin/+page.svelte +2 -2
  20. package/src/routes/api/v1/user/+server.ts +13 -14
  21. package/src/routes/auth/[slug]/+server.ts +11 -6
  22. package/src/routes/auth/forgot/+server.ts +23 -23
  23. package/src/routes/auth/google/+server.ts +44 -45
  24. package/src/routes/auth/reset/+server.ts +1 -1
  25. package/src/routes/auth/reset/[token]/+page.svelte +117 -95
  26. package/src/routes/auth/reset/[token]/+page.ts +4 -4
  27. package/src/routes/forgot/+page.svelte +74 -63
  28. package/src/routes/info/+page.svelte +1 -1
  29. package/src/routes/login/+page.svelte +140 -120
  30. package/src/routes/profile/+page.server.ts +9 -9
  31. package/src/routes/profile/+page.svelte +142 -88
  32. package/src/routes/register/+page.server.ts +3 -2
  33. package/src/routes/register/+page.svelte +159 -104
  34. package/src/routes/teachers/+page.server.ts +5 -5
  35. package/src/routes/teachers/+page.svelte +2 -2
  36. package/src/stores.ts +1 -1
  37. package/svelte.config.js +1 -1
  38. package/.prettierrc +0 -9
@@ -1,57 +1,56 @@
1
1
  <script lang="ts">
2
- import { onMount } from 'svelte'
3
- import { goto } from '$app/navigation'
4
- import { loginSession } from '../../stores'
5
- import { focusOnFirstError } from '$lib/focus'
6
- import { initializeGoogleAccounts, renderGoogleButton } from '$lib/google'
2
+ import { onMount } from 'svelte'
3
+ import { goto } from '$app/navigation'
4
+ import { loginSession } from '../../stores'
5
+ import { focusOnFirstError } from '$lib/focus'
6
+ import { initializeGoogleAccounts, renderGoogleButton } from '$lib/google'
7
7
 
8
- let focusedField: HTMLInputElement
8
+ let focusedField: HTMLInputElement
9
9
 
10
- let user: User = {
11
- id: 0,
12
- role: 'student',
13
- firstName: '',
14
- lastName: '',
15
- password: '',
16
- email: '',
17
- phone: ''
18
- }
19
- let confirmPassword: HTMLInputElement
20
- let message: string
10
+ let user: User = {
11
+ id: 0,
12
+ role: 'student',
13
+ firstName: '',
14
+ lastName: '',
15
+ password: '',
16
+ email: '',
17
+ phone: ''
18
+ }
19
+ let confirmPassword: HTMLInputElement
20
+ let message: string
21
21
 
22
- async function register() {
23
- const form = <HTMLFormElement> document.getElementById('register')
24
- message = ''
22
+ async function register() {
23
+ const form = <HTMLFormElement>document.getElementById('register')
24
+ message = ''
25
25
 
26
- if (!passwordMatch()) {
27
- confirmPassword.classList.add('is-invalid')
28
- return
29
- }
26
+ if (!passwordMatch()) {
27
+ confirmPassword.classList.add('is-invalid')
28
+ return
29
+ }
30
30
 
31
- if (form.checkValidity()) {
32
- try {
33
- await registerLocal(user)
34
- } catch (err) {
35
- if (err instanceof Error) {
36
- message = err.message
37
- console.log('Login error', message)
38
- }
39
- }
40
- } else {
41
- form.classList.add('was-validated')
42
- focusOnFirstError(form)
43
- }
44
-
45
- }
31
+ if (form.checkValidity()) {
32
+ try {
33
+ await registerLocal(user)
34
+ } catch (err) {
35
+ if (err instanceof Error) {
36
+ message = err.message
37
+ console.log('Login error', message)
38
+ }
39
+ }
40
+ } else {
41
+ form.classList.add('was-validated')
42
+ focusOnFirstError(form)
43
+ }
44
+ }
46
45
 
47
- onMount(() => {
48
- initializeGoogleAccounts()
49
- renderGoogleButton()
46
+ onMount(() => {
47
+ initializeGoogleAccounts()
48
+ renderGoogleButton()
50
49
 
51
- focusedField.focus()
52
- })
50
+ focusedField.focus()
51
+ })
53
52
 
54
- async function registerLocal(user: User) {
53
+ async function registerLocal(user: User) {
55
54
  try {
56
55
  const res = await fetch('/auth/register', {
57
56
  method: 'POST',
@@ -79,71 +78,127 @@
79
78
  }
80
79
  }
81
80
 
82
- const passwordMatch = () => {
83
- if (!user) return false // placate TypeScript
84
- if (!user.password) user.password = ''
85
- return user.password == confirmPassword.value
86
- }
81
+ const passwordMatch = () => {
82
+ if (!user) return false // placate TypeScript
83
+ if (!user.password) user.password = ''
84
+ return user.password == confirmPassword.value
85
+ }
87
86
  </script>
88
87
 
89
88
  <svelte:head>
90
- <title>Register</title>
89
+ <title>Register</title>
91
90
  </svelte:head>
92
91
 
93
92
  <div class="d-flex justify-content-center my-3">
94
- <div class="card login">
95
- <div class="card-body">
96
- <h4><strong>Register</strong></h4>
97
- <p>Welcome to our community.</p>
98
- {#if user}
99
- <form id="register" autocomplete="on" novalidate class="mt-3">
100
- <div class="mb-3">
101
- <div id="googleButton"></div>
102
- </div>
103
- <div class="mb-3">
104
- <label class="form-label" for="email">Email</label>
105
- <input bind:this={focusedField} type="email" class="form-control" bind:value={user.email} required placeholder="Email" id="email" autocomplete="email"/>
106
- <div class="invalid-feedback">Email address required</div>
107
- </div>
108
- <div class="mb-3">
109
- <label class="form-label" for="password">Password</label>
110
- <input type="password" id="password" class="form-control" bind:value={user.password} required minlength="8" maxlength="80" placeholder="Password" autocomplete="new-password"/>
111
- <div class="invalid-feedback">Password with 8 chars or more required</div>
112
- <div class="form-text">Password minimum length 8, must have one capital letter, 1 number, and one unique character.</div>
113
- </div>
114
- <div class="mb-3">
115
- <label class="form-label" for="password">Confirm password</label>
116
- <input type="password" id="password" class="form-control" bind:this={confirmPassword} required minlength="8" maxlength="80" placeholder="Password (again)" autocomplete="new-password"/>
117
- <div class="form-text">Password minimum length 8, must have one capital letter, 1 number, and one unique character.</div>
118
- </div>
119
- <div class="mb-3">
120
- <label class="form-label" for="firstName">First name</label>
121
- <input bind:value={user.firstName} class="form-control" id="firstName" placeholder="First name" required autocomplete="given-name"/>
122
- <div class="invalid-feedback">First name required</div>
123
- </div>
124
- <div class="mb-3">
125
- <label class="form-label" for="lastName">Last name</label>
126
- <input bind:value={user.lastName} class="form-control" id="lastName" placeholder="Last name" required autocomplete="family-name"/>
127
- <div class="invalid-feedback">Last name required</div>
128
- </div>
129
- <div class="mb-3">
130
- <label class="form-label" for="phone">Phone</label>
131
- <input type="tel" bind:value={user.phone} id="phone" class="form-control" placeholder="Phone" autocomplete="tel-local"/>
132
- </div>
133
-
134
- {#if message}
135
- <p class="text-danger">{message}</p>
136
- {/if}
137
-
138
- <button type="button" on:click={register} class="btn btn-primary btn-lg">Register</button>
139
- </form>
140
- {/if}
141
- </div>
142
- </div>
93
+ <div class="card login">
94
+ <div class="card-body">
95
+ <h4><strong>Register</strong></h4>
96
+ <p>Welcome to our community.</p>
97
+ {#if user}
98
+ <form id="register" autocomplete="on" novalidate class="mt-3">
99
+ <div class="mb-3">
100
+ <div id="googleButton"></div>
101
+ </div>
102
+ <div class="mb-3">
103
+ <label class="form-label" for="email">Email</label>
104
+ <input
105
+ bind:this={focusedField}
106
+ type="email"
107
+ class="form-control"
108
+ bind:value={user.email}
109
+ required
110
+ placeholder="Email"
111
+ id="email"
112
+ autocomplete="email"
113
+ />
114
+ <div class="invalid-feedback">Email address required</div>
115
+ </div>
116
+ <div class="mb-3">
117
+ <label class="form-label" for="password">Password</label>
118
+ <input
119
+ type="password"
120
+ id="password"
121
+ class="form-control"
122
+ bind:value={user.password}
123
+ required
124
+ minlength="8"
125
+ maxlength="80"
126
+ placeholder="Password"
127
+ autocomplete="new-password"
128
+ />
129
+ <div class="invalid-feedback">Password with 8 chars or more required</div>
130
+ <div class="form-text">
131
+ Password minimum length 8, must have one capital letter, 1 number, and one unique
132
+ character.
133
+ </div>
134
+ </div>
135
+ <div class="mb-3">
136
+ <label class="form-label" for="password">Confirm password</label>
137
+ <input
138
+ type="password"
139
+ id="password"
140
+ class="form-control"
141
+ bind:this={confirmPassword}
142
+ required
143
+ minlength="8"
144
+ maxlength="80"
145
+ placeholder="Password (again)"
146
+ autocomplete="new-password"
147
+ />
148
+ <div class="form-text">
149
+ Password minimum length 8, must have one capital letter, 1 number, and one unique
150
+ character.
151
+ </div>
152
+ </div>
153
+ <div class="mb-3">
154
+ <label class="form-label" for="firstName">First name</label>
155
+ <input
156
+ bind:value={user.firstName}
157
+ class="form-control"
158
+ id="firstName"
159
+ placeholder="First name"
160
+ required
161
+ autocomplete="given-name"
162
+ />
163
+ <div class="invalid-feedback">First name required</div>
164
+ </div>
165
+ <div class="mb-3">
166
+ <label class="form-label" for="lastName">Last name</label>
167
+ <input
168
+ bind:value={user.lastName}
169
+ class="form-control"
170
+ id="lastName"
171
+ placeholder="Last name"
172
+ required
173
+ autocomplete="family-name"
174
+ />
175
+ <div class="invalid-feedback">Last name required</div>
176
+ </div>
177
+ <div class="mb-3">
178
+ <label class="form-label" for="phone">Phone</label>
179
+ <input
180
+ type="tel"
181
+ bind:value={user.phone}
182
+ id="phone"
183
+ class="form-control"
184
+ placeholder="Phone"
185
+ autocomplete="tel-local"
186
+ />
187
+ </div>
188
+
189
+ {#if message}
190
+ <p class="text-danger">{message}</p>
191
+ {/if}
192
+
193
+ <button type="button" on:click={register} class="btn btn-primary btn-lg">Register</button>
194
+ </form>
195
+ {/if}
196
+ </div>
197
+ </div>
143
198
  </div>
144
199
 
145
200
  <style lang="scss">
146
- .card-body {
147
- width: 25rem;
148
- }
149
- </style>
201
+ .card-body {
202
+ width: 25rem;
203
+ }
204
+ </style>
@@ -1,14 +1,14 @@
1
1
  import { redirect } from '@sveltejs/kit'
2
2
  import type { PageServerLoad } from './$types'
3
3
 
4
- export const load: PageServerLoad = async ({locals}) => {
4
+ export const load: PageServerLoad = async ({ locals }) => {
5
5
  const { user } = locals
6
6
  const authorized = ['admin', 'teacher']
7
7
  if (!user || !authorized.includes(user.role)) {
8
- redirect(302, '/login?referrer=/teachers');
8
+ redirect(302, '/login?referrer=/teachers')
9
9
  }
10
10
 
11
- return {
12
- message: 'Teachers or Admin-only content from server.'
13
- }
11
+ return {
12
+ message: 'Teachers or Admin-only content from server.'
13
+ }
14
14
  }
@@ -4,9 +4,9 @@
4
4
  </script>
5
5
 
6
6
  <svelte:head>
7
- <title>Teachers</title>
7
+ <title>Teachers</title>
8
8
  </svelte:head>
9
9
 
10
10
  <h1>Teachers</h1>
11
11
  <h4>Teacher Or Admin Role</h4>
12
- <p>{data.message}</p>
12
+ <p>{data.message}</p>
package/src/stores.ts CHANGED
@@ -8,6 +8,6 @@ export const toast = writable({
8
8
 
9
9
  // While server determines whether the user is logged in by examining RequestEvent.locals.user, the
10
10
  // loginSession is updated so all parts of the SPA client-side see the user and role.
11
- export const loginSession = <Writable<User>> writable(undefined)
11
+ export const loginSession = <Writable<User>>writable(undefined)
12
12
 
13
13
  export const googleInitialized = writable(false)
package/svelte.config.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import adapter from '@sveltejs/adapter-node'
2
- import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
2
+ import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
3
3
 
4
4
  const production = process.env.NODE_ENV === 'production'
5
5
 
package/.prettierrc DELETED
@@ -1,9 +0,0 @@
1
- {
2
- "useTabs": true,
3
- "semi": false,
4
- "singleQuote": true,
5
- "trailingComma": "none",
6
- "printWidth": 100,
7
- "pluginSearchDirs": ["."],
8
- "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
9
- }