diff --git a/js/sdk/__tests__/r2rClient.test.ts b/js/sdk/__tests__/r2rClient.test.ts index ef22683d8..478774266 100644 --- a/js/sdk/__tests__/r2rClient.test.ts +++ b/js/sdk/__tests__/r2rClient.test.ts @@ -98,18 +98,39 @@ describe("R2RClient", () => { const mockResponse = { success: true }; mockAxiosInstance.request.mockResolvedValue({ data: mockResponse }); + const email = "test@example.com"; const verification_code = "123456"; - const result = await client.verifyEmail(verification_code); + const result = await client.verifyEmail(email, verification_code); expect(result).toEqual(mockResponse); expect(mockAxiosInstance.request).toHaveBeenCalledWith({ method: "POST", url: "verify_email", - data: JSON.stringify({ verification_code }), + data: JSON.stringify({ email, verification_code }), + headers: { + "Content-Type": "application/json", + }, + responseType: "json", + }); + }); + + test("requestPasswordReset should send POST request to /request_password_reset with correct data", async () => { + const mockResponse = { success: true }; + mockAxiosInstance.request.mockResolvedValue({ data: mockResponse }); + + const email = "test@example.com"; + const result = await client.requestPasswordReset(email); + + expect(result).toEqual(mockResponse); + expect(mockAxiosInstance.request).toHaveBeenCalledWith({ + method: "POST", + url: "request_password_reset", + data: '"test@example.com"', headers: { "Content-Type": "application/json", }, responseType: "json", + params: undefined, }); }); @@ -264,26 +285,6 @@ describe("R2RClient", () => { }); }); - test("requestPasswordReset should send POST request to /request_password_reset with correct data", async () => { - const mockResponse = { success: true }; - mockAxiosInstance.request.mockResolvedValue({ data: mockResponse }); - - const email = "test@example.com"; - - const result = await client.requestPasswordReset(email); - - expect(result).toEqual(mockResponse); - expect(mockAxiosInstance.request).toHaveBeenCalledWith({ - method: "POST", - url: "request_password_reset", - data: JSON.stringify({ email }), - headers: { - "Content-Type": "application/json", - }, - responseType: "json", - }); - }); - test("confirmPasswordReset should send POST request to /reset_password/{resetToken} with correct data", async () => { const mockResponse = { success: true }; mockAxiosInstance.request.mockResolvedValue({ data: mockResponse }); diff --git a/js/sdk/__tests__/r2rClientIntegrationSuperUser.test.ts b/js/sdk/__tests__/r2rClientIntegrationSuperUser.test.ts index 34d06c77c..9a641014f 100644 --- a/js/sdk/__tests__/r2rClientIntegrationSuperUser.test.ts +++ b/js/sdk/__tests__/r2rClientIntegrationSuperUser.test.ts @@ -26,7 +26,7 @@ let newCollectionId: string; * X updateUser * - refreshAccessToken * X changePassword - * X requestPasswordReset + * - requestPasswordReset * X confirmPasswordReset * X deleteUser * Ingestion: @@ -241,6 +241,12 @@ describe("r2rClient Integration Tests", () => { await expect(client.refreshAccessToken()).resolves.not.toThrow(); }); + test("Request password reset", async () => { + await expect( + client.requestPasswordReset("admin@example.com"), + ).resolves.not.toThrow(); + }); + test("Get analytics", async () => { const filterCriteria: Record | string = { search_latencies: "search_latency", diff --git a/js/sdk/__tests__/r2rClientIntegrationUser.test.ts b/js/sdk/__tests__/r2rClientIntegrationUser.test.ts index 549c8d54a..067681e4b 100644 --- a/js/sdk/__tests__/r2rClientIntegrationUser.test.ts +++ b/js/sdk/__tests__/r2rClientIntegrationUser.test.ts @@ -22,7 +22,7 @@ const baseUrl = "http://localhost:7272"; * - updateUser * - refreshAccessToken * - changePassword - * X requestPasswordReset + * - requestPasswordReset * X confirmPasswordReset * - deleteUser * Ingestion: @@ -283,6 +283,12 @@ describe("r2rClient Integration Tests", () => { ).resolves.not.toThrow(); }); + test("Request password reset", async () => { + await expect( + client.requestPasswordReset("newemail@example.com"), + ).resolves.not.toThrow(); + }); + test("Delete User", async () => { const currentUser = await client.user(); await expect( diff --git a/js/sdk/package-lock.json b/js/sdk/package-lock.json index 61b5374ec..49372c60f 100644 --- a/js/sdk/package-lock.json +++ b/js/sdk/package-lock.json @@ -1,6 +1,6 @@ { "name": "r2r-js", - "version": "0.3.13", + "version": "0.3.15", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/js/sdk/package.json b/js/sdk/package.json index 665bf8efb..0b6452ce5 100644 --- a/js/sdk/package.json +++ b/js/sdk/package.json @@ -1,6 +1,6 @@ { "name": "r2r-js", - "version": "0.3.14", + "version": "0.3.15", "description": "", "main": "dist/index.js", "browser": "dist/index.browser.js", diff --git a/js/sdk/src/r2rClient.ts b/js/sdk/src/r2rClient.ts index 8b25cca5a..f60730402 100644 --- a/js/sdk/src/r2rClient.ts +++ b/js/sdk/src/r2rClient.ts @@ -246,9 +246,9 @@ export class r2rClient { * @returns A promise that resolves to the response from the server. */ @feature("verifyEmail") - async verifyEmail(verification_code: string): Promise { + async verifyEmail(email: string, verification_code: string): Promise { return await this._makeRequest("POST", "verify_email", { - data: { verification_code }, + data: { email, verification_code }, }); } @@ -427,8 +427,11 @@ export class r2rClient { */ @feature("requestPasswordReset") async requestPasswordReset(email: string): Promise { - return this._makeRequest("POST", "request_password_reset", { - data: { email }, + return await this._makeRequest("POST", "request_password_reset", { + data: JSON.stringify(email), + headers: { + "Content-Type": "application/json", + }, }); } @@ -687,12 +690,16 @@ export class r2rClient { @feature("updateDocumentMetadata") async updateDocumentMetadata( documentId: string, - metadata: Record + metadata: Record, ): Promise> { this._ensureAuthenticated(); - return await this._makeRequest("POST", `update_document_metadata/${documentId}`, { - data: metadata, - }); + return await this._makeRequest( + "POST", + `update_document_metadata/${documentId}`, + { + data: metadata, + }, + ); } @feature("ingestChunks") @@ -1911,7 +1918,7 @@ export class r2rClient { // // ----------------------------------------------------------------------------- - /** + /** * Search over documents. * @param query The query to search for. * @param settings Settings for the document search. @@ -1949,7 +1956,9 @@ export class r2rClient { }, }; - return await this._makeRequest("POST", "search_documents", { data: json_data }); + return await this._makeRequest("POST", "search_documents", { + data: json_data, + }); } /** diff --git a/py/core/main/app.py b/py/core/main/app.py index 5fc6ec16c..10cf5e7be 100644 --- a/py/core/main/app.py +++ b/py/core/main/app.py @@ -1,11 +1,11 @@ from typing import Union +from core.base import R2RException from fastapi import FastAPI, Request +from fastapi.responses import JSONResponse from fastapi.middleware.cors import CORSMiddleware from fastapi.openapi.utils import get_openapi -from fastapi.responses import JSONResponse -from core.base import R2RException from core.providers import ( HatchetOrchestrationProvider, SimpleOrchestrationProvider, diff --git a/py/core/main/app_entry.py b/py/core/main/app_entry.py index cfc50af76..836b7b409 100644 --- a/py/core/main/app_entry.py +++ b/py/core/main/app_entry.py @@ -5,7 +5,9 @@ from typing import Optional from apscheduler.schedulers.asyncio import AsyncIOScheduler -from fastapi import FastAPI +from core.base import R2RException +from fastapi import FastAPI, Request +from fastapi.responses import JSONResponse from fastapi.middleware.cors import CORSMiddleware from .assembly import R2RBuilder, R2RConfig @@ -117,6 +119,18 @@ async def create_r2r_app( # Create the FastAPI app app = FastAPI(lifespan=lifespan) + +@app.exception_handler(R2RException) +async def r2r_exception_handler(request: Request, exc: R2RException): + return JSONResponse( + status_code=exc.status_code, + content={ + "message": exc.message, + "error_type": type(exc).__name__, + }, + ) + + # Add CORS middleware app.add_middleware( CORSMiddleware,