sveltekit-auth-example 2.1.1 → 5.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.
package/CHANGELOG.md CHANGED
@@ -2,29 +2,44 @@
2
2
 
3
3
  - Add password complexity checking on /register and /profile pages (only checks for length currently despite what the pages say)
4
4
 
5
+ # 5.0.2
6
+ - Bump dependencies
7
+
8
+ # 5.0.1
9
+ - Migrate to Svelte 5 runes mode
10
+ - Format with prettier
11
+ - Bump dependencies
12
+
5
13
  # 2.1.0
14
+
6
15
  - Bump svelte, @sveltejs/kit, @sveltejs/adapter-node, @sveltejs/vite-plugin-svelte, @sendgrid/mail, pg, google-auth-library, @eslint/js, yarn, @types/google.accounts, @types/jsonwebtoken, @types/pg, eslint, eslint-plugin-svelte, globals, prettier-plugin-svelte, sass, svelte-check, tslib, typescript, typescript-eslint, vite, vitest
7
16
  - Change Typescript casting to use "as" since the Svelte 5 has an issue with angle brackets style
8
17
 
9
18
  # 2.0.8
19
+
10
20
  - Bump svelte, @sveltejs/kit, @sveltejs/vite-plugin-svelte, google-auth-library and other devDependencies
11
21
 
12
22
  # 2.0.7
23
+
13
24
  - Bump pg, google-auth-library, svelte, svelte-check, yarn, typescript-eslint, @types/pg, eslint, prettier, prettier-plugin-svelte, sass, tslib, typescript, vite, vitest
14
25
  - Install typescript-eslint, @eslint/js, globals, eslint-plugin-prettier
15
26
  - Change eslint config to flat
16
27
 
17
28
  # 2.0.6
29
+
18
30
  - Bump google-auth-library, @sendgrid/mail, pg, @sveltejs/kit, @sveltejs/vite-plugin-svelte, @types/pg, @typescript-eslint, eslint, eslint-config-prettier, prettier-plugin-svelte, sass, svelte, svelte-check, typescript, vite, vitest
19
31
 
20
32
  # 2.0.5
33
+
21
34
  - Bump @sveltejs/kit, @types/pg, @typescript-eslint, google-auth-library, sass, svelte-check, typescript, vite, vitest
22
35
 
23
36
  # 2.0.4
37
+
24
38
  - Tested with latest Sveltekit and google-auth-library
25
39
  - Bump @sendgrid/mail, sveltekit, adapter-node, @types, @typescript-eslint, google-auth-library, prettier, prettier-plugin-svelte, sass, svelte, svelte-check, typescript, vite, vitest, yarn
26
40
 
27
41
  # 2.0.3
42
+
28
43
  - Move to eslint's new eslint.config.js
29
44
  - Convert vite.config to TypeScript
30
45
 
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # SvelteKit Authentication and Authorization Example
2
2
 
3
- **Updated for Svelte 5 and SvelteKit 2.7.3**
3
+ **Updated for Svelte 5 and SvelteKit 2.19**
4
4
 
5
5
  This is an example of how to register, authenticate, and update users and limit their access to
6
6
  areas of the website by role (admin, teacher, student). It includes profile management and password resets via SendGrid.
package/eslint.config.js CHANGED
@@ -13,4 +13,4 @@ export default tseslint.config(
13
13
  ...tseslint.configs.recommended,
14
14
  ...sveltePlugin.configs['flat/prettier'],
15
15
  prettierPluginRecommended
16
- )
16
+ )
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sveltekit-auth-example",
3
3
  "description": "SvelteKit Authentication Example",
4
- "version": "2.1.1",
4
+ "version": "5.0.2",
5
5
  "author": "Nate Stuyvesant",
6
6
  "license": "https://github.com/nstuyvesant/sveltekit-auth-example/blob/master/LICENSE",
7
7
  "repository": {
@@ -31,41 +31,41 @@
31
31
  "format": "prettier --write . --ignore-path ./.eslintignore"
32
32
  },
33
33
  "engines": {
34
- "node": "^18.19.1"
34
+ "node": "^20.18.0"
35
35
  },
36
36
  "type": "module",
37
37
  "dependencies": {
38
38
  "@sendgrid/mail": "^8.1.4",
39
- "pg": "^8.13.1"
39
+ "pg": "^8.13.3"
40
40
  },
41
41
  "devDependencies": {
42
- "@eslint/js": "^9.13.0",
43
- "@sveltejs/adapter-node": "^5.2.9",
44
- "@sveltejs/kit": "^2.7.3",
45
- "@sveltejs/vite-plugin-svelte": "^4.0.0",
42
+ "@eslint/js": "^9.22.0",
43
+ "@sveltejs/adapter-node": "^5.2.12",
44
+ "@sveltejs/kit": "^2.19.0",
45
+ "@sveltejs/vite-plugin-svelte": "^5.0.3",
46
46
  "@types/bootstrap": "5.2.10",
47
47
  "@types/google.accounts": "^0.0.15",
48
- "@types/jsonwebtoken": "^9.0.7",
49
- "@types/pg": "^8.11.10",
48
+ "@types/jsonwebtoken": "^9.0.9",
49
+ "@types/pg": "^8.11.11",
50
50
  "bootstrap": "^5.3.3",
51
- "eslint": "^9.13.0",
52
- "eslint-config-prettier": "^9.1.0",
53
- "eslint-plugin-prettier": "^5.2.1",
54
- "eslint-plugin-svelte": "^2.46.0",
55
- "globals": "^15.11.0",
56
- "google-auth-library": "^9.14.2",
51
+ "eslint": "^9.22.0",
52
+ "eslint-config-prettier": "^10.1.1",
53
+ "eslint-plugin-prettier": "^5.2.3",
54
+ "eslint-plugin-svelte": "^3.0.3",
55
+ "globals": "^16.0.0",
56
+ "google-auth-library": "^9.15.1",
57
57
  "jsonwebtoken": "^9.0.2",
58
- "prettier": "^3.3.3",
59
- "prettier-plugin-svelte": "^3.2.7",
60
- "sass": "^1.80.4",
61
- "svelte": "^5.1.4",
62
- "svelte-check": "^4.0.5",
63
- "tslib": "^2.8.0",
64
- "typescript": "^5.6.3",
65
- "typescript-eslint": "^8.12.1",
66
- "vite": "^5.4.10",
67
- "vitest": "^2.1.4"
58
+ "prettier": "^3.5.3",
59
+ "prettier-plugin-svelte": "^3.3.3",
60
+ "sass": "^1.85.1",
61
+ "svelte": "^5.22.6",
62
+ "svelte-check": "^4.1.5",
63
+ "tslib": "^2.8.1",
64
+ "typescript": "^5.8.2",
65
+ "typescript-eslint": "^8.26.0",
66
+ "vite": "^6.2.1",
67
+ "vitest": "^3.0.8"
68
68
  },
69
- "packageManager": "yarn@4.5.1",
69
+ "packageManager": "yarn@4.7.0",
70
70
  "prettier": "./prettier.config.mjs"
71
71
  }
@@ -1,4 +1,4 @@
1
- <script lang="ts" context="module">
1
+ <script lang="ts" module>
2
2
  import { page } from '$app/stores'
3
3
  </script>
4
4
 
@@ -7,7 +7,12 @@
7
7
 
8
8
  import 'bootstrap/scss/bootstrap.scss' // preferred way to load Bootstrap SCSS for hot module reloading
9
9
 
10
- export let data: LayoutServerData
10
+ interface Props {
11
+ data: LayoutServerData
12
+ children?: import('svelte').Snippet
13
+ }
14
+
15
+ let { data, children }: Props = $props()
11
16
 
12
17
  // If returning from different website, runs once (as it's an SPA) to restore user session if session cookie is still valid
13
18
  const { user } = data
@@ -34,7 +39,8 @@
34
39
  if (!$loginSession) google.accounts.id.prompt()
35
40
  })
36
41
 
37
- async function logout() {
42
+ async function logout(event: MouseEvent) {
43
+ event.preventDefault()
38
44
  // Request server delete httpOnly cookie called loginSession
39
45
  const url = '/auth/logout'
40
46
  const res = await fetch(url, {
@@ -54,7 +60,9 @@
54
60
  }
55
61
  }
56
62
 
57
- $: openToast($toast.isOpen)
63
+ $effect(() => {
64
+ openToast($toast.isOpen)
65
+ })
58
66
  </script>
59
67
 
60
68
  <nav class="navbar navbar-expand-lg navbar-light bg-light">
@@ -117,7 +125,7 @@
117
125
  </li>
118
126
  <li>
119
127
  <a
120
- on:click|preventDefault={logout}
128
+ onclick={logout}
121
129
  class="dropdown-item"
122
130
  class:d-none={!$loginSession || $loginSession.id === 0}
123
131
  href={'#'}>Logout</a
@@ -136,7 +144,7 @@
136
144
  </nav>
137
145
 
138
146
  <main class="container">
139
- <slot />
147
+ {@render children?.()}
140
148
 
141
149
  <div
142
150
  id="authToast"
@@ -1,6 +1,10 @@
1
1
  <script lang="ts">
2
2
  import type { PageData } from './$types'
3
- export let data: PageData
3
+ interface Props {
4
+ data: PageData
5
+ }
6
+
7
+ let { data }: Props = $props()
4
8
  </script>
5
9
 
6
10
  <svelte:head>
@@ -5,20 +5,24 @@
5
5
  import { toast } from '../../../../stores'
6
6
  import { focusOnFirstError } from '$lib/focus'
7
7
 
8
- export let data: PageData
8
+ interface Props {
9
+ data: PageData
10
+ }
11
+
12
+ let { data }: Props = $props()
9
13
 
10
- let focusedField: HTMLInputElement
11
- let password: string
12
- let confirmPassword: HTMLInputElement
13
- let message: string
14
+ let focusedField: HTMLInputElement | undefined = $state()
15
+ let password = $state('')
16
+ let confirmPassword: HTMLInputElement | undefined = $state()
17
+ let message = $state('')
14
18
 
15
19
  onMount(() => {
16
- focusedField.focus()
20
+ focusedField?.focus()
17
21
  })
18
22
 
19
23
  const passwordMatch = () => {
20
24
  if (!password) password = ''
21
- return password == confirmPassword.value
25
+ return password == confirmPassword?.value
22
26
  }
23
27
 
24
28
  const resetPassword = async () => {
@@ -26,7 +30,7 @@
26
30
  const form = document.getElementById('reset') as HTMLFormElement
27
31
 
28
32
  if (!passwordMatch()) {
29
- confirmPassword.classList.add('is-invalid')
33
+ confirmPassword?.classList.add('is-invalid')
30
34
  }
31
35
 
32
36
  if (form.checkValidity()) {
@@ -111,7 +115,7 @@
111
115
  <p class="text-danger">{message}</p>
112
116
  {/if}
113
117
  <div class="d-grid gap-2">
114
- <button on:click|preventDefault={resetPassword} class="btn btn-primary btn-lg"
118
+ <button onclick={resetPassword} type="button" class="btn btn-primary btn-lg"
115
119
  >Send Email</button
116
120
  >
117
121
  </div>
@@ -4,12 +4,12 @@
4
4
  import { toast } from '../../stores'
5
5
  import { focusOnFirstError } from '$lib/focus'
6
6
 
7
- let focusedField: HTMLInputElement
8
- let email: string
9
- let message: string
7
+ let focusedField: HTMLInputElement | undefined = $state()
8
+ let email: string = $state('')
9
+ let message: string = $state('')
10
10
 
11
11
  onMount(() => {
12
- focusedField.focus()
12
+ focusedField?.focus()
13
13
  })
14
14
 
15
15
  const sendPasswordReset = async () => {
@@ -72,7 +72,7 @@
72
72
  <p class="text-danger">{message}</p>
73
73
  {/if}
74
74
  <div class="d-grid gap-2">
75
- <button on:click|preventDefault={sendPasswordReset} class="btn btn-primary btn-lg"
75
+ <button onclick={sendPasswordReset} type="button" class="btn btn-primary btn-lg"
76
76
  >Send Email</button
77
77
  >
78
78
  </div>
@@ -6,12 +6,12 @@
6
6
  import { focusOnFirstError } from '$lib/focus'
7
7
  import { initializeGoogleAccounts, renderGoogleButton } from '$lib/google'
8
8
 
9
- let focusedField: HTMLInputElement
10
- let message: string
11
- const credentials: Credentials = {
9
+ let focusedField: HTMLInputElement | undefined = $state()
10
+ let message = $state('')
11
+ const credentials: Credentials = $state({
12
12
  email: '',
13
13
  password: ''
14
- }
14
+ })
15
15
 
16
16
  async function login() {
17
17
  message = ''
@@ -36,7 +36,7 @@
36
36
  initializeGoogleAccounts()
37
37
  renderGoogleButton()
38
38
 
39
- focusedField.focus()
39
+ focusedField?.focus()
40
40
  })
41
41
 
42
42
  async function loginLocal(credentials: Credentials) {
@@ -135,7 +135,7 @@
135
135
  <p class="text-danger">{message}</p>
136
136
  {/if}
137
137
  <div class="d-grid gap-2">
138
- <button on:click|preventDefault={login} class="btn btn-primary btn-lg">Sign In</button>
138
+ <button onclick={login} type="button" class="btn btn-primary btn-lg">Sign In</button>
139
139
  </div>
140
140
  </form>
141
141
  </div>
@@ -4,15 +4,19 @@
4
4
  import { focusOnFirstError } from '$lib/focus'
5
5
  import { loginSession } from '../../stores'
6
6
 
7
- export let data: PageData
8
- const { user }: { user: User } = data
7
+ interface Props {
8
+ data: PageData
9
+ }
10
+
11
+ let { data }: Props = $props()
12
+ const { user }: { user: User } = $state(data)
9
13
 
10
- let focusedField: HTMLInputElement
11
- let message: string
12
- let confirmPassword: HTMLInputElement
14
+ let focusedField: HTMLInputElement | undefined = $state()
15
+ let message = $state('')
16
+ let confirmPassword: HTMLInputElement | undefined = $state()
13
17
 
14
18
  onMount(() => {
15
- focusedField.focus()
19
+ focusedField?.focus()
16
20
  })
17
21
 
18
22
  async function update() {
@@ -20,7 +24,7 @@
20
24
  const form = document.getElementById('profile') as HTMLFormElement
21
25
 
22
26
  if (!user?.email?.includes('gmail.com') && !passwordMatch()) {
23
- confirmPassword.classList.add('is-invalid')
27
+ confirmPassword?.classList.add('is-invalid')
24
28
  return
25
29
  }
26
30
 
@@ -44,7 +48,7 @@
44
48
 
45
49
  const passwordMatch = () => {
46
50
  if (!user.password) user.password = ''
47
- return user.password == confirmPassword.value
51
+ return user.password == confirmPassword?.value
48
52
  }
49
53
  </script>
50
54
 
@@ -150,7 +154,7 @@
150
154
  <p>{message}</p>
151
155
  {/if}
152
156
 
153
- <button type="button" on:click={update} class="btn btn-primary btn-lg">Update</button>
157
+ <button onclick={update} type="button" class="btn btn-primary btn-lg">Update</button>
154
158
  </form>
155
159
  </div>
156
160
  </div>
@@ -5,9 +5,9 @@
5
5
  import { focusOnFirstError } from '$lib/focus'
6
6
  import { initializeGoogleAccounts, renderGoogleButton } from '$lib/google'
7
7
 
8
- let focusedField: HTMLInputElement
8
+ let focusedField: HTMLInputElement | undefined = $state()
9
9
 
10
- let user: User = {
10
+ let user: User = $state({
11
11
  id: 0,
12
12
  role: 'student',
13
13
  firstName: '',
@@ -15,16 +15,16 @@
15
15
  password: '',
16
16
  email: '',
17
17
  phone: ''
18
- }
19
- let confirmPassword: HTMLInputElement
20
- let message: string
18
+ })
19
+ let confirmPassword: HTMLInputElement | undefined = $state()
20
+ let message = $state('')
21
21
 
22
22
  async function register() {
23
23
  const form = document.getElementById('register') as HTMLFormElement
24
24
  message = ''
25
25
 
26
26
  if (!passwordMatch()) {
27
- confirmPassword.classList.add('is-invalid')
27
+ confirmPassword?.classList.add('is-invalid')
28
28
  return
29
29
  }
30
30
 
@@ -47,7 +47,7 @@
47
47
  initializeGoogleAccounts()
48
48
  renderGoogleButton()
49
49
 
50
- focusedField.focus()
50
+ focusedField?.focus()
51
51
  })
52
52
 
53
53
  async function registerLocal(user: User) {
@@ -81,7 +81,7 @@
81
81
  const passwordMatch = () => {
82
82
  if (!user) return false // placate TypeScript
83
83
  if (!user.password) user.password = ''
84
- return user.password == confirmPassword.value
84
+ return user.password == confirmPassword?.value
85
85
  }
86
86
  </script>
87
87
 
@@ -190,7 +190,7 @@
190
190
  <p class="text-danger">{message}</p>
191
191
  {/if}
192
192
 
193
- <button type="button" on:click={register} class="btn btn-primary btn-lg">Register</button>
193
+ <button onclick={register} type="button" class="btn btn-primary btn-lg">Register</button>
194
194
  </form>
195
195
  {/if}
196
196
  </div>
@@ -1,6 +1,10 @@
1
1
  <script lang="ts">
2
2
  import type { PageData } from './$types'
3
- export let data: PageData
3
+ interface Props {
4
+ data: PageData
5
+ }
6
+
7
+ let { data }: Props = $props()
4
8
  </script>
5
9
 
6
10
  <svelte:head>