Skip to content

Commit

Permalink
update user api
Browse files Browse the repository at this point in the history
  • Loading branch information
kylekz committed Dec 29, 2024
1 parent 6b13479 commit 4fcade8
Show file tree
Hide file tree
Showing 10 changed files with 201 additions and 46 deletions.
12 changes: 2 additions & 10 deletions src/api/artist.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { randomUUID } from "crypto";
import { BaseAPI } from "./base-api";
import { AccessTokenMissing } from "../errors";
import { ValidArtist } from "../types/artist-common";

export class ArtistAPI extends BaseAPI {
/**
Expand Down Expand Up @@ -33,7 +33,7 @@ export class ArtistAPI extends BaseAPI {

const params = new URLSearchParams({
artistName: artist,
tid: randomUUID(),
tid: crypto.randomUUID(),
});

return await this.request<Artist.ArtistV1>(
Expand All @@ -42,14 +42,6 @@ export class ArtistAPI extends BaseAPI {
}
}

/**
* The list of artists available.
*
* `(string & {})` allows any string through while giving typesafety on known artists.
*/
export const validArtists = ["tripleS", "ARTMS"] as const;
export type ValidArtist = (typeof validArtists)[number] | (string & {});

export namespace Artist {
export type Artist = {
id: string;
Expand Down
12 changes: 1 addition & 11 deletions src/api/legacy-artist.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ValidArtist } from "../types/artist-common";
import { BaseAPI } from "./base-api";

/**
Expand Down Expand Up @@ -33,17 +34,6 @@ export class LegacyArtistAPI extends BaseAPI {
}
}

/**
* The list of artists available.
*
* `(string & {})` allows any string through while giving typesafety on known artists.
*/
const validArtists = ["tripleS", "ARTMS"] as const;
type ValidArtist = (typeof validArtists)[number] | (string & {});

/**
* @deprecated Use `Artist` instead.
*/
export namespace LegacyArtist {
export type Artist = {
name: string;
Expand Down
6 changes: 3 additions & 3 deletions src/api/news.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { z } from "zod";
import { LegacyArtist, ValidArtist } from "./legacy-artist";
import { BaseAPI } from "./base-api";
import { bffNewsFeedSchema, newsFeedSchema } from "../zod/news";
import { AccessTokenMissing } from "../errors";
import { randomUUID } from "crypto";
import { ValidArtist } from "../types/artist-common";
import { LegacyArtist } from "./legacy-artist";

export class NewsAPI extends BaseAPI {
/**
Expand Down Expand Up @@ -67,7 +67,7 @@ export class NewsAPI extends BaseAPI {

const params = new URLSearchParams({
artistName: artistName,
tid: randomUUID(),
tid: crypto.randomUUID(),
page: page.toString(),
size: size.toString(),
});
Expand Down
7 changes: 3 additions & 4 deletions src/api/rewards.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { randomUUID } from "crypto";
import { BaseAPI } from "./base-api";
import { AccessTokenMissing, BadRequestError } from "../errors";

Expand All @@ -14,7 +13,7 @@ export class RewardsAPI extends BaseAPI {
}

const params = new URLSearchParams({
tid: randomUUID(),
tid: crypto.randomUUID(),
});

return await this.request<Rewards.RewardList>(
Expand All @@ -33,7 +32,7 @@ export class RewardsAPI extends BaseAPI {
}

const params = new URLSearchParams({
tid: randomUUID(),
tid: crypto.randomUUID(),
});

return await this.request<{ isClaimable: boolean }>(
Expand All @@ -52,7 +51,7 @@ export class RewardsAPI extends BaseAPI {
}

const params = new URLSearchParams({
tid: randomUUID(),
tid: crypto.randomUUID(),
});

return await this.request<boolean>(
Expand Down
52 changes: 47 additions & 5 deletions src/api/user.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { AccessTokenMissing } from "../errors";
import { LegacyArtist, ValidArtist } from "./legacy-artist";
import { ValidArtist } from "../types/artist-common";
import { Artist } from "./artist";
import { BaseAPI } from "./base-api";
import { LegacyArtist } from "./legacy-artist";

export class UserAPI extends BaseAPI {
/**
* Get the currently authenticated user.
*
* Authentication is required.
*/
async me() {
Expand All @@ -18,9 +19,26 @@ export class UserAPI extends BaseAPI {
);
}

/**
* Get the currently authenticated user.
* Authentication is required.
*/
async meBff() {
if (!this.config.accessToken) {
throw new AccessTokenMissing();
}

const params = new URLSearchParams({
tid: crypto.randomUUID(),
});

return await this.request<User.UserBFF>(
`/bff/v1/users/me?${params.toString()}`
);
}

/**
* Search for users.
*
* Authentication is required.
*/
async search(query: string) {
Expand All @@ -35,7 +53,6 @@ export class UserAPI extends BaseAPI {

/**
* Get a search result by nickname.
*
* Authentication is not required.
*/
async byNickname(nickname: string) {
Expand All @@ -46,7 +63,6 @@ export class UserAPI extends BaseAPI {

/**
* Update the current user's device profile.
*
* Authentication is required.
*/
async updateDeviceProfile(profile: User.DeviceProfile) {
Expand All @@ -64,6 +80,7 @@ export class UserAPI extends BaseAPI {
export namespace User {
export type User = {
id: number;
guid: string;
email: string;
nickname: string;
address: string;
Expand Down Expand Up @@ -94,6 +111,31 @@ export namespace User {
};
};

export type UserBFF = {
id: number;
nickname: string;
address: string;
profileImageUrl: string;
birth: string;
loginChannel: "email";
socialLoginUserId: string | null;
isBanned: boolean;
marketingConsentDate: string | null;
lastViewedArtist: ValidArtist;
lastActiveAt: string;
locale: string;
country: string;
os: string;
appVersion: string;
createdAt: string;
updatedAt: string;
artists: Artist.ArtistV1[];
profileImages: {
artistName: ValidArtist;
profileImageUrl: string;
}[];
};

export type DeviceProfile = {
locale: string;
country: string;
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { createClient, CosmoClient } from "./client";
export * from "./types/artist-common";
export { Artist } from "./api/artist";
export { Auth } from "./api/auth";
export { Grid } from "./api/grid";
Expand Down
6 changes: 6 additions & 0 deletions src/types/artist-common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* The list of artists available.
* `(string & {})` allows any string through while giving typesafety on known artists.
*/
export const validArtists = ["tripleS", "ARTMS"] as const;
export type ValidArtist = (typeof validArtists)[number] | (string & {});
26 changes: 24 additions & 2 deletions tests/api/user.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, it, expect, beforeEach } from "vitest";
import { CosmoClient, createClient } from "../../src/client";
import { unauthorizedHandler } from "../mocks";
import { unauthorizedBffHandler, unauthorizedHandler } from "../mocks";
import { server } from "../setup";
import { AccessTokenMissing, UnauthorizedError } from "../../src/errors";
import json from "../mocks.json";
Expand Down Expand Up @@ -35,6 +35,11 @@ describe("UserAPI", () => {
});
expect(response).toEqual(true);
});

it("should get the currently authenticated user via /bff endpoint", async () => {
const response = await cosmo.users.meBff();
expect(response).toEqual(json.getUserBFF);
});
});

describe("unauthenticated", () => {
Expand All @@ -60,27 +65,35 @@ describe("UserAPI", () => {
})
).rejects.toThrowError(new AccessTokenMissing());
});

it("getting the current user via /bff endpoint should throw an error", async () => {
await expect(cosmo.users.meBff()).rejects.toThrowError(
new AccessTokenMissing()
);
});
});

describe("invalid token", () => {
beforeEach(() => {
cosmo.setAccessToken("someInvalidAccessToken");
server.use(unauthorizedHandler);
});

it("getting the current user should handle unauthorized requests", async () => {
server.use(unauthorizedHandler);
await expect(() => cosmo.users.me()).rejects.toThrowError(
new UnauthorizedError("missing Authorization header")
);
});

it("user search should handle unauthorized requests", async () => {
server.use(unauthorizedHandler);
await expect(() => cosmo.users.search("example")).rejects.toThrowError(
new UnauthorizedError("missing Authorization header")
);
});

it("updating the device profile should handle unauthorized requests", async () => {
server.use(unauthorizedHandler);
await expect(() =>
cosmo.users.updateDeviceProfile({
locale: "en",
Expand All @@ -92,6 +105,15 @@ describe("UserAPI", () => {
new UnauthorizedError("missing Authorization header")
);
});

it("getting the current user via /bff endpoint should handle unauthorized requests", async () => {
server.use(unauthorizedBffHandler);
await expect(cosmo.users.meBff()).rejects.toThrowError(
new UnauthorizedError(
"Sorry, your username or password was entered Incorrectly"
)
);
});
});

it("should get a user by their nickname", async () => {
Expand Down
Loading

0 comments on commit 4fcade8

Please sign in to comment.