From aec3aa46b07918d1e9b60749edf73dbb6c6d17b1 Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Thu, 16 Jan 2025 18:30:44 +0100 Subject: [PATCH 01/34] refac: move DTOs dir up one level --- src/{constants => }/DTOs/RegistrationDTO.ts | 0 src/repositories/UserRepository.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/{constants => }/DTOs/RegistrationDTO.ts (100%) diff --git a/src/constants/DTOs/RegistrationDTO.ts b/src/DTOs/RegistrationDTO.ts similarity index 100% rename from src/constants/DTOs/RegistrationDTO.ts rename to src/DTOs/RegistrationDTO.ts diff --git a/src/repositories/UserRepository.ts b/src/repositories/UserRepository.ts index a7224e7..541e780 100644 --- a/src/repositories/UserRepository.ts +++ b/src/repositories/UserRepository.ts @@ -1,4 +1,4 @@ -import type { RegistrationDetails } from "../constants/DTOs/RegistrationDTO.js"; +import type { RegistrationDetails } from "../DTOs/RegistrationDTO.js"; import { BaseRepository, type BaseRepositoryConstructorArgs, From 412a0e901825652bfab282f4ecae687001b3c284 Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Thu, 16 Jan 2025 18:58:11 +0100 Subject: [PATCH 02/34] feat: port over and split up UserDetailsDTO --- src/DTOs/GroupDetailsDTO.ts | 7 +++++++ src/DTOs/GroupMemberDTO.ts | 5 +++++ src/DTOs/UserDetailsDTO.ts | 8 ++++++++ 3 files changed, 20 insertions(+) create mode 100644 src/DTOs/GroupDetailsDTO.ts create mode 100644 src/DTOs/GroupMemberDTO.ts create mode 100644 src/DTOs/UserDetailsDTO.ts diff --git a/src/DTOs/GroupDetailsDTO.ts b/src/DTOs/GroupDetailsDTO.ts new file mode 100644 index 0000000..5788890 --- /dev/null +++ b/src/DTOs/GroupDetailsDTO.ts @@ -0,0 +1,7 @@ +import type { GroupMemberProfileDTO } from "./GroupMemberDTO.js"; + +export interface GroupDetailsDTO { + groupName: string; + members: GroupMemberProfileDTO[]; + inviteCode: string; +} diff --git a/src/DTOs/GroupMemberDTO.ts b/src/DTOs/GroupMemberDTO.ts new file mode 100644 index 0000000..148b470 --- /dev/null +++ b/src/DTOs/GroupMemberDTO.ts @@ -0,0 +1,5 @@ +export interface GroupMemberProfileDTO { + userId: string; + username: string; + profileImageUri: string; +} diff --git a/src/DTOs/UserDetailsDTO.ts b/src/DTOs/UserDetailsDTO.ts new file mode 100644 index 0000000..d7cab98 --- /dev/null +++ b/src/DTOs/UserDetailsDTO.ts @@ -0,0 +1,8 @@ +import type { GroupDetailsDTO } from "./GroupDetailsDTO.js"; + +export interface UserDetailsDTO { + userId: string; + personalGoal: number; + personalProgress: number; + groupInfo: GroupDetailsDTO; +} From b795e4850d2745013927cc84302fb6b2e4576dfd Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Thu, 16 Jan 2025 22:19:54 +0100 Subject: [PATCH 03/34] feat: add UserResponseDTO interface --- src/DTOs/SimpleResponseDTO.ts | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/DTOs/SimpleResponseDTO.ts diff --git a/src/DTOs/SimpleResponseDTO.ts b/src/DTOs/SimpleResponseDTO.ts new file mode 100644 index 0000000..7d6e6a1 --- /dev/null +++ b/src/DTOs/SimpleResponseDTO.ts @@ -0,0 +1,9 @@ +import type { Serializable } from "child_process"; + +export interface SimpleResponse< + BodyType extends Serializable | undefined = undefined, +> { + ok: boolean; + statusCode: number; + data?: BodyType; +} From 6b1d60ffc9535bd0adbe8f0e9bcbd01190a37a53 Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Thu, 16 Jan 2025 22:20:20 +0100 Subject: [PATCH 04/34] doc: adjust JDoc to reflect reusable method --- src/repositories/UserRepository.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/repositories/UserRepository.ts b/src/repositories/UserRepository.ts index 541e780..2ae4242 100644 --- a/src/repositories/UserRepository.ts +++ b/src/repositories/UserRepository.ts @@ -14,7 +14,7 @@ export class UserRepository extends BaseRepository { } /** - * Sends a request to register the new user with {@link RegistrationDetails} and handles saving the sessionID from the Responses Cookie + * Sends a request to register the new user with {@link RegistrationDetails} and handles saving the sessionID from the Responses Header * @throws any `fetch()` related error * @throws any {@link sessionRepository} related Error */ From 26145580758c08bc5dd47417744ba7521f2c3775 Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Thu, 16 Jan 2025 22:22:48 +0100 Subject: [PATCH 05/34] feat!: digest fetch Response in Repository directly --- src/repositories/UserRepository.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/repositories/UserRepository.ts b/src/repositories/UserRepository.ts index 2ae4242..c431b61 100644 --- a/src/repositories/UserRepository.ts +++ b/src/repositories/UserRepository.ts @@ -1,4 +1,5 @@ import type { RegistrationDetails } from "../DTOs/RegistrationDTO.js"; +import type { SimpleResponse } from "../DTOs/SimpleResponseDTO.js"; import { BaseRepository, type BaseRepositoryConstructorArgs, @@ -18,7 +19,7 @@ export class UserRepository extends BaseRepository { * @throws any `fetch()` related error * @throws any {@link sessionRepository} related Error */ - async registerUser(body: RegistrationDetails) { + async registerUser(body: RegistrationDetails): Promise { const RESPONSE = await fetch( await this._bulildRequest({ route: BaseRepository.Routes.registration, @@ -30,7 +31,7 @@ export class UserRepository extends BaseRepository { await this._handleResponseAfterAuthentication(RESPONSE); - return RESPONSE; + return { ok: RESPONSE.ok, statusCode: RESPONSE.status }; } /** From 85ee5826f6fc630e5bdc1deabff8f9a249529836 Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Thu, 16 Jan 2025 22:24:55 +0100 Subject: [PATCH 06/34] doc: add throw tag to base repo --- src/repositories/BaseRepository.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/repositories/BaseRepository.ts b/src/repositories/BaseRepository.ts index 3f96196..3e5c92c 100644 --- a/src/repositories/BaseRepository.ts +++ b/src/repositories/BaseRepository.ts @@ -28,6 +28,9 @@ export abstract class BaseRepository { public sessionRepository: SessionRepositoryInterface, ) {} + /** + * @throws any {@link sessionRepository} related Error + */ private async buildBaseHeaders() { const HEADERS = new Headers(); HEADERS.append( @@ -42,6 +45,7 @@ export abstract class BaseRepository { /** * @protected + * @throws any {@link sessionRepository} related Error */ async _bulildRequest({ route, @@ -76,6 +80,7 @@ export abstract class BaseRepository { /** * @protected + * @throws any {@link sessionRepository} related Error */ async _handleResponseAfterAuthentication( response: Response, From 61f702973594a6ef4265ceae029164f329a6913c Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Thu, 16 Jan 2025 22:40:29 +0100 Subject: [PATCH 07/34] feat: add helper to extract SimpleResponse from fetch Response --- src/DTOs/SimpleResponseDTO.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/DTOs/SimpleResponseDTO.ts b/src/DTOs/SimpleResponseDTO.ts index 7d6e6a1..5698b97 100644 --- a/src/DTOs/SimpleResponseDTO.ts +++ b/src/DTOs/SimpleResponseDTO.ts @@ -7,3 +7,19 @@ export interface SimpleResponse< statusCode: number; data?: BodyType; } + +/** + * Due to limitations of NextJs Server Actions, [this can not be a class](https://react.dev/reference/rsc/use-server#serializable-parameters-and-return-values). + * @throws any `Response.json()` related error + */ +export async function transformToSimpleResponse< + ResponseDTO extends Serializable | undefined = undefined, +>(fetchResponse: Response): Promise> { + return { + ok: fetchResponse.ok, + statusCode: fetchResponse.status, + data: fetchResponse.headers.has("application/json") + ? ((await fetchResponse.json()) as ResponseDTO) + : undefined, + }; +} From 100df0dbdec38debf998aea37f2e8a5a38db81a2 Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Thu, 16 Jan 2025 22:41:44 +0100 Subject: [PATCH 08/34] feat!: incorporate new helper --- src/repositories/UserRepository.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/repositories/UserRepository.ts b/src/repositories/UserRepository.ts index c431b61..be5b28c 100644 --- a/src/repositories/UserRepository.ts +++ b/src/repositories/UserRepository.ts @@ -1,5 +1,8 @@ import type { RegistrationDetails } from "../DTOs/RegistrationDTO.js"; -import type { SimpleResponse } from "../DTOs/SimpleResponseDTO.js"; +import { + transformToSimpleResponse, + type SimpleResponse, +} from "../DTOs/SimpleResponseDTO.js"; import { BaseRepository, type BaseRepositoryConstructorArgs, @@ -17,6 +20,7 @@ export class UserRepository extends BaseRepository { /** * Sends a request to register the new user with {@link RegistrationDetails} and handles saving the sessionID from the Responses Header * @throws any `fetch()` related error + * @throws any `Response.json()` related error * @throws any {@link sessionRepository} related Error */ async registerUser(body: RegistrationDetails): Promise { @@ -31,7 +35,7 @@ export class UserRepository extends BaseRepository { await this._handleResponseAfterAuthentication(RESPONSE); - return { ok: RESPONSE.ok, statusCode: RESPONSE.status }; + return transformToSimpleResponse(RESPONSE); } /** From 5dc75a3d9c9b5539d9babaf44209a1943a1abc66 Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Thu, 16 Jan 2025 22:47:29 +0100 Subject: [PATCH 09/34] feat!: adjust remaining existing User Repo methods to new helper --- src/repositories/UserRepository.ts | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/repositories/UserRepository.ts b/src/repositories/UserRepository.ts index be5b28c..b94cef9 100644 --- a/src/repositories/UserRepository.ts +++ b/src/repositories/UserRepository.ts @@ -3,6 +3,7 @@ import { transformToSimpleResponse, type SimpleResponse, } from "../DTOs/SimpleResponseDTO.js"; +import type { UserDetailsDTO } from "../DTOs/UserDetailsDTO.js"; import { BaseRepository, type BaseRepositoryConstructorArgs, @@ -40,10 +41,11 @@ export class UserRepository extends BaseRepository { /** * @throws any `fetch()` related error + * @throws any `Response.json()` related error * @throws any {@link sessionRepository} related Error */ - async verifyUser(verificationCode: string) { - return fetch( + async verifyUser(verificationCode: string): Promise { + const RESPONSE = await fetch( await this._bulildRequest({ route: BaseRepository.Routes.activation, method: "POST", @@ -51,14 +53,17 @@ export class UserRepository extends BaseRepository { body: JSON.stringify(verificationCode), }), ); + + return transformToSimpleResponse(RESPONSE); } /** * @throws any `fetch()` related error + * @throws any `Response.json()` related error * @throws any {@link sessionRepository} related Error */ - async updatePersonalGoal(goalPerWeek: number) { - return fetch( + async updatePersonalGoal(goalPerWeek: number): Promise { + const RESPONSE = await fetch( await this._bulildRequest({ route: BaseRepository.Routes.personalGoal, method: "PUT", @@ -68,21 +73,26 @@ export class UserRepository extends BaseRepository { body: JSON.stringify(goalPerWeek), }), ); + + return transformToSimpleResponse(RESPONSE); } /** - * - * * @throws any `fetch()` related error + * @throws any `Response.json()` related error * @throws any {@link sessionRepository} related Error */ - async getUserInfo(abortSignal: AbortSignal) { - return fetch( + async getUserInfo( + abortSignal: AbortSignal, + ): Promise> { + const RESPONSE = await fetch( await this._bulildRequest({ route: BaseRepository.Routes.userInfo, method: "GET", signal: abortSignal, }), ); + + return transformToSimpleResponse(RESPONSE); } } From cafaedb6e128591ed433b993002144b3bbad832a Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Thu, 16 Jan 2025 22:51:01 +0100 Subject: [PATCH 10/34] fix: correct check for json content type --- src/DTOs/SimpleResponseDTO.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/DTOs/SimpleResponseDTO.ts b/src/DTOs/SimpleResponseDTO.ts index 5698b97..e2d138c 100644 --- a/src/DTOs/SimpleResponseDTO.ts +++ b/src/DTOs/SimpleResponseDTO.ts @@ -18,8 +18,9 @@ export async function transformToSimpleResponse< return { ok: fetchResponse.ok, statusCode: fetchResponse.status, - data: fetchResponse.headers.has("application/json") - ? ((await fetchResponse.json()) as ResponseDTO) - : undefined, + data: + fetchResponse.headers.get("Content-Type") === "application/json" + ? ((await fetchResponse.json()) as ResponseDTO) + : undefined, }; } From 7b941b34c38c52c62eb3161776d62066b58e15c3 Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Thu, 16 Jan 2025 22:52:30 +0100 Subject: [PATCH 11/34] docs(changeset): Repository method read json data themselves and return it as part of the SimpleResponseDTO return value --- .changeset/wild-rats-attack.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/wild-rats-attack.md diff --git a/.changeset/wild-rats-attack.md b/.changeset/wild-rats-attack.md new file mode 100644 index 0000000..adcc7b1 --- /dev/null +++ b/.changeset/wild-rats-attack.md @@ -0,0 +1,6 @@ +--- +"motidata": major +--- + +Repository methods read json-data themselves and return it as part of the `SimpleResponseDTO` return value. +Remove calls to `Response.json` and instead handle the new return Type `SimpleResponseDTO`. From 746e477021a176aa45ee465da63dc776eeb85113 Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Fri, 17 Jan 2025 00:05:48 +0100 Subject: [PATCH 12/34] test: add test for SimpleResponseDTO helper --- src/DTOs/__tests__/SimpleResponseDTO.test.ts | 39 ++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/DTOs/__tests__/SimpleResponseDTO.test.ts diff --git a/src/DTOs/__tests__/SimpleResponseDTO.test.ts b/src/DTOs/__tests__/SimpleResponseDTO.test.ts new file mode 100644 index 0000000..f698f7f --- /dev/null +++ b/src/DTOs/__tests__/SimpleResponseDTO.test.ts @@ -0,0 +1,39 @@ +import { expect, test } from "vitest"; +import { + extractDataBasedOnContentType, + transformToSimpleResponse, + type SimpleResponse, +} from "../SimpleResponseDTO.js"; + +test("should transform to SimpleResponseDTO", async () => { + //GIVEN + const EXPECTED_STATUS = 200; + const EXPECTED_DATA = { aKey: "aValue" }; + const RESPONSE = new Response(JSON.stringify(EXPECTED_DATA), { + status: EXPECTED_STATUS, + headers: new Headers({ "Content-Type": "application/json" }), + }); + + //WHEN + const ACTUAL = + await transformToSimpleResponse(RESPONSE); + + //THEN + expect(ACTUAL).toEqual>({ + ok: RESPONSE.ok, + statusCode: RESPONSE.status, + data: EXPECTED_DATA, + }); +}); + +test("should handle default, non json response", async () => { + //GIVEN + const EXPECTED_DATA = "12345"; + const RESPONSE = new Response(EXPECTED_DATA); + + //WHEN + const ACTUAL = await extractDataBasedOnContentType(RESPONSE); + + //THEN + expect(ACTUAL).toEqual(EXPECTED_DATA); +}); From 8a675cf68076b42296966d811cb9af72d832249d Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Fri, 17 Jan 2025 00:07:11 +0100 Subject: [PATCH 13/34] feat: extend and enhance content type differentiation --- src/DTOs/SimpleResponseDTO.ts | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/DTOs/SimpleResponseDTO.ts b/src/DTOs/SimpleResponseDTO.ts index e2d138c..d522c53 100644 --- a/src/DTOs/SimpleResponseDTO.ts +++ b/src/DTOs/SimpleResponseDTO.ts @@ -18,9 +18,21 @@ export async function transformToSimpleResponse< return { ok: fetchResponse.ok, statusCode: fetchResponse.status, - data: - fetchResponse.headers.get("Content-Type") === "application/json" - ? ((await fetchResponse.json()) as ResponseDTO) - : undefined, + data: (await extractDataBasedOnContentType( + fetchResponse, + )) as ResponseDTO, }; } + +export async function extractDataBasedOnContentType( + fetchResponse: Response, +): Promise { + const CONTENT_TYPE = fetchResponse.headers.get("Content-Type"); + if (CONTENT_TYPE === null) { + return undefined; + } else if (CONTENT_TYPE.includes("application/json")) { + return await fetchResponse.json(); + } else if (CONTENT_TYPE.includes("text/plain")) { + return await fetchResponse.text(); + } +} From 65ffe5a57ac58ca7ce75aa834825ed49530fa957 Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Fri, 17 Jan 2025 20:47:58 +0100 Subject: [PATCH 14/34] refac: rename module private helper with underscore --- src/DTOs/SimpleResponseDTO.ts | 4 ++-- src/DTOs/__tests__/SimpleResponseDTO.test.ts | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/DTOs/SimpleResponseDTO.ts b/src/DTOs/SimpleResponseDTO.ts index d522c53..2bf7a78 100644 --- a/src/DTOs/SimpleResponseDTO.ts +++ b/src/DTOs/SimpleResponseDTO.ts @@ -18,13 +18,13 @@ export async function transformToSimpleResponse< return { ok: fetchResponse.ok, statusCode: fetchResponse.status, - data: (await extractDataBasedOnContentType( + data: (await _extractDataBasedOnContentType( fetchResponse, )) as ResponseDTO, }; } -export async function extractDataBasedOnContentType( +export async function _extractDataBasedOnContentType( fetchResponse: Response, ): Promise { const CONTENT_TYPE = fetchResponse.headers.get("Content-Type"); diff --git a/src/DTOs/__tests__/SimpleResponseDTO.test.ts b/src/DTOs/__tests__/SimpleResponseDTO.test.ts index f698f7f..616b6df 100644 --- a/src/DTOs/__tests__/SimpleResponseDTO.test.ts +++ b/src/DTOs/__tests__/SimpleResponseDTO.test.ts @@ -1,6 +1,6 @@ import { expect, test } from "vitest"; import { - extractDataBasedOnContentType, + _extractDataBasedOnContentType, transformToSimpleResponse, type SimpleResponse, } from "../SimpleResponseDTO.js"; @@ -30,7 +30,12 @@ test("should handle default, non json response", async () => { //GIVEN const EXPECTED_DATA = "12345"; const RESPONSE = new Response(EXPECTED_DATA); + //WHEN + const ACTUAL = await _extractDataBasedOnContentType(RESPONSE); + //THEN + expect(ACTUAL).toEqual(EXPECTED_DATA); +}); //WHEN const ACTUAL = await extractDataBasedOnContentType(RESPONSE); From d1739e4512df53952c98c58973da59ed3cfc2a3f Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Fri, 17 Jan 2025 21:02:44 +0100 Subject: [PATCH 15/34] test: extend SimpleResponse Helper Test Coverage --- src/DTOs/__tests__/SimpleResponseDTO.test.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/DTOs/__tests__/SimpleResponseDTO.test.ts b/src/DTOs/__tests__/SimpleResponseDTO.test.ts index 616b6df..185244a 100644 --- a/src/DTOs/__tests__/SimpleResponseDTO.test.ts +++ b/src/DTOs/__tests__/SimpleResponseDTO.test.ts @@ -36,8 +36,18 @@ test("should handle default, non json response", async () => { //THEN expect(ACTUAL).toEqual(EXPECTED_DATA); }); + +test("should handle Content-Type=application/json response", async () => { + //GIVEN + const EXPECTED_DATA = { testKey: "testValue" }; + const RESPONSE = new Response(JSON.stringify(EXPECTED_DATA), { + headers: new Headers({ + "Content-Type": "application/json; charset=utf-8", + }), + }); + //WHEN - const ACTUAL = await extractDataBasedOnContentType(RESPONSE); + const ACTUAL = await _extractDataBasedOnContentType(RESPONSE); //THEN expect(ACTUAL).toEqual(EXPECTED_DATA); From 5e6392cdffa8521c87cb3418365d3f0998a0402f Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Fri, 17 Jan 2025 21:10:39 +0100 Subject: [PATCH 16/34] refac: put helpers on object instead of module scope --- src/DTOs/SimpleResponseDTO.ts | 58 +++++++++++--------- src/DTOs/__tests__/SimpleResponseDTO.test.ts | 13 +++-- src/repositories/UserRepository.ts | 10 ++-- 3 files changed, 46 insertions(+), 35 deletions(-) diff --git a/src/DTOs/SimpleResponseDTO.ts b/src/DTOs/SimpleResponseDTO.ts index 2bf7a78..1fb86d9 100644 --- a/src/DTOs/SimpleResponseDTO.ts +++ b/src/DTOs/SimpleResponseDTO.ts @@ -9,30 +9,38 @@ export interface SimpleResponse< } /** - * Due to limitations of NextJs Server Actions, [this can not be a class](https://react.dev/reference/rsc/use-server#serializable-parameters-and-return-values). - * @throws any `Response.json()` related error + * Collection of {@link SimpleResponse} Helpers */ -export async function transformToSimpleResponse< - ResponseDTO extends Serializable | undefined = undefined, ->(fetchResponse: Response): Promise> { - return { - ok: fetchResponse.ok, - statusCode: fetchResponse.status, - data: (await _extractDataBasedOnContentType( - fetchResponse, - )) as ResponseDTO, - }; -} +export const SimpleResponseHelpers = { + /** + * Due to limitations of NextJs Server Actions, [this can not be a class](https://react.dev/reference/rsc/use-server#serializable-parameters-and-return-values). + * @throws any `Response.json()` related error + */ + async transformToSimpleResponse< + ResponseDTO extends Serializable | undefined = undefined, + >(fetchResponse: Response): Promise> { + return { + ok: fetchResponse.ok, + statusCode: fetchResponse.status, + data: (await this._extractDataBasedOnContentType( + fetchResponse, + )) as ResponseDTO, + }; + }, -export async function _extractDataBasedOnContentType( - fetchResponse: Response, -): Promise { - const CONTENT_TYPE = fetchResponse.headers.get("Content-Type"); - if (CONTENT_TYPE === null) { - return undefined; - } else if (CONTENT_TYPE.includes("application/json")) { - return await fetchResponse.json(); - } else if (CONTENT_TYPE.includes("text/plain")) { - return await fetchResponse.text(); - } -} + /** + * @private + */ + async _extractDataBasedOnContentType( + fetchResponse: Response, + ): Promise { + const CONTENT_TYPE = fetchResponse.headers.get("Content-Type"); + if (CONTENT_TYPE === null) { + return undefined; + } else if (CONTENT_TYPE.includes("application/json")) { + return await fetchResponse.json(); + } else if (CONTENT_TYPE.includes("text/plain")) { + return await fetchResponse.text(); + } + }, +}; diff --git a/src/DTOs/__tests__/SimpleResponseDTO.test.ts b/src/DTOs/__tests__/SimpleResponseDTO.test.ts index 185244a..96d3455 100644 --- a/src/DTOs/__tests__/SimpleResponseDTO.test.ts +++ b/src/DTOs/__tests__/SimpleResponseDTO.test.ts @@ -1,7 +1,6 @@ import { expect, test } from "vitest"; import { - _extractDataBasedOnContentType, - transformToSimpleResponse, + SimpleResponseHelpers, type SimpleResponse, } from "../SimpleResponseDTO.js"; @@ -16,7 +15,9 @@ test("should transform to SimpleResponseDTO", async () => { //WHEN const ACTUAL = - await transformToSimpleResponse(RESPONSE); + await SimpleResponseHelpers.transformToSimpleResponse< + typeof EXPECTED_DATA + >(RESPONSE); //THEN expect(ACTUAL).toEqual>({ @@ -31,7 +32,8 @@ test("should handle default, non json response", async () => { const EXPECTED_DATA = "12345"; const RESPONSE = new Response(EXPECTED_DATA); //WHEN - const ACTUAL = await _extractDataBasedOnContentType(RESPONSE); + const ACTUAL = + await SimpleResponseHelpers._extractDataBasedOnContentType(RESPONSE); //THEN expect(ACTUAL).toEqual(EXPECTED_DATA); @@ -47,7 +49,8 @@ test("should handle Content-Type=application/json response", async () => { }); //WHEN - const ACTUAL = await _extractDataBasedOnContentType(RESPONSE); + const ACTUAL = + await SimpleResponseHelpers._extractDataBasedOnContentType(RESPONSE); //THEN expect(ACTUAL).toEqual(EXPECTED_DATA); diff --git a/src/repositories/UserRepository.ts b/src/repositories/UserRepository.ts index b94cef9..11f273d 100644 --- a/src/repositories/UserRepository.ts +++ b/src/repositories/UserRepository.ts @@ -1,6 +1,6 @@ import type { RegistrationDetails } from "../DTOs/RegistrationDTO.js"; import { - transformToSimpleResponse, + SimpleResponseHelpers, type SimpleResponse, } from "../DTOs/SimpleResponseDTO.js"; import type { UserDetailsDTO } from "../DTOs/UserDetailsDTO.js"; @@ -36,7 +36,7 @@ export class UserRepository extends BaseRepository { await this._handleResponseAfterAuthentication(RESPONSE); - return transformToSimpleResponse(RESPONSE); + return SimpleResponseHelpers.transformToSimpleResponse(RESPONSE); } /** @@ -54,7 +54,7 @@ export class UserRepository extends BaseRepository { }), ); - return transformToSimpleResponse(RESPONSE); + return SimpleResponseHelpers.transformToSimpleResponse(RESPONSE); } /** @@ -74,7 +74,7 @@ export class UserRepository extends BaseRepository { }), ); - return transformToSimpleResponse(RESPONSE); + return SimpleResponseHelpers.transformToSimpleResponse(RESPONSE); } /** @@ -93,6 +93,6 @@ export class UserRepository extends BaseRepository { }), ); - return transformToSimpleResponse(RESPONSE); + return SimpleResponseHelpers.transformToSimpleResponse(RESPONSE); } } From 4edb96da8afcda6b671d347df38c5ed268ac3fa1 Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Fri, 17 Jan 2025 21:56:18 +0100 Subject: [PATCH 17/34] doc: add info to jsdoc about content type --- src/repositories/BaseRepository.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/repositories/BaseRepository.ts b/src/repositories/BaseRepository.ts index 3e5c92c..1cd7fc5 100644 --- a/src/repositories/BaseRepository.ts +++ b/src/repositories/BaseRepository.ts @@ -44,6 +44,7 @@ export abstract class BaseRepository { } /** + * Sets the Content-Type to application/json by default. Can be overridden by settin {@link extraHeaders}. * @protected * @throws any {@link sessionRepository} related Error */ From 1046af3963a399e7b00364708fb16b180d9515fa Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Fri, 17 Jan 2025 22:03:25 +0100 Subject: [PATCH 18/34] feat: add content type constants --- src/constants/ContentTypeHeader.ts | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/constants/ContentTypeHeader.ts diff --git a/src/constants/ContentTypeHeader.ts b/src/constants/ContentTypeHeader.ts new file mode 100644 index 0000000..12b5fb4 --- /dev/null +++ b/src/constants/ContentTypeHeader.ts @@ -0,0 +1,5 @@ +export const ContentType = "Content-Type"; +export const MimeTypes = { + textPlain: "text/plain", + applicationJson: "application/json", +}; From da903b78b8485020860fba95be582287bfafbc7c Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Fri, 17 Jan 2025 22:04:42 +0100 Subject: [PATCH 19/34] refac: use smarter Headers constructor --- src/repositories/BaseRepository.ts | 13 ++++++------- src/repositories/__tests__/UserRepository.test.ts | 4 +++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/repositories/BaseRepository.ts b/src/repositories/BaseRepository.ts index 1cd7fc5..7b7025a 100644 --- a/src/repositories/BaseRepository.ts +++ b/src/repositories/BaseRepository.ts @@ -1,3 +1,4 @@ +import { ContentType, MimeTypes } from "../constants/ContentTypeHeader.js"; import { CustomHeadersNames } from "../constants/CustomHeaders.js"; import type { SessionRepositoryInterface } from "./SessionRepositoryInterface.js"; @@ -32,13 +33,11 @@ export abstract class BaseRepository { * @throws any {@link sessionRepository} related Error */ private async buildBaseHeaders() { - const HEADERS = new Headers(); - HEADERS.append( - CustomHeadersNames.sessionId, - await this.sessionRepository.readSessionId(), - ); - - HEADERS.append(CustomHeadersNames.apiKey, this.publicApiKey); + const HEADERS = new Headers({ + [CustomHeadersNames.sessionId]: + await this.sessionRepository.readSessionId(), + [CustomHeadersNames.apiKey]: this.publicApiKey, + }); return HEADERS; } diff --git a/src/repositories/__tests__/UserRepository.test.ts b/src/repositories/__tests__/UserRepository.test.ts index 6919961..d3e7413 100644 --- a/src/repositories/__tests__/UserRepository.test.ts +++ b/src/repositories/__tests__/UserRepository.test.ts @@ -4,6 +4,7 @@ import { UserRepository } from "../UserRepository.js"; import { CustomHeadersNames } from "../../constants/CustomHeaders.js"; import { MockSessionRepository } from "./mocks/SessionRepositoryMock.js"; import { afterEach } from "node:test"; +import { ContentType, MimeTypes } from "../../constants/ContentTypeHeader.js"; const EXPECTED_TEST_KEY = "TEST12345"; @@ -17,7 +18,7 @@ afterEach(() => { MockSessionRepository.saveSessionId(""); }); -test("should append SessionId and ApiKey as Headers", async () => { +test("should append SessionId, ApiKey and Json-ContentType as Headers", async () => { //GIVEN const EXPECTED_SESSION_ID = "ID1111"; MockSessionRepository.saveSessionId(EXPECTED_SESSION_ID); @@ -30,6 +31,7 @@ test("should append SessionId and ApiKey as Headers", async () => { //THEN expect(ACTUAL.get(CustomHeadersNames.sessionId)).toBe(EXPECTED_SESSION_ID); expect(ACTUAL.get(CustomHeadersNames.apiKey)).toBe(EXPECTED_TEST_KEY); + expect(ACTUAL.get(ContentType)).toBe(MimeTypes.applicationJson); }); test("should save session id from header to session repo", async () => { From 404b8df37631fb0a8fa1fd535e66b472693fc015 Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Fri, 17 Jan 2025 22:07:20 +0100 Subject: [PATCH 20/34] feat: add default application/json content type --- src/repositories/BaseRepository.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/repositories/BaseRepository.ts b/src/repositories/BaseRepository.ts index 7b7025a..034cee0 100644 --- a/src/repositories/BaseRepository.ts +++ b/src/repositories/BaseRepository.ts @@ -37,6 +37,7 @@ export abstract class BaseRepository { [CustomHeadersNames.sessionId]: await this.sessionRepository.readSessionId(), [CustomHeadersNames.apiKey]: this.publicApiKey, + [ContentType]: MimeTypes.applicationJson, }); return HEADERS; From c3a501133223af35cbd616a2335064980fb18722 Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Fri, 17 Jan 2025 22:09:25 +0100 Subject: [PATCH 21/34] refac: sort exports --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index cde19f9..aaff5ad 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,2 @@ -export { UserRepository } from "./repositories/UserRepository.js"; export type { SessionRepositoryInterface } from "./repositories/SessionRepositoryInterface.ts"; +export { UserRepository } from "./repositories/UserRepository.js"; From 5cec4b77dcee56049b63c5f14c971932f1997704 Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Fri, 17 Jan 2025 22:34:23 +0100 Subject: [PATCH 22/34] refac: rename to RegistrationDTO --- src/DTOs/RegistrationDTO.ts | 4 ++-- src/repositories/UserRepository.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/DTOs/RegistrationDTO.ts b/src/DTOs/RegistrationDTO.ts index 10e8bc5..09f1569 100644 --- a/src/DTOs/RegistrationDTO.ts +++ b/src/DTOs/RegistrationDTO.ts @@ -1,7 +1,7 @@ /** * A Data Transfer Object containing details about a new user to be registered */ -export class RegistrationDetails { +export class RegistrationDTO { static formFieldNames = { username: "username", email: "email", @@ -13,7 +13,7 @@ export class RegistrationDetails { email = "", password = "", }: Record) { - return new RegistrationDetails(username, email, password); + return new RegistrationDTO(username, email, password); } constructor( diff --git a/src/repositories/UserRepository.ts b/src/repositories/UserRepository.ts index 11f273d..8d77332 100644 --- a/src/repositories/UserRepository.ts +++ b/src/repositories/UserRepository.ts @@ -1,4 +1,4 @@ -import type { RegistrationDetails } from "../DTOs/RegistrationDTO.js"; +import type { RegistrationDTO } from "../DTOs/RegistrationDTO.js"; import { SimpleResponseHelpers, type SimpleResponse, @@ -19,12 +19,12 @@ export class UserRepository extends BaseRepository { } /** - * Sends a request to register the new user with {@link RegistrationDetails} and handles saving the sessionID from the Responses Header + * Sends a request to register the new user with {@link RegistrationDTO} and handles saving the sessionID from the Responses Header * @throws any `fetch()` related error * @throws any `Response.json()` related error * @throws any {@link sessionRepository} related Error */ - async registerUser(body: RegistrationDetails): Promise { + async registerUser(body: RegistrationDTO): Promise { const RESPONSE = await fetch( await this._bulildRequest({ route: BaseRepository.Routes.registration, From cc6f78cb2d077725f08b88878b557e1a70887f02 Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Fri, 17 Jan 2025 23:09:48 +0100 Subject: [PATCH 23/34] refac: transform ResponseDTO into interface and add helper Object --- src/DTOs/RegistrationDTO.ts | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/src/DTOs/RegistrationDTO.ts b/src/DTOs/RegistrationDTO.ts index 09f1569..081e6c3 100644 --- a/src/DTOs/RegistrationDTO.ts +++ b/src/DTOs/RegistrationDTO.ts @@ -1,24 +1,15 @@ -/** - * A Data Transfer Object containing details about a new user to be registered - */ -export class RegistrationDTO { - static formFieldNames = { - username: "username", - email: "email", - password: "password", - }; +export interface RegistrationDTO { + username: string; + email: string; + password: string; +} - static buildFromObject({ +export const RegistrationHelper = { + buildFromObject({ username = "", email = "", password = "", - }: Record) { - return new RegistrationDTO(username, email, password); - } - - constructor( - public username: string, - public email: string, - public password: string, - ) {} -} + }: RegistrationDTO) { + return { username, email, password }; + }, +}; From c6cfab8d033ff43931dd19d9f4611778b37e47fe Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Sat, 18 Jan 2025 12:01:26 +0100 Subject: [PATCH 24/34] refac: extract buildRequest Param to type --- src/repositories/BaseRepository.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/repositories/BaseRepository.ts b/src/repositories/BaseRepository.ts index 034cee0..d1b4698 100644 --- a/src/repositories/BaseRepository.ts +++ b/src/repositories/BaseRepository.ts @@ -11,6 +11,15 @@ export interface BaseRepositoryConstructorArgs { sessionRepository: SessionRepositoryInterface; } +export interface RequestParams { + route: string; + method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE"; + queryParams?: URLSearchParams; + extraHeaders?: Headers; + body?: RequestInit["body"]; + signal?: AbortSignal | null; +} + export abstract class BaseRepository { static Api = { mockaroo: "https://my.api.mockaroo.com" }; @@ -55,14 +64,7 @@ export abstract class BaseRepository { extraHeaders = new Headers(), body, signal, - }: { - route: string; - method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE"; - queryParams?: URLSearchParams; - extraHeaders?: Headers; - body?: RequestInit["body"]; - signal?: AbortSignal | null; - }): Promise { + }: RequestParams): Promise { const headers = await this.buildBaseHeaders(); extraHeaders.forEach((headerValue, headerName) => { headers.append(headerName, headerValue); From f0431349c216fcd64c196f614a555e35acadd608 Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Sat, 18 Jan 2025 12:05:43 +0100 Subject: [PATCH 25/34] refac: rename type --- src/repositories/BaseRepository.ts | 2 +- src/repositories/UserRepository.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/repositories/BaseRepository.ts b/src/repositories/BaseRepository.ts index d1b4698..cdfa3fc 100644 --- a/src/repositories/BaseRepository.ts +++ b/src/repositories/BaseRepository.ts @@ -5,7 +5,7 @@ import type { SessionRepositoryInterface } from "./SessionRepositoryInterface.js type ApiBaseUrlType = (typeof BaseRepository.Api)[keyof typeof BaseRepository.Api]; -export interface BaseRepositoryConstructorArgs { +export interface BaseRepositoryConstructorParam { apiBaseUrl: ApiBaseUrlType; publicApiKey: string; sessionRepository: SessionRepositoryInterface; diff --git a/src/repositories/UserRepository.ts b/src/repositories/UserRepository.ts index 8d77332..0adf721 100644 --- a/src/repositories/UserRepository.ts +++ b/src/repositories/UserRepository.ts @@ -6,11 +6,11 @@ import { import type { UserDetailsDTO } from "../DTOs/UserDetailsDTO.js"; import { BaseRepository, - type BaseRepositoryConstructorArgs, + type BaseRepositoryConstructorParam, } from "./BaseRepository.js"; export class UserRepository extends BaseRepository { - constructor(baseArgs: BaseRepositoryConstructorArgs) { + constructor(baseArgs: BaseRepositoryConstructorParam) { super( baseArgs.apiBaseUrl, baseArgs.publicApiKey, From 5f0dde39f86c18b3659a516f64e1cb875328adba Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Sat, 18 Jan 2025 12:07:29 +0100 Subject: [PATCH 26/34] feat: export missing files from index.js --- src/index.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/index.ts b/src/index.ts index aaff5ad..f7988c8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,12 @@ +// Repositories: export type { SessionRepositoryInterface } from "./repositories/SessionRepositoryInterface.ts"; export { UserRepository } from "./repositories/UserRepository.js"; +//DTOs: +export type { SimpleResponse } from "./DTOs/SimpleResponseDTO.ts"; +export type { RegistrationDTO } from "./DTOs/RegistrationDTO.ts"; +export type { UserDetailsDTO } from "./DTOs/UserDetailsDTO.ts"; +//DTO-Helpers: +export { SimpleResponseHelpers } from "./DTOs/SimpleResponseDTO.js"; +export { RegistrationHelper } from "./DTOs/RegistrationDTO.js"; +// Miscellanieous Types: +export type { BaseRepositoryConstructorParam } from "./repositories/BaseRepository.ts"; From dff8a98dc2bae371eb743dbbd400ec5ca774fc6c Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Sat, 18 Jan 2025 12:08:09 +0100 Subject: [PATCH 27/34] fix: make type internal --- src/repositories/BaseRepository.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/repositories/BaseRepository.ts b/src/repositories/BaseRepository.ts index cdfa3fc..0c98bf5 100644 --- a/src/repositories/BaseRepository.ts +++ b/src/repositories/BaseRepository.ts @@ -11,7 +11,7 @@ export interface BaseRepositoryConstructorParam { sessionRepository: SessionRepositoryInterface; } -export interface RequestParams { +interface RequestParams { route: string; method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE"; queryParams?: URLSearchParams; From 62dcd2486348dc5e1263cc137a913209c8965c3d Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Sat, 18 Jan 2025 12:08:29 +0100 Subject: [PATCH 28/34] feat: add buildRequest variant for JSON bodies --- src/repositories/BaseRepository.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/repositories/BaseRepository.ts b/src/repositories/BaseRepository.ts index 0c98bf5..5bd860c 100644 --- a/src/repositories/BaseRepository.ts +++ b/src/repositories/BaseRepository.ts @@ -1,3 +1,4 @@ +import type { Serializable } from "child_process"; import { ContentType, MimeTypes } from "../constants/ContentTypeHeader.js"; import { CustomHeadersNames } from "../constants/CustomHeaders.js"; import type { SessionRepositoryInterface } from "./SessionRepositoryInterface.js"; @@ -81,6 +82,19 @@ export abstract class BaseRepository { ); } + /** + * @protected + */ + async _buildJsonRequest( + unserializedBody: Serializable, + requestParams: Omit, + ): Promise { + return this._bulildRequest({ + ...requestParams, + body: JSON.stringify(unserializedBody), + }); + } + /** * @protected * @throws any {@link sessionRepository} related Error From 58c9d3d7e2b2491309192e4bbe75341f81a74dcb Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Sat, 18 Jan 2025 13:38:19 +0100 Subject: [PATCH 29/34] refac: rename to SimpleResponseDTO --- src/DTOs/SimpleResponseDTO.ts | 6 +++--- src/DTOs/__tests__/SimpleResponseDTO.test.ts | 4 ++-- src/index.ts | 2 +- src/repositories/UserRepository.ts | 10 +++++----- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/DTOs/SimpleResponseDTO.ts b/src/DTOs/SimpleResponseDTO.ts index 1fb86d9..be81a0f 100644 --- a/src/DTOs/SimpleResponseDTO.ts +++ b/src/DTOs/SimpleResponseDTO.ts @@ -1,6 +1,6 @@ import type { Serializable } from "child_process"; -export interface SimpleResponse< +export interface SimpleResponseDTO< BodyType extends Serializable | undefined = undefined, > { ok: boolean; @@ -9,7 +9,7 @@ export interface SimpleResponse< } /** - * Collection of {@link SimpleResponse} Helpers + * Collection of {@link SimpleResponseDTO} Helpers */ export const SimpleResponseHelpers = { /** @@ -18,7 +18,7 @@ export const SimpleResponseHelpers = { */ async transformToSimpleResponse< ResponseDTO extends Serializable | undefined = undefined, - >(fetchResponse: Response): Promise> { + >(fetchResponse: Response): Promise> { return { ok: fetchResponse.ok, statusCode: fetchResponse.status, diff --git a/src/DTOs/__tests__/SimpleResponseDTO.test.ts b/src/DTOs/__tests__/SimpleResponseDTO.test.ts index 96d3455..e3f3048 100644 --- a/src/DTOs/__tests__/SimpleResponseDTO.test.ts +++ b/src/DTOs/__tests__/SimpleResponseDTO.test.ts @@ -1,7 +1,7 @@ import { expect, test } from "vitest"; import { SimpleResponseHelpers, - type SimpleResponse, + type SimpleResponseDTO, } from "../SimpleResponseDTO.js"; test("should transform to SimpleResponseDTO", async () => { @@ -20,7 +20,7 @@ test("should transform to SimpleResponseDTO", async () => { >(RESPONSE); //THEN - expect(ACTUAL).toEqual>({ + expect(ACTUAL).toEqual>({ ok: RESPONSE.ok, statusCode: RESPONSE.status, data: EXPECTED_DATA, diff --git a/src/index.ts b/src/index.ts index f7988c8..7a67501 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,7 +2,7 @@ export type { SessionRepositoryInterface } from "./repositories/SessionRepositoryInterface.ts"; export { UserRepository } from "./repositories/UserRepository.js"; //DTOs: -export type { SimpleResponse } from "./DTOs/SimpleResponseDTO.ts"; +export type { SimpleResponseDTO as SimpleResponse } from "./DTOs/SimpleResponseDTO.ts"; export type { RegistrationDTO } from "./DTOs/RegistrationDTO.ts"; export type { UserDetailsDTO } from "./DTOs/UserDetailsDTO.ts"; //DTO-Helpers: diff --git a/src/repositories/UserRepository.ts b/src/repositories/UserRepository.ts index 0adf721..d54a892 100644 --- a/src/repositories/UserRepository.ts +++ b/src/repositories/UserRepository.ts @@ -1,7 +1,7 @@ import type { RegistrationDTO } from "../DTOs/RegistrationDTO.js"; import { SimpleResponseHelpers, - type SimpleResponse, + type SimpleResponseDTO, } from "../DTOs/SimpleResponseDTO.js"; import type { UserDetailsDTO } from "../DTOs/UserDetailsDTO.js"; import { @@ -24,7 +24,7 @@ export class UserRepository extends BaseRepository { * @throws any `Response.json()` related error * @throws any {@link sessionRepository} related Error */ - async registerUser(body: RegistrationDTO): Promise { + async registerUser(body: RegistrationDTO): Promise { const RESPONSE = await fetch( await this._bulildRequest({ route: BaseRepository.Routes.registration, @@ -44,7 +44,7 @@ export class UserRepository extends BaseRepository { * @throws any `Response.json()` related error * @throws any {@link sessionRepository} related Error */ - async verifyUser(verificationCode: string): Promise { + async verifyUser(verificationCode: string): Promise { const RESPONSE = await fetch( await this._bulildRequest({ route: BaseRepository.Routes.activation, @@ -62,7 +62,7 @@ export class UserRepository extends BaseRepository { * @throws any `Response.json()` related error * @throws any {@link sessionRepository} related Error */ - async updatePersonalGoal(goalPerWeek: number): Promise { + async updatePersonalGoal(goalPerWeek: number): Promise { const RESPONSE = await fetch( await this._bulildRequest({ route: BaseRepository.Routes.personalGoal, @@ -84,7 +84,7 @@ export class UserRepository extends BaseRepository { */ async getUserInfo( abortSignal: AbortSignal, - ): Promise> { + ): Promise> { const RESPONSE = await fetch( await this._bulildRequest({ route: BaseRepository.Routes.userInfo, From ef3079bba3e3bec7ec437ce268309d426d686434 Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Sat, 18 Jan 2025 13:49:44 +0100 Subject: [PATCH 30/34] feat: add Group Message DTOs for new and existing messages --- src/DTOs/GroupMessageDTO.ts | 14 ++++++++++++++ src/index.ts | 4 ++++ 2 files changed, 18 insertions(+) create mode 100644 src/DTOs/GroupMessageDTO.ts diff --git a/src/DTOs/GroupMessageDTO.ts b/src/DTOs/GroupMessageDTO.ts new file mode 100644 index 0000000..5586870 --- /dev/null +++ b/src/DTOs/GroupMessageDTO.ts @@ -0,0 +1,14 @@ +export interface BaseGroupMessageDTO { + timestamp: string; + content: string; + //TODO: Research which Image Types are returned by Expo and Browser Camera, e.g. Blob or a Stream; + type: "TEXT" | "IMAGE"; + isMotiMateMessage: boolean; +} + +export interface GroupMessageDTO extends BaseGroupMessageDTO { + messageId: string; + authorId: string | null; + content: string; + clapCount: number; +} diff --git a/src/index.ts b/src/index.ts index 7a67501..dde0b39 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,6 +5,10 @@ export { UserRepository } from "./repositories/UserRepository.js"; export type { SimpleResponseDTO as SimpleResponse } from "./DTOs/SimpleResponseDTO.ts"; export type { RegistrationDTO } from "./DTOs/RegistrationDTO.ts"; export type { UserDetailsDTO } from "./DTOs/UserDetailsDTO.ts"; +export type { + GroupMessageDTO, + BaseGroupMessageDTO, +} from "./DTOs/GroupMessageDTO.ts"; //DTO-Helpers: export { SimpleResponseHelpers } from "./DTOs/SimpleResponseDTO.js"; export { RegistrationHelper } from "./DTOs/RegistrationDTO.js"; From eb17af1337a37b9410b554f07461b6c4c7596938 Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Sat, 18 Jan 2025 13:50:45 +0100 Subject: [PATCH 31/34] feat: add GroupRepository --- src/index.ts | 1 + src/repositories/GroupRepository.ts | 134 ++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 src/repositories/GroupRepository.ts diff --git a/src/index.ts b/src/index.ts index dde0b39..3b429da 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,7 @@ // Repositories: export type { SessionRepositoryInterface } from "./repositories/SessionRepositoryInterface.ts"; export { UserRepository } from "./repositories/UserRepository.js"; +export { GroupRepository } from "./repositories/GroupRepository.js"; //DTOs: export type { SimpleResponseDTO as SimpleResponse } from "./DTOs/SimpleResponseDTO.ts"; export type { RegistrationDTO } from "./DTOs/RegistrationDTO.ts"; diff --git a/src/repositories/GroupRepository.ts b/src/repositories/GroupRepository.ts new file mode 100644 index 0000000..6936c83 --- /dev/null +++ b/src/repositories/GroupRepository.ts @@ -0,0 +1,134 @@ +import { ContentType, MimeTypes } from "../constants/ContentTypeHeader.js"; +import type { BaseGroupMessageDTO } from "../DTOs/GroupMessageDTO.js"; +import { + SimpleResponseHelpers, + type SimpleResponseDTO, +} from "../DTOs/SimpleResponseDTO.js"; +import { + BaseRepository, + type BaseRepositoryConstructorParam, +} from "./BaseRepository.js"; + +export class GroupRepository extends BaseRepository { + constructor(baseArgs: BaseRepositoryConstructorParam) { + super( + baseArgs.apiBaseUrl, + baseArgs.publicApiKey, + baseArgs.sessionRepository, + ); + } + + /** + * @throws any `fetch()` related error + * @throws any `Response.json()` related error + * @throws any {@link sessionRepository} related Error + */ + async create(groupName: string): Promise { + const RESPONSE = await fetch( + await this._bulildRequest({ + route: "group", + method: "POST", + queryParams: new URLSearchParams({ name: groupName }), + body: groupName, + extraHeaders: new Headers({ + [ContentType]: MimeTypes.textPlain, + }), + }), + ); + + return await SimpleResponseHelpers.transformToSimpleResponse(RESPONSE); + } + + /** + * @throws any `fetch()` related error + * @throws any `Response.json()` related error + * @throws any {@link sessionRepository} related Error + */ + async join(joinCode: string): Promise { + const RESPONSE = await fetch( + await this._bulildRequest({ + route: "group/join", + method: "POST", + queryParams: new URLSearchParams({ code: joinCode }), + body: joinCode, + extraHeaders: new Headers({ + [ContentType]: MimeTypes.textPlain, + }), + }), + ); + + return await SimpleResponseHelpers.transformToSimpleResponse(RESPONSE); + } + + /** + * @throws any `fetch()` related error + * @throws any `Response.json()` related error + * @throws any {@link sessionRepository} related Error + */ + async sendMessage( + newMessageDTO: BaseGroupMessageDTO, + ): Promise { + //TODO: if process.env.NODE_ENV === "development" + const RESPONSE = await fetch( + await this._buildJsonRequest(newMessageDTO, { + route: "group/message", + method: "POST", + queryParams: new URLSearchParams({ + message: newMessageDTO.content, + }), + }), + ); + + return await SimpleResponseHelpers.transformToSimpleResponse(RESPONSE); + } + + /** + * @throws any `fetch()` related error + * @throws any `Response.json()` related error + * @throws any {@link sessionRepository} related Error + */ + async receiveExistingMessages(): Promise { + const RESPONSE = await fetch( + await this._bulildRequest({ + route: "group/message", + method: "GET", + queryParams: new URLSearchParams({ amount: "20" }), + }), + ); + + return await SimpleResponseHelpers.transformToSimpleResponse(RESPONSE); + } + + /** + * @throws any `fetch()` related error + * @throws any `Response.json()` related error + * @throws any {@link sessionRepository} related Error + */ + async receiveNewMessages(): Promise { + const RESPONSE = await fetch( + await this._bulildRequest({ + route: "group/message", + method: "GET", + queryParams: new URLSearchParams({ amount: "2" }), + }), + ); + + return await SimpleResponseHelpers.transformToSimpleResponse(RESPONSE); + } + + /** + * @throws any `fetch()` related error + * @throws any `Response.json()` related error + * @throws any {@link sessionRepository} related Error + */ + async leaveCurrentGroup(): Promise { + const RESPONSE = await fetch( + await this._bulildRequest({ + route: "group/leave", + method: "POST", + }), + ); + + return await SimpleResponseHelpers.transformToSimpleResponse(RESPONSE); + } +} From 47596c2eeeab9714f65c6783e26ee4d07b5d9a46 Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Sat, 18 Jan 2025 13:51:13 +0100 Subject: [PATCH 32/34] fix: export missing DTOs --- src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/index.ts b/src/index.ts index 3b429da..c1654b5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,6 +6,8 @@ export { GroupRepository } from "./repositories/GroupRepository.js"; export type { SimpleResponseDTO as SimpleResponse } from "./DTOs/SimpleResponseDTO.ts"; export type { RegistrationDTO } from "./DTOs/RegistrationDTO.ts"; export type { UserDetailsDTO } from "./DTOs/UserDetailsDTO.ts"; +export type { GroupDetailsDTO } from "./DTOs/GroupDetailsDTO.ts"; +export type { GroupMemberProfileDTO } from "./DTOs/GroupMemberDTO.ts"; export type { GroupMessageDTO, BaseGroupMessageDTO, From 558ba1ec2d6f113650c014a13a230477a2c77bfc Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Sat, 18 Jan 2025 14:00:01 +0100 Subject: [PATCH 33/34] docs(changeset): Ported over GroupRepository --- .changeset/funny-games-dance.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/funny-games-dance.md diff --git a/.changeset/funny-games-dance.md b/.changeset/funny-games-dance.md new file mode 100644 index 0000000..9fe5dd4 --- /dev/null +++ b/.changeset/funny-games-dance.md @@ -0,0 +1,5 @@ +--- +"motidata": minor +--- + +Ported over GroupRepository From 3b03696205f3465f357a131c84bc14a1dad1bf86 Mon Sep 17 00:00:00 2001 From: Christian Sturm Date: Sat, 18 Jan 2025 14:00:30 +0100 Subject: [PATCH 34/34] chore: add changeset script --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index a401bf5..d7ea28e 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "watch": "vitest", "test": "vitest run", "ci": "npm run lint && npm run check-format && npm run test && npm run check-exports && npm run build", + "changeset": "changeset", "local-release": "changeset version && changeset publish", "release": "changeset publish", "prepublishOnly": "npm run ci"