Skip to content

Commit a334194

Browse files
committed
feat(login): rework login to skip fetch
1 parent 7ffe2c3 commit a334194

File tree

10 files changed

+61
-27
lines changed

10 files changed

+61
-27
lines changed

src/components/common/navbar/NavbarSettingsDopdown.vue

+1-6
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,6 @@ const options = computed<DropdownProps['options']>(() => {
9393
return baseOptions;
9494
});
9595
96-
const login = async () => {
97-
const response = await TraktService.approve();
98-
return createTab({ url: response.url });
99-
};
100-
10196
const loadUser = async (account: string) => {
10297
const auth = await syncRestoreAuth(account);
10398
return TraktService.importAuthentication(auth);
@@ -113,7 +108,7 @@ const onSelect: DropdownProps['onSelect'] = async (key: string, { label }) => {
113108
url: ExternaLinks.trakt[TraktService.isStaging ? 'staging' : 'production'],
114109
});
115110
case 'login':
116-
return login();
111+
return TraktService.approve({ prompt: true });
117112
case 'logout':
118113
await TraktService.logout();
119114
await setCurrentUser();

src/components/views/login/LoginComponent.vue

+1-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { useRoute, useRouter } from 'vue-router';
88
import { TraktService } from '~/services/trakt.service';
99
import { useAuthSettingsStoreRefs } from '~/stores/settings/auth.store';
1010
import { useI18n } from '~/utils';
11-
import { createTab } from '~/utils/browser/browser.utils';
1211
1312
const i18n = useI18n('global');
1413
@@ -28,8 +27,7 @@ onMounted(() => {
2827
2928
const redirect = async () => {
3029
try {
31-
const response = await TraktService.approve();
32-
await createTab({ url: response.url });
30+
await TraktService.approve();
3331
} catch (error) {
3432
console.error('Error:', error);
3533
}

src/models/tmdb/tmdb-client.model.ts

-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ import {
1212
} from '~/services/common/base-client';
1313

1414
export type TmdbClientSettings = BaseSettings<{
15-
/** The domain name (e.g. https://api4.thetmdb.com) */
16-
endpoint: string;
1715
/** The consumer client identifier */
1816
useragent: string;
1917
/** The app api key */

src/models/trakt/trakt-authentication.model.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export type TraktAuthenticationAuthorizeRequest = {
3939
/** Prefer the account sign up page to be the default. */
4040
signup?: boolean;
4141
/** Force the user to sign in and authorize your app. */
42-
prompt?: 'login';
42+
prompt?: 'login' | boolean;
4343
};
4444

4545
export type TraktAuthenticationBaseRequest = {
@@ -75,3 +75,8 @@ export type TraktAuthenticationRevokeRequest = {
7575
/** Get this from your app settings. */
7676
client_secret: string;
7777
};
78+
79+
export type TraktAuthenticationApprove = Pick<TraktAuthenticationAuthorizeRequest, 'state' | 'signup' | 'prompt'> & {
80+
redirect?: RequestRedirect;
81+
redirect_uri?: string;
82+
};

src/models/trakt/trakt-client.model.ts

-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ export type TraktClientSettings = BaseSettings<{
3737
client_secret: string;
3838
/** URI specified in your app settings. */
3939
redirect_uri: string;
40-
/** The domain name (i.e. https://api.trakt.tv) */
41-
endpoint: string;
4240
/** The consumer client identifier */
4341
useragent: string;
4442
}>;

src/models/tvdb/tvdb-client.model.ts

-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ import {
1515
* @see [documentation]{@link https://thetvdb.github.io/v4-api/#/Login/post_login}
1616
*/
1717
export type TvdbClientSettings = BaseSettings<{
18-
/** The domain name (e.g. https://api4.thetvdb.com) */
19-
endpoint: string;
2018
/** The api version (e.g. v4) */
2119
version: string;
2220
/** The consumer client identifier */

src/services/common/base-client.ts

+18-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ export type BaseQuery<R extends BaseRequest = BaseRequest, Q = unknown> = {
3535
};
3636

3737
export type BaseSettings<S extends RecursiveRecord = RecursiveRecord> = S & {
38+
/** The domain name (i.e. https://api.domain.ext) */
39+
endpoint: string;
3840
/** A cors proxy endpoint to use for requests when in a browser */
3941
corsProxy?: string;
4042
/** A cors prefix to use for requests when in a browser */
@@ -118,8 +120,10 @@ export class ClientEndpoint<
118120
opts: Option;
119121
body?: BaseBody<string | keyof Parameter>;
120122
init?: BaseInit;
123+
transform?: (param: Parameter) => Parameter;
121124
validate?: (param: Parameter) => boolean;
122125
cached: Cache extends true ? Omit<this, 'cached'> & ClientEndpointCache<Parameter, Response> : never;
126+
resolve: (param?: Parameter) => URL;
123127

124128
constructor(template: BaseTemplate<Parameter, Option>) {
125129
this.method = template.method;
@@ -129,7 +133,11 @@ export class ClientEndpoint<
129133
this.body = template.body;
130134

131135
this.validate = template.validate;
136+
this.transform = template.transform;
132137
this.cached = (template.opts?.cache ? this : null) as never;
138+
this.resolve = () => {
139+
throw new Error('Not implemented');
140+
};
133141
}
134142
}
135143

@@ -172,7 +180,7 @@ export abstract class BaseClient<
172180
private _authentication: ObservableState<AuthenticationType>;
173181
private _callListeners: Observable<QueryType>;
174182

175-
protected get settings() {
183+
get settings() {
176184
if (this._settings.corsProxy) return { ...this._settings, endpoint: this._settings.corsProxy };
177185
return this._settings;
178186
}
@@ -282,9 +290,18 @@ export abstract class BaseClient<
282290
}
283291
};
284292

293+
const parseUrl = (param: Record<string, unknown> = {}) => {
294+
const _params = template.transform?.(param) ?? param;
295+
template.validate?.(_params);
296+
return this._parseUrl(template, _params);
297+
};
298+
285299
Object.entries(client[endpoint]).forEach(([key, value]) => {
286300
if (key === 'cached') {
287301
if (template.opts?.cache) Object.defineProperty(fn, 'cached', { value: cachedFn });
302+
} else if (key === 'resolve') {
303+
Object.defineProperty(fn, 'resolve', { value: parseUrl });
304+
if (template.opts?.cache) Object.defineProperty(cachedFn, 'resolve', { value: parseUrl });
288305
} else {
289306
Object.defineProperty(fn, key, { value });
290307
if (template.opts?.cache) Object.defineProperty(cachedFn, key, { value });

src/services/trakt-client/api/endpoints/authentication.endpoint.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export const authentication = {
4040
*/
4141
authorize: new TraktClientEndpoint<TraktAuthenticationAuthorizeRequest, unknown, false>({
4242
method: HttpMethod.GET,
43-
url: '/oauth/authorize?response_type=code&client_id=&redirect_uri=&state=',
43+
url: '/oauth/authorize?response_type=code&client_id=&redirect_uri=&state=&signup=&prompt=',
4444
init: {
4545
redirect: 'manual',
4646
credentials: 'omit',
@@ -58,6 +58,7 @@ export const authentication = {
5858
},
5959
},
6060
},
61+
transform: params => ({ ...params, prompt: params.prompt ? 'login' : params.prompt }),
6162
}),
6263
/** @see [get-token]{@link https://trakt.docs.apiary.io/#reference/authentication-oauth/get-token} */
6364
token: {

src/services/trakt-client/clients/trakt-client.ts

+27-6
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { BaseTraktClient, isResponseOk } from './base-trakt-client';
22

33
import type {
44
TraktAuthentication,
5-
TraktAuthenticationAuthorizeRequest,
5+
TraktAuthenticationApprove,
66
TraktAuthenticationBaseRequest,
77
TraktAuthenticationCodeRequest,
88
TraktAuthenticationRefreshRequest,
@@ -277,11 +277,7 @@ export class TraktClient extends BaseTraktClient {
277277
*
278278
* @see [authorize]{@link https://trakt.docs.apiary.io/#reference/authentication-oauth/authorize}
279279
*/
280-
redirectToAuthentication({
281-
redirect,
282-
redirect_uri,
283-
...request
284-
}: Pick<TraktAuthenticationAuthorizeRequest, 'state' | 'signup' | 'prompt'> & { redirect?: RequestRedirect; redirect_uri?: string } = {}) {
280+
redirectToAuthentication({ redirect, redirect_uri, ...request }: TraktAuthenticationApprove = {}) {
285281
this.updateAuth(auth => ({ ...auth, state: request.state ?? randomHex() }));
286282
const init: TraktApiInit = {
287283
credentials: 'omit',
@@ -299,6 +295,31 @@ export class TraktClient extends BaseTraktClient {
299295
);
300296
}
301297

298+
/**
299+
* Initiates the OAuth process by generating a URL to the Trakt website.
300+
* Users will be prompted to sign in and authorize the application.
301+
*
302+
* Once redirected back to the application, the code should be exchanged for an access token using {@link exchangeCodeForToken}.
303+
*
304+
* @param redirect - The type of redirect to use (defaults to manual).
305+
* @param redirect_uri - The URL to redirect to after the user has authorized the application (defaults to client settings).
306+
* @param request - Additional parameters for the authorization request.
307+
* @returns A promise resolving to the url to authorize the application.
308+
*
309+
* @see [authorize]{@link https://trakt.docs.apiary.io/#reference/authentication-oauth/authorize}
310+
*/
311+
redirectToAuthenticationUrl({ redirect, redirect_uri, ...request }: TraktAuthenticationApprove = {}) {
312+
return this.authentication.oAuth.authorize
313+
.resolve({
314+
response_type: 'code',
315+
client_id: this.settings.client_id,
316+
redirect_uri: redirect_uri ?? this.settings.redirect_uri,
317+
state: this.auth.state,
318+
...request,
319+
})
320+
.toString();
321+
}
322+
302323
/**
303324
* Exchanges the authorization code obtained after the user has authorized the application with {@link redirectToAuthentication}.
304325
*

src/services/trakt.service.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { TmdbApiResponse } from '~/models/tmdb/tmdb-client.model';
22

3+
import type { TraktAuthenticationApprove } from '~/models/trakt/trakt-authentication.model';
34
import type { TraktApiResponse } from '~/models/trakt/trakt-client.model';
45
import type { SettingsAuth, UserSetting } from '~/models/trakt-service.model';
56
import type { TvdbApiResponse } from '~/models/tvdb/tvdb-client.model';
@@ -14,10 +15,11 @@ import { traktClientSettings } from '~/settings/traktv.api';
1415
import { tvdbClientSettings } from '~/settings/tvdb.api';
1516
import { useAuthSettingsStore } from '~/stores/settings/auth.store';
1617
import { useUserSettingsStore } from '~/stores/settings/user.store';
18+
import { createTab } from '~/utils/browser/browser.utils';
1719
import { ChromeCacheStore } from '~/utils/cache.utils';
1820

1921
export class TraktService {
20-
private static traktClient: TraktClient;
22+
static traktClient: TraktClient;
2123
private static tmdbClient: TmdbClient;
2224
private static tvdbClient: TvdbClient;
2325

@@ -79,8 +81,9 @@ export class TraktService {
7981
return this.saveAuth({ trakt, tvdb, tmdb });
8082
}
8183

82-
static async approve({ redirect_uri, redirect }: { redirect_uri?: string; redirect?: RequestRedirect } = {}) {
83-
return this.traktClient.redirectToAuthentication({ redirect_uri, redirect });
84+
static async approve(params: TraktAuthenticationApprove = {}) {
85+
const url = this.traktClient.redirectToAuthenticationUrl(params);
86+
return createTab({ url });
8487
}
8588

8689
static async login(token: string): Promise<{ auth: SettingsAuth; settings: UserSetting }> {

0 commit comments

Comments
 (0)