@absolutejs/auth 0.2.3 → 0.2.5

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 (37) hide show
  1. package/.prettierignore +4 -0
  2. package/.prettierrc.json +9 -0
  3. package/dist/index.js +1 -329
  4. package/package.json +3 -9
  5. package/src/authorize.ts +119 -0
  6. package/src/callback.ts +127 -0
  7. package/src/constants.ts +13 -0
  8. package/src/index.ts +88 -0
  9. package/src/logout.ts +39 -0
  10. package/src/protectRoute.ts +33 -0
  11. package/src/providers.ts +109 -0
  12. package/src/refresh.ts +63 -0
  13. package/src/revoke.ts +61 -0
  14. package/src/sessionStore.ts +10 -0
  15. package/src/status.ts +100 -0
  16. package/src/typeGuards.ts +32 -0
  17. package/src/types.ts +78 -0
  18. package/src/utils.ts +55 -0
  19. package/tsconfig.json +17 -0
  20. package/dist/example/components/AuthOptions.d.ts +0 -1
  21. package/dist/example/components/Example.d.ts +0 -1
  22. package/dist/example/components/Head.d.ts +0 -6
  23. package/dist/example/components/Modal.d.ts +0 -8
  24. package/dist/example/components/Navbar.d.ts +0 -10
  25. package/dist/example/components/NotAuthorized.d.ts +0 -1
  26. package/dist/example/components/Protected.d.ts +0 -1
  27. package/dist/example/db/migrate.d.ts +0 -1
  28. package/dist/example/db/schema.d.ts +0 -248
  29. package/dist/example/hooks/useAuthStatus.d.ts +0 -19
  30. package/dist/example/indexes/ExampleIndex.d.ts +0 -1
  31. package/dist/example/indexes/NotAuthorizedIndex.d.ts +0 -1
  32. package/dist/example/indexes/ProtectedIndex.d.ts +0 -1
  33. package/dist/example/server.d.ts +0 -1
  34. package/dist/example/utils/networking.d.ts +0 -1
  35. package/dist/example/utils/pageUtils.d.ts +0 -2
  36. package/dist/example/utils/styles.d.ts +0 -15
  37. package/dist/example/utils/userUtils.d.ts +0 -36
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.2.3",
2
+ "version": "0.2.5",
3
3
  "name": "@absolutejs/auth",
4
4
  "description": "An authorization library for absolutejs",
5
5
  "repository": {
@@ -10,7 +10,7 @@
10
10
  "license": "CC BY-NC 4.0",
11
11
  "author": "Alex Kahn",
12
12
  "scripts": {
13
- "build": "rm -rf dist && bun build src/index.ts --outdir dist --minify --splitting --target=bun && tsc --emitDeclarationOnly --project tsconfig.json",
13
+ "build": "rm -rf dist && bun build src/index.ts --outdir dist --minify --splitting --target=bun --external arctic --external elysia && tsc --emitDeclarationOnly --project tsconfig.json",
14
14
  "test": "echo \"Error: no test specified\" && exit 1",
15
15
  "format": "prettier --write \"./**/*.{js,jsx,ts,tsx,css,json}\"",
16
16
  "dev": "bun run --watch example/server.ts",
@@ -27,7 +27,6 @@
27
27
  "oauth"
28
28
  ],
29
29
  "types": "dist/src/index.d.ts",
30
- "dependencies": {},
31
30
  "peerDependencies": {
32
31
  "arctic": ">= 3.6.0",
33
32
  "elysia": ">= 1.2.0"
@@ -47,10 +46,5 @@
47
46
  "elysia": "1.2.25",
48
47
  "typescript": "5.8.3"
49
48
  },
50
- "module": "dist/index.js",
51
- "files": [
52
- "dist/",
53
- "README.md",
54
- "LICENSE"
55
- ]
49
+ "module": "dist/index.js"
56
50
  }
@@ -0,0 +1,119 @@
1
+ import { generateState, generateCodeVerifier } from 'arctic';
2
+ import { Elysia } from 'elysia';
3
+ import { isValidProviderKey } from './typeGuards';
4
+ import { ClientProviders } from './types';
5
+ import { COOKIE_DURATION } from './constants';
6
+
7
+ type AuthorizeProps = {
8
+ clientProviders: ClientProviders;
9
+ authorizeRoute?: string;
10
+ onAuthorize?: () => void;
11
+ };
12
+
13
+ export const authorize = ({
14
+ clientProviders,
15
+ authorizeRoute = 'authorize',
16
+ onAuthorize
17
+ }: AuthorizeProps) =>
18
+ new Elysia().get(
19
+ `/${authorizeRoute}/:provider`,
20
+ ({
21
+ error,
22
+ redirect,
23
+ cookie: { state, code_verifier, auth_provider, redirect_url },
24
+ params: { provider },
25
+ headers
26
+ }) => {
27
+ if (provider === undefined)
28
+ return error('Bad Request', 'Provider is required');
29
+
30
+ if (!isValidProviderKey(provider)) {
31
+ return error('Bad Request', 'Invalid provider');
32
+ }
33
+
34
+ try {
35
+ const normalizedProvider = provider.toLowerCase();
36
+ const { providerInstance, scopes, searchParams } =
37
+ clientProviders[normalizedProvider];
38
+
39
+ const redirectUrl = headers['referer'] ?? '/';
40
+
41
+ redirect_url.set({
42
+ httpOnly: true,
43
+ maxAge: COOKIE_DURATION,
44
+ path: '/',
45
+ sameSite: 'lax',
46
+ secure: true,
47
+ value: redirectUrl
48
+ });
49
+
50
+ auth_provider.set({
51
+ httpOnly: true,
52
+ maxAge: COOKIE_DURATION,
53
+ path: '/',
54
+ sameSite: 'lax',
55
+ secure: true,
56
+ value: provider
57
+ });
58
+
59
+ const currentState = generateState();
60
+
61
+ state.set({
62
+ httpOnly: true,
63
+ maxAge: COOKIE_DURATION,
64
+ path: '/',
65
+ sameSite: 'lax',
66
+ secure: true,
67
+ value: currentState
68
+ });
69
+
70
+ const usesCodeVerifier = providerInstance.createAuthorizationURL
71
+ .toString()
72
+ .includes('codeVerifier');
73
+ const verifier = usesCodeVerifier
74
+ ? generateCodeVerifier()
75
+ : undefined;
76
+ void (
77
+ usesCodeVerifier &&
78
+ code_verifier.set({
79
+ httpOnly: true,
80
+ maxAge: COOKIE_DURATION,
81
+ path: '/',
82
+ sameSite: 'lax',
83
+ secure: true,
84
+ value: verifier ?? ''
85
+ })
86
+ );
87
+
88
+ const authorizationURL = usesCodeVerifier
89
+ ? providerInstance.createAuthorizationURL(
90
+ currentState,
91
+ // @ts-expect-error - This is a dynamic check
92
+ verifier,
93
+ scopes
94
+ )
95
+ : // @ts-expect-error - This is a dynamic check
96
+ providerInstance.createAuthorizationURL(
97
+ currentState,
98
+ scopes
99
+ );
100
+
101
+ searchParams.forEach(([key, value]) => {
102
+ authorizationURL.searchParams.set(key, value);
103
+ });
104
+
105
+ onAuthorize?.();
106
+
107
+ return redirect(authorizationURL.toString());
108
+ } catch (err) {
109
+ if (err instanceof Error) {
110
+ return error(
111
+ 'Internal Server Error',
112
+ `${err.message} - ${err.stack ?? ''}`
113
+ );
114
+ }
115
+
116
+ return error('Internal Server Error', `Unknown error: ${err}`);
117
+ }
118
+ }
119
+ );
@@ -0,0 +1,127 @@
1
+ import { decodeIdToken } from 'arctic';
2
+ import { Elysia } from 'elysia';
3
+ import { sessionStore } from './sessionStore';
4
+ import { isNonEmptyString, isValidProviderKey } from './typeGuards';
5
+ import { ClientProviders, OnCallback } from './types';
6
+
7
+ type CallbackProps<UserType> = {
8
+ clientProviders: ClientProviders;
9
+ callbackRoute?: string;
10
+ onCallback?: OnCallback<UserType>;
11
+ };
12
+
13
+ export const callback = <UserType>({
14
+ clientProviders,
15
+ callbackRoute = 'authorize/callback',
16
+ onCallback
17
+ }: CallbackProps<UserType>) =>
18
+ new Elysia()
19
+ .use(sessionStore<UserType>())
20
+ .get(
21
+ `/${callbackRoute}`,
22
+ async ({
23
+ error,
24
+ redirect,
25
+ store: { session },
26
+ cookie: {
27
+ state: stored_state,
28
+ code_verifier,
29
+ redirect_url,
30
+ user_session_id,
31
+ auth_provider
32
+ },
33
+ query: { code, state: callback_state }
34
+ }) => {
35
+ if (
36
+ !isNonEmptyString(code) ||
37
+ stored_state.value === undefined
38
+ ) {
39
+ return error('Bad Request', 'Invalid callback request');
40
+ }
41
+
42
+ if (callback_state !== stored_state.value) {
43
+ return error('Bad Request', 'Invalid state mismatch');
44
+ }
45
+
46
+ if (auth_provider.value === undefined) {
47
+ return error('Unauthorized', 'No auth provider found');
48
+ }
49
+
50
+ if (!isValidProviderKey(auth_provider.value)) {
51
+ return error('Unauthorized', 'Invalid provider');
52
+ }
53
+
54
+ const normalizedProvider = auth_provider.value.toLowerCase();
55
+ const { providerInstance } =
56
+ clientProviders[normalizedProvider];
57
+
58
+ try {
59
+ // Clear the stored state so the next request doesn't use it
60
+ stored_state.remove();
61
+
62
+ const hasCodeVerifier =
63
+ providerInstance.validateAuthorizationCode
64
+ .toString()
65
+ .includes('codeVerifier');
66
+ const verifier = code_verifier.value;
67
+ if (hasCodeVerifier && verifier === undefined)
68
+ return error(
69
+ 'Bad Request',
70
+ 'Code verifier not found and is required'
71
+ );
72
+
73
+ const safeVerifier = verifier ?? '';
74
+ const tokens = await (hasCodeVerifier
75
+ ? providerInstance.validateAuthorizationCode(
76
+ code,
77
+ safeVerifier
78
+ )
79
+ : // @ts-expect-error - This is a dynamic check
80
+ providerInstance.validateAuthorizationCode(code));
81
+ if (hasCodeVerifier) code_verifier.remove();
82
+
83
+ const decodedIdToken = Object.fromEntries(
84
+ Object.entries(decodeIdToken(tokens.idToken())).map(
85
+ ([key, value]) => [
86
+ key,
87
+ typeof value === 'string' ? value : undefined
88
+ ]
89
+ )
90
+ );
91
+
92
+ const authProvider = auth_provider.value;
93
+
94
+ console.log(
95
+ 'in route user_session_id before',
96
+ user_session_id.value
97
+ );
98
+
99
+ await onCallback?.({
100
+ authProvider,
101
+ decodedIdToken,
102
+ session,
103
+ user_session_id
104
+ });
105
+
106
+ console.log(
107
+ 'in route user_session_id after',
108
+ user_session_id.value
109
+ );
110
+
111
+ const redirectUrl = redirect_url.value ?? '/';
112
+
113
+ return redirect(redirectUrl);
114
+ } catch (err) {
115
+ if (err instanceof Error)
116
+ return error(
117
+ 'Internal Server Error',
118
+ `${err.message} - ${err.stack ?? ''}`
119
+ );
120
+
121
+ return error(
122
+ 'Internal Server Error',
123
+ `Failed to validate authorization code: Unknown error: ${err}`
124
+ );
125
+ }
126
+ }
127
+ );
@@ -0,0 +1,13 @@
1
+ export const SECONDS_IN_A_MINUTE = 60;
2
+ export const MILLISECONDS_IN_A_SECOND = 1000;
3
+ export const MILLISECONDS_IN_A_MINUTE =
4
+ MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE;
5
+ export const MINUTES_IN_AN_HOUR = 60;
6
+ export const HOURS_IN_A_DAY = 24;
7
+ export const MILLISECONDS_IN_A_DAY =
8
+ MILLISECONDS_IN_A_SECOND *
9
+ SECONDS_IN_A_MINUTE *
10
+ MINUTES_IN_AN_HOUR *
11
+ HOURS_IN_A_DAY;
12
+ export const COOKIE_MINUTES = 30; // TODO : See if i can remove
13
+ export const COOKIE_DURATION = SECONDS_IN_A_MINUTE * COOKIE_MINUTES;
package/src/index.ts ADDED
@@ -0,0 +1,88 @@
1
+ import { OAuth2RequestError, ArcticFetchError } from 'arctic';
2
+ import { Elysia } from 'elysia';
3
+ import { authorize } from './authorize';
4
+ import { callback } from './callback';
5
+ import { logout } from './logout';
6
+ import { protectRoute } from './protectRoute';
7
+ import { normalizedProviderKeys, providers } from './providers';
8
+ import { refresh } from './refresh';
9
+ import { revoke } from './revoke';
10
+ import { status } from './status';
11
+ import { isValidProviderKey } from './typeGuards';
12
+ import { AbsoluteAuthProps, ClientProviders } from './types';
13
+
14
+ export const absoluteAuth = <UserType>({
15
+ config,
16
+ authorizeRoute,
17
+ callbackRoute,
18
+ logoutRoute,
19
+ statusRoute,
20
+ refreshRoute,
21
+ revokeRoute,
22
+ onAuthorize,
23
+ onCallback,
24
+ onStatus,
25
+ onRefresh,
26
+ onLogout,
27
+ onRevoke
28
+ }: AbsoluteAuthProps<UserType>) => {
29
+ const clientProviders = Object.keys(config).reduce<ClientProviders>(
30
+ (acc, key) => {
31
+ if (!Object.prototype.hasOwnProperty.call(config, key)) return acc;
32
+
33
+ if (!isValidProviderKey(key)) {
34
+ console.error(`Provider ${key} is not supported`);
35
+
36
+ return acc;
37
+ }
38
+
39
+ const options = config[key];
40
+ if (!options) return acc;
41
+
42
+ const normalizedProvider = key.toLowerCase();
43
+ const originalProviderKey =
44
+ normalizedProviderKeys[normalizedProvider];
45
+
46
+ if (!isValidProviderKey(originalProviderKey)) {
47
+ console.error(`Provider ${key} is not supported`);
48
+
49
+ return acc;
50
+ }
51
+
52
+ const Provider = providers[originalProviderKey];
53
+ const { credentials, scopes = [], searchParams = [] } = options;
54
+
55
+ // @ts-expect-error: dynamic constructor parameters
56
+ const providerInstance = new Provider(...credentials);
57
+
58
+ acc[normalizedProvider] = {
59
+ providerInstance,
60
+ scopes,
61
+ searchParams
62
+ };
63
+
64
+ return acc;
65
+ },
66
+ {}
67
+ );
68
+
69
+ return new Elysia()
70
+ .error('OAUTH2_REQUEST_ERROR', OAuth2RequestError)
71
+ .error('ARCTIC_FETCH_ERROR', ArcticFetchError)
72
+ .use(logout({ logoutRoute, onLogout }))
73
+ .use(revoke({ clientProviders, onRevoke, revokeRoute }))
74
+ .use(status<UserType>({ clientProviders, onStatus, statusRoute }))
75
+ .use(refresh({ clientProviders, onRefresh, refreshRoute }))
76
+ .use(authorize({ authorizeRoute, clientProviders, onAuthorize }))
77
+ .use(
78
+ callback<UserType>({
79
+ callbackRoute,
80
+ clientProviders,
81
+ onCallback
82
+ })
83
+ )
84
+ .use(protectRoute())
85
+ .as('plugin');
86
+ };
87
+
88
+ export * from './utils';
package/src/logout.ts ADDED
@@ -0,0 +1,39 @@
1
+ import { Elysia } from 'elysia';
2
+
3
+ type LogoutProps = {
4
+ logoutRoute?: string;
5
+ onLogout?: () => void;
6
+ };
7
+
8
+ export const logout = ({ logoutRoute = 'logout', onLogout }: LogoutProps) =>
9
+ new Elysia().post(
10
+ `/${logoutRoute}`,
11
+ async ({ error, cookie: { user_session_id, auth_provider } }) => {
12
+ if (auth_provider.value === undefined) {
13
+ return error('Unauthorized', 'No auth provider found');
14
+ }
15
+
16
+ try {
17
+ onLogout?.();
18
+
19
+ user_session_id.remove();
20
+ auth_provider.remove();
21
+
22
+ return new Response('Succesfuly Logged Out', {
23
+ status: 204
24
+ });
25
+ } catch (err) {
26
+ if (err instanceof Error) {
27
+ return error(
28
+ 'Internal Server Error',
29
+ `Failed to logout: ${err.message}`
30
+ );
31
+ }
32
+
33
+ return error(
34
+ 'Internal Server Error',
35
+ `Failed to logout: Unknown error: ${err}`
36
+ );
37
+ }
38
+ }
39
+ );
@@ -0,0 +1,33 @@
1
+ import { Elysia } from 'elysia';
2
+ import { sessionStore } from './sessionStore';
3
+
4
+ export const protectRoute = <UserType>() =>
5
+ new Elysia()
6
+ .use(sessionStore<UserType>())
7
+ .derive(
8
+ ({ store: { session }, cookie: { user_session_id }, error }) => ({
9
+ protectRoute: async (
10
+ handleAuth: () => Promise<Response>,
11
+ handleAuthFail?: () => Promise<Response>
12
+ ) => {
13
+ if (user_session_id.value === undefined) {
14
+ return (
15
+ handleAuthFail?.() ??
16
+ error('Unauthorized', 'No session ID found')
17
+ );
18
+ }
19
+
20
+ const userSession = session[user_session_id.value];
21
+
22
+ if (userSession === undefined) {
23
+ return (
24
+ handleAuthFail?.() ??
25
+ error('Unauthorized', 'No session found')
26
+ );
27
+ }
28
+
29
+ return handleAuth();
30
+ }
31
+ })
32
+ )
33
+ .as('plugin');
@@ -0,0 +1,109 @@
1
+ import {
2
+ AmazonCognito,
3
+ AniList,
4
+ Apple,
5
+ Atlassian,
6
+ Auth0,
7
+ Authentik,
8
+ Bitbucket,
9
+ Box,
10
+ Coinbase,
11
+ Discord,
12
+ Dribbble,
13
+ Dropbox,
14
+ Facebook,
15
+ Figma,
16
+ Intuit,
17
+ GitHub,
18
+ GitLab,
19
+ Google,
20
+ Kakao,
21
+ KeyCloak,
22
+ Lichess,
23
+ Line,
24
+ Linear,
25
+ LinkedIn,
26
+ MicrosoftEntraId,
27
+ MyAnimeList,
28
+ Notion,
29
+ Okta,
30
+ Osu,
31
+ Patreon,
32
+ Reddit,
33
+ Roblox,
34
+ Salesforce,
35
+ Shikimori,
36
+ Slack,
37
+ Spotify,
38
+ Strava,
39
+ Tiltify,
40
+ Tumblr,
41
+ Twitch,
42
+ Twitter,
43
+ VK,
44
+ WorkOS,
45
+ Yahoo,
46
+ Yandex,
47
+ Zoom,
48
+ FortyTwo
49
+ } from 'arctic';
50
+
51
+ // TODO: When arctic adds better way to get the providers give a type to the object
52
+ // eslint-disable-next-line custom/explicit-object-types
53
+ export const providers = {
54
+ AmazonCognito,
55
+ AniList,
56
+ Apple,
57
+ Atlassian,
58
+ Auth0,
59
+ Authentik,
60
+ Bitbucket,
61
+ Box,
62
+ Coinbase,
63
+ Discord,
64
+ Dribbble,
65
+ Dropbox,
66
+ Facebook,
67
+ Figma,
68
+ FortyTwo,
69
+ GitHub,
70
+ GitLab,
71
+ Google,
72
+ Intuit,
73
+ Kakao,
74
+ KeyCloak,
75
+ Lichess,
76
+ Line,
77
+ Linear,
78
+ LinkedIn,
79
+ MicrosoftEntraId,
80
+ MyAnimeList,
81
+ Notion,
82
+ Okta,
83
+ Osu,
84
+ Patreon,
85
+ Reddit,
86
+ Roblox,
87
+ Salesforce,
88
+ Shikimori,
89
+ Slack,
90
+ Spotify,
91
+ Strava,
92
+ Tiltify,
93
+ Tumblr,
94
+ Twitch,
95
+ Twitter,
96
+ VK,
97
+ WorkOS,
98
+ Yahoo,
99
+ Yandex,
100
+ Zoom
101
+ };
102
+
103
+ export const normalizedProviderKeys = Object.keys(providers).reduce<
104
+ Record<string, string>
105
+ >((map, key) => {
106
+ map[key.toLowerCase()] = key;
107
+
108
+ return map;
109
+ }, {});
package/src/refresh.ts ADDED
@@ -0,0 +1,63 @@
1
+ import { Elysia } from 'elysia';
2
+ import { isRefreshableProvider } from './typeGuards';
3
+ import { ClientProviders } from './types';
4
+
5
+ type RefreshProps = {
6
+ clientProviders: ClientProviders;
7
+ refreshRoute?: string;
8
+ onRefresh?: () => void;
9
+ };
10
+
11
+ export const refresh = ({
12
+ clientProviders,
13
+ refreshRoute = 'refresh',
14
+ onRefresh
15
+ }: RefreshProps) =>
16
+ new Elysia().post(
17
+ `/${refreshRoute}`,
18
+ async ({ error, cookie: { user_refresh_token, auth_provider } }) => {
19
+ if (user_refresh_token.value === undefined) {
20
+ return error('Unauthorized', 'No refresh token found');
21
+ }
22
+
23
+ if (auth_provider.value === undefined) {
24
+ return error('Unauthorized', 'No auth provider found');
25
+ }
26
+
27
+ const normalizedProvider = auth_provider.value.toLowerCase();
28
+ const { providerInstance } = clientProviders[normalizedProvider];
29
+
30
+ if (!isRefreshableProvider(providerInstance)) {
31
+ return error('Not Implemented', 'Provider is not refreshable');
32
+ }
33
+
34
+ try {
35
+ //consider passing tokens to onRefresh
36
+ // const tokens = await providerInstance.refreshAccessToken(
37
+ // user_refresh_token.value
38
+ // );
39
+
40
+ await providerInstance.refreshAccessToken(
41
+ user_refresh_token.value
42
+ );
43
+
44
+ onRefresh?.();
45
+
46
+ return new Response('Token refreshed', {
47
+ status: 204
48
+ });
49
+ } catch (err) {
50
+ if (err instanceof Error) {
51
+ return error(
52
+ 'Internal Server Error',
53
+ `Failed to refresh token: ${err.message}`
54
+ );
55
+ }
56
+
57
+ return error(
58
+ 'Internal Server Error',
59
+ `Faile to refresh token: Unknown error: ${err}`
60
+ );
61
+ }
62
+ }
63
+ );
package/src/revoke.ts ADDED
@@ -0,0 +1,61 @@
1
+ import { Elysia } from 'elysia';
2
+ import { isRevocableProvider } from './typeGuards';
3
+ import { ClientProviders } from './types';
4
+
5
+ type RevokeProps = {
6
+ clientProviders: ClientProviders;
7
+ revokeRoute?: string;
8
+ onRevoke?: () => void;
9
+ };
10
+
11
+ export const revoke = ({
12
+ clientProviders,
13
+ revokeRoute = 'revoke',
14
+ onRevoke
15
+ }: RevokeProps) =>
16
+ new Elysia().post(
17
+ `/${revokeRoute}/access-token`,
18
+ async ({ error, cookie: { user_refresh_token, auth_provider } }) => {
19
+ if (user_refresh_token.value === undefined) {
20
+ return error('Unauthorized', 'No refresh token found');
21
+ }
22
+
23
+ if (auth_provider.value === undefined) {
24
+ return error('Unauthorized', 'No auth provider found');
25
+ }
26
+
27
+ const normalizedProvider = auth_provider.value.toLowerCase();
28
+ const { providerInstance } = clientProviders[normalizedProvider];
29
+
30
+ if (!isRevocableProvider(providerInstance)) {
31
+ return error(
32
+ 'Not Implemented',
33
+ 'Provider does not support revocation'
34
+ );
35
+ }
36
+
37
+ try {
38
+ await providerInstance.revokeAccessToken(
39
+ user_refresh_token.value
40
+ );
41
+
42
+ onRevoke?.();
43
+
44
+ return new Response('Token revoked', {
45
+ status: 204
46
+ });
47
+ } catch (err) {
48
+ if (err instanceof Error) {
49
+ return error(
50
+ 'Internal Server Error',
51
+ `Failed to revoke token: ${err.message}`
52
+ );
53
+ }
54
+
55
+ return error(
56
+ 'Internal Server Error',
57
+ `Failed to revoke token: Unknown error: ${err}`
58
+ );
59
+ }
60
+ }
61
+ );
@@ -0,0 +1,10 @@
1
+ import { Elysia } from 'elysia';
2
+ import { SessionRecord } from './types';
3
+
4
+ export const sessionStore = <UserType>() => {
5
+ const initialSession: SessionRecord<UserType> = {};
6
+
7
+ return new Elysia({ name: 'sessionStore' }).state({
8
+ session: initialSession
9
+ });
10
+ };