Skip to content

Commit 482feb4

Browse files
committed
Extract Nuxt SDK API route paths into shared constants
Signed-off-by: janithjay <janithjayashan018@gmail.com>
1 parent cd30859 commit 482feb4

7 files changed

Lines changed: 90 additions & 32 deletions

File tree

‎packages/nuxt/src/module.ts‎

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
import type {Nuxt} from '@nuxt/schema';
1616
import {VendorConstants} from '@thunderid/node';
1717
import {defu} from 'defu';
18+
import NuxtAPIRoutes from './runtime/constants/NuxtAPIRoutes';
1819
import type {ThunderIDNuxtConfig, ThunderIDSessionPayload, ThunderIDSSRData} from './runtime/types';
1920

2021
type ViteUserConfig = Parameters<Parameters<typeof extendViteConfig>[0]>[0];
@@ -141,39 +142,39 @@ export default defineNuxtModule<ThunderIDNuxtConfig>({
141142
// Register server API routes
142143
const serverRoutes: ServerRoute[] = [
143144
// ── Auth flow ──────────────────────────────────────────────────────
144-
{handler: resolve('./runtime/server/routes/auth/session/signin.get'), route: '/api/auth/signin'},
145+
{handler: resolve('./runtime/server/routes/auth/session/signin.get'), route: NuxtAPIRoutes.SIGN_IN},
145146
{
146147
handler: resolve('./runtime/server/routes/auth/session/signin.post'),
147148
method: 'post' as const,
148-
route: '/api/auth/signin',
149+
route: NuxtAPIRoutes.SIGN_IN,
149150
},
150151
{
151152
handler: resolve('./runtime/server/routes/auth/session/signup.post'),
152153
method: 'post' as const,
153-
route: '/api/auth/signup',
154+
route: NuxtAPIRoutes.SIGN_UP,
154155
},
155-
{handler: resolve('./runtime/server/routes/auth/session/callback.get'), route: '/api/auth/callback'},
156+
{handler: resolve('./runtime/server/routes/auth/session/callback.get'), route: NuxtAPIRoutes.CALLBACK},
156157
{
157158
handler: resolve('./runtime/server/routes/auth/session/callback.post'),
158159
method: 'post' as const,
159-
route: '/api/auth/callback',
160+
route: NuxtAPIRoutes.CALLBACK,
160161
},
161162
{
162163
handler: resolve('./runtime/server/routes/auth/session/signout.post'),
163164
method: 'post' as const,
164-
route: '/api/auth/signout',
165+
route: NuxtAPIRoutes.SIGN_OUT,
165166
},
166167
// ── Session / token ───────────────────────────────────────────────
167-
{handler: resolve('./runtime/server/routes/auth/session/session.get'), route: '/api/auth/session'},
168-
{handler: resolve('./runtime/server/routes/auth/session/token.get'), route: '/api/auth/token'},
169-
{handler: resolve('./runtime/server/routes/auth/session/meta.get'), route: '/api/auth/meta'},
168+
{handler: resolve('./runtime/server/routes/auth/session/session.get'), route: NuxtAPIRoutes.SESSION},
169+
{handler: resolve('./runtime/server/routes/auth/session/token.get'), route: NuxtAPIRoutes.TOKEN},
170+
{handler: resolve('./runtime/server/routes/auth/session/meta.get'), route: NuxtAPIRoutes.META},
170171
// ── User ──────────────────────────────────────────────────────────
171-
{handler: resolve('./runtime/server/routes/auth/user/user.get'), route: '/api/auth/user'},
172-
{handler: resolve('./runtime/server/routes/auth/user/profile.get'), route: '/api/auth/user/profile'},
172+
{handler: resolve('./runtime/server/routes/auth/user/user.get'), route: NuxtAPIRoutes.USER},
173+
{handler: resolve('./runtime/server/routes/auth/user/profile.get'), route: NuxtAPIRoutes.USER_PROFILE},
173174
{
174175
handler: resolve('./runtime/server/routes/auth/user/profile.patch'),
175176
method: 'patch' as const,
176-
route: '/api/auth/user/profile',
177+
route: NuxtAPIRoutes.USER_PROFILE,
177178
},
178179
];
179180

‎packages/nuxt/src/runtime/components/ThunderIDRoot.ts‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {generateFlattenedUserProfile} from '@thunderid/browser';
55
import type {AttributeSchema, FlowMetadataResponse, UpdateMeProfileConfig, User, UserProfile} from '@thunderid/node';
66
import {FlowMetaProvider, FlowProvider, I18nProvider, ThemeProvider, UserProvider} from '@thunderid/vue';
77
import {defineComponent, h, type Component, type Ref, type SetupContext, type VNode} from 'vue';
8+
import NuxtAPIRoutes from '../constants/NuxtAPIRoutes';
89
import type {ThunderIDAuthState, ThunderIDNuxtConfig} from '../types';
910
import {getAuthStateKey, getFlowMetaStateKey, getUserProfileStateKey, getUserSchemaStateKey} from '../utils/stateKeys';
1011
import {useState, useRuntimeConfig} from '#imports';
@@ -100,7 +101,7 @@ const ThunderIDRoot: Component = defineComponent({
100101
};
101102

102103
/**
103-
* profile PATCH via the `/api/auth/user/profile` Nitro route.
104+
* profile PATCH via the `NuxtAPIRoutes.USER_PROFILE` Nitro route.
104105
* Signature matches `UserProvider.updateProfile` exactly.
105106
*
106107
* On success, applies an optimistic local update via `onUpdateProfile`
@@ -116,7 +117,7 @@ const ThunderIDRoot: Component = defineComponent({
116117
// no-op: session is resolved server-side
117118
}
118119
try {
119-
const result: {data: {user: User}; error: string; success: boolean} = await $fetch('/api/auth/user/profile', {
120+
const result: {data: {user: User}; error: string; success: boolean} = await $fetch(NuxtAPIRoutes.USER_PROFILE, {
120121
body: requestConfig,
121122
method: 'PATCH',
122123
});
@@ -130,13 +131,13 @@ const ThunderIDRoot: Component = defineComponent({
130131
};
131132

132133
/**
133-
* Re-fetch the full user profile (and its attribute schema) from `/api/auth/user/profile`.
134+
* Re-fetch the full user profile (and its attribute schema) from `NuxtAPIRoutes.USER_PROFILE`.
134135
*/
135136
const revalidateProfile = async (): Promise<void> => {
136137
try {
137138
const res: (UserProfile & {userSchema?: Record<string, AttributeSchema> | null}) | null = await $fetch<
138139
UserProfile & {userSchema?: Record<string, AttributeSchema> | null}
139-
>('/api/auth/user/profile');
140+
>(NuxtAPIRoutes.USER_PROFILE);
140141
if (res) {
141142
const {userSchema: fetchedSchema, ...profile} = res;
142143
userProfileState.value = profile as UserProfile;
@@ -148,14 +149,14 @@ const ThunderIDRoot: Component = defineComponent({
148149
};
149150

150151
/**
151-
* Fetches flow metadata via the `/api/auth/meta` Nitro route instead of `FlowMetaProvider`'s
152+
* Fetches flow metadata via the `NuxtAPIRoutes.META` Nitro route instead of `FlowMetaProvider`'s
152153
* default direct browser-to-`baseUrl` fetch — so the browser never talks to the ThunderID
153154
* server directly and no CORS configuration is required there. Used for both the initial
154155
* fetch (when SSR seeding via `flowMetaState` didn't happen, e.g. it failed server-side) and
155156
* subsequent `switchLanguage()` calls.
156157
*/
157158
const fetchMeta = async (params: {applicationId?: string; language?: string}): Promise<FlowMetadataResponse> =>
158-
$fetch<FlowMetadataResponse>('/api/auth/meta', {
159+
$fetch<FlowMetadataResponse>(NuxtAPIRoutes.META, {
159160
query: {...(params.language ? {language: params.language} : {})},
160161
});
161162

‎packages/nuxt/src/runtime/composables/useThunderID.ts‎

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {navigateTo, useState, useRuntimeConfig} from '#app';
55
import {EmbeddedSignInFlowStatus, EmbeddedSignUpFlowStatus, getRedirectBasedSignUpUrl} from '@thunderid/browser';
66
import {useThunderID as useThunderIDVue, type ThunderIDContext} from '@thunderid/vue';
77
import type {Ref} from 'vue';
8+
import NuxtAPIRoutes from '../constants/NuxtAPIRoutes';
89
import type {ThunderIDAuthState} from '../types';
910

1011
/**
@@ -53,7 +54,7 @@ export function useThunderID(): ThunderIDContext {
5354
if (isEmbedded) {
5455
const payload: Record<string, unknown> = arg0 as Record<string, unknown>;
5556
const request: Record<string, unknown> = (args[1] ?? {}) as Record<string, unknown>;
56-
const res: {data: any; success: boolean} = await $fetch<{data: any; success: boolean}>('/api/auth/signin', {
57+
const res: {data: any; success: boolean} = await $fetch<{data: any; success: boolean}>(NuxtAPIRoutes.SIGN_IN, {
5758
body: {payload, request},
5859
method: 'POST',
5960
});
@@ -71,7 +72,7 @@ export function useThunderID(): ThunderIDContext {
7172
if (res.data?.afterSignInUrl) {
7273
if (import.meta.client) {
7374
try {
74-
const session: ThunderIDAuthState = await $fetch<ThunderIDAuthState>('/api/auth/session');
75+
const session: ThunderIDAuthState = await $fetch<ThunderIDAuthState>(NuxtAPIRoutes.SESSION);
7576
const authState: Ref<ThunderIDAuthState> = useState<ThunderIDAuthState>('thunderid:auth');
7677
authState.value = session;
7778
} catch {
@@ -89,13 +90,15 @@ export function useThunderID(): ThunderIDContext {
8990
// Redirect flow.
9091
const options: Record<string, unknown> | undefined = arg0 as Record<string, unknown> | undefined;
9192
const returnTo: string | undefined = typeof options?.returnTo === 'string' ? options.returnTo : undefined;
92-
const url: string = returnTo ? `/api/auth/signin?returnTo=${encodeURIComponent(returnTo)}` : '/api/auth/signin';
93+
const url: string = returnTo
94+
? `${NuxtAPIRoutes.SIGN_IN}?returnTo=${encodeURIComponent(returnTo)}`
95+
: NuxtAPIRoutes.SIGN_IN;
9396
await navigateTo(url, {external: true});
9497
return undefined;
9598
};
9699

97100
const signOut = async (): Promise<void> => {
98-
const res: {redirectUrl: string} = await $fetch<{redirectUrl: string}>('/api/auth/signout', {method: 'POST'});
101+
const res: {redirectUrl: string} = await $fetch<{redirectUrl: string}>(NuxtAPIRoutes.SIGN_OUT, {method: 'POST'});
99102
await navigateTo(res.redirectUrl || '/', {external: true});
100103
};
101104

@@ -120,7 +123,7 @@ export function useThunderID(): ThunderIDContext {
120123
const isEmbedded: boolean = typeof payload === 'object' && payload !== null && 'flowType' in payload;
121124

122125
if (isEmbedded) {
123-
const res: {data: any; success: boolean} = await $fetch<{data: any; success: boolean}>('/api/auth/signup', {
126+
const res: {data: any; success: boolean} = await $fetch<{data: any; success: boolean}>(NuxtAPIRoutes.SIGN_UP, {
124127
body: {payload},
125128
method: 'POST',
126129
});
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2025 The ThunderID Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
/**
5+
* Nitro API route paths registered by the ThunderID Nuxt SDK.
6+
*
7+
* Single source of truth for the `/api/auth/*` paths registered as server
8+
* handlers in `module.ts` and consumed across `runtime/composables/useThunderID.ts`,
9+
* `runtime/components/ThunderIDRoot.ts`, `runtime/plugins/thunderid.ts`,
10+
* `runtime/middleware/defineThunderIDMiddleware.ts`, and
11+
* `runtime/server/plugins/thunderid-ssr.ts`. Update a route here, not at each
12+
* call site.
13+
*
14+
* @example
15+
* ```typescript
16+
* await $fetch(NuxtAPIRoutes.SIGN_IN, { method: 'POST' });
17+
* ```
18+
*/
19+
const NuxtAPIRoutes: {
20+
CALLBACK: string;
21+
META: string;
22+
SESSION: string;
23+
SIGN_IN: string;
24+
SIGN_OUT: string;
25+
SIGN_UP: string;
26+
TOKEN: string;
27+
USER: string;
28+
USER_PROFILE: string;
29+
} = {
30+
/** Resolves the OAuth callback and completes sign-in. */
31+
CALLBACK: '/api/auth/callback',
32+
/** Serves flow metadata (design config + i18n bundle). */
33+
META: '/api/auth/meta',
34+
/** Returns the current server-verified session. */
35+
SESSION: '/api/auth/session',
36+
/** Starts (embedded) or redirects to (redirect flow) sign-in. */
37+
SIGN_IN: '/api/auth/signin',
38+
/** Clears the session and returns a post-sign-out redirect URL. */
39+
SIGN_OUT: '/api/auth/signout',
40+
/** Starts (embedded) or redirects to (redirect flow) sign-up. */
41+
SIGN_UP: '/api/auth/signup',
42+
/** Returns the current access token. */
43+
TOKEN: '/api/auth/token',
44+
/** Returns the current user object. */
45+
USER: '/api/auth/user',
46+
/** Fetches (GET) and updates (PATCH) the user profile. */
47+
USER_PROFILE: '/api/auth/user/profile',
48+
} as const;
49+
50+
export default NuxtAPIRoutes;

‎packages/nuxt/src/runtime/middleware/defineThunderIDMiddleware.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44
import {defineNuxtRouteMiddleware, navigateTo, useRuntimeConfig, useState} from '#app';
55
import type {Ref} from 'vue';
66
import type {RouteLocationNormalized} from 'vue-router';
7+
import NuxtAPIRoutes from '../constants/NuxtAPIRoutes';
78
import type {ThunderIDAuthState} from '../types';
89
import {getAuthStateKey} from '../utils/stateKeys';
910

1011
export interface ThunderIDMiddlewareOptions {
1112
/**
1213
* The path to redirect unauthenticated (or unauthorised) requests to.
13-
* Defaults to `'/api/auth/signin'`.
14+
* Defaults to `NuxtAPIRoutes.SIGN_IN`.
1415
*/
1516
redirectTo?: string;
1617
/**
@@ -25,7 +26,7 @@ export interface ThunderIDMiddlewareOptions {
2526
requireScopes?: string[];
2627
}
2728

28-
const DEFAULT_REDIRECT_TO = '/api/auth/signin';
29+
const DEFAULT_REDIRECT_TO = NuxtAPIRoutes.SIGN_IN;
2930

3031
/**
3132
* Typed factory for ThunderID route middleware.

‎packages/nuxt/src/runtime/plugins/thunderid.ts‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type {H3Event} from 'h3';
99
import {computed} from 'vue';
1010
import type {ComputedRef, Ref} from 'vue';
1111
import ThunderIDRoot from '../components/ThunderIDRoot';
12+
import NuxtAPIRoutes from '../constants/NuxtAPIRoutes';
1213
import type {ThunderIDAuthState, ThunderIDSSRData} from '../types';
1314
import {getAuthStateKey, getFlowMetaStateKey, getUserProfileStateKey, getUserSchemaStateKey} from '../utils/stateKeys';
1415
import type {NuxtApp} from '#app';
@@ -154,12 +155,14 @@ export default defineNuxtPlugin((nuxtApp: NuxtApp) => {
154155
// ── 3. Action helpers (Nuxt-aware navigation) ───────────────────────────
155156
const signIn = async (options?: Record<string, unknown>): Promise<void> => {
156157
const returnTo: string | undefined = typeof options?.returnTo === 'string' ? options.returnTo : undefined;
157-
const url: string = returnTo ? `/api/auth/signin?returnTo=${encodeURIComponent(returnTo)}` : '/api/auth/signin';
158+
const url: string = returnTo
159+
? `${NuxtAPIRoutes.SIGN_IN}?returnTo=${encodeURIComponent(returnTo)}`
160+
: NuxtAPIRoutes.SIGN_IN;
158161
await navigateTo(url, {external: true});
159162
};
160163

161164
const signOut = async (): Promise<void> => {
162-
const res: {redirectUrl: string} = await $fetch<{redirectUrl: string}>('/api/auth/signout', {method: 'POST'});
165+
const res: {redirectUrl: string} = await $fetch<{redirectUrl: string}>(NuxtAPIRoutes.SIGN_OUT, {method: 'POST'});
163166
await navigateTo(res.redirectUrl || '/', {external: true});
164167
};
165168

@@ -187,12 +190,12 @@ export default defineNuxtPlugin((nuxtApp: NuxtApp) => {
187190
// Last-resort fallback for unrecognised baseUrls — keeps the historical
188191
// behaviour of hitting the (POST-only) Nitro route, which will surface a
189192
// 405 in the network tab and make the misconfiguration obvious.
190-
await navigateTo('/api/auth/signup', {external: true});
193+
await navigateTo(NuxtAPIRoutes.SIGN_UP, {external: true});
191194
};
192195

193196
const getAccessToken = async (): Promise<string> => {
194197
try {
195-
const res: {accessToken: string} = await $fetch<{accessToken: string}>('/api/auth/token');
198+
const res: {accessToken: string} = await $fetch<{accessToken: string}>(NuxtAPIRoutes.TOKEN);
196199
return res.accessToken ?? '';
197200
} catch {
198201
return '';

‎packages/nuxt/src/runtime/server/plugins/thunderid-ssr.ts‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
} from '@thunderid/node';
1111
import {getRequestURL, type H3Event} from 'h3';
1212
import {defineNitroPlugin} from 'nitropack/runtime';
13+
import NuxtAPIRoutes from '../../constants/NuxtAPIRoutes';
1314
import type {ThunderIDAuthState, ThunderIDNuxtConfig, ThunderIDSSRData} from '../../types';
1415
import {createLogger} from '../../utils/log';
1516
import ThunderIDNuxtClient from '../ThunderIDNuxtClient';
@@ -18,15 +19,13 @@ import {useRuntimeConfig} from '#imports';
1819

1920
const log: ReturnType<typeof createLogger> = createLogger('thunderid-ssr');
2021

21-
const CALLBACK_PATH = '/api/auth/callback';
22-
2322
/**
2423
* Build the OAuth redirect_uri from the incoming request origin.
2524
* Honors X-Forwarded-* headers so it works correctly behind a reverse proxy.
2625
*/
2726
function resolveCallbackUrl(event: H3Event): string {
2827
const url: URL = getRequestURL(event, {xForwardedHost: true, xForwardedProto: true});
29-
return `${url.origin}${CALLBACK_PATH}`;
28+
return `${url.origin}${NuxtAPIRoutes.CALLBACK}`;
3029
}
3130

3231
/**

0 commit comments

Comments
 (0)