Skip to content

Commit dcc8fc3

Browse files
committedDec 7, 2023
refactor: 🎨 tab format
1 parent fc91736 commit dcc8fc3

26 files changed

+619
-614
lines changed
 

‎.eslintignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
node_modules
33
/build
44
/.svelte-kit
5+
/static
56
/package
67
.env
78
.env.*

‎.eslintrc.cjs

+31-31
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,34 @@
11
/** @type { import("eslint").Linter.FlatConfig } */
22
module.exports = {
3-
root: true,
4-
extends: [
5-
'eslint:recommended',
6-
'plugin:@typescript-eslint/recommended',
7-
'plugin:svelte/recommended',
8-
'prettier'
9-
],
10-
parser: '@typescript-eslint/parser',
11-
plugins: ['@typescript-eslint'],
12-
parserOptions: {
13-
sourceType: 'module',
14-
ecmaVersion: 2020,
15-
extraFileExtensions: ['.svelte']
16-
},
17-
rules: {
18-
'@typescript-eslint/no-explicit-any': 1
19-
},
20-
env: {
21-
browser: true,
22-
es2017: true,
23-
node: true
24-
},
25-
overrides: [
26-
{
27-
files: ['*.svelte'],
28-
parser: 'svelte-eslint-parser',
29-
parserOptions: {
30-
parser: '@typescript-eslint/parser'
31-
}
32-
}
33-
]
3+
root: true,
4+
extends: [
5+
'eslint:recommended',
6+
'plugin:@typescript-eslint/recommended',
7+
'plugin:svelte/recommended',
8+
'prettier'
9+
],
10+
parser: '@typescript-eslint/parser',
11+
plugins: ['@typescript-eslint'],
12+
parserOptions: {
13+
sourceType: 'module',
14+
ecmaVersion: 2020,
15+
extraFileExtensions: ['.svelte']
16+
},
17+
rules: {
18+
'@typescript-eslint/no-explicit-any': 1
19+
},
20+
env: {
21+
browser: true,
22+
es2017: true,
23+
node: true
24+
},
25+
overrides: [
26+
{
27+
files: ['*.svelte'],
28+
parser: 'svelte-eslint-parser',
29+
parserOptions: {
30+
parser: '@typescript-eslint/parser'
31+
}
32+
}
33+
]
3434
};

‎.prettierignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
.DS_Store
22
node_modules
33
/build
4+
/static
45
/.svelte-kit
56
/package
67
.env

‎.prettierrc

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
{
2-
"useTabs": true,
3-
"singleQuote": true,
4-
"trailingComma": "none",
5-
"printWidth": 100,
6-
"plugins": ["prettier-plugin-svelte"],
7-
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
2+
"useTabs": false,
3+
"tabWidth": 2,
4+
"singleQuote": true,
5+
"semi": true,
6+
"bracketSameLine": true,
7+
"trailingComma": "none",
8+
"printWidth": 100,
9+
"plugins": ["prettier-plugin-svelte"],
10+
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
811
}

‎.vscode/extensions.json

+11-11
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
{
2-
"recommendations": [
3-
"streetsidesoftware.code-spell-checker",
4-
"vivaxy.vscode-conventional-commits",
5-
"aaron-bond.better-comments",
6-
"editorconfig.editorconfig",
7-
"dbaeumer.vscode-eslint",
8-
"eamodio.gitlens",
9-
"github.copilot",
10-
"esbenp.prettier-vscode",
11-
"svelte.svelte-vscode"
12-
]
2+
"recommendations": [
3+
"streetsidesoftware.code-spell-checker",
4+
"vivaxy.vscode-conventional-commits",
5+
"aaron-bond.better-comments",
6+
"editorconfig.editorconfig",
7+
"dbaeumer.vscode-eslint",
8+
"eamodio.gitlens",
9+
"github.copilot",
10+
"esbenp.prettier-vscode",
11+
"svelte.svelte-vscode"
12+
]
1313
}

‎.vscode/settings.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"cSpell.words": ["willin"]
2+
"cSpell.words": ["willin"]
33
}

‎README.md

+64-64
Original file line numberDiff line numberDiff line change
@@ -46,46 +46,46 @@ import { Auth } from '@svelte-dev/auth';
4646
import { OAuth2Strategy } from '@svelte-dev/auth-oauth2';
4747

4848
export const handle = sequence(
49-
handleSession({
50-
adapter: {
51-
name: 'cookie',
52-
options: {
53-
chunk: true
54-
}
55-
},
56-
session: {
57-
secrets: ['s3cr3t']
58-
},
59-
cookie: {
60-
secure: !!env.SSO_CALLBACK_URL,
61-
sameSite: 'lax',
62-
path: '/',
63-
httpOnly: !!env.SSO_CALLBACK_URL
64-
}
65-
}),
66-
async function handle({ event, resolve }) {
67-
const auth = new Auth(event);
68-
const oauthStrategy = new OAuth2Strategy(
69-
{
70-
clientID: env.SSO_ID,
71-
clientSecret: env.SSO_SECRET,
72-
callbackURL: env.SSO_CALLBACK_URL || 'http://localhost:8788/auth/sso/callback'
73-
},
74-
async ({ profile }) => {
75-
// Get the user data from your DB or API using the tokens and profile
76-
return profile;
77-
}
78-
);
79-
auth.use(oauthStrategy);
80-
event.locals.auth = auth;
81-
event.locals.user = event.locals.session.get(
82-
// replace your session key, AuthOptions.sessionKey
83-
'user'
84-
);
85-
const response = await resolve(event);
86-
87-
return response;
88-
}
49+
handleSession({
50+
adapter: {
51+
name: 'cookie',
52+
options: {
53+
chunk: true
54+
}
55+
},
56+
session: {
57+
secrets: ['s3cr3t']
58+
},
59+
cookie: {
60+
secure: !!env.SSO_CALLBACK_URL,
61+
sameSite: 'lax',
62+
path: '/',
63+
httpOnly: !!env.SSO_CALLBACK_URL
64+
}
65+
}),
66+
async function handle({ event, resolve }) {
67+
const auth = new Auth(event);
68+
const oauthStrategy = new OAuth2Strategy(
69+
{
70+
clientID: env.SSO_ID,
71+
clientSecret: env.SSO_SECRET,
72+
callbackURL: env.SSO_CALLBACK_URL || 'http://localhost:8788/auth/sso/callback'
73+
},
74+
async ({ profile }) => {
75+
// Get the user data from your DB or API using the tokens and profile
76+
return profile;
77+
}
78+
);
79+
auth.use(oauthStrategy);
80+
event.locals.auth = auth;
81+
event.locals.user = event.locals.session.get(
82+
// replace your session key, AuthOptions.sessionKey
83+
'user'
84+
);
85+
const response = await resolve(event);
86+
87+
return response;
88+
}
8989
);
9090
```
9191

@@ -99,30 +99,30 @@ Modify `app.d.ts`, here is an example:
9999
// See https://kit.svelte.dev/docs/types#app
100100
// for information about these interfaces
101101
declare global {
102-
namespace App {
103-
// interface Error {}
104-
interface Locals {
105-
auth: Auth;
106-
session: SessionStorage<{ user: any }>;
107-
user:
108-
| {
109-
invalid?: boolean;
110-
[key: string]: unknown;
111-
}
112-
| unknown;
113-
}
114-
// interface PageData {}
115-
interface Platform {
116-
env: {
117-
SSO_ID: string;
118-
SSO_SECRET: string;
119-
};
120-
context: {
121-
waitUntil(promise: Promise<unknown>): void;
122-
};
123-
caches: CacheStorage & { default: Cache };
124-
}
125-
}
102+
namespace App {
103+
// interface Error {}
104+
interface Locals {
105+
auth: Auth;
106+
session: SessionStorage<{ user: any }>;
107+
user:
108+
| {
109+
invalid?: boolean;
110+
[key: string]: unknown;
111+
}
112+
| unknown;
113+
}
114+
// interface PageData {}
115+
interface Platform {
116+
env: {
117+
SSO_ID: string;
118+
SSO_SECRET: string;
119+
};
120+
context: {
121+
waitUntil(promise: Promise<unknown>): void;
122+
};
123+
caches: CacheStorage & { default: Cache };
124+
}
125+
}
126126
}
127127

128128
export {};

‎package.json

+100-100
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,102 @@
11
{
2-
"name": "@svelte-dev/auth",
3-
"version": "0.1.0",
4-
"description": "Simple Authentication for Svelte",
5-
"author": "Willin Wang <willin@willin.org> (https://willin.wang/)",
6-
"keywords": [
7-
"svelte",
8-
"auth",
9-
"authentication",
10-
"local",
11-
"auth0",
12-
"authing",
13-
"oauth2",
14-
"strategies"
15-
],
16-
"homepage": "https://github.com/willin/svelte-auth#readme",
17-
"scripts": {
18-
"dev": "vite dev --port 8788",
19-
"dev:docs": "typedoc --watch",
20-
"build": "vite build && npm run package",
21-
"build:docs": "typedoc",
22-
"preview": "vite preview",
23-
"package": "svelte-kit sync && svelte-package && publint",
24-
"prepublishOnly": "npm run package",
25-
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
26-
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
27-
"version": "conventional-changelog -p angular -i CHANGELOG.md -s && git add CHANGELOG.md",
28-
"test": "vitest",
29-
"coverage": "vitest run --coverage",
30-
"prepare": "husky install",
31-
"lint": "prettier --write . && eslint . --fix"
32-
},
33-
"exports": {
34-
".": {
35-
"types": "./dist/index.d.ts",
36-
"svelte": "./dist/index.js"
37-
}
38-
},
39-
"files": [
40-
"dist",
41-
"!dist/**/*.test.*",
42-
"!dist/**/*.spec.*"
43-
],
44-
"dependencies": {},
45-
"peerDependencies": {
46-
"@svelte-dev/session": "^0.1.0",
47-
"@sveltejs/kit": "^1.0.0",
48-
"svelte": "^5.0.0||^4.0.0"
49-
},
50-
"devDependencies": {
51-
"@commitlint/cli": "latest",
52-
"@commitlint/config-conventional": "latest",
53-
"@svelte-dev/auth-sso": "^0.0.5",
54-
"@sveltejs/adapter-cloudflare": "^2.3.3",
55-
"@sveltejs/kit": "^1.27.4",
56-
"@sveltejs/package": "^2.2.3",
57-
"@typescript-eslint/eslint-plugin": "^6.0.0",
58-
"@typescript-eslint/parser": "^6.0.0",
59-
"@vitest/coverage-istanbul": "^0.34.6",
60-
"bun-types": "^1.0.15",
61-
"conventional-changelog-cli": "latest",
62-
"eslint": "^8.28.0",
63-
"eslint-config-prettier": "^9.0.0",
64-
"eslint-plugin-svelte": "^2.30.0",
65-
"husky": "latest",
66-
"lint-staged": "latest",
67-
"prettier": "^3.0.0",
68-
"prettier-plugin-svelte": "^3.0.0",
69-
"publint": "^0.1.9",
70-
"svelte": "^5.0.0-next.17",
71-
"svelte-check": "^3.6.0",
72-
"tslib": "^2.4.1",
73-
"typedoc-plugin-extras": "^3.0.0",
74-
"typedoc-plugin-google-ads": "^1.6.0",
75-
"typedoc-plugin-keywords": "^1.6.0",
76-
"typedocs": "^0.6.7",
77-
"typescript": "^5.0.0",
78-
"vite": "^4.4.2",
79-
"vitest": "^0.34.0"
80-
},
81-
"svelte": "./dist/index.js",
82-
"types": "./dist/index.d.ts",
83-
"type": "module",
84-
"publishConfig": {
85-
"access": "public"
86-
},
87-
"repository": {
88-
"type": "git",
89-
"url": "git+https://github.com/willin/svelte-auth.git"
90-
},
91-
"bugs": {
92-
"url": "https://github.com/willin/svelte-auth/issues"
93-
},
94-
"lint-staged": {
95-
"*.+(js|jsx|json|yml|yaml|css|less|scss|ts|tsx|md|graphql|mdx|vue)": [
96-
"prettier --write"
97-
],
98-
"*.+(js|jsx|ts|tsx|vue)": [
99-
"eslint --fix"
100-
]
101-
}
2+
"name": "@svelte-dev/auth",
3+
"version": "0.1.0",
4+
"description": "Simple Authentication for Svelte",
5+
"author": "Willin Wang <willin@willin.org> (https://willin.wang/)",
6+
"keywords": [
7+
"svelte",
8+
"auth",
9+
"authentication",
10+
"local",
11+
"auth0",
12+
"authing",
13+
"oauth2",
14+
"strategies"
15+
],
16+
"homepage": "https://github.com/willin/svelte-auth#readme",
17+
"scripts": {
18+
"dev": "vite dev --port 8788",
19+
"dev:docs": "typedoc --watch",
20+
"build": "vite build && npm run package",
21+
"build:docs": "typedoc",
22+
"preview": "vite preview",
23+
"package": "svelte-kit sync && svelte-package && publint",
24+
"prepublishOnly": "npm run package",
25+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
26+
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
27+
"version": "conventional-changelog -p angular -i CHANGELOG.md -s && git add CHANGELOG.md",
28+
"test": "vitest",
29+
"coverage": "vitest run --coverage",
30+
"prepare": "husky install",
31+
"lint": "prettier --write . && eslint . --fix"
32+
},
33+
"exports": {
34+
".": {
35+
"types": "./dist/index.d.ts",
36+
"svelte": "./dist/index.js"
37+
}
38+
},
39+
"files": [
40+
"dist",
41+
"!dist/**/*.test.*",
42+
"!dist/**/*.spec.*"
43+
],
44+
"dependencies": {},
45+
"peerDependencies": {
46+
"@svelte-dev/session": "^0.1.0",
47+
"@sveltejs/kit": "^1.0.0",
48+
"svelte": "^5.0.0||^4.0.0"
49+
},
50+
"devDependencies": {
51+
"@commitlint/cli": "latest",
52+
"@commitlint/config-conventional": "latest",
53+
"@svelte-dev/auth-sso": "^0.0.5",
54+
"@sveltejs/adapter-cloudflare": "^2.3.3",
55+
"@sveltejs/kit": "^1.27.4",
56+
"@sveltejs/package": "^2.2.3",
57+
"@typescript-eslint/eslint-plugin": "^6.0.0",
58+
"@typescript-eslint/parser": "^6.0.0",
59+
"@vitest/coverage-istanbul": "^0.34.6",
60+
"bun-types": "^1.0.15",
61+
"conventional-changelog-cli": "latest",
62+
"eslint": "^8.28.0",
63+
"eslint-config-prettier": "^9.0.0",
64+
"eslint-plugin-svelte": "^2.30.0",
65+
"husky": "latest",
66+
"lint-staged": "latest",
67+
"prettier": "^3.0.0",
68+
"prettier-plugin-svelte": "^3.0.0",
69+
"publint": "^0.1.9",
70+
"svelte": "^5.0.0-next.17",
71+
"svelte-check": "^3.6.0",
72+
"tslib": "^2.4.1",
73+
"typedoc-plugin-extras": "^3.0.0",
74+
"typedoc-plugin-google-ads": "^1.6.0",
75+
"typedoc-plugin-keywords": "^1.6.0",
76+
"typedocs": "^0.6.7",
77+
"typescript": "^5.0.0",
78+
"vite": "^4.4.2",
79+
"vitest": "^0.34.0"
80+
},
81+
"svelte": "./dist/index.js",
82+
"types": "./dist/index.d.ts",
83+
"type": "module",
84+
"publishConfig": {
85+
"access": "public"
86+
},
87+
"repository": {
88+
"type": "git",
89+
"url": "git+https://github.com/willin/svelte-auth.git"
90+
},
91+
"bugs": {
92+
"url": "https://github.com/willin/svelte-auth/issues"
93+
},
94+
"lint-staged": {
95+
"*.+(js|jsx|json|yml|yaml|css|less|scss|ts|tsx|md|graphql|mdx|vue)": [
96+
"prettier --write"
97+
],
98+
"*.+(js|jsx|ts|tsx|vue)": [
99+
"eslint --fix"
100+
]
101+
}
102102
}

‎src/app.d.ts

+24-24
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,30 @@ import type { Auth } from '$lib/auth/auth.ts';
66
// See https://kit.svelte.dev/docs/types#app
77
// for information about these interfaces
88
declare global {
9-
namespace App {
10-
// interface Error {}
11-
interface Locals {
12-
auth: Auth;
13-
session: SessionStorage<{ user: any }>;
14-
user?:
15-
| {
16-
invalid?: boolean;
17-
[key: string]: unknown;
18-
}
19-
| unknown;
20-
}
21-
// interface PageData {}
22-
interface Platform {
23-
env: {
24-
SSO_ID: string;
25-
SSO_SECRET: string;
26-
};
27-
context: {
28-
waitUntil(promise: Promise<unknown>): void;
29-
};
30-
caches: CacheStorage & { default: Cache };
31-
}
32-
}
9+
namespace App {
10+
// interface Error {}
11+
interface Locals {
12+
auth: Auth;
13+
session: SessionStorage<{ user: any }>;
14+
user?:
15+
| {
16+
invalid?: boolean;
17+
[key: string]: unknown;
18+
}
19+
| unknown;
20+
}
21+
// interface PageData {}
22+
interface Platform {
23+
env: {
24+
SSO_ID: string;
25+
SSO_SECRET: string;
26+
};
27+
context: {
28+
waitUntil(promise: Promise<unknown>): void;
29+
};
30+
caches: CacheStorage & { default: Cache };
31+
}
32+
}
3333
}
3434

3535
export {};

‎src/app.html

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<!doctype html>
22
<html lang="en">
3-
<head>
4-
<meta charset="utf-8" />
5-
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
6-
<meta name="viewport" content="width=device-width, initial-scale=1" />
7-
%sveltekit.head%
8-
</head>
9-
<body data-sveltekit-preload-data="hover">
10-
<div>%sveltekit.body%</div>
11-
</body>
3+
<head>
4+
<meta charset="utf-8" />
5+
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1" />
7+
%sveltekit.head%
8+
</head>
9+
<body data-sveltekit-preload-data="hover">
10+
<div>%sveltekit.body%</div>
11+
</body>
1212
</html>

‎src/hooks.server.ts

+38-38
Original file line numberDiff line numberDiff line change
@@ -5,43 +5,43 @@ import { Auth } from '$lib/auth/auth.js';
55
import { SSOStrategy } from '@svelte-dev/auth-sso';
66

77
export const handle = sequence(
8-
handleSession({
9-
adapter: {
10-
name: 'cookie',
11-
options: {
12-
chunk: true
13-
}
14-
},
15-
session: {
16-
secrets: ['s3cr3t']
17-
},
18-
cookie: {
19-
secure: !!env.SSO_CALLBACK_URL,
20-
sameSite: 'lax',
21-
path: '/',
22-
httpOnly: !!env.SSO_CALLBACK_URL,
23-
maxAge: 604800000
24-
}
25-
}),
26-
async function handle({ event, resolve }) {
27-
const auth = new Auth(event);
28-
const ssoStrategy = new SSOStrategy(
29-
{
30-
clientID: env.SSO_ID,
31-
clientSecret: env.SSO_SECRET,
32-
callbackURL: env.SSO_CALLBACK_URL || 'http://localhost:8788/auth/sso/callback'
33-
},
34-
async ({ profile }) => {
35-
// Get the user data from your DB or API using the tokens and profile
36-
return profile;
37-
}
38-
);
39-
auth.use(ssoStrategy as any);
40-
event.locals.auth = auth;
41-
const user = event.locals.session.get('user');
42-
event.locals.user = user;
43-
const response = await resolve(event);
8+
handleSession({
9+
adapter: {
10+
name: 'cookie',
11+
options: {
12+
chunk: true
13+
}
14+
},
15+
session: {
16+
secrets: ['s3cr3t']
17+
},
18+
cookie: {
19+
secure: !!env.SSO_CALLBACK_URL,
20+
sameSite: 'lax',
21+
path: '/',
22+
httpOnly: !!env.SSO_CALLBACK_URL,
23+
maxAge: 604800000
24+
}
25+
}),
26+
async function handle({ event, resolve }) {
27+
const auth = new Auth(event);
28+
const ssoStrategy = new SSOStrategy(
29+
{
30+
clientID: env.SSO_ID,
31+
clientSecret: env.SSO_SECRET,
32+
callbackURL: env.SSO_CALLBACK_URL || 'http://localhost:8788/auth/sso/callback'
33+
},
34+
async ({ profile }) => {
35+
// Get the user data from your DB or API using the tokens and profile
36+
return profile;
37+
}
38+
);
39+
auth.use(ssoStrategy as any);
40+
event.locals.auth = auth;
41+
const user = event.locals.session.get('user');
42+
event.locals.user = user;
43+
const response = await resolve(event);
4444

45-
return response;
46-
}
45+
return response;
46+
}
4747
);

‎src/lib/auth/auth.ts

+64-64
Original file line numberDiff line numberDiff line change
@@ -4,73 +4,73 @@ import type { Strategy } from './strategy.js';
44
import type { AuthOptions } from './types.js';
55

66
export class Auth<User = unknown> {
7-
/**
8-
* A map of the configured strategies, the key is the name of the strategy
9-
* @private
10-
*/
11-
#strategies = new Map<string, Strategy<User, never>>();
12-
#session: SessionStorage;
7+
/**
8+
* A map of the configured strategies, the key is the name of the strategy
9+
* @private
10+
*/
11+
#strategies = new Map<string, Strategy<User, never>>();
12+
#session: SessionStorage;
1313

14-
constructor(event: RequestEvent) {
15-
this.#session = (event.locals as any)?.session;
16-
}
14+
constructor(event: RequestEvent) {
15+
this.#session = (event.locals as any)?.session;
16+
}
1717

18-
/**
19-
* Call this method with the Strategy, the optional name allows you to setup
20-
* the same strategy multiple times with different names.
21-
* It returns the Authenticator instance for concatenation.
22-
* @example
23-
* auth
24-
* .use(new SomeStrategy({}, (user) => Promise.resolve(user)))
25-
* .use(new SomeStrategy({}, (user) => Promise.resolve(user)), "another");
26-
*/
27-
use(strategy: Strategy<User, never>, name?: string): Auth<User> {
28-
this.#strategies.set(name ?? strategy.name, strategy);
29-
return this;
30-
}
18+
/**
19+
* Call this method with the Strategy, the optional name allows you to setup
20+
* the same strategy multiple times with different names.
21+
* It returns the Authenticator instance for concatenation.
22+
* @example
23+
* auth
24+
* .use(new SomeStrategy({}, (user) => Promise.resolve(user)))
25+
* .use(new SomeStrategy({}, (user) => Promise.resolve(user)), "another");
26+
*/
27+
use(strategy: Strategy<User, never>, name?: string): Auth<User> {
28+
this.#strategies.set(name ?? strategy.name, strategy);
29+
return this;
30+
}
3131

32-
/**
33-
* Call this method with the name of the strategy you want to remove.
34-
* It returns the Authenticator instance for concatenation.
35-
* @example
36-
* auth.unuse("another").unuse("some");
37-
*/
38-
unuse(name: string): Auth<User> {
39-
this.#strategies.delete(name);
40-
return this;
41-
}
32+
/**
33+
* Call this method with the name of the strategy you want to remove.
34+
* It returns the Authenticator instance for concatenation.
35+
* @example
36+
* auth.unuse("another").unuse("some");
37+
*/
38+
unuse(name: string): Auth<User> {
39+
this.#strategies.delete(name);
40+
return this;
41+
}
4242

43-
/**
44-
* Call this to authenticate a request using some strategy. You pass the name
45-
* of the strategy you want to use and the request to authenticate.
46-
* @example
47-
* async function action({ locals }: RequestEvent) {
48-
* return locals.auth.authenticate("some", {
49-
* successRedirect: "/private",
50-
* failureRedirect: "/login",
51-
* });
52-
* };
53-
*/
54-
async authenticate(
55-
event: RequestEvent,
56-
strategy: string,
57-
options: AuthOptions
58-
): Promise<User | void> {
59-
const strategyObj = this.#strategies.get(strategy);
60-
if (!strategyObj) throw new Error(`Strategy ${strategy} not found.`);
61-
return strategyObj.authenticate(event, {
62-
...options,
63-
name: strategy
64-
});
65-
}
43+
/**
44+
* Call this to authenticate a request using some strategy. You pass the name
45+
* of the strategy you want to use and the request to authenticate.
46+
* @example
47+
* async function action({ locals }: RequestEvent) {
48+
* return locals.auth.authenticate("some", {
49+
* successRedirect: "/private",
50+
* failureRedirect: "/login",
51+
* });
52+
* };
53+
*/
54+
async authenticate(
55+
event: RequestEvent,
56+
strategy: string,
57+
options: AuthOptions
58+
): Promise<User | void> {
59+
const strategyObj = this.#strategies.get(strategy);
60+
if (!strategyObj) throw new Error(`Strategy ${strategy} not found.`);
61+
return strategyObj.authenticate(event, {
62+
...options,
63+
name: strategy
64+
});
65+
}
6666

67-
/**
68-
* Destroy the user session throw a redirect to another URL.
69-
* @example
70-
* await auth.logout({ redirectTo: "/login" });
71-
*/
72-
async logout(options: { redirectTo: string }): Promise<never> {
73-
await this.#session.destory();
74-
throw redirect(307, options.redirectTo);
75-
}
67+
/**
68+
* Destroy the user session throw a redirect to another URL.
69+
* @example
70+
* await auth.logout({ redirectTo: "/login" });
71+
*/
72+
async logout(options: { redirectTo: string }): Promise<never> {
73+
await this.#session.destory();
74+
throw redirect(307, options.redirectTo);
75+
}
7676
}

‎src/lib/auth/error.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
export class AuthorizationError extends Error {
2-
constructor(
3-
message?: string,
4-
public cause?: Error
5-
) {
6-
super(message);
7-
}
2+
constructor(
3+
message?: string,
4+
public cause?: Error
5+
) {
6+
super(message);
7+
}
88
}

‎src/lib/auth/strategy.ts

+63-63
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import type { SessionStorage } from '@svelte-dev/session';
1212
* @throws {AuthorizationError} If the user was not found. Any other error will be ignored and thrown again by the strategy.
1313
*/
1414
export interface StrategyVerifyCallback<User, VerifyParams> {
15-
(params: VerifyParams): Promise<User>;
15+
(params: VerifyParams): Promise<User>;
1616
}
1717

1818
/**
@@ -29,70 +29,70 @@ export interface StrategyVerifyCallback<User, VerifyParams> {
2929
* from within the strategy `authenticate` method.
3030
*/
3131
export abstract class Strategy<User, VerifyOptions> {
32-
/**
33-
* The name of the strategy.
34-
* This will be used by the Authenticator to identify and retrieve the
35-
* strategy.
36-
*/
37-
public abstract name: string;
32+
/**
33+
* The name of the strategy.
34+
* This will be used by the Authenticator to identify and retrieve the
35+
* strategy.
36+
*/
37+
public abstract name: string;
3838

39-
public constructor(protected verify: StrategyVerifyCallback<User, VerifyOptions>) {}
39+
public constructor(protected verify: StrategyVerifyCallback<User, VerifyOptions>) {}
4040

41-
/**
42-
* The authentication flow of the strategy.
43-
*
44-
* This method receives the Request to authenticator and the session storage
45-
* to use from the Authenticator. It may receive a custom callback.
46-
*
47-
* At the end of the flow, it will return a Response to be used by the
48-
* application.
49-
*/
50-
public abstract authenticate(event: RequestEvent, options: AuthOptions): Promise<User>;
41+
/**
42+
* The authentication flow of the strategy.
43+
*
44+
* This method receives the Request to authenticator and the session storage
45+
* to use from the Authenticator. It may receive a custom callback.
46+
*
47+
* At the end of the flow, it will return a Response to be used by the
48+
* application.
49+
*/
50+
public abstract authenticate(event: RequestEvent, options: AuthOptions): Promise<User>;
5151

52-
/**
53-
* Throw an AuthorizationError or a redirect to the failureRedirect.
54-
* @param message The error message to set in the session.
55-
* @param event The RequestEvent to get the session out of.
56-
* @param options The strategy options.
57-
* @throws {AuthorizationError} If the throwOnError is set to true.
58-
* @throws {Response} If the failureRedirect is set or throwOnError is false.
59-
* @returns {Promise<never>}
60-
*/
61-
protected async failure(
62-
message: string,
63-
event: RequestEvent,
64-
options: AuthOptions,
65-
cause?: Error
66-
): Promise<void> {
67-
// if a failureRedirect is not set, we throw a 401 Response or an error
68-
if (!options.failureRedirect) {
69-
if (options.throwOnError) throw new AuthorizationError(message, cause);
70-
throw json(
71-
{ message },
72-
{
73-
status: 401
74-
}
75-
);
76-
}
77-
const session = (event.locals as any).session as SessionStorage;
78-
session.flash(options.sessionErrorKey ?? 'auth:error', { message });
79-
throw redirect(307, options.failureRedirect);
80-
}
52+
/**
53+
* Throw an AuthorizationError or a redirect to the failureRedirect.
54+
* @param message The error message to set in the session.
55+
* @param event The RequestEvent to get the session out of.
56+
* @param options The strategy options.
57+
* @throws {AuthorizationError} If the throwOnError is set to true.
58+
* @throws {Response} If the failureRedirect is set or throwOnError is false.
59+
* @returns {Promise<never>}
60+
*/
61+
protected async failure(
62+
message: string,
63+
event: RequestEvent,
64+
options: AuthOptions,
65+
cause?: Error
66+
): Promise<void> {
67+
// if a failureRedirect is not set, we throw a 401 Response or an error
68+
if (!options.failureRedirect) {
69+
if (options.throwOnError) throw new AuthorizationError(message, cause);
70+
throw json(
71+
{ message },
72+
{
73+
status: 401
74+
}
75+
);
76+
}
77+
const session = (event.locals as any).session as SessionStorage;
78+
session.flash(options.sessionErrorKey ?? 'auth:error', { message });
79+
throw redirect(307, options.failureRedirect);
80+
}
8181

82-
/**
83-
* Returns the user data or throw a redirect to the successRedirect.
84-
* @param user The user data to set in the session.
85-
* @param event The RequestEvent to get the session out of.
86-
* @param options The strategy options.
87-
* @returns {Promise<User>} The user data.
88-
* @throws {Response} If the successRedirect is set, it will redirect to it.
89-
*/
90-
protected async success(user: User, event: RequestEvent, options: AuthOptions): Promise<User> {
91-
// if a successRedirect is not set, we return the user
92-
if (!options.successRedirect) return user;
93-
const session = (event.locals as any).session as SessionStorage;
94-
await session.set(options?.sessionKey ?? 'user', user);
95-
await session.set('strategy', this.name);
96-
throw redirect(307, options.successRedirect);
97-
}
82+
/**
83+
* Returns the user data or throw a redirect to the successRedirect.
84+
* @param user The user data to set in the session.
85+
* @param event The RequestEvent to get the session out of.
86+
* @param options The strategy options.
87+
* @returns {Promise<User>} The user data.
88+
* @throws {Response} If the successRedirect is set, it will redirect to it.
89+
*/
90+
protected async success(user: User, event: RequestEvent, options: AuthOptions): Promise<User> {
91+
// if a successRedirect is not set, we return the user
92+
if (!options.successRedirect) return user;
93+
const session = (event.locals as any).session as SessionStorage;
94+
await session.set(options?.sessionKey ?? 'user', user);
95+
await session.set('strategy', this.name);
96+
throw redirect(307, options.successRedirect);
97+
}
9898
}

‎src/lib/auth/types.ts

+35-35
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,39 @@ export type { SessionStorageOptions, SessionStorage } from '@svelte-dev/session'
33
* Extra information from the Authenticator to the strategy
44
*/
55
export interface AuthOptions {
6-
/**
7-
* The name used to register the strategy
8-
*/
9-
name?: string;
10-
/**
11-
* The key of the session used to set the user data.
12-
* @default "user"
13-
*/
14-
sessionKey?: string;
15-
/**
16-
* In what key of the session the errors will be set.
17-
* @default "auth:error"
18-
*/
19-
sessionErrorKey?: string;
20-
/**
21-
* The key of the session used to set the strategy used to authenticate the
22-
* user.
23-
*/
24-
sessionStrategyKey?: string;
25-
/**
26-
* To what URL redirect in case of a successful authentication.
27-
* If not defined, it will return the user data.
28-
*/
29-
successRedirect?: string;
30-
/**
31-
* To what URL redirect in case of a failed authentication.
32-
* If not defined, it will return null
33-
*/
34-
failureRedirect?: string;
35-
/**
36-
* Set if the strategy should throw an error instead of a Reponse in case of
37-
* a failed authentication.
38-
* @default true
39-
*/
40-
throwOnError?: boolean;
6+
/**
7+
* The name used to register the strategy
8+
*/
9+
name?: string;
10+
/**
11+
* The key of the session used to set the user data.
12+
* @default "user"
13+
*/
14+
sessionKey?: string;
15+
/**
16+
* In what key of the session the errors will be set.
17+
* @default "auth:error"
18+
*/
19+
sessionErrorKey?: string;
20+
/**
21+
* The key of the session used to set the strategy used to authenticate the
22+
* user.
23+
*/
24+
sessionStrategyKey?: string;
25+
/**
26+
* To what URL redirect in case of a successful authentication.
27+
* If not defined, it will return the user data.
28+
*/
29+
successRedirect?: string;
30+
/**
31+
* To what URL redirect in case of a failed authentication.
32+
* If not defined, it will return null
33+
*/
34+
failureRedirect?: string;
35+
/**
36+
* Set if the strategy should throw an error instead of a Reponse in case of
37+
* a failed authentication.
38+
* @default true
39+
*/
40+
throwOnError?: boolean;
4141
}

‎src/routes/+layout.server.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import type { LayoutServerLoad } from './$types.js';
22

33
export const load: LayoutServerLoad = ({ locals }) => {
4-
const { user } = locals; // locals.user set by hooks.server.ts/handle(), undefined if not logged in
5-
return {
6-
user
7-
};
4+
const { user } = locals; // locals.user set by hooks.server.ts/handle(), undefined if not logged in
5+
return {
6+
user
7+
};
88
};
99

1010
export const trailingSlash = 'always';

‎src/routes/+layout.svelte

+23-23
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
11
<main>
2-
<h1>@svelte-dev/auth</h1>
3-
<nav>
4-
<a href="/">Demo</a> |
5-
<a href="https://github.com/willin/svelte-auth" target="_blank">Tutorial</a> |
6-
<a href="/docs/" target="_blank">Docs</a>
7-
</nav>
8-
<article>
9-
<h2>Demo</h2>
10-
<slot />
11-
</article>
2+
<h1>@svelte-dev/auth</h1>
3+
<nav>
4+
<a href="/">Demo</a> |
5+
<a href="https://github.com/willin/svelte-auth" target="_blank">Tutorial</a> |
6+
<a href="/docs/" target="_blank">Docs</a>
7+
</nav>
8+
<article>
9+
<h2>Demo</h2>
10+
<slot />
11+
</article>
1212
</main>
1313

1414
<style>
15-
main {
16-
display: flex;
17-
flex-direction: column;
18-
align-items: center;
19-
justify-content: center;
20-
min-height: 100vh;
21-
}
22-
a,
23-
a:link,
24-
a:visited {
25-
text-decoration: none;
26-
color: #69f;
27-
}
15+
main {
16+
display: flex;
17+
flex-direction: column;
18+
align-items: center;
19+
justify-content: center;
20+
min-height: 100vh;
21+
}
22+
a,
23+
a:link,
24+
a:visited {
25+
text-decoration: none;
26+
color: #69f;
27+
}
2828
</style>

‎src/routes/auth/[provider]/+server.ts

+11-11
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import { redirect, type RequestEvent } from '@sveltejs/kit';
22

33
export const GET = async (event: RequestEvent) => {
4-
if (event.locals.user) {
5-
throw redirect(307, '/demo');
6-
}
7-
const { request } = event;
8-
const provider = event.params.provider;
9-
const referer = request.headers.get('referer');
10-
const returnPath = referer ? new URL(referer).pathname : '/';
4+
if (event.locals.user) {
5+
throw redirect(307, '/demo');
6+
}
7+
const { request } = event;
8+
const provider = event.params.provider;
9+
const referer = request.headers.get('referer');
10+
const returnPath = referer ? new URL(referer).pathname : '/';
1111

12-
return await event.locals.auth.authenticate(event, provider as string, {
13-
successRedirect: returnPath,
14-
failureRedirect: returnPath
15-
});
12+
return await event.locals.auth.authenticate(event, provider as string, {
13+
successRedirect: returnPath,
14+
failureRedirect: returnPath
15+
});
1616
};
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import type { RequestEvent } from '@sveltejs/kit';
22

33
export const GET = async (event: RequestEvent) => {
4-
const provider = event.params.provider;
4+
const provider = event.params.provider;
55

6-
return await event.locals.auth.authenticate(event, provider as string, {
7-
successRedirect: '/demo',
8-
failureRedirect: '/'
9-
});
6+
return await event.locals.auth.authenticate(event, provider as string, {
7+
successRedirect: '/demo',
8+
failureRedirect: '/'
9+
});
1010
};

‎src/routes/demo/+page.server.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { PageServerLoad } from './$types.js';
22

33
export const load: PageServerLoad = async (event) => {
4-
const user = event.locals.user || { invalid: true };
5-
return { user };
4+
const user = event.locals.user || { invalid: true };
5+
return { user };
66
};

‎src/routes/demo/+page.svelte

+10-10
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
<script>
2-
import { goto } from '$app/navigation';
2+
import { goto } from '$app/navigation';
33
4-
let { data } = $props();
4+
let { data } = $props();
55
6-
$effect(() => {
7-
if (data.user && data.user.invalid) {
8-
goto('/');
9-
}
10-
});
6+
$effect(() => {
7+
if (data.user && data.user.invalid) {
8+
goto('/');
9+
}
10+
});
1111
</script>
1212

1313
{#if data && !data.user.invalid}
14-
<div>
15-
<pre>{JSON.stringify(data, null, 2)}</pre>
16-
</div>
14+
<div>
15+
<pre>{JSON.stringify(data, null, 2)}</pre>
16+
</div>
1717
{/if}

‎svelte.config.js

+17-17
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,23 @@ import { vitePreprocess } from '@sveltejs/kit/vite';
33

44
/** @type {import('@sveltejs/kit').Config} */
55
const config = {
6-
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
7-
// for more information about preprocessors
8-
preprocess: vitePreprocess(),
9-
compilerOptions: {
10-
runes: true
11-
},
12-
kit: {
13-
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
14-
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
15-
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
16-
adapter: adapter({
17-
routes: {
18-
include: ['/*'],
19-
exclude: ['<build>', '<prerendered>', '/favicon.png', '/docs/*']
20-
}
21-
})
22-
}
6+
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
7+
// for more information about preprocessors
8+
preprocess: vitePreprocess(),
9+
compilerOptions: {
10+
runes: true
11+
},
12+
kit: {
13+
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
14+
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
15+
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
16+
adapter: adapter({
17+
routes: {
18+
include: ['/*'],
19+
exclude: ['<build>', '<prerendered>', '/favicon.png', '/docs/*']
20+
}
21+
})
22+
}
2323
};
2424

2525
export default config;

‎tsconfig.json

+15-15
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
{
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-
"module": "NodeNext",
13-
"types": ["bun-types"],
14-
"moduleResolution": "NodeNext",
15-
"noImplicitAny": false
16-
}
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+
"module": "NodeNext",
13+
"types": ["bun-types"],
14+
"moduleResolution": "NodeNext",
15+
"noImplicitAny": false
16+
}
1717
}

‎tsconfig.typedoc.json

+15-15
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
{
2-
"extends": ["./tsconfig.json", "typedoc/tsdoc.json"],
3-
"include": [
4-
"./.svelte-kit/ambient.d.ts",
5-
"./.svelte-kit/types/**/$types.d.ts",
6-
"./types/**/*.ts",
7-
"./vite.config.ts",
8-
"./src/**/*.ts",
9-
"./src/**/*.svelte",
10-
"./tests/**/*.js",
11-
"./tests/**/*.ts",
12-
"./tests/**/*.svelte",
13-
"./dist/**/*.ts",
14-
"./dist/**/*.svelte"
15-
],
16-
"exclude": ["**/*.test.ts", "**/*.js"]
2+
"extends": ["./tsconfig.json", "typedoc/tsdoc.json"],
3+
"include": [
4+
"./.svelte-kit/ambient.d.ts",
5+
"./.svelte-kit/types/**/$types.d.ts",
6+
"./types/**/*.ts",
7+
"./vite.config.ts",
8+
"./src/**/*.ts",
9+
"./src/**/*.svelte",
10+
"./tests/**/*.js",
11+
"./tests/**/*.ts",
12+
"./tests/**/*.svelte",
13+
"./dist/**/*.ts",
14+
"./dist/**/*.svelte"
15+
],
16+
"exclude": ["**/*.test.ts", "**/*.js"]
1717
}

‎typedoc.json

+40-40
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,42 @@
11
{
2-
"$schema": "https://typedoc.org/schema.json",
3-
"entryPoints": ["./dist/index.d.ts"],
4-
"out": "./static/docs",
5-
"tsconfig": "tsconfig.typedoc.json",
6-
"externalPattern": ["**/node_modules/[!svelte]**"],
7-
"exclude": ["**/*+(index|.test|.spec|.e2e).ts"],
8-
"cleanOutputDir": true,
9-
"disableSources": true,
10-
"hideParameterTypesInTitle": false,
11-
"navigationLinks": {
12-
"Demo": "https://svelte-auth.js.cool/",
13-
"GitHub": "https://github.com/willin/svelte-auth",
14-
"NPM": "https://npmjs.com/package/@svelte-dev/auth",
15-
"Willin": "https://willin.wang"
16-
},
17-
"plugin": ["typedoc-plugin-extras", "typedoc-plugin-keywords", "typedoc-plugin-google-ads"],
18-
"theme": "default",
19-
"googleAdsId": "ca-pub-5059418763237956",
20-
"name": "@svelet-dev/auth",
21-
"customTitle": "@svelet-dev/auth",
22-
"customDescription": "OIDC / OAuth2 authentication and authorization for prerendered / client-side-rendered SvelteKit apps.",
23-
"favicon": "./static/favicon.png",
24-
"footerTypedocVersion": true,
25-
"keywords": [
26-
"auth",
27-
"authentication",
28-
"authorization",
29-
"svelte",
30-
"sveltekit",
31-
"oidc",
32-
"oauth",
33-
"oauth2",
34-
"client",
35-
"browser",
36-
"prerender",
37-
"client-side-rendering",
38-
"csr",
39-
"spa",
40-
"mpa"
41-
]
2+
"$schema": "https://typedoc.org/schema.json",
3+
"entryPoints": ["./dist/index.d.ts"],
4+
"out": "./static/docs",
5+
"tsconfig": "tsconfig.typedoc.json",
6+
"externalPattern": ["**/node_modules/[!svelte]**"],
7+
"exclude": ["**/*+(index|.test|.spec|.e2e).ts"],
8+
"cleanOutputDir": true,
9+
"disableSources": true,
10+
"hideParameterTypesInTitle": false,
11+
"navigationLinks": {
12+
"Demo": "https://svelte-auth.js.cool/",
13+
"GitHub": "https://github.com/willin/svelte-auth",
14+
"NPM": "https://npmjs.com/package/@svelte-dev/auth",
15+
"Willin": "https://willin.wang"
16+
},
17+
"plugin": ["typedoc-plugin-extras", "typedoc-plugin-keywords", "typedoc-plugin-google-ads"],
18+
"theme": "default",
19+
"googleAdsId": "ca-pub-5059418763237956",
20+
"name": "@svelet-dev/auth",
21+
"customTitle": "@svelet-dev/auth",
22+
"customDescription": "OIDC / OAuth2 authentication and authorization for prerendered / client-side-rendered SvelteKit apps.",
23+
"favicon": "./static/favicon.png",
24+
"footerTypedocVersion": true,
25+
"keywords": [
26+
"auth",
27+
"authentication",
28+
"authorization",
29+
"svelte",
30+
"sveltekit",
31+
"oidc",
32+
"oauth",
33+
"oauth2",
34+
"client",
35+
"browser",
36+
"prerender",
37+
"client-side-rendering",
38+
"csr",
39+
"spa",
40+
"mpa"
41+
]
4242
}

‎vite.config.ts

+20-20
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,24 @@ import { sveltekit } from '@sveltejs/kit/vite';
22
import { defineConfig } from 'vitest/config';
33

44
export default defineConfig({
5-
plugins: [sveltekit()],
6-
test: {
7-
include: ['src/lib/**/*.{test,spec}.{js,ts}'],
8-
coverage: {
9-
provider: 'istanbul',
10-
reporter: ['text', 'json', 'html', 'lcov'],
11-
include: ['src/lib/**/*.{js,ts}'],
12-
exclude: [
13-
'**/auth/handler.ts',
14-
'**/types/**',
15-
'**/hooks.server.ts',
16-
'**/index.ts',
17-
'**/constants/**',
18-
'**/icons/**',
19-
'**/*.d.ts',
20-
'**/*.spec.{js,ts}'
21-
],
22-
reportsDirectory: './.coverage'
23-
}
24-
}
5+
plugins: [sveltekit()],
6+
test: {
7+
include: ['src/lib/**/*.{test,spec}.{js,ts}'],
8+
coverage: {
9+
provider: 'istanbul',
10+
reporter: ['text', 'json', 'html', 'lcov'],
11+
include: ['src/lib/**/*.{js,ts}'],
12+
exclude: [
13+
'**/auth/handler.ts',
14+
'**/types/**',
15+
'**/hooks.server.ts',
16+
'**/index.ts',
17+
'**/constants/**',
18+
'**/icons/**',
19+
'**/*.d.ts',
20+
'**/*.spec.{js,ts}'
21+
],
22+
reportsDirectory: './.coverage'
23+
}
24+
}
2525
});

0 commit comments

Comments
 (0)
Please sign in to comment.