diff --git a/packages/api/src/Domain/Client/Auth/AuthApiService.ts b/packages/api/src/Domain/Client/Auth/AuthApiService.ts index 4787f28dc..520d5bdb4 100644 --- a/packages/api/src/Domain/Client/Auth/AuthApiService.ts +++ b/packages/api/src/Domain/Client/Auth/AuthApiService.ts @@ -1,10 +1,11 @@ +import { HttpResponse } from '@standardnotes/responses' import { ApiVersion } from '../../Api' import { ApiCallError } from '../../Error/ApiCallError' import { ErrorMessage } from '../../Error/ErrorMessage' import { - GenerateRecoveryCodesResponse, - RecoveryKeyParamsResponse, - SignInWithRecoveryCodesResponse, + GenerateRecoveryCodesResponseBody, + RecoveryKeyParamsResponseBody, + SignInWithRecoveryCodesResponseBody, } from '../../Response' import { AuthServerInterface } from '../../Server' @@ -18,7 +19,7 @@ export class AuthApiService implements AuthApiServiceInterface { this.operationsInProgress = new Map() } - async generateRecoveryCodes(): Promise { + async generateRecoveryCodes(): Promise> { if (this.operationsInProgress.get(AuthApiOperations.GenerateRecoveryCodes)) { throw new ApiCallError(ErrorMessage.GenericInProgress) } @@ -40,7 +41,7 @@ export class AuthApiService implements AuthApiServiceInterface { username: string codeChallenge: string recoveryCodes: string - }): Promise { + }): Promise> { if (this.operationsInProgress.get(AuthApiOperations.GetRecoveryKeyParams)) { throw new ApiCallError(ErrorMessage.GenericInProgress) } @@ -68,7 +69,7 @@ export class AuthApiService implements AuthApiServiceInterface { password: string codeVerifier: string recoveryCodes: string - }): Promise { + }): Promise> { if (this.operationsInProgress.get(AuthApiOperations.SignInWithRecoveryCodes)) { throw new ApiCallError(ErrorMessage.GenericInProgress) } diff --git a/packages/api/src/Domain/Client/Auth/AuthApiServiceInterface.ts b/packages/api/src/Domain/Client/Auth/AuthApiServiceInterface.ts index 822ce1c96..e7026b415 100644 --- a/packages/api/src/Domain/Client/Auth/AuthApiServiceInterface.ts +++ b/packages/api/src/Domain/Client/Auth/AuthApiServiceInterface.ts @@ -1,20 +1,21 @@ +import { HttpResponse } from '@standardnotes/responses' import { - GenerateRecoveryCodesResponse, - RecoveryKeyParamsResponse, - SignInWithRecoveryCodesResponse, + GenerateRecoveryCodesResponseBody, + RecoveryKeyParamsResponseBody, + SignInWithRecoveryCodesResponseBody, } from '../../Response' export interface AuthApiServiceInterface { - generateRecoveryCodes(): Promise + generateRecoveryCodes(): Promise> recoveryKeyParams(dto: { username: string codeChallenge: string recoveryCodes: string - }): Promise + }): Promise> signInWithRecoveryCodes(dto: { username: string password: string codeVerifier: string recoveryCodes: string - }): Promise + }): Promise> } diff --git a/packages/api/src/Domain/Client/Authenticator/AuthenticatorApiService.ts b/packages/api/src/Domain/Client/Authenticator/AuthenticatorApiService.ts index ff58a3e49..902886bdd 100644 --- a/packages/api/src/Domain/Client/Authenticator/AuthenticatorApiService.ts +++ b/packages/api/src/Domain/Client/Authenticator/AuthenticatorApiService.ts @@ -1,14 +1,15 @@ import { ErrorMessage } from '../../Error/ErrorMessage' import { ApiCallError } from '../../Error/ApiCallError' +import { HttpResponse } from '@standardnotes/responses' import { AuthenticatorApiServiceInterface } from './AuthenticatorApiServiceInterface' import { AuthenticatorApiOperations } from './AuthenticatorApiOperations' import { - ListAuthenticatorsResponse, - DeleteAuthenticatorResponse, - GenerateAuthenticatorRegistrationOptionsResponse, - VerifyAuthenticatorRegistrationResponseResponse, - GenerateAuthenticatorAuthenticationOptionsResponse, + ListAuthenticatorsResponseBody, + DeleteAuthenticatorResponseBody, + GenerateAuthenticatorRegistrationOptionsResponseBody, + VerifyAuthenticatorRegistrationResponseBody, + GenerateAuthenticatorAuthenticationOptionsResponseBody, } from '../../Response' import { AuthenticatorServerInterface } from '../../Server/Authenticator/AuthenticatorServerInterface' @@ -19,7 +20,7 @@ export class AuthenticatorApiService implements AuthenticatorApiServiceInterface this.operationsInProgress = new Map() } - async list(): Promise { + async list(): Promise> { if (this.operationsInProgress.get(AuthenticatorApiOperations.List)) { throw new ApiCallError(ErrorMessage.GenericInProgress) } @@ -37,7 +38,7 @@ export class AuthenticatorApiService implements AuthenticatorApiServiceInterface } } - async delete(authenticatorId: string): Promise { + async delete(authenticatorId: string): Promise> { if (this.operationsInProgress.get(AuthenticatorApiOperations.Delete)) { throw new ApiCallError(ErrorMessage.GenericInProgress) } @@ -57,7 +58,7 @@ export class AuthenticatorApiService implements AuthenticatorApiServiceInterface } } - async generateRegistrationOptions(): Promise { + async generateRegistrationOptions(): Promise> { if (this.operationsInProgress.get(AuthenticatorApiOperations.GenerateRegistrationOptions)) { throw new ApiCallError(ErrorMessage.GenericInProgress) } @@ -79,7 +80,7 @@ export class AuthenticatorApiService implements AuthenticatorApiServiceInterface userUuid: string, name: string, attestationResponse: Record, - ): Promise { + ): Promise> { if (this.operationsInProgress.get(AuthenticatorApiOperations.VerifyRegistrationResponse)) { throw new ApiCallError(ErrorMessage.GenericInProgress) } @@ -101,7 +102,9 @@ export class AuthenticatorApiService implements AuthenticatorApiServiceInterface } } - async generateAuthenticationOptions(username: string): Promise { + async generateAuthenticationOptions( + username: string, + ): Promise> { if (this.operationsInProgress.get(AuthenticatorApiOperations.GenerateAuthenticationOptions)) { throw new ApiCallError(ErrorMessage.GenericInProgress) } diff --git a/packages/api/src/Domain/Client/Authenticator/AuthenticatorApiServiceInterface.ts b/packages/api/src/Domain/Client/Authenticator/AuthenticatorApiServiceInterface.ts index 1c81ef2c3..ffbfd3315 100644 --- a/packages/api/src/Domain/Client/Authenticator/AuthenticatorApiServiceInterface.ts +++ b/packages/api/src/Domain/Client/Authenticator/AuthenticatorApiServiceInterface.ts @@ -1,19 +1,22 @@ +import { HttpResponse } from '@standardnotes/responses' import { - ListAuthenticatorsResponse, - DeleteAuthenticatorResponse, - GenerateAuthenticatorRegistrationOptionsResponse, - VerifyAuthenticatorRegistrationResponseResponse, - GenerateAuthenticatorAuthenticationOptionsResponse, + ListAuthenticatorsResponseBody, + DeleteAuthenticatorResponseBody, + GenerateAuthenticatorRegistrationOptionsResponseBody, + VerifyAuthenticatorRegistrationResponseBody, + GenerateAuthenticatorAuthenticationOptionsResponseBody, } from '../../Response' export interface AuthenticatorApiServiceInterface { - list(): Promise - delete(authenticatorId: string): Promise - generateRegistrationOptions(): Promise + list(): Promise> + delete(authenticatorId: string): Promise> + generateRegistrationOptions(): Promise> verifyRegistrationResponse( userUuid: string, name: string, attestationResponse: Record, - ): Promise - generateAuthenticationOptions(username: string): Promise + ): Promise> + generateAuthenticationOptions( + username: string, + ): Promise> } diff --git a/packages/api/src/Domain/Client/Revision/RevisionApiService.ts b/packages/api/src/Domain/Client/Revision/RevisionApiService.ts index a2f4a46d1..48dcd025c 100644 --- a/packages/api/src/Domain/Client/Revision/RevisionApiService.ts +++ b/packages/api/src/Domain/Client/Revision/RevisionApiService.ts @@ -1,12 +1,13 @@ import { ErrorMessage } from '../../Error/ErrorMessage' import { ApiCallError } from '../../Error/ApiCallError' +import { HttpResponse } from '@standardnotes/responses' import { RevisionApiServiceInterface } from './RevisionApiServiceInterface' import { RevisionApiOperations } from './RevisionApiOperations' import { RevisionServerInterface } from '../../Server' -import { DeleteRevisionResponse } from '../../Response/Revision/DeleteRevisionResponse' -import { GetRevisionResponse } from '../../Response/Revision/GetRevisionResponse' -import { ListRevisionsResponse } from '../../Response/Revision/ListRevisionsResponse' +import { DeleteRevisionResponseBody } from '../../Response/Revision/DeleteRevisionResponseBody' +import { GetRevisionResponseBody } from '../../Response/Revision/GetRevisionResponseBody' +import { ListRevisionsResponseBody } from '../../Response/Revision/ListRevisionsResponseBody' export class RevisionApiService implements RevisionApiServiceInterface { private operationsInProgress: Map @@ -15,7 +16,7 @@ export class RevisionApiService implements RevisionApiServiceInterface { this.operationsInProgress = new Map() } - async listRevisions(itemUuid: string): Promise { + async listRevisions(itemUuid: string): Promise> { if (this.operationsInProgress.get(RevisionApiOperations.List)) { throw new ApiCallError(ErrorMessage.GenericInProgress) } @@ -35,7 +36,7 @@ export class RevisionApiService implements RevisionApiServiceInterface { } } - async getRevision(itemUuid: string, revisionUuid: string): Promise { + async getRevision(itemUuid: string, revisionUuid: string): Promise> { if (this.operationsInProgress.get(RevisionApiOperations.Get)) { throw new ApiCallError(ErrorMessage.GenericInProgress) } @@ -56,7 +57,7 @@ export class RevisionApiService implements RevisionApiServiceInterface { } } - async deleteRevision(itemUuid: string, revisionUuid: string): Promise { + async deleteRevision(itemUuid: string, revisionUuid: string): Promise> { if (this.operationsInProgress.get(RevisionApiOperations.Delete)) { throw new ApiCallError(ErrorMessage.GenericInProgress) } diff --git a/packages/api/src/Domain/Client/Revision/RevisionApiServiceInterface.ts b/packages/api/src/Domain/Client/Revision/RevisionApiServiceInterface.ts index 4805e0be6..6b625ff92 100644 --- a/packages/api/src/Domain/Client/Revision/RevisionApiServiceInterface.ts +++ b/packages/api/src/Domain/Client/Revision/RevisionApiServiceInterface.ts @@ -1,9 +1,10 @@ -import { DeleteRevisionResponse } from '../../Response/Revision/DeleteRevisionResponse' -import { GetRevisionResponse } from '../../Response/Revision/GetRevisionResponse' -import { ListRevisionsResponse } from '../../Response/Revision/ListRevisionsResponse' +import { HttpResponse } from '@standardnotes/responses' +import { DeleteRevisionResponseBody } from '../../Response/Revision/DeleteRevisionResponseBody' +import { GetRevisionResponseBody } from '../../Response/Revision/GetRevisionResponseBody' +import { ListRevisionsResponseBody } from '../../Response/Revision/ListRevisionsResponseBody' export interface RevisionApiServiceInterface { - listRevisions(itemUuid: string): Promise - getRevision(itemUuid: string, revisionUuid: string): Promise - deleteRevision(itemUuid: string, revisionUuid: string): Promise + listRevisions(itemUuid: string): Promise> + getRevision(itemUuid: string, revisionUuid: string): Promise> + deleteRevision(itemUuid: string, revisionUuid: string): Promise> } diff --git a/packages/api/src/Domain/Client/Subscription/SubscriptionApiService.ts b/packages/api/src/Domain/Client/Subscription/SubscriptionApiService.ts index 81e754643..f9343fd0e 100644 --- a/packages/api/src/Domain/Client/Subscription/SubscriptionApiService.ts +++ b/packages/api/src/Domain/Client/Subscription/SubscriptionApiService.ts @@ -3,14 +3,15 @@ import { ApiCallError } from '../../Error/ApiCallError' import { ApiVersion } from '../../Api/ApiVersion' import { ApiEndpointParam } from '../../Request/ApiEndpointParam' import { SubscriptionServerInterface } from '../../Server/Subscription/SubscriptionServerInterface' -import { SubscriptionInviteResponse } from '../../Response/Subscription/SubscriptionInviteResponse' -import { SubscriptionInviteListResponse } from '../../Response/Subscription/SubscriptionInviteListResponse' -import { SubscriptionInviteCancelResponse } from '../../Response/Subscription/SubscriptionInviteCancelResponse' -import { SubscriptionInviteAcceptResponse } from '../../Response/Subscription/SubscriptionInviteAcceptResponse' +import { AppleIAPConfirmResponseBody } from './../../Response/Subscription/AppleIAPConfirmResponseBody' +import { SubscriptionInviteAcceptResponseBody } from '../../Response/Subscription/SubscriptionInviteAcceptResponseBody' +import { SubscriptionInviteCancelResponseBody } from '../../Response/Subscription/SubscriptionInviteCancelResponseBody' +import { SubscriptionInviteListResponseBody } from '../../Response/Subscription/SubscriptionInviteListResponseBody' +import { SubscriptionInviteResponseBody } from '../../Response/Subscription/SubscriptionInviteResponseBody' +import { HttpResponse } from '@standardnotes/responses' import { SubscriptionApiServiceInterface } from './SubscriptionApiServiceInterface' import { SubscriptionApiOperations } from './SubscriptionApiOperations' -import { AppleIAPConfirmResponse } from './../../Response/Subscription/AppleIAPConfirmResponse' import { AppleIAPConfirmRequestParams } from '../../Request' export class SubscriptionApiService implements SubscriptionApiServiceInterface { @@ -20,7 +21,7 @@ export class SubscriptionApiService implements SubscriptionApiServiceInterface { this.operationsInProgress = new Map() } - async listInvites(): Promise { + async listInvites(): Promise> { if (this.operationsInProgress.get(SubscriptionApiOperations.ListingInvites)) { throw new ApiCallError(ErrorMessage.GenericInProgress) } @@ -40,7 +41,7 @@ export class SubscriptionApiService implements SubscriptionApiServiceInterface { } } - async cancelInvite(inviteUuid: string): Promise { + async cancelInvite(inviteUuid: string): Promise> { if (this.operationsInProgress.get(SubscriptionApiOperations.CancelingInvite)) { throw new ApiCallError(ErrorMessage.GenericInProgress) } @@ -61,7 +62,7 @@ export class SubscriptionApiService implements SubscriptionApiServiceInterface { } } - async invite(inviteeEmail: string): Promise { + async invite(inviteeEmail: string): Promise> { if (this.operationsInProgress.get(SubscriptionApiOperations.Inviting)) { throw new ApiCallError(ErrorMessage.GenericInProgress) } @@ -82,7 +83,7 @@ export class SubscriptionApiService implements SubscriptionApiServiceInterface { } } - async acceptInvite(inviteUuid: string): Promise { + async acceptInvite(inviteUuid: string): Promise> { if (this.operationsInProgress.get(SubscriptionApiOperations.AcceptingInvite)) { throw new ApiCallError(ErrorMessage.GenericInProgress) } @@ -102,7 +103,7 @@ export class SubscriptionApiService implements SubscriptionApiServiceInterface { } } - async confirmAppleIAP(params: AppleIAPConfirmRequestParams): Promise { + async confirmAppleIAP(params: AppleIAPConfirmRequestParams): Promise> { if (this.operationsInProgress.get(SubscriptionApiOperations.ConfirmAppleIAP)) { throw new ApiCallError(ErrorMessage.GenericInProgress) } diff --git a/packages/api/src/Domain/Client/Subscription/SubscriptionApiServiceInterface.ts b/packages/api/src/Domain/Client/Subscription/SubscriptionApiServiceInterface.ts index 1f5df672d..5f4279f41 100644 --- a/packages/api/src/Domain/Client/Subscription/SubscriptionApiServiceInterface.ts +++ b/packages/api/src/Domain/Client/Subscription/SubscriptionApiServiceInterface.ts @@ -1,14 +1,15 @@ -import { AppleIAPConfirmResponse } from './../../Response/Subscription/AppleIAPConfirmResponse' import { AppleIAPConfirmRequestParams } from '../../Request' -import { SubscriptionInviteAcceptResponse } from '../../Response/Subscription/SubscriptionInviteAcceptResponse' -import { SubscriptionInviteCancelResponse } from '../../Response/Subscription/SubscriptionInviteCancelResponse' -import { SubscriptionInviteListResponse } from '../../Response/Subscription/SubscriptionInviteListResponse' -import { SubscriptionInviteResponse } from '../../Response/Subscription/SubscriptionInviteResponse' +import { AppleIAPConfirmResponseBody } from './../../Response/Subscription/AppleIAPConfirmResponseBody' +import { SubscriptionInviteAcceptResponseBody } from '../../Response/Subscription/SubscriptionInviteAcceptResponseBody' +import { SubscriptionInviteCancelResponseBody } from '../../Response/Subscription/SubscriptionInviteCancelResponseBody' +import { SubscriptionInviteListResponseBody } from '../../Response/Subscription/SubscriptionInviteListResponseBody' +import { SubscriptionInviteResponseBody } from '../../Response/Subscription/SubscriptionInviteResponseBody' +import { HttpResponse } from '@standardnotes/responses' export interface SubscriptionApiServiceInterface { - invite(inviteeEmail: string): Promise - listInvites(): Promise - cancelInvite(inviteUuid: string): Promise - acceptInvite(inviteUuid: string): Promise - confirmAppleIAP(params: AppleIAPConfirmRequestParams): Promise + invite(inviteeEmail: string): Promise> + listInvites(): Promise> + cancelInvite(inviteUuid: string): Promise> + acceptInvite(inviteUuid: string): Promise> + confirmAppleIAP(params: AppleIAPConfirmRequestParams): Promise> } diff --git a/packages/api/src/Domain/Client/User/UserApiService.ts b/packages/api/src/Domain/Client/User/UserApiService.ts index 351b1d79a..c37daaf57 100644 --- a/packages/api/src/Domain/Client/User/UserApiService.ts +++ b/packages/api/src/Domain/Client/User/UserApiService.ts @@ -3,12 +3,14 @@ import { UserRequestType } from '@standardnotes/common' import { ErrorMessage } from '../../Error/ErrorMessage' import { ApiCallError } from '../../Error/ApiCallError' -import { UserRegistrationResponse } from '../../Response/User/UserRegistrationResponse' import { UserServerInterface } from '../../Server/User/UserServerInterface' import { ApiVersion } from '../../Api/ApiVersion' import { ApiEndpointParam } from '../../Request/ApiEndpointParam' -import { UserRequestResponse } from '../../Response/UserRequest/UserRequestResponse' -import { UserDeletionResponse } from '../../Response/User/UserDeletionResponse' +import { HttpResponse } from '@standardnotes/responses' + +import { UserDeletionResponseBody } from '../../Response/User/UserDeletionResponseBody' +import { UserRegistrationResponseBody } from '../../Response/User/UserRegistrationResponseBody' +import { UserRequestResponseBody } from '../../Response/UserRequest/UserRequestResponseBody' import { UserRequestServerInterface } from '../../Server/UserRequest/UserRequestServerInterface' import { UserApiOperations } from './UserApiOperations' @@ -21,7 +23,7 @@ export class UserApiService implements UserApiServiceInterface { this.operationsInProgress = new Map() } - async deleteAccount(userUuid: string): Promise { + async deleteAccount(userUuid: string): Promise> { this.lockOperation(UserApiOperations.DeletingAccount) try { @@ -37,7 +39,10 @@ export class UserApiService implements UserApiServiceInterface { } } - async submitUserRequest(dto: { userUuid: string; requestType: UserRequestType }): Promise { + async submitUserRequest(dto: { + userUuid: string + requestType: UserRequestType + }): Promise> { this.lockOperation(UserApiOperations.SubmittingRequest) try { @@ -59,7 +64,7 @@ export class UserApiService implements UserApiServiceInterface { serverPassword: string keyParams: RootKeyParamsInterface ephemeral: boolean - }): Promise { + }): Promise> { this.lockOperation(UserApiOperations.Registering) try { diff --git a/packages/api/src/Domain/Client/User/UserApiServiceInterface.ts b/packages/api/src/Domain/Client/User/UserApiServiceInterface.ts index fc8c17d46..e951b7f62 100644 --- a/packages/api/src/Domain/Client/User/UserApiServiceInterface.ts +++ b/packages/api/src/Domain/Client/User/UserApiServiceInterface.ts @@ -1,9 +1,10 @@ import { UserRequestType } from '@standardnotes/common' import { type RootKeyParamsInterface } from '@standardnotes/models' +import { HttpResponse } from '@standardnotes/responses' -import { UserDeletionResponse } from '../../Response/User/UserDeletionResponse' -import { UserRegistrationResponse } from '../../Response/User/UserRegistrationResponse' -import { UserRequestResponse } from '../../Response/UserRequest/UserRequestResponse' +import { UserDeletionResponseBody } from '../../Response/User/UserDeletionResponseBody' +import { UserRegistrationResponseBody } from '../../Response/User/UserRegistrationResponseBody' +import { UserRequestResponseBody } from '../../Response/UserRequest/UserRequestResponseBody' export interface UserApiServiceInterface { register(registerDTO: { @@ -11,7 +12,10 @@ export interface UserApiServiceInterface { serverPassword: string keyParams: RootKeyParamsInterface ephemeral: boolean - }): Promise - submitUserRequest(dto: { userUuid: string; requestType: UserRequestType }): Promise - deleteAccount(userUuid: string): Promise + }): Promise> + submitUserRequest(dto: { + userUuid: string + requestType: UserRequestType + }): Promise> + deleteAccount(userUuid: string): Promise> } diff --git a/packages/api/src/Domain/Client/WebSocket/WebSocketApiService.ts b/packages/api/src/Domain/Client/WebSocket/WebSocketApiService.ts index 6a6817161..49cad332a 100644 --- a/packages/api/src/Domain/Client/WebSocket/WebSocketApiService.ts +++ b/packages/api/src/Domain/Client/WebSocket/WebSocketApiService.ts @@ -4,7 +4,8 @@ import { ApiCallError } from '../../Error/ApiCallError' import { WebSocketApiServiceInterface } from './WebSocketApiServiceInterface' import { WebSocketApiOperations } from './WebSocketApiOperations' import { WebSocketServerInterface } from '../../Server' -import { WebSocketConnectionTokenResponse } from '../../Response' +import { HttpResponse } from '@standardnotes/responses' +import { WebSocketConnectionTokenResponseBody } from '../../Response' export class WebSocketApiService implements WebSocketApiServiceInterface { private operationsInProgress: Map @@ -13,7 +14,7 @@ export class WebSocketApiService implements WebSocketApiServiceInterface { this.operationsInProgress = new Map() } - async createConnectionToken(): Promise { + async createConnectionToken(): Promise> { if (this.operationsInProgress.get(WebSocketApiOperations.CreatingConnectionToken)) { throw new ApiCallError(ErrorMessage.GenericInProgress) } diff --git a/packages/api/src/Domain/Client/WebSocket/WebSocketApiServiceInterface.ts b/packages/api/src/Domain/Client/WebSocket/WebSocketApiServiceInterface.ts index 6770e2e4d..7e9b04cfb 100644 --- a/packages/api/src/Domain/Client/WebSocket/WebSocketApiServiceInterface.ts +++ b/packages/api/src/Domain/Client/WebSocket/WebSocketApiServiceInterface.ts @@ -1,5 +1,6 @@ -import { WebSocketConnectionTokenResponse } from '../../Response' +import { HttpResponse } from '@standardnotes/responses' +import { WebSocketConnectionTokenResponseBody } from '../../Response' export interface WebSocketApiServiceInterface { - createConnectionToken(): Promise + createConnectionToken(): Promise> } diff --git a/packages/api/src/Domain/Http/HttpErrorResponseBody.ts b/packages/api/src/Domain/Http/HttpErrorResponseBody.ts deleted file mode 100644 index 788a8d46e..000000000 --- a/packages/api/src/Domain/Http/HttpErrorResponseBody.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { ErrorTag } from './ErrorTag' - -export type HttpErrorResponseBody = { - error: { - message: string - tag?: ErrorTag - } -} diff --git a/packages/api/src/Domain/Http/HttpResponse.ts b/packages/api/src/Domain/Http/HttpResponse.ts deleted file mode 100644 index 4fa6a6a92..000000000 --- a/packages/api/src/Domain/Http/HttpResponse.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { HttpStatusCode } from './HttpStatusCode' -import { HttpResponseBody } from './HttpResponseBody' -import { HttpErrorResponseBody } from './HttpErrorResponseBody' -import { HttpResponseMeta } from './HttpResponseMeta' -import { HttpHeaders } from './HttpHeaders' - -export interface HttpResponse { - status: HttpStatusCode - data?: HttpResponseBody | HttpErrorResponseBody - meta?: HttpResponseMeta - headers?: HttpHeaders -} diff --git a/packages/api/src/Domain/Http/HttpResponseBody.ts b/packages/api/src/Domain/Http/HttpResponseBody.ts deleted file mode 100644 index cc2dcc5de..000000000 --- a/packages/api/src/Domain/Http/HttpResponseBody.ts +++ /dev/null @@ -1 +0,0 @@ -export type HttpResponseBody = Record diff --git a/packages/api/src/Domain/Http/HttpService.ts b/packages/api/src/Domain/Http/HttpService.ts index 372bf54f7..e3606adc2 100644 --- a/packages/api/src/Domain/Http/HttpService.ts +++ b/packages/api/src/Domain/Http/HttpService.ts @@ -1,35 +1,50 @@ import { isString, joinPaths, sleep } from '@standardnotes/utils' import { Environment } from '@standardnotes/models' import { Session, SessionToken } from '@standardnotes/domain-core' - -import { HttpRequestParams } from './HttpRequestParams' -import { HttpVerb } from './HttpVerb' -import { HttpRequest } from './HttpRequest' -import { HttpResponse } from './HttpResponse' +import { + HttpStatusCode, + HttpRequestParams, + HttpVerb, + HttpRequest, + HttpResponse, + HttpResponseMeta, + HttpErrorResponse, + isErrorResponse, +} from '@standardnotes/responses' import { HttpServiceInterface } from './HttpServiceInterface' -import { HttpStatusCode } from './HttpStatusCode' import { XMLHttpRequestState } from './XMLHttpRequestState' import { ErrorMessage } from '../Error/ErrorMessage' -import { HttpResponseMeta } from './HttpResponseMeta' -import { HttpErrorResponseBody } from './HttpErrorResponseBody' + import { Paths } from '../Server/Auth/Paths' -import { SessionRefreshResponse } from '../Response/Auth/SessionRefreshResponse' +import { SessionRefreshResponseBody } from '../Response/Auth/SessionRefreshResponseBody' export class HttpService implements HttpServiceInterface { private session: Session | null private __latencySimulatorMs?: number private declare host: string - constructor( - private environment: Environment, - private appVersion: string, - private snjsVersion: string, - private updateMetaCallback: (meta: HttpResponseMeta) => void, - private refreshSessionCallback: (session: Session) => void, - ) { + private inProgressRefreshSessionPromise?: Promise + private updateMetaCallback!: (meta: HttpResponseMeta) => void + private refreshSessionCallback!: (session: Session) => void + + constructor(private environment: Environment, private appVersion: string, private snjsVersion: string) { this.session = null } + setCallbacks( + updateMetaCallback: (meta: HttpResponseMeta) => void, + refreshSessionCallback: (session: Session) => void, + ): void { + this.updateMetaCallback = updateMetaCallback + this.refreshSessionCallback = refreshSessionCallback + } + + public deinit(): void { + this.session = null + ;(this.updateMetaCallback as unknown) = undefined + ;(this.refreshSessionCallback as unknown) = undefined + } + setSession(session: Session): void { this.session = session } @@ -38,7 +53,7 @@ export class HttpService implements HttpServiceInterface { this.host = host } - async get(path: string, params?: HttpRequestParams, authentication?: string): Promise { + async get(path: string, params?: HttpRequestParams, authentication?: string): Promise> { return this.runHttp({ url: joinPaths(this.host, path), params, @@ -47,7 +62,7 @@ export class HttpService implements HttpServiceInterface { }) } - async post(path: string, params?: HttpRequestParams, authentication?: string): Promise { + async post(path: string, params?: HttpRequestParams, authentication?: string): Promise> { return this.runHttp({ url: joinPaths(this.host, path), params, @@ -56,7 +71,7 @@ export class HttpService implements HttpServiceInterface { }) } - async put(path: string, params?: HttpRequestParams, authentication?: string): Promise { + async put(path: string, params?: HttpRequestParams, authentication?: string): Promise> { return this.runHttp({ url: joinPaths(this.host, path), params, @@ -65,7 +80,7 @@ export class HttpService implements HttpServiceInterface { }) } - async patch(path: string, params: HttpRequestParams, authentication?: string): Promise { + async patch(path: string, params: HttpRequestParams, authentication?: string): Promise> { return this.runHttp({ url: joinPaths(this.host, path), params, @@ -74,7 +89,7 @@ export class HttpService implements HttpServiceInterface { }) } - async delete(path: string, params?: HttpRequestParams, authentication?: string): Promise { + async delete(path: string, params?: HttpRequestParams, authentication?: string): Promise> { return this.runHttp({ url: joinPaths(this.host, path), params, @@ -83,23 +98,36 @@ export class HttpService implements HttpServiceInterface { }) } - private async runHttp(httpRequest: HttpRequest): Promise { + async runHttp(httpRequest: HttpRequest): Promise> { + if (this.inProgressRefreshSessionPromise) { + await this.inProgressRefreshSessionPromise + + httpRequest.authentication = this.session?.accessToken.value + } + const request = this.createXmlRequest(httpRequest) if (this.__latencySimulatorMs) { await sleep(this.__latencySimulatorMs, true) } - const response = await this.runRequest(request, this.createRequestBody(httpRequest)) + const response = await this.runRequest(request, this.createRequestBody(httpRequest)) if (response.meta) { - this.updateMetaCallback(response.meta) + this.updateMetaCallback?.(response.meta) } if (response.status === HttpStatusCode.ExpiredAccessToken) { - const isSessionRefreshed = await this.refreshSession() - if (!isSessionRefreshed) { - return response + if (this.inProgressRefreshSessionPromise) { + await this.inProgressRefreshSessionPromise + } else { + this.inProgressRefreshSessionPromise = this.refreshSession() + const isSessionRefreshed = await this.inProgressRefreshSessionPromise + this.inProgressRefreshSessionPromise = undefined + + if (!isSessionRefreshed) { + return response + } } httpRequest.authentication = this.session?.accessToken.value @@ -115,17 +143,17 @@ export class HttpService implements HttpServiceInterface { return false } - const response = (await this.post(Paths.v1.refreshSession, { + const response = await this.post(Paths.v1.refreshSession, { access_token: this.session.accessToken.value, refresh_token: this.session.refreshToken.value, - })) as SessionRefreshResponse + }) - if (response.data.error) { + if (isErrorResponse(response)) { return false } if (response.meta) { - this.updateMetaCallback(response.meta) + this.updateMetaCallback?.(response.meta) } const accessTokenOrError = SessionToken.create( @@ -135,6 +163,7 @@ export class HttpService implements HttpServiceInterface { if (accessTokenOrError.isFailed()) { return false } + const accessToken = accessTokenOrError.getValue() const refreshTokenOrError = SessionToken.create( @@ -144,6 +173,7 @@ export class HttpService implements HttpServiceInterface { if (refreshTokenOrError.isFailed()) { return false } + const refreshToken = refreshTokenOrError.getValue() const sessionOrError = Session.create(accessToken, refreshToken, response.data.session.readonly_access) @@ -204,27 +234,24 @@ export class HttpService implements HttpServiceInterface { return request } - private async runRequest(request: XMLHttpRequest, body?: string | Uint8Array): Promise { - return new Promise((resolve, reject) => { + private async runRequest(request: XMLHttpRequest, body?: string | Uint8Array): Promise> { + return new Promise((resolve) => { request.onreadystatechange = () => { - this.stateChangeHandlerForRequest(request, resolve, reject) + this.stateChangeHandlerForRequest(request, resolve) } request.send(body) }) } - private stateChangeHandlerForRequest( - request: XMLHttpRequest, - resolve: (response: HttpResponse) => void, - reject: (response: HttpResponse) => void, - ) { + private stateChangeHandlerForRequest(request: XMLHttpRequest, resolve: (response: HttpResponse) => void) { if (request.readyState !== XMLHttpRequestState.Completed) { return } const httpStatus = request.status - const response: HttpResponse = { + const response: HttpResponse = { status: httpStatus, headers: new Map(), + data: {} as T, } const responseHeaderLines = request @@ -266,12 +293,29 @@ export class HttpService implements HttpServiceInterface { console.error(error) } if (httpStatus >= HttpStatusCode.Success && httpStatus < HttpStatusCode.InternalServerError) { - if (httpStatus === HttpStatusCode.Forbidden && response.data && response.data.error !== undefined) { - ;(response.data as HttpErrorResponseBody).error.message = ErrorMessage.RateLimited + if ( + httpStatus === HttpStatusCode.Forbidden && + response.data && + (response as HttpErrorResponse).data.error !== undefined + ) { + ;(response as HttpErrorResponse).data.error.message = ErrorMessage.RateLimited } resolve(response) } else { - reject(response) + const errorResponse = response as HttpErrorResponse + if (!errorResponse.data) { + errorResponse.data = { + error: { + message: 'Unknown error', + }, + } + } + if (!errorResponse.data.error) { + errorResponse.data.error = { + message: 'Unknown error', + } + } + resolve(response as HttpErrorResponse) } } diff --git a/packages/api/src/Domain/Http/HttpServiceInterface.ts b/packages/api/src/Domain/Http/HttpServiceInterface.ts index db1e0db22..cff0fd875 100644 --- a/packages/api/src/Domain/Http/HttpServiceInterface.ts +++ b/packages/api/src/Domain/Http/HttpServiceInterface.ts @@ -1,14 +1,18 @@ import { Session } from '@standardnotes/domain-core' - -import { HttpRequestParams } from './HttpRequestParams' -import { HttpResponse } from './HttpResponse' +import { HttpRequest, HttpRequestParams, HttpResponse, HttpResponseMeta } from '@standardnotes/responses' export interface HttpServiceInterface { setHost(host: string): void setSession(session: Session): void - get(path: string, params?: HttpRequestParams, authentication?: string): Promise - post(path: string, params?: HttpRequestParams, authentication?: string): Promise - put(path: string, params?: HttpRequestParams, authentication?: string): Promise - patch(path: string, params: HttpRequestParams, authentication?: string): Promise - delete(path: string, params?: HttpRequestParams, authentication?: string): Promise + get(path: string, params?: HttpRequestParams, authentication?: string): Promise> + post(path: string, params?: HttpRequestParams, authentication?: string): Promise> + put(path: string, params?: HttpRequestParams, authentication?: string): Promise> + patch(path: string, params: HttpRequestParams, authentication?: string): Promise> + delete(path: string, params?: HttpRequestParams, authentication?: string): Promise> + runHttp(httpRequest: HttpRequest): Promise> + setCallbacks( + updateMetaCallback: (meta: HttpResponseMeta) => void, + refreshSessionCallback: (session: Session) => void, + ): void + deinit(): void } diff --git a/packages/api/src/Domain/Http/index.ts b/packages/api/src/Domain/Http/index.ts index 9b4c93dda..fab54d4ca 100644 --- a/packages/api/src/Domain/Http/index.ts +++ b/packages/api/src/Domain/Http/index.ts @@ -1,13 +1,3 @@ -export * from './ErrorTag' -export * from './HttpErrorResponseBody' -export * from './HttpHeaders' -export * from './HttpRequest' -export * from './HttpRequestParams' -export * from './HttpResponse' -export * from './HttpResponseBody' -export * from './HttpResponseMeta' export * from './HttpService' export * from './HttpServiceInterface' -export * from './HttpStatusCode' -export * from './HttpVerb' export * from './XMLHttpRequestState' diff --git a/packages/api/src/Domain/Response/Auth/SessionRefreshResponse.ts b/packages/api/src/Domain/Response/Auth/SessionRefreshResponse.ts deleted file mode 100644 index 0fd8b6287..000000000 --- a/packages/api/src/Domain/Response/Auth/SessionRefreshResponse.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Either } from '@standardnotes/common' - -import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody' -import { HttpResponse } from '../../Http/HttpResponse' -import { SessionRefreshResponseBody } from './SessionRefreshResponseBody' - -export interface SessionRefreshResponse extends HttpResponse { - data: Either -} diff --git a/packages/api/src/Domain/Response/Authenticator/DeleteAuthenticatorResponse.ts b/packages/api/src/Domain/Response/Authenticator/DeleteAuthenticatorResponse.ts deleted file mode 100644 index 1e0b0591d..000000000 --- a/packages/api/src/Domain/Response/Authenticator/DeleteAuthenticatorResponse.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Either } from '@standardnotes/common' - -import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody' -import { HttpResponse } from '../../Http/HttpResponse' - -import { DeleteAuthenticatorResponseBody } from './DeleteAuthenticatorResponseBody' - -export interface DeleteAuthenticatorResponse extends HttpResponse { - data: Either -} diff --git a/packages/api/src/Domain/Response/Authenticator/GenerateAuthenticatorAuthenticationOptionsResponse.ts b/packages/api/src/Domain/Response/Authenticator/GenerateAuthenticatorAuthenticationOptionsResponse.ts deleted file mode 100644 index 6f55af926..000000000 --- a/packages/api/src/Domain/Response/Authenticator/GenerateAuthenticatorAuthenticationOptionsResponse.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Either } from '@standardnotes/common' - -import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody' -import { HttpResponse } from '../../Http/HttpResponse' - -import { GenerateAuthenticatorAuthenticationOptionsResponseBody } from './GenerateAuthenticatorAuthenticationOptionsResponseBody' - -export interface GenerateAuthenticatorAuthenticationOptionsResponse extends HttpResponse { - data: Either -} diff --git a/packages/api/src/Domain/Response/Authenticator/GenerateAuthenticatorRegistrationOptionsResponse.ts b/packages/api/src/Domain/Response/Authenticator/GenerateAuthenticatorRegistrationOptionsResponse.ts deleted file mode 100644 index 1b63c6609..000000000 --- a/packages/api/src/Domain/Response/Authenticator/GenerateAuthenticatorRegistrationOptionsResponse.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Either } from '@standardnotes/common' - -import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody' -import { HttpResponse } from '../../Http/HttpResponse' - -import { GenerateAuthenticatorRegistrationOptionsResponseBody } from './GenerateAuthenticatorRegistrationOptionsResponseBody' - -export interface GenerateAuthenticatorRegistrationOptionsResponse extends HttpResponse { - data: Either -} diff --git a/packages/api/src/Domain/Response/Authenticator/ListAuthenticatorsResponse.ts b/packages/api/src/Domain/Response/Authenticator/ListAuthenticatorsResponse.ts deleted file mode 100644 index 3b7264777..000000000 --- a/packages/api/src/Domain/Response/Authenticator/ListAuthenticatorsResponse.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Either } from '@standardnotes/common' - -import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody' -import { HttpResponse } from '../../Http/HttpResponse' - -import { ListAuthenticatorsResponseBody } from './ListAuthenticatorsResponseBody' - -export interface ListAuthenticatorsResponse extends HttpResponse { - data: Either -} diff --git a/packages/api/src/Domain/Response/Authenticator/VerifyAuthenticatorRegistrationResponseBody.ts b/packages/api/src/Domain/Response/Authenticator/VerifyAuthenticatorRegistrationResponseBody.ts new file mode 100644 index 000000000..0018bafb9 --- /dev/null +++ b/packages/api/src/Domain/Response/Authenticator/VerifyAuthenticatorRegistrationResponseBody.ts @@ -0,0 +1,3 @@ +export interface VerifyAuthenticatorRegistrationResponseBody { + success: boolean +} diff --git a/packages/api/src/Domain/Response/Authenticator/VerifyAuthenticatorRegistrationResponseResponse.ts b/packages/api/src/Domain/Response/Authenticator/VerifyAuthenticatorRegistrationResponseResponse.ts deleted file mode 100644 index 1f7033e25..000000000 --- a/packages/api/src/Domain/Response/Authenticator/VerifyAuthenticatorRegistrationResponseResponse.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Either } from '@standardnotes/common' - -import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody' -import { HttpResponse } from '../../Http/HttpResponse' - -import { VerifyAuthenticatorRegistrationResponseResponseBody } from './VerifyAuthenticatorRegistrationResponseResponseBody' - -export interface VerifyAuthenticatorRegistrationResponseResponse extends HttpResponse { - data: Either -} diff --git a/packages/api/src/Domain/Response/Authenticator/VerifyAuthenticatorRegistrationResponseResponseBody.ts b/packages/api/src/Domain/Response/Authenticator/VerifyAuthenticatorRegistrationResponseResponseBody.ts deleted file mode 100644 index faf06a8b5..000000000 --- a/packages/api/src/Domain/Response/Authenticator/VerifyAuthenticatorRegistrationResponseResponseBody.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface VerifyAuthenticatorRegistrationResponseResponseBody { - success: boolean -} diff --git a/packages/api/src/Domain/Response/Recovery/GenerateRecoveryCodesResponse.ts b/packages/api/src/Domain/Response/Recovery/GenerateRecoveryCodesResponse.ts deleted file mode 100644 index 31faab7a4..000000000 --- a/packages/api/src/Domain/Response/Recovery/GenerateRecoveryCodesResponse.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Either } from '@standardnotes/common' - -import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody' -import { HttpResponse } from '../../Http/HttpResponse' - -import { GenerateRecoveryCodesResponseBody } from './GenerateRecoveryCodesResponseBody' - -export interface GenerateRecoveryCodesResponse extends HttpResponse { - data: Either -} diff --git a/packages/api/src/Domain/Response/Recovery/RecoveryKeyParamsResponse.ts b/packages/api/src/Domain/Response/Recovery/RecoveryKeyParamsResponse.ts deleted file mode 100644 index d0f0efe23..000000000 --- a/packages/api/src/Domain/Response/Recovery/RecoveryKeyParamsResponse.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Either } from '@standardnotes/common' - -import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody' -import { HttpResponse } from '../../Http/HttpResponse' - -import { RecoveryKeyParamsResponseBody } from './RecoveryKeyParamsResponseBody' - -export interface RecoveryKeyParamsResponse extends HttpResponse { - data: Either -} diff --git a/packages/api/src/Domain/Response/Recovery/SignInWithRecoveryCodesResponse.ts b/packages/api/src/Domain/Response/Recovery/SignInWithRecoveryCodesResponse.ts deleted file mode 100644 index cd6c53169..000000000 --- a/packages/api/src/Domain/Response/Recovery/SignInWithRecoveryCodesResponse.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Either } from '@standardnotes/common' - -import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody' -import { HttpResponse } from '../../Http/HttpResponse' - -import { SignInWithRecoveryCodesResponseBody } from './SignInWithRecoveryCodesResponseBody' - -export interface SignInWithRecoveryCodesResponse extends HttpResponse { - data: Either -} diff --git a/packages/api/src/Domain/Response/Revision/DeleteRevisionResponse.ts b/packages/api/src/Domain/Response/Revision/DeleteRevisionResponse.ts deleted file mode 100644 index fe6fda7d6..000000000 --- a/packages/api/src/Domain/Response/Revision/DeleteRevisionResponse.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Either } from '@standardnotes/common' - -import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody' -import { HttpResponse } from '../../Http/HttpResponse' - -import { DeleteRevisionResponseBody } from './DeleteRevisionResponseBody' - -export interface DeleteRevisionResponse extends HttpResponse { - data: Either -} diff --git a/packages/api/src/Domain/Response/Revision/GetRevisionResponse.ts b/packages/api/src/Domain/Response/Revision/GetRevisionResponse.ts deleted file mode 100644 index ec8b467cf..000000000 --- a/packages/api/src/Domain/Response/Revision/GetRevisionResponse.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Either } from '@standardnotes/common' - -import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody' -import { HttpResponse } from '../../Http/HttpResponse' - -import { GetRevisionResponseBody } from './GetRevisionResponseBody' - -export interface GetRevisionResponse extends HttpResponse { - data: Either -} diff --git a/packages/api/src/Domain/Response/Revision/ListRevisionsResponse.ts b/packages/api/src/Domain/Response/Revision/ListRevisionsResponse.ts deleted file mode 100644 index 5c4947535..000000000 --- a/packages/api/src/Domain/Response/Revision/ListRevisionsResponse.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Either } from '@standardnotes/common' - -import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody' -import { HttpResponse } from '../../Http/HttpResponse' - -import { ListRevisionsResponseBody } from './ListRevisionsResponseBody' - -export interface ListRevisionsResponse extends HttpResponse { - data: Either -} diff --git a/packages/api/src/Domain/Response/Subscription/AppleIAPConfirmResponse.ts b/packages/api/src/Domain/Response/Subscription/AppleIAPConfirmResponse.ts deleted file mode 100644 index 39a23f745..000000000 --- a/packages/api/src/Domain/Response/Subscription/AppleIAPConfirmResponse.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Either } from '@standardnotes/common' - -import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody' -import { HttpResponse } from '../../Http/HttpResponse' -import { AppleIAPConfirmResponseBody } from './AppleIAPConfirmResponseBody' - -export interface AppleIAPConfirmResponse extends HttpResponse { - data: Either -} diff --git a/packages/api/src/Domain/Response/Subscription/SubscriptionInviteAcceptResponse.ts b/packages/api/src/Domain/Response/Subscription/SubscriptionInviteAcceptResponse.ts deleted file mode 100644 index c69ff7229..000000000 --- a/packages/api/src/Domain/Response/Subscription/SubscriptionInviteAcceptResponse.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Either } from '@standardnotes/common' - -import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody' -import { HttpResponse } from '../../Http/HttpResponse' -import { SubscriptionInviteAcceptResponseBody } from './SubscriptionInviteAcceptResponseBody' - -export interface SubscriptionInviteAcceptResponse extends HttpResponse { - data: Either -} diff --git a/packages/api/src/Domain/Response/Subscription/SubscriptionInviteCancelResponse.ts b/packages/api/src/Domain/Response/Subscription/SubscriptionInviteCancelResponse.ts deleted file mode 100644 index ac7d11c34..000000000 --- a/packages/api/src/Domain/Response/Subscription/SubscriptionInviteCancelResponse.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Either } from '@standardnotes/common' - -import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody' -import { HttpResponse } from '../../Http/HttpResponse' -import { SubscriptionInviteCancelResponseBody } from './SubscriptionInviteCancelResponseBody' - -export interface SubscriptionInviteCancelResponse extends HttpResponse { - data: Either -} diff --git a/packages/api/src/Domain/Response/Subscription/SubscriptionInviteDeclineResponse.ts b/packages/api/src/Domain/Response/Subscription/SubscriptionInviteDeclineResponse.ts deleted file mode 100644 index 59705f445..000000000 --- a/packages/api/src/Domain/Response/Subscription/SubscriptionInviteDeclineResponse.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Either } from '@standardnotes/common' - -import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody' -import { HttpResponse } from '../../Http/HttpResponse' -import { SubscriptionInviteDeclineResponseBody } from './SubscriptionInviteDeclineResponseBody' - -export interface SubscriptionInviteDeclineResponse extends HttpResponse { - data: Either -} diff --git a/packages/api/src/Domain/Response/Subscription/SubscriptionInviteListResponse.ts b/packages/api/src/Domain/Response/Subscription/SubscriptionInviteListResponse.ts deleted file mode 100644 index 1311d627c..000000000 --- a/packages/api/src/Domain/Response/Subscription/SubscriptionInviteListResponse.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Either } from '@standardnotes/common' - -import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody' -import { HttpResponse } from '../../Http/HttpResponse' -import { SubscriptionInviteListResponseBody } from './SubscriptionInviteListResponseBody' - -export interface SubscriptionInviteListResponse extends HttpResponse { - data: Either -} diff --git a/packages/api/src/Domain/Response/Subscription/SubscriptionInviteResponse.ts b/packages/api/src/Domain/Response/Subscription/SubscriptionInviteResponse.ts deleted file mode 100644 index a26b71f2c..000000000 --- a/packages/api/src/Domain/Response/Subscription/SubscriptionInviteResponse.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Either } from '@standardnotes/common' - -import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody' -import { HttpResponse } from '../../Http/HttpResponse' -import { SubscriptionInviteResponseBody } from './SubscriptionInviteResponseBody' - -export interface SubscriptionInviteResponse extends HttpResponse { - data: Either -} diff --git a/packages/api/src/Domain/Response/User/UserDeletionResponse.ts b/packages/api/src/Domain/Response/User/UserDeletionResponse.ts deleted file mode 100644 index bb783f443..000000000 --- a/packages/api/src/Domain/Response/User/UserDeletionResponse.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Either } from '@standardnotes/common' -import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody' -import { HttpResponse } from '../../Http/HttpResponse' - -import { UserDeletionResponseBody } from './UserDeletionResponseBody' - -export interface UserDeletionResponse extends HttpResponse { - data: Either -} diff --git a/packages/api/src/Domain/Response/User/UserRegistrationResponse.ts b/packages/api/src/Domain/Response/User/UserRegistrationResponse.ts deleted file mode 100644 index 9f83b2960..000000000 --- a/packages/api/src/Domain/Response/User/UserRegistrationResponse.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody' -import { HttpResponse } from '../../Http/HttpResponse' -import { UserRegistrationResponseBody } from './UserRegistrationResponseBody' - -export interface UserRegistrationResponse extends HttpResponse { - data: UserRegistrationResponseBody | HttpErrorResponseBody -} diff --git a/packages/api/src/Domain/Response/UserRequest/UserRequestResponse.ts b/packages/api/src/Domain/Response/UserRequest/UserRequestResponse.ts deleted file mode 100644 index cc58c63c1..000000000 --- a/packages/api/src/Domain/Response/UserRequest/UserRequestResponse.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Either } from '@standardnotes/common' - -import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody' -import { HttpResponse } from '../../Http/HttpResponse' -import { UserRequestResponseBody } from './UserRequestResponseBody' - -export interface UserRequestResponse extends HttpResponse { - data: Either -} diff --git a/packages/api/src/Domain/Response/WebSocket/WebSocketConnectionTokenResponse.ts b/packages/api/src/Domain/Response/WebSocket/WebSocketConnectionTokenResponse.ts deleted file mode 100644 index a2629c0a4..000000000 --- a/packages/api/src/Domain/Response/WebSocket/WebSocketConnectionTokenResponse.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Either } from '@standardnotes/common' - -import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody' -import { HttpResponse } from '../../Http/HttpResponse' -import { WebSocketConnectionTokenResponseBody } from './WebSocketConnectionTokenResponseBody' - -export interface WebSocketConnectionTokenResponse extends HttpResponse { - data: Either -} diff --git a/packages/api/src/Domain/Response/index.ts b/packages/api/src/Domain/Response/index.ts index 24e936e9e..4a183af46 100644 --- a/packages/api/src/Domain/Response/index.ts +++ b/packages/api/src/Domain/Response/index.ts @@ -1,44 +1,22 @@ -export * from './Auth/SessionRefreshResponse' export * from './Auth/SessionRefreshResponseBody' -export * from './Authenticator/DeleteAuthenticatorResponse' export * from './Authenticator/DeleteAuthenticatorResponseBody' -export * from './Authenticator/GenerateAuthenticatorAuthenticationOptionsResponse' export * from './Authenticator/GenerateAuthenticatorAuthenticationOptionsResponseBody' -export * from './Authenticator/GenerateAuthenticatorRegistrationOptionsResponse' export * from './Authenticator/GenerateAuthenticatorRegistrationOptionsResponseBody' -export * from './Authenticator/ListAuthenticatorsResponse' export * from './Authenticator/ListAuthenticatorsResponseBody' -export * from './Authenticator/VerifyAuthenticatorRegistrationResponseResponse' -export * from './Authenticator/VerifyAuthenticatorRegistrationResponseResponseBody' -export * from './Recovery/GenerateRecoveryCodesResponse' +export * from './Authenticator/VerifyAuthenticatorRegistrationResponseBody' export * from './Recovery/GenerateRecoveryCodesResponseBody' -export * from './Recovery/RecoveryKeyParamsResponse' export * from './Recovery/RecoveryKeyParamsResponseBody' -export * from './Recovery/SignInWithRecoveryCodesResponse' export * from './Recovery/SignInWithRecoveryCodesResponseBody' -export * from './Recovery/GenerateRecoveryCodesResponse' export * from './Recovery/GenerateRecoveryCodesResponseBody' -export * from './Recovery/RecoveryKeyParamsResponse' export * from './Recovery/RecoveryKeyParamsResponseBody' -export * from './Recovery/SignInWithRecoveryCodesResponse' export * from './Recovery/SignInWithRecoveryCodesResponseBody' -export * from './Subscription/AppleIAPConfirmResponse' export * from './Subscription/AppleIAPConfirmResponseBody' -export * from './Subscription/SubscriptionInviteAcceptResponse' export * from './Subscription/SubscriptionInviteAcceptResponseBody' -export * from './Subscription/SubscriptionInviteCancelResponse' export * from './Subscription/SubscriptionInviteCancelResponseBody' -export * from './Subscription/SubscriptionInviteDeclineResponse' export * from './Subscription/SubscriptionInviteDeclineResponseBody' -export * from './Subscription/SubscriptionInviteListResponse' export * from './Subscription/SubscriptionInviteListResponseBody' -export * from './Subscription/SubscriptionInviteResponse' export * from './Subscription/SubscriptionInviteResponseBody' -export * from './User/UserDeletionResponse' export * from './User/UserDeletionResponseBody' -export * from './User/UserRegistrationResponse' export * from './User/UserRegistrationResponseBody' -export * from './UserRequest/UserRequestResponse' export * from './UserRequest/UserRequestResponseBody' -export * from './WebSocket/WebSocketConnectionTokenResponse' export * from './WebSocket/WebSocketConnectionTokenResponseBody' diff --git a/packages/api/src/Domain/Server/Auth/AuthServer.ts b/packages/api/src/Domain/Server/Auth/AuthServer.ts index 9689a6d57..e53e83c49 100644 --- a/packages/api/src/Domain/Server/Auth/AuthServer.ts +++ b/packages/api/src/Domain/Server/Auth/AuthServer.ts @@ -1,9 +1,10 @@ import { HttpServiceInterface } from '../../Http/HttpServiceInterface' import { RecoveryKeyParamsRequestParams, SignInWithRecoveryCodesRequestParams } from '../../Request' +import { HttpResponse } from '@standardnotes/responses' import { - GenerateRecoveryCodesResponse, - RecoveryKeyParamsResponse, - SignInWithRecoveryCodesResponse, + GenerateRecoveryCodesResponseBody, + RecoveryKeyParamsResponseBody, + SignInWithRecoveryCodesResponseBody, } from '../../Response' import { AuthServerInterface } from './AuthServerInterface' import { Paths } from './Paths' @@ -11,23 +12,19 @@ import { Paths } from './Paths' export class AuthServer implements AuthServerInterface { constructor(private httpService: HttpServiceInterface) {} - async generateRecoveryCodes(): Promise { - const response = await this.httpService.post(Paths.v1.generateRecoveryCodes) - - return response as GenerateRecoveryCodesResponse + async generateRecoveryCodes(): Promise> { + return this.httpService.post(Paths.v1.generateRecoveryCodes) } - async recoveryKeyParams(params: RecoveryKeyParamsRequestParams): Promise { - const response = await this.httpService.post(Paths.v1.recoveryKeyParams, params) - - return response as RecoveryKeyParamsResponse + async recoveryKeyParams( + params: RecoveryKeyParamsRequestParams, + ): Promise> { + return this.httpService.post(Paths.v1.recoveryKeyParams, params) } async signInWithRecoveryCodes( params: SignInWithRecoveryCodesRequestParams, - ): Promise { - const response = await this.httpService.post(Paths.v1.signInWithRecoveryCodes, params) - - return response as SignInWithRecoveryCodesResponse + ): Promise> { + return this.httpService.post(Paths.v1.signInWithRecoveryCodes, params) } } diff --git a/packages/api/src/Domain/Server/Auth/AuthServerInterface.ts b/packages/api/src/Domain/Server/Auth/AuthServerInterface.ts index 0a72d626e..e0d38a8a8 100644 --- a/packages/api/src/Domain/Server/Auth/AuthServerInterface.ts +++ b/packages/api/src/Domain/Server/Auth/AuthServerInterface.ts @@ -1,12 +1,15 @@ +import { HttpResponse } from '@standardnotes/responses' import { RecoveryKeyParamsRequestParams, SignInWithRecoveryCodesRequestParams } from '../../Request' import { - GenerateRecoveryCodesResponse, - RecoveryKeyParamsResponse, - SignInWithRecoveryCodesResponse, + GenerateRecoveryCodesResponseBody, + RecoveryKeyParamsResponseBody, + SignInWithRecoveryCodesResponseBody, } from '../../Response' export interface AuthServerInterface { - generateRecoveryCodes(): Promise - recoveryKeyParams(params: RecoveryKeyParamsRequestParams): Promise - signInWithRecoveryCodes(params: SignInWithRecoveryCodesRequestParams): Promise + generateRecoveryCodes(): Promise> + recoveryKeyParams(params: RecoveryKeyParamsRequestParams): Promise> + signInWithRecoveryCodes( + params: SignInWithRecoveryCodesRequestParams, + ): Promise> } diff --git a/packages/api/src/Domain/Server/Authenticator/AuthenticatorServer.ts b/packages/api/src/Domain/Server/Authenticator/AuthenticatorServer.ts index 7148af928..7f3860c40 100644 --- a/packages/api/src/Domain/Server/Authenticator/AuthenticatorServer.ts +++ b/packages/api/src/Domain/Server/Authenticator/AuthenticatorServer.ts @@ -5,12 +5,13 @@ import { DeleteAuthenticatorRequestParams, VerifyAuthenticatorRegistrationResponseRequestParams, } from '../../Request' +import { HttpResponse } from '@standardnotes/responses' import { - ListAuthenticatorsResponse, - DeleteAuthenticatorResponse, - GenerateAuthenticatorRegistrationOptionsResponse, - VerifyAuthenticatorRegistrationResponseResponse, - GenerateAuthenticatorAuthenticationOptionsResponse, + ListAuthenticatorsResponseBody, + DeleteAuthenticatorResponseBody, + GenerateAuthenticatorRegistrationOptionsResponseBody, + VerifyAuthenticatorRegistrationResponseBody, + GenerateAuthenticatorAuthenticationOptionsResponseBody, } from '../../Response' import { AuthenticatorServerInterface } from './AuthenticatorServerInterface' import { Paths } from './Paths' @@ -18,37 +19,27 @@ import { Paths } from './Paths' export class AuthenticatorServer implements AuthenticatorServerInterface { constructor(private httpService: HttpServiceInterface) {} - async list(params: ListAuthenticatorsRequestParams): Promise { - const response = await this.httpService.get(Paths.v1.listAuthenticators, params) - - return response as ListAuthenticatorsResponse + async list(params: ListAuthenticatorsRequestParams): Promise> { + return this.httpService.get(Paths.v1.listAuthenticators, params) } - async delete(params: DeleteAuthenticatorRequestParams): Promise { - const response = await this.httpService.delete(Paths.v1.deleteAuthenticator(params.authenticatorId), params) - - return response as DeleteAuthenticatorResponse + async delete(params: DeleteAuthenticatorRequestParams): Promise> { + return this.httpService.delete(Paths.v1.deleteAuthenticator(params.authenticatorId), params) } - async generateRegistrationOptions(): Promise { - const response = await this.httpService.get(Paths.v1.generateRegistrationOptions) - - return response as GenerateAuthenticatorRegistrationOptionsResponse + async generateRegistrationOptions(): Promise> { + return this.httpService.get(Paths.v1.generateRegistrationOptions) } async verifyRegistrationResponse( params: VerifyAuthenticatorRegistrationResponseRequestParams, - ): Promise { - const response = await this.httpService.post(Paths.v1.verifyRegistrationResponse, params) - - return response as VerifyAuthenticatorRegistrationResponseResponse + ): Promise> { + return this.httpService.post(Paths.v1.verifyRegistrationResponse, params) } async generateAuthenticationOptions( params: GenerateAuthenticatorAuthenticationOptionsRequestParams, - ): Promise { - const response = await this.httpService.post(Paths.v1.generateAuthenticationOptions, params) - - return response as GenerateAuthenticatorAuthenticationOptionsResponse + ): Promise> { + return this.httpService.post(Paths.v1.generateAuthenticationOptions, params) } } diff --git a/packages/api/src/Domain/Server/Authenticator/AuthenticatorServerInterface.ts b/packages/api/src/Domain/Server/Authenticator/AuthenticatorServerInterface.ts index b5c00cb7a..a6b03d6fa 100644 --- a/packages/api/src/Domain/Server/Authenticator/AuthenticatorServerInterface.ts +++ b/packages/api/src/Domain/Server/Authenticator/AuthenticatorServerInterface.ts @@ -1,3 +1,4 @@ +import { HttpResponse } from '@standardnotes/responses' import { ListAuthenticatorsRequestParams, DeleteAuthenticatorRequestParams, @@ -5,21 +6,21 @@ import { GenerateAuthenticatorAuthenticationOptionsRequestParams, } from '../../Request' import { - ListAuthenticatorsResponse, - DeleteAuthenticatorResponse, - GenerateAuthenticatorRegistrationOptionsResponse, - VerifyAuthenticatorRegistrationResponseResponse, - GenerateAuthenticatorAuthenticationOptionsResponse, + ListAuthenticatorsResponseBody, + DeleteAuthenticatorResponseBody, + GenerateAuthenticatorRegistrationOptionsResponseBody, + VerifyAuthenticatorRegistrationResponseBody, + GenerateAuthenticatorAuthenticationOptionsResponseBody, } from '../../Response' export interface AuthenticatorServerInterface { - list(params: ListAuthenticatorsRequestParams): Promise - delete(params: DeleteAuthenticatorRequestParams): Promise - generateRegistrationOptions(): Promise + list(params: ListAuthenticatorsRequestParams): Promise> + delete(params: DeleteAuthenticatorRequestParams): Promise> + generateRegistrationOptions(): Promise> verifyRegistrationResponse( params: VerifyAuthenticatorRegistrationResponseRequestParams, - ): Promise + ): Promise> generateAuthenticationOptions( params: GenerateAuthenticatorAuthenticationOptionsRequestParams, - ): Promise + ): Promise> } diff --git a/packages/api/src/Domain/Server/Revision/RevisionServer.ts b/packages/api/src/Domain/Server/Revision/RevisionServer.ts index a25ff521e..6ff241647 100644 --- a/packages/api/src/Domain/Server/Revision/RevisionServer.ts +++ b/packages/api/src/Domain/Server/Revision/RevisionServer.ts @@ -1,8 +1,9 @@ import { HttpServiceInterface } from '../../Http/HttpServiceInterface' import { DeleteRevisionRequestParams, GetRevisionRequestParams, ListRevisionsRequestParams } from '../../Request' -import { DeleteRevisionResponse } from '../../Response/Revision/DeleteRevisionResponse' -import { GetRevisionResponse } from '../../Response/Revision/GetRevisionResponse' -import { ListRevisionsResponse } from '../../Response/Revision/ListRevisionsResponse' +import { HttpResponse } from '@standardnotes/responses' +import { DeleteRevisionResponseBody } from '../../Response/Revision/DeleteRevisionResponseBody' +import { GetRevisionResponseBody } from '../../Response/Revision/GetRevisionResponseBody' +import { ListRevisionsResponseBody } from '../../Response/Revision/ListRevisionsResponseBody' import { Paths } from './Paths' import { RevisionServerInterface } from './RevisionServerInterface' @@ -10,21 +11,15 @@ import { RevisionServerInterface } from './RevisionServerInterface' export class RevisionServer implements RevisionServerInterface { constructor(private httpService: HttpServiceInterface) {} - async listRevisions(params: ListRevisionsRequestParams): Promise { - const response = await this.httpService.get(Paths.v2.listRevisions(params.itemUuid)) - - return response as ListRevisionsResponse + async listRevisions(params: ListRevisionsRequestParams): Promise> { + return this.httpService.get(Paths.v2.listRevisions(params.itemUuid)) } - async getRevision(params: GetRevisionRequestParams): Promise { - const response = await this.httpService.get(Paths.v2.getRevision(params.itemUuid, params.revisionUuid)) - - return response as GetRevisionResponse + async getRevision(params: GetRevisionRequestParams): Promise> { + return this.httpService.get(Paths.v2.getRevision(params.itemUuid, params.revisionUuid)) } - async deleteRevision(params: DeleteRevisionRequestParams): Promise { - const response = await this.httpService.delete(Paths.v2.deleteRevision(params.itemUuid, params.revisionUuid)) - - return response as DeleteRevisionResponse + async deleteRevision(params: DeleteRevisionRequestParams): Promise> { + return this.httpService.delete(Paths.v2.deleteRevision(params.itemUuid, params.revisionUuid)) } } diff --git a/packages/api/src/Domain/Server/Revision/RevisionServerInterface.ts b/packages/api/src/Domain/Server/Revision/RevisionServerInterface.ts index f6b76b738..7bcee6e02 100644 --- a/packages/api/src/Domain/Server/Revision/RevisionServerInterface.ts +++ b/packages/api/src/Domain/Server/Revision/RevisionServerInterface.ts @@ -1,12 +1,13 @@ +import { HttpResponse } from '@standardnotes/responses' import { DeleteRevisionRequestParams } from '../../Request/Revision/DeleteRevisionRequestParams' import { GetRevisionRequestParams } from '../../Request/Revision/GetRevisionRequestParams' import { ListRevisionsRequestParams } from '../../Request/Revision/ListRevisionsRequestParams' -import { DeleteRevisionResponse } from '../../Response/Revision/DeleteRevisionResponse' -import { GetRevisionResponse } from '../../Response/Revision/GetRevisionResponse' -import { ListRevisionsResponse } from '../../Response/Revision/ListRevisionsResponse' +import { DeleteRevisionResponseBody } from '../../Response/Revision/DeleteRevisionResponseBody' +import { GetRevisionResponseBody } from '../../Response/Revision/GetRevisionResponseBody' +import { ListRevisionsResponseBody } from '../../Response/Revision/ListRevisionsResponseBody' export interface RevisionServerInterface { - listRevisions(params: ListRevisionsRequestParams): Promise - getRevision(params: GetRevisionRequestParams): Promise - deleteRevision(params: DeleteRevisionRequestParams): Promise + listRevisions(params: ListRevisionsRequestParams): Promise> + getRevision(params: GetRevisionRequestParams): Promise> + deleteRevision(params: DeleteRevisionRequestParams): Promise> } diff --git a/packages/api/src/Domain/Server/Subscription/SubscriptionServer.ts b/packages/api/src/Domain/Server/Subscription/SubscriptionServer.ts index 92b85cf83..9d4de393a 100644 --- a/packages/api/src/Domain/Server/Subscription/SubscriptionServer.ts +++ b/packages/api/src/Domain/Server/Subscription/SubscriptionServer.ts @@ -1,4 +1,3 @@ -import { AppleIAPConfirmResponse } from './../../Response/Subscription/AppleIAPConfirmResponse' import { HttpServiceInterface } from '../../Http/HttpServiceInterface' import { AppleIAPConfirmRequestParams } from '../../Request' import { SubscriptionInviteAcceptRequestParams } from '../../Request/Subscription/SubscriptionInviteAcceptRequestParams' @@ -6,11 +5,13 @@ import { SubscriptionInviteCancelRequestParams } from '../../Request/Subscriptio import { SubscriptionInviteDeclineRequestParams } from '../../Request/Subscription/SubscriptionInviteDeclineRequestParams' import { SubscriptionInviteListRequestParams } from '../../Request/Subscription/SubscriptionInviteListRequestParams' import { SubscriptionInviteRequestParams } from '../../Request/Subscription/SubscriptionInviteRequestParams' -import { SubscriptionInviteAcceptResponse } from '../../Response/Subscription/SubscriptionInviteAcceptResponse' -import { SubscriptionInviteCancelResponse } from '../../Response/Subscription/SubscriptionInviteCancelResponse' -import { SubscriptionInviteDeclineResponse } from '../../Response/Subscription/SubscriptionInviteDeclineResponse' -import { SubscriptionInviteListResponse } from '../../Response/Subscription/SubscriptionInviteListResponse' -import { SubscriptionInviteResponse } from '../../Response/Subscription/SubscriptionInviteResponse' +import { AppleIAPConfirmResponseBody } from './../../Response/Subscription/AppleIAPConfirmResponseBody' +import { SubscriptionInviteAcceptResponseBody } from '../../Response/Subscription/SubscriptionInviteAcceptResponseBody' +import { SubscriptionInviteCancelResponseBody } from '../../Response/Subscription/SubscriptionInviteCancelResponseBody' +import { SubscriptionInviteDeclineResponseBody } from '../../Response/Subscription/SubscriptionInviteDeclineResponseBody' +import { SubscriptionInviteListResponseBody } from '../../Response/Subscription/SubscriptionInviteListResponseBody' +import { SubscriptionInviteResponseBody } from '../../Response/Subscription/SubscriptionInviteResponseBody' +import { HttpResponse } from '@standardnotes/responses' import { Paths } from './Paths' import { SubscriptionServerInterface } from './SubscriptionServerInterface' @@ -18,39 +19,35 @@ import { SubscriptionServerInterface } from './SubscriptionServerInterface' export class SubscriptionServer implements SubscriptionServerInterface { constructor(private httpService: HttpServiceInterface) {} - async acceptInvite(params: SubscriptionInviteAcceptRequestParams): Promise { - const response = await this.httpService.post(Paths.v1.acceptInvite(params.inviteUuid), params) - - return response as SubscriptionInviteAcceptResponse + async acceptInvite( + params: SubscriptionInviteAcceptRequestParams, + ): Promise> { + return this.httpService.post(Paths.v1.acceptInvite(params.inviteUuid), params) } - async declineInvite(params: SubscriptionInviteDeclineRequestParams): Promise { - const response = await this.httpService.get(Paths.v1.declineInvite(params.inviteUuid), params) - - return response as SubscriptionInviteDeclineResponse + async declineInvite( + params: SubscriptionInviteDeclineRequestParams, + ): Promise> { + return this.httpService.get(Paths.v1.declineInvite(params.inviteUuid), params) } - async cancelInvite(params: SubscriptionInviteCancelRequestParams): Promise { - const response = await this.httpService.delete(Paths.v1.cancelInvite(params.inviteUuid), params) - - return response as SubscriptionInviteCancelResponse + async cancelInvite( + params: SubscriptionInviteCancelRequestParams, + ): Promise> { + return this.httpService.delete(Paths.v1.cancelInvite(params.inviteUuid), params) } - async listInvites(params: SubscriptionInviteListRequestParams): Promise { - const response = await this.httpService.get(Paths.v1.listInvites, params) - - return response as SubscriptionInviteListResponse + async listInvites( + params: SubscriptionInviteListRequestParams, + ): Promise> { + return this.httpService.get(Paths.v1.listInvites, params) } - async invite(params: SubscriptionInviteRequestParams): Promise { - const response = await this.httpService.post(Paths.v1.invite, params) - - return response as SubscriptionInviteResponse + async invite(params: SubscriptionInviteRequestParams): Promise> { + return this.httpService.post(Paths.v1.invite, params) } - async confirmAppleIAP(params: AppleIAPConfirmRequestParams): Promise { - const response = await this.httpService.post(Paths.v1.confirmAppleIAP, params) - - return response as AppleIAPConfirmResponse + async confirmAppleIAP(params: AppleIAPConfirmRequestParams): Promise> { + return this.httpService.post(Paths.v1.confirmAppleIAP, params) } } diff --git a/packages/api/src/Domain/Server/Subscription/SubscriptionServerInterface.ts b/packages/api/src/Domain/Server/Subscription/SubscriptionServerInterface.ts index 48bba2ee8..9f1dd0799 100644 --- a/packages/api/src/Domain/Server/Subscription/SubscriptionServerInterface.ts +++ b/packages/api/src/Domain/Server/Subscription/SubscriptionServerInterface.ts @@ -1,21 +1,29 @@ -import { AppleIAPConfirmResponse } from './../../Response/Subscription/AppleIAPConfirmResponse' import { AppleIAPConfirmRequestParams } from './../../Request/Subscription/AppleIAPConfirmRequestParams' import { SubscriptionInviteAcceptRequestParams } from '../../Request/Subscription/SubscriptionInviteAcceptRequestParams' import { SubscriptionInviteCancelRequestParams } from '../../Request/Subscription/SubscriptionInviteCancelRequestParams' import { SubscriptionInviteDeclineRequestParams } from '../../Request/Subscription/SubscriptionInviteDeclineRequestParams' import { SubscriptionInviteListRequestParams } from '../../Request/Subscription/SubscriptionInviteListRequestParams' import { SubscriptionInviteRequestParams } from '../../Request/Subscription/SubscriptionInviteRequestParams' -import { SubscriptionInviteAcceptResponse } from '../../Response/Subscription/SubscriptionInviteAcceptResponse' -import { SubscriptionInviteCancelResponse } from '../../Response/Subscription/SubscriptionInviteCancelResponse' -import { SubscriptionInviteDeclineResponse } from '../../Response/Subscription/SubscriptionInviteDeclineResponse' -import { SubscriptionInviteListResponse } from '../../Response/Subscription/SubscriptionInviteListResponse' -import { SubscriptionInviteResponse } from '../../Response/Subscription/SubscriptionInviteResponse' + +import { AppleIAPConfirmResponseBody } from './../../Response/Subscription/AppleIAPConfirmResponseBody' +import { SubscriptionInviteAcceptResponseBody } from '../../Response/Subscription/SubscriptionInviteAcceptResponseBody' +import { SubscriptionInviteCancelResponseBody } from '../../Response/Subscription/SubscriptionInviteCancelResponseBody' +import { SubscriptionInviteDeclineResponseBody } from '../../Response/Subscription/SubscriptionInviteDeclineResponseBody' +import { SubscriptionInviteListResponseBody } from '../../Response/Subscription/SubscriptionInviteListResponseBody' +import { SubscriptionInviteResponseBody } from '../../Response/Subscription/SubscriptionInviteResponseBody' +import { HttpResponse } from '@standardnotes/responses' export interface SubscriptionServerInterface { - invite(params: SubscriptionInviteRequestParams): Promise - acceptInvite(params: SubscriptionInviteAcceptRequestParams): Promise - declineInvite(params: SubscriptionInviteDeclineRequestParams): Promise - cancelInvite(params: SubscriptionInviteCancelRequestParams): Promise - listInvites(params: SubscriptionInviteListRequestParams): Promise - confirmAppleIAP(params: AppleIAPConfirmRequestParams): Promise + invite(params: SubscriptionInviteRequestParams): Promise> + acceptInvite( + params: SubscriptionInviteAcceptRequestParams, + ): Promise> + declineInvite( + params: SubscriptionInviteDeclineRequestParams, + ): Promise> + cancelInvite( + params: SubscriptionInviteCancelRequestParams, + ): Promise> + listInvites(params: SubscriptionInviteListRequestParams): Promise> + confirmAppleIAP(params: AppleIAPConfirmRequestParams): Promise> } diff --git a/packages/api/src/Domain/Server/User/UserServer.ts b/packages/api/src/Domain/Server/User/UserServer.ts index a18a3e8d3..7b5e22838 100644 --- a/packages/api/src/Domain/Server/User/UserServer.ts +++ b/packages/api/src/Domain/Server/User/UserServer.ts @@ -1,23 +1,20 @@ import { HttpServiceInterface } from '../../Http/HttpServiceInterface' import { UserDeletionRequestParams } from '../../Request/User/UserDeletionRequestParams' import { UserRegistrationRequestParams } from '../../Request/User/UserRegistrationRequestParams' -import { UserDeletionResponse } from '../../Response/User/UserDeletionResponse' -import { UserRegistrationResponse } from '../../Response/User/UserRegistrationResponse' +import { HttpResponse } from '@standardnotes/responses' +import { UserDeletionResponseBody } from '../../Response/User/UserDeletionResponseBody' +import { UserRegistrationResponseBody } from '../../Response/User/UserRegistrationResponseBody' import { Paths } from './Paths' import { UserServerInterface } from './UserServerInterface' export class UserServer implements UserServerInterface { constructor(private httpService: HttpServiceInterface) {} - async deleteAccount(params: UserDeletionRequestParams): Promise { - const response = await this.httpService.delete(Paths.v1.deleteAccount(params.userUuid), params) - - return response as UserDeletionResponse + async deleteAccount(params: UserDeletionRequestParams): Promise> { + return this.httpService.delete(Paths.v1.deleteAccount(params.userUuid), params) } - async register(params: UserRegistrationRequestParams): Promise { - const response = await this.httpService.post(Paths.v1.register, params) - - return response as UserRegistrationResponse + async register(params: UserRegistrationRequestParams): Promise> { + return this.httpService.post(Paths.v1.register, params) } } diff --git a/packages/api/src/Domain/Server/User/UserServerInterface.ts b/packages/api/src/Domain/Server/User/UserServerInterface.ts index 67c796861..b2016019b 100644 --- a/packages/api/src/Domain/Server/User/UserServerInterface.ts +++ b/packages/api/src/Domain/Server/User/UserServerInterface.ts @@ -1,9 +1,10 @@ +import { HttpResponse } from '@standardnotes/responses' import { UserDeletionRequestParams } from '../../Request/User/UserDeletionRequestParams' import { UserRegistrationRequestParams } from '../../Request/User/UserRegistrationRequestParams' -import { UserDeletionResponse } from '../../Response/User/UserDeletionResponse' -import { UserRegistrationResponse } from '../../Response/User/UserRegistrationResponse' +import { UserDeletionResponseBody } from '../../Response/User/UserDeletionResponseBody' +import { UserRegistrationResponseBody } from '../../Response/User/UserRegistrationResponseBody' export interface UserServerInterface { - register(params: UserRegistrationRequestParams): Promise - deleteAccount(params: UserDeletionRequestParams): Promise + register(params: UserRegistrationRequestParams): Promise> + deleteAccount(params: UserDeletionRequestParams): Promise> } diff --git a/packages/api/src/Domain/Server/UserRequest/UserRequestServer.ts b/packages/api/src/Domain/Server/UserRequest/UserRequestServer.ts index 1c8273e14..8b00e4def 100644 --- a/packages/api/src/Domain/Server/UserRequest/UserRequestServer.ts +++ b/packages/api/src/Domain/Server/UserRequest/UserRequestServer.ts @@ -1,6 +1,7 @@ import { HttpServiceInterface } from '../../Http/HttpServiceInterface' import { UserRequestRequestParams } from '../../Request/UserRequest/UserRequestRequestParams' -import { UserRequestResponse } from '../../Response/UserRequest/UserRequestResponse' +import { HttpResponse } from '@standardnotes/responses' +import { UserRequestResponseBody } from '../../Response/UserRequest/UserRequestResponseBody' import { Paths } from './Paths' import { UserRequestServerInterface } from './UserRequestServerInterface' @@ -8,9 +9,7 @@ import { UserRequestServerInterface } from './UserRequestServerInterface' export class UserRequestServer implements UserRequestServerInterface { constructor(private httpService: HttpServiceInterface) {} - async submitUserRequest(params: UserRequestRequestParams): Promise { - const response = await this.httpService.post(Paths.v1.submitUserRequest(params.userUuid), params) - - return response as UserRequestResponse + async submitUserRequest(params: UserRequestRequestParams): Promise> { + return this.httpService.post(Paths.v1.submitUserRequest(params.userUuid), params) } } diff --git a/packages/api/src/Domain/Server/UserRequest/UserRequestServerInterface.ts b/packages/api/src/Domain/Server/UserRequest/UserRequestServerInterface.ts index 0a06d37d5..bd92e6eab 100644 --- a/packages/api/src/Domain/Server/UserRequest/UserRequestServerInterface.ts +++ b/packages/api/src/Domain/Server/UserRequest/UserRequestServerInterface.ts @@ -1,6 +1,7 @@ +import { HttpResponse } from '@standardnotes/responses' import { UserRequestRequestParams } from '../../Request/UserRequest/UserRequestRequestParams' -import { UserRequestResponse } from '../../Response/UserRequest/UserRequestResponse' +import { UserRequestResponseBody } from '../../Response/UserRequest/UserRequestResponseBody' export interface UserRequestServerInterface { - submitUserRequest(params: UserRequestRequestParams): Promise + submitUserRequest(params: UserRequestRequestParams): Promise> } diff --git a/packages/api/src/Domain/Server/WebSocket/WebSocketServer.ts b/packages/api/src/Domain/Server/WebSocket/WebSocketServer.ts index 19213b2d6..fd6b2f963 100644 --- a/packages/api/src/Domain/Server/WebSocket/WebSocketServer.ts +++ b/packages/api/src/Domain/Server/WebSocket/WebSocketServer.ts @@ -1,6 +1,7 @@ import { HttpServiceInterface } from '../../Http/HttpServiceInterface' import { WebSocketConnectionTokenRequestParams } from '../../Request/WebSocket/WebSocketConnectionTokenRequestParams' -import { WebSocketConnectionTokenResponse } from '../../Response/WebSocket/WebSocketConnectionTokenResponse' +import { HttpResponse } from '@standardnotes/responses' +import { WebSocketConnectionTokenResponseBody } from '../../Response/WebSocket/WebSocketConnectionTokenResponseBody' import { Paths } from './Paths' import { WebSocketServerInterface } from './WebSocketServerInterface' @@ -9,9 +10,7 @@ export class WebSocketServer implements WebSocketServerInterface { async createConnectionToken( params: WebSocketConnectionTokenRequestParams, - ): Promise { - const response = await this.httpService.post(Paths.v1.createConnectionToken, params) - - return response as WebSocketConnectionTokenResponse + ): Promise> { + return this.httpService.post(Paths.v1.createConnectionToken, params) } } diff --git a/packages/api/src/Domain/Server/WebSocket/WebSocketServerInterface.ts b/packages/api/src/Domain/Server/WebSocket/WebSocketServerInterface.ts index 3faec05a5..c6204b798 100644 --- a/packages/api/src/Domain/Server/WebSocket/WebSocketServerInterface.ts +++ b/packages/api/src/Domain/Server/WebSocket/WebSocketServerInterface.ts @@ -1,6 +1,9 @@ +import { HttpResponse } from '@standardnotes/responses' import { WebSocketConnectionTokenRequestParams } from '../../Request/WebSocket/WebSocketConnectionTokenRequestParams' -import { WebSocketConnectionTokenResponse } from '../../Response/WebSocket/WebSocketConnectionTokenResponse' +import { WebSocketConnectionTokenResponseBody } from '../../Response/WebSocket/WebSocketConnectionTokenResponseBody' export interface WebSocketServerInterface { - createConnectionToken(params: WebSocketConnectionTokenRequestParams): Promise + createConnectionToken( + params: WebSocketConnectionTokenRequestParams, + ): Promise> } diff --git a/packages/encryption/src/Domain/Keys/RootKey/KeyParamsFunctions.ts b/packages/encryption/src/Domain/Keys/RootKey/KeyParamsFunctions.ts index 885a84570..672ad0b79 100644 --- a/packages/encryption/src/Domain/Keys/RootKey/KeyParamsFunctions.ts +++ b/packages/encryption/src/Domain/Keys/RootKey/KeyParamsFunctions.ts @@ -48,13 +48,13 @@ export function CreateAnyKeyParams(keyParams: AnyKeyParamsContent) { export function KeyParamsFromApiResponse(response: KeyParamsResponse, identifier?: string) { const rawKeyParams: AnyKeyParamsContent = { - identifier: identifier || response.data.identifier!, - pw_cost: response.data.pw_cost!, - pw_nonce: response.data.pw_nonce!, - pw_salt: response.data.pw_salt!, - version: ProtocolVersionForKeyParams(response.data), - origination: response.data.origination, - created: response.data.created, + identifier: identifier || response.identifier!, + pw_cost: response.pw_cost!, + pw_nonce: response.pw_nonce!, + pw_salt: response.pw_salt!, + version: ProtocolVersionForKeyParams(response), + origination: response.origination, + created: response.created, } return CreateAnyKeyParams(rawKeyParams) } diff --git a/packages/files/src/Domain/Api/FilesApiInterface.ts b/packages/files/src/Domain/Api/FilesApiInterface.ts index 9060043b3..07bae17ab 100644 --- a/packages/files/src/Domain/Api/FilesApiInterface.ts +++ b/packages/files/src/Domain/Api/FilesApiInterface.ts @@ -1,8 +1,8 @@ -import { StartUploadSessionResponse, MinimalHttpResponse, ClientDisplayableError } from '@standardnotes/responses' +import { StartUploadSessionResponse, HttpResponse, ClientDisplayableError } from '@standardnotes/responses' import { FileContent } from '@standardnotes/models' export interface FilesApiInterface { - startUploadSession(apiToken: string): Promise + startUploadSession(apiToken: string): Promise> uploadFileBytes(apiToken: string, chunkId: number, encryptedBytes: Uint8Array): Promise @@ -16,7 +16,7 @@ export interface FilesApiInterface { onBytesReceived: (bytes: Uint8Array) => Promise, ): Promise - deleteFile(apiToken: string): Promise + deleteFile(apiToken: string): Promise createFileValetToken( remoteIdentifier: string, diff --git a/packages/responses/src/Domain/Auth/ChangeCredentialsResponse.ts b/packages/responses/src/Domain/Auth/ChangeCredentialsResponse.ts index 4b451f1a5..148da600e 100644 --- a/packages/responses/src/Domain/Auth/ChangeCredentialsResponse.ts +++ b/packages/responses/src/Domain/Auth/ChangeCredentialsResponse.ts @@ -1,6 +1,3 @@ -import { HttpResponse } from '../Http/HttpResponse' import { ChangeCredentialsData } from './ChangeCredentialsData' -export type ChangeCredentialsResponse = HttpResponse & { - data: ChangeCredentialsData -} +export type ChangeCredentialsResponse = ChangeCredentialsData diff --git a/packages/responses/src/Domain/Auth/KeyParamsResponse.ts b/packages/responses/src/Domain/Auth/KeyParamsResponse.ts index 23a7bb562..4f73e3f26 100644 --- a/packages/responses/src/Domain/Auth/KeyParamsResponse.ts +++ b/packages/responses/src/Domain/Auth/KeyParamsResponse.ts @@ -1,6 +1,3 @@ -import { HttpResponse } from '../Http/HttpResponse' import { KeyParamsData } from './KeyParamsData' -export type KeyParamsResponse = HttpResponse & { - data: KeyParamsData -} +export type KeyParamsResponse = KeyParamsData diff --git a/packages/responses/src/Domain/Auth/RegistrationResponse.ts b/packages/responses/src/Domain/Auth/RegistrationResponse.ts index 4ca7d30ee..0483e9f33 100644 --- a/packages/responses/src/Domain/Auth/RegistrationResponse.ts +++ b/packages/responses/src/Domain/Auth/RegistrationResponse.ts @@ -1,6 +1,3 @@ -import { HttpResponse } from '../Http/HttpResponse' import { RegistrationData } from './RegistrationData' -export type RegistrationResponse = HttpResponse & { - data: RegistrationData -} +export type RegistrationResponse = RegistrationData diff --git a/packages/responses/src/Domain/Auth/SessionListResponse.ts b/packages/responses/src/Domain/Auth/SessionListResponse.ts index f35eb6fe6..764c8890e 100644 --- a/packages/responses/src/Domain/Auth/SessionListResponse.ts +++ b/packages/responses/src/Domain/Auth/SessionListResponse.ts @@ -1,4 +1,3 @@ -import { HttpResponse } from '../Http/HttpResponse' import { SessionListEntry } from './SessionListEntry' -export type SessionListResponse = HttpResponse & { data: SessionListEntry[] } +export type SessionListResponse = SessionListEntry[] diff --git a/packages/responses/src/Domain/Auth/SessionRenewalResponse.ts b/packages/responses/src/Domain/Auth/SessionRenewalResponse.ts index 46740600d..d3beca2b5 100644 --- a/packages/responses/src/Domain/Auth/SessionRenewalResponse.ts +++ b/packages/responses/src/Domain/Auth/SessionRenewalResponse.ts @@ -1,6 +1,3 @@ -import { HttpResponse } from '../Http/HttpResponse' import { SessionRenewalData } from './SessionRenewalData' -export type SessionRenewalResponse = HttpResponse & { - data: SessionRenewalData -} +export type SessionRenewalResponse = SessionRenewalData diff --git a/packages/responses/src/Domain/Auth/SignInResponse.ts b/packages/responses/src/Domain/Auth/SignInResponse.ts index 44efa2bff..2973cf882 100644 --- a/packages/responses/src/Domain/Auth/SignInResponse.ts +++ b/packages/responses/src/Domain/Auth/SignInResponse.ts @@ -1,6 +1,3 @@ -import { HttpResponse } from '../Http/HttpResponse' import { SignInData } from './SignInData' -export type SignInResponse = HttpResponse & { - data: SignInData -} +export type SignInResponse = SignInData diff --git a/packages/responses/src/Domain/Auth/SignOutResponse.ts b/packages/responses/src/Domain/Auth/SignOutResponse.ts index 9141940cd..a0c40ce7f 100644 --- a/packages/responses/src/Domain/Auth/SignOutResponse.ts +++ b/packages/responses/src/Domain/Auth/SignOutResponse.ts @@ -1,3 +1,3 @@ -import { HttpResponse } from '../Http/HttpResponse' +import { HttpSuccessResponse } from '../Http/HttpResponse' -export type SignOutResponse = HttpResponse & Record +export type SignOutResponse = HttpSuccessResponse diff --git a/packages/responses/src/Domain/Error/ClientError.ts b/packages/responses/src/Domain/Error/ClientError.ts index 1693b71ab..fa04f0055 100644 --- a/packages/responses/src/Domain/Error/ClientError.ts +++ b/packages/responses/src/Domain/Error/ClientError.ts @@ -1,11 +1,9 @@ -import { Error } from '../Http/Error' - export class ClientDisplayableError { constructor(public text: string, public title?: string, public tag?: string) { console.error('Client Displayable Error:', text, title || '', tag || '') } - static FromError(error: Error) { + static FromError(error: { message: string; tag?: string }) { return new ClientDisplayableError(error.message, undefined, error.tag) } } diff --git a/packages/responses/src/Domain/Files/CloseUploadSessionResponse.ts b/packages/responses/src/Domain/Files/CloseUploadSessionResponse.ts index 3e3890233..13807bc3f 100644 --- a/packages/responses/src/Domain/Files/CloseUploadSessionResponse.ts +++ b/packages/responses/src/Domain/Files/CloseUploadSessionResponse.ts @@ -1,6 +1 @@ -import { MinimalHttpResponse } from '../Http/MinimalHttpResponses' - -export type CloseUploadSessionResponse = MinimalHttpResponse & { - success: boolean - message: string -} +export type CloseUploadSessionResponse = { success: boolean; message: string } diff --git a/packages/responses/src/Domain/Files/CreateValetTokenResponse.ts b/packages/responses/src/Domain/Files/CreateValetTokenResponse.ts index 859eb34d3..945d1bcda 100644 --- a/packages/responses/src/Domain/Files/CreateValetTokenResponse.ts +++ b/packages/responses/src/Domain/Files/CreateValetTokenResponse.ts @@ -1,6 +1,3 @@ -import { MinimalHttpResponse } from '../Http/MinimalHttpResponses' import { CreateValetTokenResponseData } from './CreateValetTokenResponseData' -export type CreateValetTokenResponse = MinimalHttpResponse & { - data: CreateValetTokenResponseData -} +export type CreateValetTokenResponse = CreateValetTokenResponseData diff --git a/packages/responses/src/Domain/Files/DownloadFileChunkResponse.ts b/packages/responses/src/Domain/Files/DownloadFileChunkResponse.ts index d563f3b67..99c1fe233 100644 --- a/packages/responses/src/Domain/Files/DownloadFileChunkResponse.ts +++ b/packages/responses/src/Domain/Files/DownloadFileChunkResponse.ts @@ -1,5 +1 @@ -import { MinimalHttpResponse } from '../Http/MinimalHttpResponses' - -export type DownloadFileChunkResponse = MinimalHttpResponse & { - data: ArrayBuffer -} +export type DownloadFileChunkResponse = ArrayBuffer diff --git a/packages/responses/src/Domain/Files/StartUploadSessionResponse.ts b/packages/responses/src/Domain/Files/StartUploadSessionResponse.ts index 97d6392cf..cd3a8e99f 100644 --- a/packages/responses/src/Domain/Files/StartUploadSessionResponse.ts +++ b/packages/responses/src/Domain/Files/StartUploadSessionResponse.ts @@ -1,6 +1,4 @@ -import { MinimalHttpResponse } from '../Http/MinimalHttpResponses' - -export type StartUploadSessionResponse = MinimalHttpResponse & { +export type StartUploadSessionResponse = { success: boolean uploadId: string } diff --git a/packages/responses/src/Domain/Files/UploadFileChunkResponse.ts b/packages/responses/src/Domain/Files/UploadFileChunkResponse.ts index ed63813f0..0c6b70c17 100644 --- a/packages/responses/src/Domain/Files/UploadFileChunkResponse.ts +++ b/packages/responses/src/Domain/Files/UploadFileChunkResponse.ts @@ -1,5 +1,3 @@ -import { MinimalHttpResponse } from '../Http/MinimalHttpResponses' - -export type UploadFileChunkResponse = MinimalHttpResponse & { +export type UploadFileChunkResponse = { success: boolean } diff --git a/packages/responses/src/Domain/Http/DeprecatedError.ts b/packages/responses/src/Domain/Http/DeprecatedError.ts new file mode 100644 index 000000000..dae9177e4 --- /dev/null +++ b/packages/responses/src/Domain/Http/DeprecatedError.ts @@ -0,0 +1,5 @@ +export type DeprecatedError = { + message: string + status: number + tag?: string +} diff --git a/packages/responses/src/Domain/Http/DeprecatedHttpResponse.ts b/packages/responses/src/Domain/Http/DeprecatedHttpResponse.ts new file mode 100644 index 000000000..fe67cbeb7 --- /dev/null +++ b/packages/responses/src/Domain/Http/DeprecatedHttpResponse.ts @@ -0,0 +1,13 @@ +import { DeprecatedError } from './DeprecatedError' +import { HttpStatusCode } from './HttpStatusCode' +import { DeprecatedResponseMeta } from './DeprecatedResponseMeta' + +export type DeprecatedHttpResponse = { + status: HttpStatusCode + error?: DeprecatedError + data?: { + error?: DeprecatedError + } + meta?: DeprecatedResponseMeta + headers?: Map +} diff --git a/packages/responses/src/Domain/Http/DeprecatedMinimalHttpResponses.ts b/packages/responses/src/Domain/Http/DeprecatedMinimalHttpResponses.ts new file mode 100644 index 000000000..c51831fdf --- /dev/null +++ b/packages/responses/src/Domain/Http/DeprecatedMinimalHttpResponses.ts @@ -0,0 +1,8 @@ +import { DeprecatedError } from './DeprecatedError' +import { HttpStatusCode } from './HttpStatusCode' + +export type DeprecatedMinimalHttpResponse = { + status: HttpStatusCode + error?: DeprecatedError + headers?: Map +} diff --git a/packages/responses/src/Domain/Http/ResponseMeta.ts b/packages/responses/src/Domain/Http/DeprecatedResponseMeta.ts similarity index 79% rename from packages/responses/src/Domain/Http/ResponseMeta.ts rename to packages/responses/src/Domain/Http/DeprecatedResponseMeta.ts index e21278419..2957694fc 100644 --- a/packages/responses/src/Domain/Http/ResponseMeta.ts +++ b/packages/responses/src/Domain/Http/DeprecatedResponseMeta.ts @@ -1,6 +1,6 @@ import { Role } from '@standardnotes/security' -export type ResponseMeta = { +export type DeprecatedResponseMeta = { auth: { userUuid?: string roles?: Role[] diff --git a/packages/responses/src/Domain/Http/StatusCode.ts b/packages/responses/src/Domain/Http/DeprecatedStatusCode.ts similarity index 91% rename from packages/responses/src/Domain/Http/StatusCode.ts rename to packages/responses/src/Domain/Http/DeprecatedStatusCode.ts index da009f76e..f8236103b 100644 --- a/packages/responses/src/Domain/Http/StatusCode.ts +++ b/packages/responses/src/Domain/Http/DeprecatedStatusCode.ts @@ -1,7 +1,6 @@ -export enum StatusCode { +export enum DeprecatedStatusCode { LocalValidationError = 10, CanceledMfa = 11, - UnknownError = 12, HttpStatusMinSuccess = 200, HttpStatusNoContent = 204, diff --git a/packages/responses/src/Domain/Http/Error.ts b/packages/responses/src/Domain/Http/Error.ts deleted file mode 100644 index e62d465f0..000000000 --- a/packages/responses/src/Domain/Http/Error.ts +++ /dev/null @@ -1,10 +0,0 @@ -export type Error = { - message: string - status: number - tag?: string - /** In the case of MFA required responses, - * the required prompt is returned as part of the error */ - payload?: { - mfa_key?: string - } -} diff --git a/packages/api/src/Domain/Http/ErrorTag.ts b/packages/responses/src/Domain/Http/ErrorTag.ts similarity index 80% rename from packages/api/src/Domain/Http/ErrorTag.ts rename to packages/responses/src/Domain/Http/ErrorTag.ts index 52772a125..715c3a4be 100644 --- a/packages/api/src/Domain/Http/ErrorTag.ts +++ b/packages/responses/src/Domain/Http/ErrorTag.ts @@ -9,4 +9,7 @@ export enum ErrorTag { RevokedSession = 'revoked-session', AuthInvalid = 'invalid-auth', ReadOnlyAccess = 'read-only-access', + + ClientValidationError = 'client-validation-error', + ClientCanceledMfa = 'client-canceled-mfa', } diff --git a/packages/responses/src/Domain/Http/Functions.ts b/packages/responses/src/Domain/Http/Functions.ts deleted file mode 100644 index 4fc2de34e..000000000 --- a/packages/responses/src/Domain/Http/Functions.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { HttpResponse } from './HttpResponse' -import { StatusCode } from './StatusCode' - -export function isErrorResponseExpiredToken(errorResponse: HttpResponse): boolean { - return errorResponse.status === StatusCode.HttpStatusExpiredAccessToken -} diff --git a/packages/responses/src/Domain/Http/HttpError.ts b/packages/responses/src/Domain/Http/HttpError.ts new file mode 100644 index 000000000..32d7c6cee --- /dev/null +++ b/packages/responses/src/Domain/Http/HttpError.ts @@ -0,0 +1,6 @@ +import { ErrorTag } from './ErrorTag' + +export type HttpError = { + message: string + tag?: ErrorTag +} diff --git a/packages/responses/src/Domain/Http/HttpErrorResponseBody.ts b/packages/responses/src/Domain/Http/HttpErrorResponseBody.ts new file mode 100644 index 000000000..6ec191c98 --- /dev/null +++ b/packages/responses/src/Domain/Http/HttpErrorResponseBody.ts @@ -0,0 +1,5 @@ +import { HttpError } from './HttpError' + +export type HttpErrorResponseBody = { + error: HttpError +} diff --git a/packages/api/src/Domain/Http/HttpHeaders.ts b/packages/responses/src/Domain/Http/HttpHeaders.ts similarity index 100% rename from packages/api/src/Domain/Http/HttpHeaders.ts rename to packages/responses/src/Domain/Http/HttpHeaders.ts diff --git a/packages/api/src/Domain/Http/HttpRequest.ts b/packages/responses/src/Domain/Http/HttpRequest.ts similarity index 100% rename from packages/api/src/Domain/Http/HttpRequest.ts rename to packages/responses/src/Domain/Http/HttpRequest.ts diff --git a/packages/api/src/Domain/Http/HttpRequestParams.ts b/packages/responses/src/Domain/Http/HttpRequestParams.ts similarity index 100% rename from packages/api/src/Domain/Http/HttpRequestParams.ts rename to packages/responses/src/Domain/Http/HttpRequestParams.ts diff --git a/packages/responses/src/Domain/Http/HttpResponse.ts b/packages/responses/src/Domain/Http/HttpResponse.ts index a9c8a556f..0f3536d8b 100644 --- a/packages/responses/src/Domain/Http/HttpResponse.ts +++ b/packages/responses/src/Domain/Http/HttpResponse.ts @@ -1,13 +1,26 @@ -import { StatusCode } from './StatusCode' -import { Error } from './Error' -import { ResponseMeta } from './ResponseMeta' +import { HttpErrorResponseBody } from './HttpErrorResponseBody' +import { HttpResponseMeta } from './HttpResponseMeta' +import { HttpHeaders } from './HttpHeaders' +import { HttpStatusCode } from './HttpStatusCode' -export type HttpResponse = { - status?: StatusCode - error?: Error - data?: { - error?: Error - } - meta?: ResponseMeta - headers?: Map +type AnySuccessRecord = Record & { error?: never } + +interface HttpResponseBase { + status: HttpStatusCode + meta?: HttpResponseMeta + headers?: HttpHeaders +} + +export interface HttpErrorResponse extends HttpResponseBase { + data: HttpErrorResponseBody +} + +export interface HttpSuccessResponse extends HttpResponseBase { + data: T +} + +export type HttpResponse = HttpErrorResponse | HttpSuccessResponse + +export function isErrorResponse(response: HttpResponse): response is HttpErrorResponse { + return (response.data as HttpErrorResponseBody)?.error != undefined } diff --git a/packages/api/src/Domain/Http/HttpResponseMeta.ts b/packages/responses/src/Domain/Http/HttpResponseMeta.ts similarity index 100% rename from packages/api/src/Domain/Http/HttpResponseMeta.ts rename to packages/responses/src/Domain/Http/HttpResponseMeta.ts diff --git a/packages/api/src/Domain/Http/HttpStatusCode.ts b/packages/responses/src/Domain/Http/HttpStatusCode.ts similarity index 100% rename from packages/api/src/Domain/Http/HttpStatusCode.ts rename to packages/responses/src/Domain/Http/HttpStatusCode.ts diff --git a/packages/api/src/Domain/Http/HttpVerb.ts b/packages/responses/src/Domain/Http/HttpVerb.ts similarity index 100% rename from packages/api/src/Domain/Http/HttpVerb.ts rename to packages/responses/src/Domain/Http/HttpVerb.ts diff --git a/packages/responses/src/Domain/Http/MinimalHttpResponses.ts b/packages/responses/src/Domain/Http/MinimalHttpResponses.ts deleted file mode 100644 index d80cd1c9a..000000000 --- a/packages/responses/src/Domain/Http/MinimalHttpResponses.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { StatusCode } from './StatusCode' -import { Error } from './Error' - -export type MinimalHttpResponse = { - status?: StatusCode - error?: Error - headers?: Map -} diff --git a/packages/responses/src/Domain/Http/index.ts b/packages/responses/src/Domain/Http/index.ts new file mode 100644 index 000000000..0d30679e1 --- /dev/null +++ b/packages/responses/src/Domain/Http/index.ts @@ -0,0 +1,15 @@ +export * from './ErrorTag' +export * from './HttpErrorResponseBody' +export * from './HttpHeaders' +export * from './HttpRequest' +export * from './HttpRequestParams' +export * from './HttpResponse' +export * from './HttpResponseMeta' +export * from './HttpVerb' +export * from './DeprecatedError' +export * from './DeprecatedHttpResponse' +export * from './DeprecatedMinimalHttpResponses' +export * from './DeprecatedResponseMeta' +export * from './DeprecatedStatusCode' +export * from './HttpStatusCode' +export * from './HttpError' diff --git a/packages/responses/src/Domain/Item/CheckIntegrityResponse.ts b/packages/responses/src/Domain/Item/CheckIntegrityResponse.ts index 691b4838e..65ac6b6e0 100644 --- a/packages/responses/src/Domain/Item/CheckIntegrityResponse.ts +++ b/packages/responses/src/Domain/Item/CheckIntegrityResponse.ts @@ -1,8 +1,5 @@ -import { MinimalHttpResponse } from '../Http/MinimalHttpResponses' import { IntegrityPayload } from './IntegrityPayload' -export type CheckIntegrityResponse = MinimalHttpResponse & { - data: { - mismatches: IntegrityPayload[] - } +export type CheckIntegrityResponse = { + mismatches: IntegrityPayload[] } diff --git a/packages/responses/src/Domain/Item/GetSingleItemResponse.ts b/packages/responses/src/Domain/Item/GetSingleItemResponse.ts index 7cb334400..0446f5003 100644 --- a/packages/responses/src/Domain/Item/GetSingleItemResponse.ts +++ b/packages/responses/src/Domain/Item/GetSingleItemResponse.ts @@ -1,14 +1,11 @@ -import { MinimalHttpResponse } from '../Http/MinimalHttpResponses' import { ServerItemResponse } from './ServerItemResponse' -export type GetSingleItemResponse = MinimalHttpResponse & { - data: - | { - success: true - item: ServerItemResponse - } - | { - success: false - message: string - } -} +export type GetSingleItemResponse = + | { + success: true + item: ServerItemResponse + } + | { + success: false + message: string + } diff --git a/packages/responses/src/Domain/Item/RawSyncResponse.ts b/packages/responses/src/Domain/Item/RawSyncResponse.ts index 7308ee6d1..53299e64a 100644 --- a/packages/responses/src/Domain/Item/RawSyncResponse.ts +++ b/packages/responses/src/Domain/Item/RawSyncResponse.ts @@ -1,4 +1,3 @@ -import { HttpResponse } from '../Http/HttpResponse' import { RawSyncData } from './RawSyncData' -export type RawSyncResponse = HttpResponse & { data: RawSyncData } +export type RawSyncResponse = RawSyncData diff --git a/packages/responses/src/Domain/Listed/ActionResponse.ts b/packages/responses/src/Domain/Listed/ActionResponse.ts index 1c931d8f9..0b61db50b 100644 --- a/packages/responses/src/Domain/Listed/ActionResponse.ts +++ b/packages/responses/src/Domain/Listed/ActionResponse.ts @@ -1,8 +1,8 @@ import { AnyKeyParamsContent, ContentType } from '@standardnotes/common' -import { HttpResponse } from '../Http/HttpResponse' +import { DeprecatedHttpResponse } from '../Http/DeprecatedHttpResponse' import { ServerItemResponse } from '../Item/ServerItemResponse' -export type ActionResponse = HttpResponse & { +export type ActionResponse = DeprecatedHttpResponse & { description: string supported_types: ContentType[] deprecation?: string diff --git a/packages/responses/src/Domain/Listed/ListedAccountInfoResponse.ts b/packages/responses/src/Domain/Listed/ListedAccountInfoResponse.ts index 13e415466..00a0adb84 100644 --- a/packages/responses/src/Domain/Listed/ListedAccountInfoResponse.ts +++ b/packages/responses/src/Domain/Listed/ListedAccountInfoResponse.ts @@ -1,6 +1,3 @@ -import { HttpResponse } from '../Http/HttpResponse' import { ListedAccountInfo } from './ListedAccountInfo' -export type ListedAccountInfoResponse = HttpResponse & { - data: ListedAccountInfo -} +export type ListedAccountInfoResponse = ListedAccountInfo diff --git a/packages/responses/src/Domain/Listed/ListedRegistrationResponse.ts b/packages/responses/src/Domain/Listed/ListedRegistrationResponse.ts index 977d4be39..04ba477cc 100644 --- a/packages/responses/src/Domain/Listed/ListedRegistrationResponse.ts +++ b/packages/responses/src/Domain/Listed/ListedRegistrationResponse.ts @@ -1,5 +1 @@ -import { MinimalHttpResponse } from '../Http/MinimalHttpResponses' - -export type ListedRegistrationResponse = MinimalHttpResponse & { - data?: unknown -} +export type ListedRegistrationResponse = unknown diff --git a/packages/responses/src/Domain/User/DeleteSettingResponse.ts b/packages/responses/src/Domain/User/DeleteSettingResponse.ts index cf2b77cda..9471f77dc 100644 --- a/packages/responses/src/Domain/User/DeleteSettingResponse.ts +++ b/packages/responses/src/Domain/User/DeleteSettingResponse.ts @@ -1,3 +1,3 @@ -import { MinimalHttpResponse } from '../Http/MinimalHttpResponses' +import { HttpResponse } from '../Http/HttpResponse' -export type DeleteSettingResponse = MinimalHttpResponse +export type DeleteSettingResponse = HttpResponse diff --git a/packages/responses/src/Domain/User/GetAvailableSubscriptionsResponse.ts b/packages/responses/src/Domain/User/GetAvailableSubscriptionsResponse.ts index aed440c18..70c4c45ae 100644 --- a/packages/responses/src/Domain/User/GetAvailableSubscriptionsResponse.ts +++ b/packages/responses/src/Domain/User/GetAvailableSubscriptionsResponse.ts @@ -1,6 +1,3 @@ -import { MinimalHttpResponse } from '../Http/MinimalHttpResponses' import { AvailableSubscriptions } from './AvailableSubscriptions' -export type GetAvailableSubscriptionsResponse = MinimalHttpResponse & { - data?: AvailableSubscriptions -} +export type GetAvailableSubscriptionsResponse = AvailableSubscriptions diff --git a/packages/responses/src/Domain/User/GetOfflineFeaturesResponse.ts b/packages/responses/src/Domain/User/GetOfflineFeaturesResponse.ts index 4c564ab1f..ed94ddab5 100644 --- a/packages/responses/src/Domain/User/GetOfflineFeaturesResponse.ts +++ b/packages/responses/src/Domain/User/GetOfflineFeaturesResponse.ts @@ -1,9 +1,6 @@ import { FeatureDescription } from '@standardnotes/features' -import { MinimalHttpResponse } from '../Http/MinimalHttpResponses' -export type GetOfflineFeaturesResponse = MinimalHttpResponse & { - data?: { - features: FeatureDescription[] - roles: string[] - } +export type GetOfflineFeaturesResponse = { + features: FeatureDescription[] + roles: string[] } diff --git a/packages/responses/src/Domain/User/GetSettingResponse.ts b/packages/responses/src/Domain/User/GetSettingResponse.ts index ccda9aea2..d1fb7abae 100644 --- a/packages/responses/src/Domain/User/GetSettingResponse.ts +++ b/packages/responses/src/Domain/User/GetSettingResponse.ts @@ -1,9 +1,6 @@ -import { MinimalHttpResponse } from '../Http/MinimalHttpResponses' import { SettingData } from './SettingData' -export type GetSettingResponse = MinimalHttpResponse & { - data?: { - success?: boolean - setting?: SettingData - } +export type GetSettingResponse = { + success?: boolean + setting?: SettingData } diff --git a/packages/responses/src/Domain/User/GetSubscriptionResponse.ts b/packages/responses/src/Domain/User/GetSubscriptionResponse.ts index d926b31b1..a6608474b 100644 --- a/packages/responses/src/Domain/User/GetSubscriptionResponse.ts +++ b/packages/responses/src/Domain/User/GetSubscriptionResponse.ts @@ -1,8 +1,5 @@ import { Subscription } from '@standardnotes/security' -import { MinimalHttpResponse } from '../Http/MinimalHttpResponses' -export type GetSubscriptionResponse = MinimalHttpResponse & { - data?: { - subscription?: Subscription - } +export type GetSubscriptionResponse = { + subscription?: Subscription } diff --git a/packages/responses/src/Domain/User/ListSettingsResponse.ts b/packages/responses/src/Domain/User/ListSettingsResponse.ts index 48d649097..c9c7aa2fa 100644 --- a/packages/responses/src/Domain/User/ListSettingsResponse.ts +++ b/packages/responses/src/Domain/User/ListSettingsResponse.ts @@ -1,8 +1,5 @@ -import { MinimalHttpResponse } from '../Http/MinimalHttpResponses' import { SettingData } from './SettingData' -export type ListSettingsResponse = MinimalHttpResponse & { - data?: { - settings?: SettingData[] - } +export type ListSettingsResponse = { + settings?: SettingData[] } diff --git a/packages/responses/src/Domain/User/PostSubscriptionTokensResponse.ts b/packages/responses/src/Domain/User/PostSubscriptionTokensResponse.ts index 3d0c250e0..e68caec89 100644 --- a/packages/responses/src/Domain/User/PostSubscriptionTokensResponse.ts +++ b/packages/responses/src/Domain/User/PostSubscriptionTokensResponse.ts @@ -1,7 +1,3 @@ -import { MinimalHttpResponse } from '../Http/MinimalHttpResponses' - -export type PostSubscriptionTokensResponse = MinimalHttpResponse & { - data?: { - token: string - } +export type PostSubscriptionTokensResponse = { + token: string } diff --git a/packages/responses/src/Domain/User/UpdateSettingResponse.ts b/packages/responses/src/Domain/User/UpdateSettingResponse.ts index 69de90098..393e8f44e 100644 --- a/packages/responses/src/Domain/User/UpdateSettingResponse.ts +++ b/packages/responses/src/Domain/User/UpdateSettingResponse.ts @@ -1,3 +1 @@ -import { MinimalHttpResponse } from '../Http/MinimalHttpResponses' - -export type UpdateSettingResponse = MinimalHttpResponse +export type UpdateSettingResponse = unknown diff --git a/packages/responses/src/Domain/User/UserFeaturesResponse.ts b/packages/responses/src/Domain/User/UserFeaturesResponse.ts index 60dd075fc..d45fbc87b 100644 --- a/packages/responses/src/Domain/User/UserFeaturesResponse.ts +++ b/packages/responses/src/Domain/User/UserFeaturesResponse.ts @@ -1,6 +1,3 @@ -import { HttpResponse } from '../Http/HttpResponse' import { UserFeaturesData } from './UserFeaturesData' -export type UserFeaturesResponse = HttpResponse & { - data: UserFeaturesData -} +export type UserFeaturesResponse = UserFeaturesData diff --git a/packages/responses/src/Domain/index.ts b/packages/responses/src/Domain/index.ts index 2b49b6e7f..f926d5b39 100644 --- a/packages/responses/src/Domain/index.ts +++ b/packages/responses/src/Domain/index.ts @@ -21,12 +21,7 @@ export * from './Files/CreateValetTokenResponseData' export * from './Files/DownloadFileChunkResponse' export * from './Files/StartUploadSessionResponse' export * from './Files/UploadFileChunkResponse' -export * from './Http/Error' -export * from './Http/Functions' -export * from './Http/HttpResponse' -export * from './Http/MinimalHttpResponses' -export * from './Http/ResponseMeta' -export * from './Http/StatusCode' +export * from './Http' export * from './Item/ApiEndpointParam' export * from './Item/CheckIntegrityResponse' export * from './Item/ConflictParams' diff --git a/packages/services/src/Domain/Auth/AuthManager.ts b/packages/services/src/Domain/Auth/AuthManager.ts index 465e56eeb..857e77c66 100644 --- a/packages/services/src/Domain/Auth/AuthManager.ts +++ b/packages/services/src/Domain/Auth/AuthManager.ts @@ -1,6 +1,6 @@ import { AuthApiServiceInterface } from '@standardnotes/api' import { AnyKeyParamsContent } from '@standardnotes/common' -import { SessionBody } from '@standardnotes/responses' +import { isErrorResponse, SessionBody } from '@standardnotes/responses' import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface' import { AbstractService } from '../Service/AbstractService' @@ -18,7 +18,7 @@ export class AuthManager extends AbstractService implements AuthClientInterface try { const result = await this.authApiService.generateRecoveryCodes() - if (result.data.error) { + if (isErrorResponse(result)) { return false } @@ -35,8 +35,7 @@ export class AuthManager extends AbstractService implements AuthClientInterface }): Promise { try { const result = await this.authApiService.recoveryKeyParams(dto) - - if (result.data.error) { + if (isErrorResponse(result)) { return false } @@ -66,7 +65,7 @@ export class AuthManager extends AbstractService implements AuthClientInterface try { const result = await this.authApiService.signInWithRecoveryCodes(dto) - if (result.data.error) { + if (isErrorResponse(result)) { return false } diff --git a/packages/services/src/Domain/Authenticator/AuthenticatorManager.ts b/packages/services/src/Domain/Authenticator/AuthenticatorManager.ts index 100f86e4f..0ccff2479 100644 --- a/packages/services/src/Domain/Authenticator/AuthenticatorManager.ts +++ b/packages/services/src/Domain/Authenticator/AuthenticatorManager.ts @@ -2,6 +2,7 @@ import { AuthenticatorApiServiceInterface } from '@standardnotes/api' import { Username, Uuid } from '@standardnotes/domain-core' +import { isErrorResponse } from '@standardnotes/responses' import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface' import { AbstractService } from '../Service/AbstractService' @@ -19,7 +20,7 @@ export class AuthenticatorManager extends AbstractService implements Authenticat try { const result = await this.authenticatorApiService.list() - if (result.data.error) { + if (isErrorResponse(result)) { return [] } @@ -32,8 +33,7 @@ export class AuthenticatorManager extends AbstractService implements Authenticat async delete(authenticatorId: Uuid): Promise { try { const result = await this.authenticatorApiService.delete(authenticatorId.value) - - if (result.data.error) { + if (isErrorResponse(result)) { return false } @@ -47,7 +47,7 @@ export class AuthenticatorManager extends AbstractService implements Authenticat try { const result = await this.authenticatorApiService.generateRegistrationOptions() - if (result.data.error) { + if (isErrorResponse(result)) { return null } @@ -69,7 +69,7 @@ export class AuthenticatorManager extends AbstractService implements Authenticat registrationCredential, ) - if (result.data.error) { + if (isErrorResponse(result)) { return false } @@ -83,7 +83,7 @@ export class AuthenticatorManager extends AbstractService implements Authenticat try { const result = await this.authenticatorApiService.generateAuthenticationOptions(username.value) - if (result.data.error) { + if (isErrorResponse(result)) { return null } diff --git a/packages/services/src/Domain/Files/FileService.spec.ts b/packages/services/src/Domain/Files/FileService.spec.ts index 3f7ed0181..f17e797df 100644 --- a/packages/services/src/Domain/Files/FileService.spec.ts +++ b/packages/services/src/Domain/Files/FileService.spec.ts @@ -154,7 +154,7 @@ describe('fileService', () => { const alertMock = (alertService.confirm = jest.fn().mockReturnValue(true)) const deleteItemMock = (itemManager.setItemToBeDeleted = jest.fn()) - apiService.deleteFile = jest.fn().mockReturnValue({ error: true }) + apiService.deleteFile = jest.fn().mockReturnValue({ data: { error: true } }) await fileService.deleteFile(file) diff --git a/packages/services/src/Domain/Files/FileService.ts b/packages/services/src/Domain/Files/FileService.ts index aaed40b57..6483cc787 100644 --- a/packages/services/src/Domain/Files/FileService.ts +++ b/packages/services/src/Domain/Files/FileService.ts @@ -1,4 +1,4 @@ -import { ClientDisplayableError } from '@standardnotes/responses' +import { ClientDisplayableError, isErrorResponse } from '@standardnotes/responses' import { ContentType } from '@standardnotes/common' import { FileItem, @@ -101,7 +101,7 @@ export class FileService extends AbstractService implements FilesClientInterface const uploadSessionStarted = await this.api.startUploadSession(tokenResult) - if (!uploadSessionStarted.uploadId) { + if (isErrorResponse(uploadSessionStarted) || !uploadSessionStarted.data.uploadId) { return new ClientDisplayableError('Could not start upload session') } @@ -243,7 +243,7 @@ export class FileService extends AbstractService implements FilesClientInterface const result = await this.api.deleteFile(tokenResult) - if (result.error) { + if (result.data?.error) { const deleteAnyway = await this.alertService.confirm( spaceSeparatedStrings( 'This file could not be deleted from the server, possibly because you are attempting to delete a file item', @@ -257,7 +257,7 @@ export class FileService extends AbstractService implements FilesClientInterface ) if (!deleteAnyway) { - return ClientDisplayableError.FromError(result.error) + return ClientDisplayableError.FromError(result.data?.error) } } diff --git a/packages/services/src/Domain/Integrity/IntegrityApiInterface.ts b/packages/services/src/Domain/Integrity/IntegrityApiInterface.ts index 3b1f46854..27f8a2ea9 100644 --- a/packages/services/src/Domain/Integrity/IntegrityApiInterface.ts +++ b/packages/services/src/Domain/Integrity/IntegrityApiInterface.ts @@ -1,5 +1,5 @@ -import { CheckIntegrityResponse, IntegrityPayload } from '@standardnotes/responses' +import { CheckIntegrityResponse, IntegrityPayload, HttpResponse } from '@standardnotes/responses' export interface IntegrityApiInterface { - checkIntegrity(integrityPayloads: IntegrityPayload[]): Promise + checkIntegrity(integrityPayloads: IntegrityPayload[]): Promise> } diff --git a/packages/services/src/Domain/Integrity/IntegrityService.spec.ts b/packages/services/src/Domain/Integrity/IntegrityService.spec.ts index 525da03bb..26c347dbf 100644 --- a/packages/services/src/Domain/Integrity/IntegrityService.spec.ts +++ b/packages/services/src/Domain/Integrity/IntegrityService.spec.ts @@ -100,7 +100,9 @@ describe('IntegrityService', () => { it('should not publish mismatches if checking integrity fails', async () => { integrityApi.checkIntegrity = jest.fn().mockReturnValue({ - error: 'Ooops', + data: { + error: 'Ooops', + }, }) await createService().handleEvent({ @@ -121,7 +123,9 @@ describe('IntegrityService', () => { }, }) itemApi.getSingleItem = jest.fn().mockReturnValue({ - error: 'Ooops', + data: { + error: 'Ooops', + }, }) await createService().handleEvent({ diff --git a/packages/services/src/Domain/Integrity/IntegrityService.ts b/packages/services/src/Domain/Integrity/IntegrityService.ts index 9705019b3..387ef1082 100644 --- a/packages/services/src/Domain/Integrity/IntegrityService.ts +++ b/packages/services/src/Domain/Integrity/IntegrityService.ts @@ -2,7 +2,7 @@ import { IntegrityEvent } from './IntegrityEvent' import { AbstractService } from '../Service/AbstractService' import { ItemsServerInterface } from '../Item/ItemsServerInterface' import { IntegrityApiInterface } from './IntegrityApiInterface' -import { GetSingleItemResponse } from '@standardnotes/responses' +import { GetSingleItemResponse, HttpResponse, isErrorResponse, ServerItemResponse } from '@standardnotes/responses' import { InternalEventHandlerInterface } from '../Internal/InternalEventHandlerInterface' import { InternalEventInterface } from '../Internal/InternalEventInterface' import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface' @@ -30,23 +30,31 @@ export class IntegrityService } const integrityCheckResponse = await this.integrityApi.checkIntegrity(this.payloadManager.integrityPayloads) - if (integrityCheckResponse.error !== undefined) { - this.log(`Could not obtain integrity check: ${integrityCheckResponse.error}`) + if (isErrorResponse(integrityCheckResponse)) { + this.log(`Could not obtain integrity check: ${integrityCheckResponse.data.error}`) return } - const serverItemResponsePromises: Promise[] = [] + const serverItemResponsePromises: Promise>[] = [] for (const mismatch of integrityCheckResponse.data.mismatches) { serverItemResponsePromises.push(this.itemApi.getSingleItem(mismatch.uuid)) } const serverItemResponses = await Promise.all(serverItemResponsePromises) - const rawPayloads = [] + const rawPayloads: ServerItemResponse[] = [] for (const serverItemResponse of serverItemResponses) { - if (serverItemResponse.data === undefined || serverItemResponse.error || !('item' in serverItemResponse.data)) { - this.log(`Could not obtain item for integrity adjustments: ${serverItemResponse.error}`) + if ( + serverItemResponse.data == undefined || + isErrorResponse(serverItemResponse) || + !('item' in serverItemResponse.data) + ) { + this.log( + `Could not obtain item for integrity adjustments: ${ + isErrorResponse(serverItemResponse) ? serverItemResponse.data.error : '' + }`, + ) continue } diff --git a/packages/services/src/Domain/Item/ItemsServerInterface.ts b/packages/services/src/Domain/Item/ItemsServerInterface.ts index 80b06cb37..332945863 100644 --- a/packages/services/src/Domain/Item/ItemsServerInterface.ts +++ b/packages/services/src/Domain/Item/ItemsServerInterface.ts @@ -1,5 +1,5 @@ -import { GetSingleItemResponse } from '@standardnotes/responses' +import { GetSingleItemResponse, HttpResponse } from '@standardnotes/responses' export interface ItemsServerInterface { - getSingleItem(itemUuid: string): Promise + getSingleItem(itemUuid: string): Promise> } diff --git a/packages/services/src/Domain/Revision/RevisionManager.ts b/packages/services/src/Domain/Revision/RevisionManager.ts index 7d492c871..a3b174dc3 100644 --- a/packages/services/src/Domain/Revision/RevisionManager.ts +++ b/packages/services/src/Domain/Revision/RevisionManager.ts @@ -1,5 +1,6 @@ import { RevisionApiServiceInterface } from '@standardnotes/api' import { Uuid } from '@standardnotes/domain-core' +import { isErrorResponse } from '@standardnotes/responses' import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface' import { AbstractService } from '../Service/AbstractService' @@ -18,7 +19,7 @@ export class RevisionManager extends AbstractService implements RevisionClientIn ): Promise<{ uuid: string; content_type: string; created_at: string; updated_at: string; required_role: string }[]> { const result = await this.revisionApiService.listRevisions(itemUuid.value) - if (result.data.error) { + if (isErrorResponse(result)) { throw new Error(result.data.error.message) } @@ -28,7 +29,7 @@ export class RevisionManager extends AbstractService implements RevisionClientIn async deleteRevision(itemUuid: Uuid, revisionUuid: Uuid): Promise { const result = await this.revisionApiService.deleteRevision(itemUuid.value, revisionUuid.value) - if (result.data.error) { + if (isErrorResponse(result)) { throw new Error(result.data.error.message) } @@ -51,7 +52,7 @@ export class RevisionManager extends AbstractService implements RevisionClientIn } | null> { const result = await this.revisionApiService.getRevision(itemUuid.value, revisionUuid.value) - if (result.data.error) { + if (isErrorResponse(result)) { throw new Error(result.data.error.message) } diff --git a/packages/services/src/Domain/Session/SessionManagerResponse.ts b/packages/services/src/Domain/Session/SessionManagerResponse.ts index cfd2302af..f32193e6d 100644 --- a/packages/services/src/Domain/Session/SessionManagerResponse.ts +++ b/packages/services/src/Domain/Session/SessionManagerResponse.ts @@ -1,9 +1,9 @@ +import { HttpResponse, SignInResponse } from '@standardnotes/responses' import { AnyKeyParamsContent } from '@standardnotes/common' import { RootKeyInterface } from '@standardnotes/models' -import { HttpResponse } from '@standardnotes/responses' export type SessionManagerResponse = { - response: HttpResponse + response: HttpResponse rootKey?: RootKeyInterface keyParams?: AnyKeyParamsContent } diff --git a/packages/services/src/Domain/Session/SessionsClientInterface.ts b/packages/services/src/Domain/Session/SessionsClientInterface.ts index 8de0a24e9..ed70bc0a4 100644 --- a/packages/services/src/Domain/Session/SessionsClientInterface.ts +++ b/packages/services/src/Domain/Session/SessionsClientInterface.ts @@ -2,7 +2,7 @@ import { UserRegistrationResponseBody } from '@standardnotes/api' import { ProtocolVersion } from '@standardnotes/common' import { SNRootKey } from '@standardnotes/encryption' import { RootKeyInterface } from '@standardnotes/models' -import { ClientDisplayableError, HttpResponse, SessionBody, SignInResponse, User } from '@standardnotes/responses' +import { ClientDisplayableError, SessionBody, SignInResponse, User, HttpResponse } from '@standardnotes/responses' import { Base64String } from '@standardnotes/sncrypto-common' import { SessionManagerResponse } from './SessionManagerResponse' @@ -25,7 +25,7 @@ export interface SessionsClientInterface { email: string, rootKey: RootKeyInterface, ephemeral: boolean, - ): Promise + ): Promise> signOut(): Promise changeCredentials(parameters: { currentServerPassword: string diff --git a/packages/services/src/Domain/Subscription/SubscriptionManager.ts b/packages/services/src/Domain/Subscription/SubscriptionManager.ts index 11d3dec01..d43965ec7 100644 --- a/packages/services/src/Domain/Subscription/SubscriptionManager.ts +++ b/packages/services/src/Domain/Subscription/SubscriptionManager.ts @@ -4,6 +4,7 @@ import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface import { AbstractService } from '../Service/AbstractService' import { SubscriptionClientInterface } from './SubscriptionClientInterface' import { AppleIAPReceipt } from './AppleIAPReceipt' +import { isErrorResponse } from '@standardnotes/responses' export class SubscriptionManager extends AbstractService implements SubscriptionClientInterface { constructor( @@ -17,7 +18,7 @@ export class SubscriptionManager extends AbstractService implements Subscription try { const result = await this.subscriptionApiService.acceptInvite(inviteUuid) - if (result.data.error) { + if (isErrorResponse(result)) { return { success: false, message: result.data.error.message } } @@ -29,9 +30,13 @@ export class SubscriptionManager extends AbstractService implements Subscription async listSubscriptionInvitations(): Promise { try { - const response = await this.subscriptionApiService.listInvites() + const result = await this.subscriptionApiService.listInvites() - return response.data.invitations ?? [] + if (isErrorResponse(result)) { + return [] + } + + return result.data.invitations ?? [] } catch (error) { return [] } @@ -41,6 +46,10 @@ export class SubscriptionManager extends AbstractService implements Subscription try { const result = await this.subscriptionApiService.invite(inviteeEmail) + if (isErrorResponse(result)) { + return false + } + return result.data.success === true } catch (error) { return false @@ -51,6 +60,10 @@ export class SubscriptionManager extends AbstractService implements Subscription try { const result = await this.subscriptionApiService.cancelInvite(inviteUuid) + if (isErrorResponse(result)) { + return false + } + return result.data.success === true } catch (error) { return false @@ -67,7 +80,7 @@ export class SubscriptionManager extends AbstractService implements Subscription subscription_token: subscriptionToken, }) - if (result.data.error) { + if (isErrorResponse(result)) { return { success: false, message: result.data.error.message } } diff --git a/packages/services/src/Domain/User/UserService.ts b/packages/services/src/Domain/User/UserService.ts index 61bbeaa9c..8f4ee14b8 100644 --- a/packages/services/src/Domain/User/UserService.ts +++ b/packages/services/src/Domain/User/UserService.ts @@ -1,6 +1,6 @@ import { Base64String } from '@standardnotes/sncrypto-common' import { EncryptionProviderInterface, SNRootKey, SNRootKeyParams } from '@standardnotes/encryption' -import { HttpResponse, SignInResponse, User } from '@standardnotes/responses' +import { HttpResponse, SignInResponse, User, HttpError, isErrorResponse } from '@standardnotes/responses' import { Either, KeyParamsOrigination, UserRequestType } from '@standardnotes/common' import { UuidGenerator } from '@standardnotes/utils' import { UserApiServiceInterface, UserRegistrationResponseBody } from '@standardnotes/api' @@ -28,8 +28,7 @@ import { ProtectionsClientInterface } from '../Protection/ProtectionClientInterf import { InternalEventHandlerInterface } from '../Internal/InternalEventHandlerInterface' import { InternalEventInterface } from '../Internal/InternalEventInterface' -export type CredentialsChangeFunctionResponse = { error?: { message: string } } -export type AccountServiceResponse = HttpResponse +export type CredentialsChangeFunctionResponse = { error?: HttpError } export enum AccountEvent { SignedInOrRegistered = 'SignedInOrRegistered', @@ -181,7 +180,7 @@ export class UserService ephemeral = false, mergeLocal = true, awaitSync = false, - ): Promise { + ): Promise> { if (this.protocolService.hasAccount()) { throw Error('Tried to sign in when an account already exists.') } @@ -196,9 +195,9 @@ export class UserService /** Prevent a timed sync from occuring while signing in. */ this.lockSyncing() - const result = await this.sessionManager.signIn(email, password, strict, ephemeral) + const { response } = await this.sessionManager.signIn(email, password, strict, ephemeral) - if (!result.response.error) { + if (!isErrorResponse(response)) { const notifyingFunction = awaitSync ? this.notifyEventSync.bind(this) : this.notifyEvent.bind(this) await notifyingFunction(AccountEvent.SignedInOrRegistered, { payload: { @@ -212,7 +211,7 @@ export class UserService this.unlockSyncing() } - return result.response + return response } finally { this.signingIn = false } @@ -237,7 +236,7 @@ export class UserService const uuid = this.sessionManager.getSureUser().uuid const response = await this.userApiService.deleteAccount(uuid) - if (response.data.error) { + if (isErrorResponse(response)) { return { error: true, message: response.data.error.message, @@ -261,7 +260,7 @@ export class UserService requestType, }) - if (result.data.error) { + if (isErrorResponse(result)) { return false } @@ -276,7 +275,7 @@ export class UserService * for missing keys or storage values. Unlike regular sign in, this doesn't worry about * performing one of marking all items as needing sync or deleting all local data. */ - public async correctiveSignIn(rootKey: SNRootKey): Promise { + public async correctiveSignIn(rootKey: SNRootKey): Promise> { this.lockSyncing() const response = await this.sessionManager.bypassChecksAndSignInWithRootKey( @@ -285,7 +284,7 @@ export class UserService false, ) - if (!response.error) { + if (!isErrorResponse(response)) { await this.notifyEvent(AccountEvent.SignedInOrRegistered, { payload: { mergeLocal: true, @@ -583,7 +582,7 @@ export class UserService this.lockSyncing() /** Now, change the credentials on the server. Roll back on failure */ - const result = await this.sessionManager.changeCredentials({ + const { response } = await this.sessionManager.changeCredentials({ currentServerPassword: rootKeys.currentRootKey.serverPassword as string, newRootKey: rootKeys.newRootKey, wrappingKey, @@ -592,29 +591,31 @@ export class UserService this.unlockSyncing() - if (!result.response.error) { - const rollback = await this.protocolService.createNewItemsKeyWithRollback() - await this.protocolService.reencryptItemsKeys() - await this.syncService.sync({ awaitAll: true }) - - const defaultItemsKey = this.protocolService.getSureDefaultItemsKey() - const itemsKeyWasSynced = !defaultItemsKey.neverSynced - - if (!itemsKeyWasSynced) { - await this.sessionManager.changeCredentials({ - currentServerPassword: rootKeys.newRootKey.serverPassword as string, - newRootKey: rootKeys.currentRootKey, - wrappingKey, - }) - await this.protocolService.reencryptItemsKeys() - await rollback() - await this.syncService.sync({ awaitAll: true }) - - return { error: Error(Messages.CredentialsChangeStrings.Failed) } - } + if (isErrorResponse(response)) { + return { error: Error(response.data.error?.message) } } - return result.response + const rollback = await this.protocolService.createNewItemsKeyWithRollback() + await this.protocolService.reencryptItemsKeys() + await this.syncService.sync({ awaitAll: true }) + + const defaultItemsKey = this.protocolService.getSureDefaultItemsKey() + const itemsKeyWasSynced = !defaultItemsKey.neverSynced + + if (!itemsKeyWasSynced) { + await this.sessionManager.changeCredentials({ + currentServerPassword: rootKeys.newRootKey.serverPassword as string, + newRootKey: rootKeys.currentRootKey, + wrappingKey, + }) + await this.protocolService.reencryptItemsKeys() + await rollback() + await this.syncService.sync({ awaitAll: true }) + + return { error: Error(Messages.CredentialsChangeStrings.Failed) } + } + + return {} } private async recomputeRootKeysForCredentialChange(parameters: { diff --git a/packages/snjs/lib/Application/Application.ts b/packages/snjs/lib/Application/Application.ts index ed641601a..dca909fdb 100644 --- a/packages/snjs/lib/Application/Application.ts +++ b/packages/snjs/lib/Application/Application.ts @@ -83,7 +83,7 @@ import { ItemStream, Platform, } from '@standardnotes/models' -import { ClientDisplayableError } from '@standardnotes/responses' +import { ClientDisplayableError, SessionListEntry } from '@standardnotes/responses' import { SnjsVersion } from './../Version' import { SNLog } from '../Log' @@ -133,7 +133,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli /** * @deprecated will be fully replaced by @standardnotes/api::HttpService */ - private deprecatedHttpService!: InternalServices.SNHttpService + private deprecatedHttpService!: InternalServices.DeprecatedHttpService private declare httpService: HttpServiceInterface private payloadManager!: InternalServices.PayloadManager public protocolService!: EncryptionService @@ -599,13 +599,13 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli return this.syncService.isDatabaseLoaded() } - public getSessions(): Promise< - (Responses.HttpResponse & { data: InternalServices.RemoteSession[] }) | Responses.HttpResponse - > { + public getSessions(): Promise> { return this.sessionManager.getSessionsList() } - public async revokeSession(sessionId: UuidString): Promise { + public async revokeSession( + sessionId: UuidString, + ): Promise | undefined> { if (await this.protectionService.authorizeSessionRevoking()) { return this.sessionManager.revokeSession(sessionId) } @@ -627,7 +627,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli return Common.compareVersions(userVersion, Common.ProtocolVersion.V004) >= 0 } - public async getUserSubscription(): Promise { + public async getUserSubscription(): Promise { return this.sessionManager.getSubscription() } @@ -897,6 +897,9 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli service.deinit() } + this.httpService.deinit() + ;(this.httpService as unknown) = undefined + this.options.crypto.deinit() ;(this.options as unknown) = undefined @@ -939,7 +942,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli ephemeral = false, mergeLocal = true, awaitSync = false, - ): Promise { + ): Promise> { return this.userService.signIn(email, password, strict, ephemeral, mergeLocal, awaitSync) } @@ -1161,8 +1164,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli this.diskStorageService.provideEncryptionProvider(this.protocolService) this.createChallengeService() this.createLegacyHttpManager() - this.createApiService() - this.createHttpService() + this.createHttpServiceAndApiService() this.createUserServer() this.createUserRequestServer() this.createUserApiService() @@ -1419,20 +1421,6 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli this.services.push(this.userService) } - private createApiService() { - this.apiService = new InternalServices.SNApiService( - this.deprecatedHttpService, - this.diskStorageService, - this.options.defaultHost, - this.inMemoryStore, - this.options.crypto, - this.sessionStorageMapper, - this.legacySessionStorageMapper, - this.internalEventBus, - ) - this.services.push(this.apiService) - } - private createUserApiService() { this.userApiService = new UserApiService(this.userServer, this.userRequestServer) } @@ -1486,7 +1474,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli } private createLegacyHttpManager() { - this.deprecatedHttpService = new InternalServices.SNHttpService( + this.deprecatedHttpService = new InternalServices.DeprecatedHttpService( this.environment, this.options.appVersion, this.internalEventBus, @@ -1494,11 +1482,22 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli this.services.push(this.deprecatedHttpService) } - private createHttpService() { - this.httpService = new HttpService( - this.environment, - this.options.appVersion, - SnjsVersion, + private createHttpServiceAndApiService() { + this.httpService = new HttpService(this.environment, this.options.appVersion, SnjsVersion) + + this.apiService = new InternalServices.SNApiService( + this.httpService, + this.diskStorageService, + this.options.defaultHost, + this.inMemoryStore, + this.options.crypto, + this.sessionStorageMapper, + this.legacySessionStorageMapper, + this.internalEventBus, + ) + this.services.push(this.apiService) + + this.httpService.setCallbacks( this.apiService.processMetaObject.bind(this.apiService), this.apiService.setSession.bind(this.apiService), ) diff --git a/packages/snjs/lib/Services/Actions/ActionsService.ts b/packages/snjs/lib/Services/Actions/ActionsService.ts index c8cacaf95..21d3bca4e 100644 --- a/packages/snjs/lib/Services/Actions/ActionsService.ts +++ b/packages/snjs/lib/Services/Actions/ActionsService.ts @@ -2,7 +2,7 @@ import { removeFromArray } from '@standardnotes/utils' import { SNRootKey } from '@standardnotes/encryption' import { ChallengeService } from '../Challenge' import { ListedService } from '../Listed/ListedService' -import { ActionResponse, HttpResponse } from '@standardnotes/responses' +import { ActionResponse, DeprecatedHttpResponse } from '@standardnotes/responses' import { ContentType } from '@standardnotes/common' import { ItemManager } from '@Lib/Services/Items/ItemManager' import { @@ -24,7 +24,7 @@ import { } from '@standardnotes/models' import { SNSyncService } from '../Sync/SyncService' import { PayloadManager } from '../Payloads/PayloadManager' -import { SNHttpService } from '../Api/HttpService' +import { DeprecatedHttpService } from '../Api/DeprecatedHttpService' import { AbstractService, DeviceInterface, @@ -61,7 +61,7 @@ export class SNActionsService extends AbstractService { private itemManager: ItemManager, private alertService: AlertService, public deviceInterface: DeviceInterface, - private httpService: SNHttpService, + private httpService: DeprecatedHttpService, private payloadManager: PayloadManager, private protocolService: EncryptionService, private syncService: SNSyncService, @@ -185,7 +185,7 @@ export class SNActionsService extends AbstractService { message: 'An issue occurred while processing this action. Please try again.', } void this.alertService.alert(error.message) - return { error } as HttpResponse + return { error } as DeprecatedHttpResponse }) return response as ActionResponse diff --git a/packages/snjs/lib/Services/Api/ApiService.ts b/packages/snjs/lib/Services/Api/ApiService.ts index cd4767d7e..1a28bf66c 100644 --- a/packages/snjs/lib/Services/Api/ApiService.ts +++ b/packages/snjs/lib/Services/Api/ApiService.ts @@ -1,7 +1,6 @@ import { FeatureDescription } from '@standardnotes/features' -import { isNullOrUndefined, joinPaths } from '@standardnotes/utils' +import { joinPaths } from '@standardnotes/utils' import { SettingName, SubscriptionSettingName } from '@standardnotes/settings' -import { ErrorTag } from '@standardnotes/common' import { AbstractService, ApiServiceInterface, @@ -34,14 +33,53 @@ import { } from '@standardnotes/services' import { FilesApiInterface } from '@standardnotes/files' import { ServerSyncPushContextualPayload, SNFeatureRepo, FileContent } from '@standardnotes/models' -import * as Responses from '@standardnotes/responses' +import { + User, + HttpStatusCode, + KeyParamsResponse, + SignInResponse, + SignOutResponse, + ChangeCredentialsResponse, + RawSyncResponse, + SessionRenewalResponse, + SessionListResponse, + UserFeaturesResponse, + ListSettingsResponse, + UpdateSettingResponse, + GetSettingResponse, + DeleteSettingResponse, + GetSubscriptionResponse, + GetAvailableSubscriptionsResponse, + PostSubscriptionTokensResponse, + GetOfflineFeaturesResponse, + ListedRegistrationResponse, + CreateValetTokenResponse, + StartUploadSessionResponse, + UploadFileChunkResponse, + CloseUploadSessionResponse, + DownloadFileChunkResponse, + IntegrityPayload, + CheckIntegrityResponse, + GetSingleItemResponse, + HttpResponse, + HttpResponseMeta, + ErrorTag, + HttpRequestParams, + HttpRequest, + HttpVerb, + ApiEndpointParam, + ClientDisplayableError, + CreateValetTokenPayload, + HttpErrorResponse, + HttpSuccessResponse, + isErrorResponse, +} from '@standardnotes/responses' import { LegacySession, MapperInterface, Session, SessionToken } from '@standardnotes/domain-core' -import { HttpResponseMeta } from '@standardnotes/api' +import { HttpServiceInterface } from '@standardnotes/api' import { SNRootKeyParams } from '@standardnotes/encryption' -import { ApiEndpointParam, ClientDisplayableError, CreateValetTokenPayload } from '@standardnotes/responses' + import { PureCryptoInterface } from '@standardnotes/sncrypto-common' -import { HttpParams, HttpRequest, HttpVerb, SNHttpService } from './HttpService' import { isUrlFirstParty, TRUSTED_FEATURE_HOSTS } from '@Lib/Hosts' import { Paths } from './Paths' import { DiskStorageService } from '../Storage/DiskStorageService' @@ -65,7 +103,7 @@ export class SNApiService SettingsServerInterface { private session: Session | LegacySession | null - public user?: Responses.User + public user?: User private registering = false private authenticating = false private changing = false @@ -74,7 +112,7 @@ export class SNApiService private filesHost?: string constructor( - private httpService: SNHttpService, + private httpService: HttpServiceInterface, private storageService: DiskStorageService, private host: string, private inMemoryStore: KeyValueStoreInterface, @@ -96,7 +134,7 @@ export class SNApiService super.deinit() } - public setUser(user?: Responses.User): void { + public setUser(user?: User): void { this.user = user } @@ -161,25 +199,22 @@ export class SNApiService return V0_API_VERSION } - private params(inParams: Record): HttpParams { + private params(inParams: Record): HttpRequestParams { const params = merge(inParams, { [ApiEndpointParam.ApiVersion]: this.apiVersion, }) return params } - public createErrorResponse(message: string, status?: Responses.StatusCode): Responses.HttpResponse { - return { error: { message, status } } as Responses.HttpResponse + public createErrorResponse(message: string, status?: HttpStatusCode, tag?: ErrorTag): HttpErrorResponse { + return { data: { error: { message, tag } }, status: status ?? HttpStatusCode.BadRequest } } - private errorResponseWithFallbackMessage(response: Responses.HttpResponse, message: string) { - if (!response.error?.message) { - response.error = { - ...response.error, - status: response.error?.status ?? Responses.StatusCode.UnknownError, - message, - } + private errorResponseWithFallbackMessage(response: HttpErrorResponse, message: string): HttpErrorResponse { + if (!response.data.error.message) { + response.data.error.message = message } + return response } @@ -196,44 +231,44 @@ export class SNApiService } } - private processResponse(response: Responses.HttpResponse) { + private processSuccessResponseForMetaBody(response: HttpSuccessResponse) { if (response.meta) { this.processMetaObject(response.meta) } } - private async request(params: { + private async request(params: { verb: HttpVerb url: string fallbackErrorMessage: string - params?: HttpParams + params?: HttpRequestParams rawBytes?: Uint8Array authentication?: string customHeaders?: Record[] responseType?: XMLHttpRequestResponseType external?: boolean - }) { + }): Promise> { try { - const response = await this.httpService.runHttp(params) - this.processResponse(response) - return response + const response = await this.httpService.runHttp(params) + if (isErrorResponse(response)) { + return this.errorResponseWithFallbackMessage(response, params.fallbackErrorMessage) + } else { + this.processSuccessResponseForMetaBody(response) + return response + } } catch (errorResponse) { - return this.errorResponseWithFallbackMessage(errorResponse as Responses.HttpResponse, params.fallbackErrorMessage) + return this.errorResponseWithFallbackMessage(errorResponse as HttpErrorResponse, params.fallbackErrorMessage) } } /** - * @param mfaKeyPath The params path the server expects for authentication against - * a particular mfa challenge. A value of foo would mean the server - * would receive parameters as params['foo'] with value equal to mfaCode. * @param mfaCode The mfa challenge response value. */ async getAccountKeyParams(dto: { email: string - mfaKeyPath?: string mfaCode?: string authenticatorResponse?: Record - }): Promise { + }): Promise> { const codeVerifier = this.crypto.generateRandomKey(256) this.inMemoryStore.setValue(StorageKey.CodeVerifier, codeVerifier) @@ -242,10 +277,10 @@ export class SNApiService const params = this.params({ email: dto.email, code_challenge: codeChallenge, - }) + }) as Record - if (dto.mfaKeyPath !== undefined && dto.mfaCode !== undefined) { - params[dto.mfaKeyPath] = dto.mfaCode + if (dto.mfaCode !== undefined) { + params['mfa_code'] = dto.mfaCode } if (dto.authenticatorResponse) { @@ -266,9 +301,9 @@ export class SNApiService email: string serverPassword: string ephemeral: boolean - }): Promise { + }): Promise> { if (this.authenticating) { - return this.createErrorResponse(API_MESSAGE_LOGIN_IN_PROGRESS) as Responses.SignInResponse + return this.createErrorResponse(API_MESSAGE_LOGIN_IN_PROGRESS, HttpStatusCode.BadRequest) } this.authenticating = true const url = joinPaths(this.host, Paths.v2.signIn) @@ -279,7 +314,7 @@ export class SNApiService code_verifier: this.inMemoryStore.getValue(StorageKey.CodeVerifier) as string, }) - const response = await this.request({ + const response = await this.request({ verb: HttpVerb.Post, url, params, @@ -293,11 +328,8 @@ export class SNApiService return response } - signOut(): Promise { - const url = joinPaths(this.host, Paths.v1.signOut) - return this.httpService.postAbsolute(url, undefined, this.getSessionAccessToken()).catch((errorResponse) => { - return errorResponse - }) as Promise + signOut(): Promise> { + return this.httpService.post(Paths.v1.signOut, undefined, this.getSessionAccessToken()) } async changeCredentials(parameters: { @@ -306,38 +338,33 @@ export class SNApiService newServerPassword: string newKeyParams: SNRootKeyParams newEmail?: string - }): Promise { + }): Promise> { if (this.changing) { - return this.createErrorResponse(API_MESSAGE_CHANGE_CREDENTIALS_IN_PROGRESS) + return this.createErrorResponse(API_MESSAGE_CHANGE_CREDENTIALS_IN_PROGRESS, HttpStatusCode.BadRequest) } const preprocessingError = this.preprocessingError() if (preprocessingError) { return preprocessingError } this.changing = true - const url = joinPaths(this.host, Paths.v1.changeCredentials(parameters.userUuid) as string) + const path = Paths.v1.changeCredentials(parameters.userUuid) const params = this.params({ current_password: parameters.currentServerPassword, new_password: parameters.newServerPassword, new_email: parameters.newEmail, ...parameters.newKeyParams.getPortableValue(), }) - const response = await this.httpService - .putAbsolute(url, params, this.getSessionAccessToken()) - .catch(async (errorResponse) => { - if (Responses.isErrorResponseExpiredToken(errorResponse)) { - return this.refreshSessionThenRetryRequest({ - verb: HttpVerb.Put, - url, - params, - }) - } - return this.errorResponseWithFallbackMessage(errorResponse, API_MESSAGE_GENERIC_CHANGE_CREDENTIALS_FAIL) - }) - this.processResponse(response) + const response = await this.httpService.put(path, params, this.getSessionAccessToken()) this.changing = false + + if (isErrorResponse(response)) { + return this.errorResponseWithFallbackMessage(response, API_MESSAGE_GENERIC_CHANGE_CREDENTIALS_FAIL) + } + + this.processSuccessResponseForMetaBody(response) + return response } @@ -346,79 +373,54 @@ export class SNApiService lastSyncToken: string, paginationToken: string, limit: number, - ): Promise { + ): Promise> { const preprocessingError = this.preprocessingError() if (preprocessingError) { return preprocessingError } - const url = joinPaths(this.host, Paths.v1.sync) + const path = Paths.v1.sync const params = this.params({ [ApiEndpointParam.SyncPayloads]: payloads, [ApiEndpointParam.LastSyncToken]: lastSyncToken, [ApiEndpointParam.PaginationToken]: paginationToken, [ApiEndpointParam.SyncDlLimit]: limit, }) - const response = await this.httpService - .postAbsolute(url, params, this.getSessionAccessToken()) - .catch(async (errorResponse) => { - this.preprocessAuthenticatedErrorResponse(errorResponse) - if (Responses.isErrorResponseExpiredToken(errorResponse)) { - return this.refreshSessionThenRetryRequest({ - verb: HttpVerb.Post, - url, - params, - }) - } - return this.errorResponseWithFallbackMessage(errorResponse, API_MESSAGE_GENERIC_SYNC_FAIL) - }) - this.processResponse(response) + const response = await this.httpService.post(path, params, this.getSessionAccessToken()) + + if (isErrorResponse(response)) { + this.preprocessAuthenticatedErrorResponse(response) + return this.errorResponseWithFallbackMessage(response, API_MESSAGE_GENERIC_SYNC_FAIL) + } + + this.processSuccessResponseForMetaBody(response) return response } - private async refreshSessionThenRetryRequest(httpRequest: HttpRequest): Promise { - const sessionResponse = await this.refreshSession() - if (sessionResponse.error || isNullOrUndefined(sessionResponse.data)) { - return sessionResponse - } else { - return this.httpService - .runHttp({ - ...httpRequest, - authentication: this.getSessionAccessToken(), - }) - .catch((errorResponse) => { - return errorResponse - }) - } - } - - async refreshSession(): Promise { + async refreshSession(): Promise> { const preprocessingError = this.preprocessingError() if (preprocessingError) { return preprocessingError } + this.refreshingSession = true - const url = joinPaths(this.host, Paths.v1.refreshSession) + const session = this.session as Session const params = this.params({ access_token: session.accessToken.value, refresh_token: session.refreshToken.value, }) - const result = await this.httpService - .postAbsolute(url, params) + + const response = await this.httpService + .post(Paths.v1.refreshSession, params) .then(async (response) => { - const sessionRenewalResponse = response as Responses.SessionRenewalResponse - if ( - sessionRenewalResponse.error || - sessionRenewalResponse.data?.error || - !sessionRenewalResponse.data.session - ) { - return null + if (isErrorResponse(response) || !response.data.session) { + return response } const accessTokenOrError = SessionToken.create( - sessionRenewalResponse.data.session.access_token, - sessionRenewalResponse.data.session.access_expiration, + response.data.session.access_token, + response.data.session.access_expiration, ) if (accessTokenOrError.isFailed()) { return null @@ -426,19 +428,15 @@ export class SNApiService const accessToken = accessTokenOrError.getValue() const refreshTokenOrError = SessionToken.create( - sessionRenewalResponse.data.session.refresh_token, - sessionRenewalResponse.data.session.refresh_expiration, + response.data.session.refresh_token, + response.data.session.refresh_expiration, ) if (refreshTokenOrError.isFailed()) { return null } const refreshToken = refreshTokenOrError.getValue() - const sessionOrError = Session.create( - accessToken, - refreshToken, - sessionRenewalResponse.data.session.readonly_access, - ) + const sessionOrError = Session.create(accessToken, refreshToken, response.data.session.readonly_access) if (sessionOrError.isFailed()) { return null } @@ -447,7 +445,7 @@ export class SNApiService this.session = session this.setSession(session) - this.processResponse(response) + this.processSuccessResponseForMetaBody(response) await this.notifyEventSync(ApiServiceEvent.SessionRefreshed, { session, @@ -455,105 +453,94 @@ export class SNApiService return response }) - .catch((errorResponse) => { - this.preprocessAuthenticatedErrorResponse(errorResponse) - return this.errorResponseWithFallbackMessage(errorResponse, API_MESSAGE_GENERIC_TOKEN_REFRESH_FAIL) - }) + this.refreshingSession = false - if (result === null) { - return this.createErrorResponse(API_MESSAGE_INVALID_SESSION) + if (response === null) { + return this.createErrorResponse(API_MESSAGE_INVALID_SESSION, HttpStatusCode.BadRequest) } - return result + if (isErrorResponse(response)) { + this.preprocessAuthenticatedErrorResponse(response) + return this.errorResponseWithFallbackMessage(response, API_MESSAGE_GENERIC_TOKEN_REFRESH_FAIL) + } + + return response } - async getSessionsList(): Promise { + async getSessionsList(): Promise> { const preprocessingError = this.preprocessingError() if (preprocessingError) { return preprocessingError } - const url = joinPaths(this.host, Paths.v1.sessions) - const response = await this.httpService - .getAbsolute(url, {}, this.getSessionAccessToken()) - .catch(async (errorResponse) => { - this.preprocessAuthenticatedErrorResponse(errorResponse) - if (Responses.isErrorResponseExpiredToken(errorResponse)) { - return this.refreshSessionThenRetryRequest({ - verb: HttpVerb.Get, - url, - }) - } - return this.errorResponseWithFallbackMessage(errorResponse, API_MESSAGE_GENERIC_SYNC_FAIL) - }) - this.processResponse(response) + const path = Paths.v1.sessions + const response = await this.httpService.get(path, {}, this.getSessionAccessToken()) + + if (isErrorResponse(response)) { + this.preprocessAuthenticatedErrorResponse(response) + return this.errorResponseWithFallbackMessage(response, API_MESSAGE_GENERIC_SYNC_FAIL) + } + + this.processSuccessResponseForMetaBody(response) return response } - async deleteSession(sessionId: UuidString): Promise { + async deleteSession(sessionId: UuidString): Promise> { const preprocessingError = this.preprocessingError() if (preprocessingError) { return preprocessingError } - const url = joinPaths(this.host, Paths.v1.session(sessionId)) - const response: Responses.SessionListResponse | Responses.HttpResponse = await this.httpService - .deleteAbsolute(url, { uuid: sessionId }, this.getSessionAccessToken()) - .catch((error: Responses.HttpResponse) => { - const errorResponse = error as Responses.HttpResponse - this.preprocessAuthenticatedErrorResponse(errorResponse) - if (Responses.isErrorResponseExpiredToken(errorResponse)) { - return this.refreshSessionThenRetryRequest({ - verb: HttpVerb.Delete, - url, - }) - } - return this.errorResponseWithFallbackMessage(errorResponse, API_MESSAGE_GENERIC_SYNC_FAIL) - }) - this.processResponse(response) + const path = Paths.v1.session(sessionId) + const response = await this.httpService.delete( + path, + { uuid: sessionId }, + this.getSessionAccessToken(), + ) + + if (isErrorResponse(response)) { + this.preprocessAuthenticatedErrorResponse(response) + return this.errorResponseWithFallbackMessage(response, API_MESSAGE_GENERIC_SYNC_FAIL) + } + + this.processSuccessResponseForMetaBody(response) return response } - async getUserFeatures(userUuid: UuidString): Promise { - const url = joinPaths(this.host, Paths.v1.userFeatures(userUuid)) - const response = await this.httpService - .getAbsolute(url, undefined, this.getSessionAccessToken()) - .catch((errorResponse: Responses.HttpResponse) => { - this.preprocessAuthenticatedErrorResponse(errorResponse) - if (Responses.isErrorResponseExpiredToken(errorResponse)) { - return this.refreshSessionThenRetryRequest({ - verb: HttpVerb.Get, - url, - }) - } - return this.errorResponseWithFallbackMessage(errorResponse, API_MESSAGE_GENERIC_SYNC_FAIL) - }) - this.processResponse(response) + async getUserFeatures(userUuid: UuidString): Promise> { + const path = Paths.v1.userFeatures(userUuid) + const response = await this.httpService.get(path, undefined, this.getSessionAccessToken()) + + if (isErrorResponse(response)) { + this.preprocessAuthenticatedErrorResponse(response) + return this.errorResponseWithFallbackMessage(response, API_MESSAGE_GENERIC_SYNC_FAIL) + } + + this.processSuccessResponseForMetaBody(response) return response } - private async tokenRefreshableRequest( + private async tokenRefreshableRequest( params: HttpRequest & { fallbackErrorMessage: string }, - ): Promise { + ): Promise> { const preprocessingError = this.preprocessingError() if (preprocessingError) { - return preprocessingError as T + return preprocessingError } - const response: T | Responses.HttpResponse = await this.httpService - .runHttp(params) - .catch((errorResponse: Responses.HttpResponse) => { - this.preprocessAuthenticatedErrorResponse(errorResponse) - if (Responses.isErrorResponseExpiredToken(errorResponse)) { - return this.refreshSessionThenRetryRequest(params) - } - return this.errorResponseWithFallbackMessage(errorResponse, params.fallbackErrorMessage) - }) - this.processResponse(response) - return response as T + + const response = await this.httpService.runHttp(params) + + if (isErrorResponse(response)) { + this.preprocessAuthenticatedErrorResponse(response) + return this.errorResponseWithFallbackMessage(response, params.fallbackErrorMessage) + } + + this.processSuccessResponseForMetaBody(response) + return response } - async listSettings(userUuid: UuidString): Promise { - return await this.tokenRefreshableRequest({ + async listSettings(userUuid: UuidString): Promise> { + return await this.tokenRefreshableRequest({ verb: HttpVerb.Get, url: joinPaths(this.host, Paths.v1.settings(userUuid)), fallbackErrorMessage: API_MESSAGE_FAILED_GET_SETTINGS, @@ -566,13 +553,13 @@ export class SNApiService settingName: string, settingValue: string | null, sensitive: boolean, - ): Promise { + ): Promise> { const params = { name: settingName, value: settingValue, sensitive: sensitive, } - return this.tokenRefreshableRequest({ + return this.tokenRefreshableRequest({ verb: HttpVerb.Put, url: joinPaths(this.host, Paths.v1.settings(userUuid)), authentication: this.getSessionAccessToken(), @@ -581,8 +568,8 @@ export class SNApiService }) } - async getSetting(userUuid: UuidString, settingName: SettingName): Promise { - return await this.tokenRefreshableRequest({ + async getSetting(userUuid: UuidString, settingName: SettingName): Promise> { + return await this.tokenRefreshableRequest({ verb: HttpVerb.Get, url: joinPaths(this.host, Paths.v1.setting(userUuid, settingName.toLowerCase() as SettingName)), authentication: this.getSessionAccessToken(), @@ -593,8 +580,8 @@ export class SNApiService async getSubscriptionSetting( userUuid: UuidString, settingName: SubscriptionSettingName, - ): Promise { - return await this.tokenRefreshableRequest({ + ): Promise> { + return await this.tokenRefreshableRequest({ verb: HttpVerb.Get, url: joinPaths( this.host, @@ -605,8 +592,8 @@ export class SNApiService }) } - async deleteSetting(userUuid: UuidString, settingName: SettingName): Promise { - return this.tokenRefreshableRequest({ + async deleteSetting(userUuid: UuidString, settingName: SettingName): Promise> { + return this.tokenRefreshableRequest({ verb: HttpVerb.Delete, url: joinPaths(this.host, Paths.v1.setting(userUuid, settingName)), authentication: this.getSessionAccessToken(), @@ -614,7 +601,7 @@ export class SNApiService }) } - public downloadFeatureUrl(url: string): Promise { + public downloadFeatureUrl(url: string): Promise { return this.request({ verb: HttpVerb.Get, url, @@ -623,38 +610,39 @@ export class SNApiService }) } - public async getSubscription(userUuid: string): Promise { + public async getSubscription(userUuid: string): Promise> { const url = joinPaths(this.host, Paths.v1.subscription(userUuid)) - const response = await this.tokenRefreshableRequest({ + return this.tokenRefreshableRequest({ verb: HttpVerb.Get, url, authentication: this.getSessionAccessToken(), fallbackErrorMessage: API_MESSAGE_FAILED_SUBSCRIPTION_INFO, }) - return response } - public async getAvailableSubscriptions(): Promise< - Responses.HttpResponse | Responses.GetAvailableSubscriptionsResponse - > { + public async getAvailableSubscriptions(): Promise> { const url = joinPaths(this.host, Paths.v2.subscriptions) - const response = await this.request({ + return this.request({ verb: HttpVerb.Get, url, fallbackErrorMessage: API_MESSAGE_FAILED_SUBSCRIPTION_INFO, }) - return response } public async getNewSubscriptionToken(): Promise { const url = joinPaths(this.host, Paths.v1.subscriptionTokens) - const response: Responses.HttpResponse | Responses.PostSubscriptionTokensResponse = await this.request({ + const response = await this.request({ verb: HttpVerb.Post, url, authentication: this.getSessionAccessToken(), fallbackErrorMessage: API_MESSAGE_FAILED_ACCESS_PURCHASE, }) - return (response as Responses.PostSubscriptionTokensResponse).data?.token + + if (isErrorResponse(response)) { + return undefined + } + + return response.data.token } public async downloadOfflineFeaturesFromRepo( @@ -673,17 +661,17 @@ export class SNApiService return new ClientDisplayableError('This offline features host is not in the trusted allowlist.') } - const response: Responses.HttpResponse | Responses.GetOfflineFeaturesResponse = await this.request({ + const response = await this.request({ verb: HttpVerb.Get, url: featuresUrl, fallbackErrorMessage: API_MESSAGE_FAILED_OFFLINE_FEATURES, customHeaders: [{ key: 'x-offline-token', value: extensionKey }], }) - if (response.error) { - return ClientDisplayableError.FromError(response.error) + if (isErrorResponse(response)) { + return ClientDisplayableError.FromError(response.data.error) } - const data = (response as Responses.GetOfflineFeaturesResponse).data + const data = response.data return { features: data?.features || [], roles: data?.roles || [], @@ -693,11 +681,11 @@ export class SNApiService } } - public async registerForListedAccount(): Promise { + public async registerForListedAccount(): Promise> { if (!this.user) { throw Error('Cannot register for Listed without user account.') } - return await this.tokenRefreshableRequest({ + return this.tokenRefreshableRequest({ verb: HttpVerb.Post, url: joinPaths(this.host, Paths.v1.listedRegistration(this.user.uuid)), fallbackErrorMessage: API_MESSAGE_FAILED_LISTED_REGISTRATION, @@ -717,7 +705,7 @@ export class SNApiService resources: [{ remoteIdentifier, unencryptedFileSize: unencryptedFileSize || 0 }], } - const response = await this.tokenRefreshableRequest({ + const response = await this.tokenRefreshableRequest({ verb: HttpVerb.Post, url: url, authentication: this.getSessionAccessToken(), @@ -725,6 +713,10 @@ export class SNApiService params, }) + if (isErrorResponse(response)) { + return new ClientDisplayableError(response.data?.error?.message as string) + } + if (!response.data?.success) { return new ClientDisplayableError(response.data?.reason as string, undefined, response.data?.reason as string) } @@ -732,30 +724,26 @@ export class SNApiService return response.data?.valetToken } - public async startUploadSession(apiToken: string): Promise { + public async startUploadSession(apiToken: string): Promise> { const url = joinPaths(this.getFilesHost(), Paths.v1.startUploadSession) - const response: Responses.HttpResponse | Responses.StartUploadSessionResponse = await this.tokenRefreshableRequest({ + return this.tokenRefreshableRequest({ verb: HttpVerb.Post, url, customHeaders: [{ key: 'x-valet-token', value: apiToken }], fallbackErrorMessage: Strings.Network.Files.FailedStartUploadSession, }) - - return response as Responses.StartUploadSessionResponse } - public async deleteFile(apiToken: string): Promise { + public async deleteFile(apiToken: string): Promise> { const url = joinPaths(this.getFilesHost(), Paths.v1.deleteFile) - const response: Responses.HttpResponse | Responses.StartUploadSessionResponse = await this.tokenRefreshableRequest({ + return this.tokenRefreshableRequest({ verb: HttpVerb.Delete, url, customHeaders: [{ key: 'x-valet-token', value: apiToken }], fallbackErrorMessage: Strings.Network.Files.FailedDeleteFile, }) - - return response as Responses.MinimalHttpResponse } public async uploadFileBytes(apiToken: string, chunkId: number, encryptedBytes: Uint8Array): Promise { @@ -764,7 +752,7 @@ export class SNApiService } const url = joinPaths(this.getFilesHost(), Paths.v1.uploadFileChunk) - const response: Responses.HttpResponse | Responses.UploadFileChunkResponse = await this.tokenRefreshableRequest({ + const response = await this.tokenRefreshableRequest({ verb: HttpVerb.Post, url, rawBytes: encryptedBytes, @@ -776,20 +764,28 @@ export class SNApiService fallbackErrorMessage: Strings.Network.Files.FailedUploadFileChunk, }) - return (response as Responses.UploadFileChunkResponse).success + if (isErrorResponse(response)) { + return false + } + + return response.data.success } public async closeUploadSession(apiToken: string): Promise { const url = joinPaths(this.getFilesHost(), Paths.v1.closeUploadSession) - const response: Responses.HttpResponse | Responses.CloseUploadSessionResponse = await this.tokenRefreshableRequest({ + const response = await this.tokenRefreshableRequest({ verb: HttpVerb.Post, url, customHeaders: [{ key: 'x-valet-token', value: apiToken }], fallbackErrorMessage: Strings.Network.Files.FailedCloseUploadSession, }) - return (response as Responses.CloseUploadSessionResponse).success + if (isErrorResponse(response)) { + return false + } + + return response.data.success } public getFilesDownloadUrl(): string { @@ -806,21 +802,24 @@ export class SNApiService const url = this.getFilesDownloadUrl() const pullChunkSize = file.encryptedChunkSizes[chunkIndex] - const response: Responses.HttpResponse | Responses.DownloadFileChunkResponse = - await this.tokenRefreshableRequest({ - verb: HttpVerb.Get, - url, - customHeaders: [ - { key: 'x-valet-token', value: apiToken }, - { - key: 'x-chunk-size', - value: pullChunkSize.toString(), - }, - { key: 'range', value: `bytes=${contentRangeStart}-` }, - ], - fallbackErrorMessage: Strings.Network.Files.FailedDownloadFileChunk, - responseType: 'arraybuffer', - }) + const response = await this.tokenRefreshableRequest({ + verb: HttpVerb.Get, + url, + customHeaders: [ + { key: 'x-valet-token', value: apiToken }, + { + key: 'x-chunk-size', + value: pullChunkSize.toString(), + }, + { key: 'range', value: `bytes=${contentRangeStart}-` }, + ], + fallbackErrorMessage: Strings.Network.Files.FailedDownloadFileChunk, + responseType: 'arraybuffer', + }) + + if (isErrorResponse(response)) { + return new ClientDisplayableError(response.data?.error?.message as string) + } const contentRangeHeader = (>response.headers).get('content-range') if (!contentRangeHeader) { @@ -836,7 +835,7 @@ export class SNApiService const rangeEnd = +matches[3] const totalSize = +matches[4] - const bytesReceived = new Uint8Array(response.data as ArrayBuffer) + const bytesReceived = new Uint8Array(response.data) await onBytesReceived(bytesReceived) @@ -847,8 +846,8 @@ export class SNApiService return undefined } - async checkIntegrity(integrityPayloads: Responses.IntegrityPayload[]): Promise { - return await this.tokenRefreshableRequest({ + async checkIntegrity(integrityPayloads: IntegrityPayload[]): Promise> { + return this.tokenRefreshableRequest({ verb: HttpVerb.Post, url: joinPaths(this.host, Paths.v1.checkIntegrity), params: { @@ -859,8 +858,8 @@ export class SNApiService }) } - async getSingleItem(itemUuid: string): Promise { - return await this.tokenRefreshableRequest({ + async getSingleItem(itemUuid: string): Promise> { + return this.tokenRefreshableRequest({ verb: HttpVerb.Get, url: joinPaths(this.host, Paths.v1.getSingleItem(itemUuid)), fallbackErrorMessage: API_MESSAGE_GENERIC_SINGLE_ITEM_SYNC_FAIL, @@ -870,18 +869,19 @@ export class SNApiService private preprocessingError() { if (this.refreshingSession) { - return this.createErrorResponse(API_MESSAGE_TOKEN_REFRESH_IN_PROGRESS) + return this.createErrorResponse(API_MESSAGE_TOKEN_REFRESH_IN_PROGRESS, HttpStatusCode.BadRequest) } + if (!this.session) { - return this.createErrorResponse(API_MESSAGE_INVALID_SESSION) + return this.createErrorResponse(API_MESSAGE_INVALID_SESSION, HttpStatusCode.BadRequest) } + return undefined } - /** Handle errored responses to authenticated requests */ - private preprocessAuthenticatedErrorResponse(response: Responses.HttpResponse) { - if (response.status === Responses.StatusCode.HttpStatusInvalidSession && this.session) { - this.invalidSessionObserver?.(response.error?.tag === ErrorTag.RevokedSession) + private preprocessAuthenticatedErrorResponse(response: HttpResponse) { + if (response.status === HttpStatusCode.Unauthorized && this.session) { + this.invalidSessionObserver?.(response.data.error?.tag === ErrorTag.RevokedSession) } } diff --git a/packages/snjs/lib/Services/Api/HttpService.ts b/packages/snjs/lib/Services/Api/DeprecatedHttpService.ts similarity index 76% rename from packages/snjs/lib/Services/Api/HttpService.ts rename to packages/snjs/lib/Services/Api/DeprecatedHttpService.ts index 1757ff920..782843c77 100644 --- a/packages/snjs/lib/Services/Api/HttpService.ts +++ b/packages/snjs/lib/Services/Api/DeprecatedHttpService.ts @@ -1,4 +1,10 @@ -import { HttpResponse, StatusCode } from '@standardnotes/responses' +import { + DeprecatedHttpResponse, + DeprecatedStatusCode, + HttpRequestParams, + HttpVerb, + HttpRequest, +} from '@standardnotes/responses' import { isString } from '@standardnotes/utils' import { SnjsVersion } from '@Lib/Version' import { @@ -9,33 +15,12 @@ import { } from '@standardnotes/services' import { Environment } from '@standardnotes/models' -export enum HttpVerb { - Get = 'GET', - Post = 'POST', - Put = 'PUT', - Patch = 'PATCH', - Delete = 'DELETE', -} - const REQUEST_READY_STATE_COMPLETED = 4 -export type HttpParams = Record - -export type HttpRequest = { - url: string - params?: HttpParams - rawBytes?: Uint8Array - verb: HttpVerb - authentication?: string - customHeaders?: Record[] - responseType?: XMLHttpRequestResponseType - external?: boolean -} - /** * A non-SNJS specific wrapper for XMLHttpRequests */ -export class SNHttpService extends AbstractService { +export class DeprecatedHttpService extends AbstractService { constructor( private readonly environment: Environment, private readonly appVersion: string, @@ -44,27 +29,47 @@ export class SNHttpService extends AbstractService { super(internalEventBus) } - public async getAbsolute(url: string, params?: HttpParams, authentication?: string): Promise { + public async getAbsolute( + url: string, + params?: HttpRequestParams, + authentication?: string, + ): Promise { return this.runHttp({ url, params, verb: HttpVerb.Get, authentication }) } - public async postAbsolute(url: string, params?: HttpParams, authentication?: string): Promise { + public async postAbsolute( + url: string, + params?: HttpRequestParams, + authentication?: string, + ): Promise { return this.runHttp({ url, params, verb: HttpVerb.Post, authentication }) } - public async putAbsolute(url: string, params?: HttpParams, authentication?: string): Promise { + public async putAbsolute( + url: string, + params?: HttpRequestParams, + authentication?: string, + ): Promise { return this.runHttp({ url, params, verb: HttpVerb.Put, authentication }) } - public async patchAbsolute(url: string, params: HttpParams, authentication?: string): Promise { + public async patchAbsolute( + url: string, + params: HttpRequestParams, + authentication?: string, + ): Promise { return this.runHttp({ url, params, verb: HttpVerb.Patch, authentication }) } - public async deleteAbsolute(url: string, params?: HttpParams, authentication?: string): Promise { + public async deleteAbsolute( + url: string, + params?: HttpRequestParams, + authentication?: string, + ): Promise { return this.runHttp({ url, params, verb: HttpVerb.Delete, authentication }) } - public async runHttp(httpRequest: HttpRequest): Promise { + public async runHttp(httpRequest: HttpRequest): Promise { const request = this.createXmlRequest(httpRequest) return this.runRequest(request, this.createRequestBody(httpRequest)) @@ -84,7 +89,7 @@ export class SNHttpService extends AbstractService { private createXmlRequest(httpRequest: HttpRequest) { const request = new XMLHttpRequest() if (httpRequest.params && httpRequest.verb === HttpVerb.Get && Object.keys(httpRequest.params).length > 0) { - httpRequest.url = this.urlForUrlAndParams(httpRequest.url, httpRequest.params) + httpRequest.url = this.urlForUrlAndParams(httpRequest.url, httpRequest.params as Record) } request.open(httpRequest.verb, httpRequest.url, true) request.responseType = httpRequest.responseType ?? '' @@ -116,7 +121,7 @@ export class SNHttpService extends AbstractService { return request } - private async runRequest(request: XMLHttpRequest, body?: string | Uint8Array): Promise { + private async runRequest(request: XMLHttpRequest, body?: string | Uint8Array): Promise { return new Promise((resolve, reject) => { request.onreadystatechange = () => { this.stateChangeHandlerForRequest(request, resolve, reject) @@ -127,14 +132,14 @@ export class SNHttpService extends AbstractService { private stateChangeHandlerForRequest( request: XMLHttpRequest, - resolve: (response: HttpResponse) => void, - reject: (response: HttpResponse) => void, + resolve: (response: DeprecatedHttpResponse) => void, + reject: (response: DeprecatedHttpResponse) => void, ) { if (request.readyState !== REQUEST_READY_STATE_COMPLETED) { return } const httpStatus = request.status - const response: HttpResponse = { + const response: DeprecatedHttpResponse = { status: httpStatus, headers: new Map(), } @@ -152,7 +157,7 @@ export class SNHttpService extends AbstractService { }) try { - if (httpStatus !== StatusCode.HttpStatusNoContent) { + if (httpStatus !== DeprecatedStatusCode.HttpStatusNoContent) { let body const contentTypeHeader = response.headers?.get('content-type') || response.headers?.get('Content-Type') @@ -177,10 +182,13 @@ export class SNHttpService extends AbstractService { } catch (error) { console.error(error) } - if (httpStatus >= StatusCode.HttpStatusMinSuccess && httpStatus <= StatusCode.HttpStatusMaxSuccess) { + if ( + httpStatus >= DeprecatedStatusCode.HttpStatusMinSuccess && + httpStatus <= DeprecatedStatusCode.HttpStatusMaxSuccess + ) { resolve(response) } else { - if (httpStatus === StatusCode.HttpStatusForbidden) { + if (httpStatus === DeprecatedStatusCode.HttpStatusForbidden) { response.error = { message: API_MESSAGE_RATE_LIMITED, status: httpStatus, @@ -200,7 +208,7 @@ export class SNHttpService extends AbstractService { } } - private urlForUrlAndParams(url: string, params: HttpParams) { + private urlForUrlAndParams(url: string, params: Record) { const keyValueString = Object.keys(params) .map((key) => { return key + '=' + encodeURIComponent(params[key] as string) diff --git a/packages/snjs/lib/Services/Api/WebsocketsService.ts b/packages/snjs/lib/Services/Api/WebsocketsService.ts index fc76572fd..de84bcc1b 100644 --- a/packages/snjs/lib/Services/Api/WebsocketsService.ts +++ b/packages/snjs/lib/Services/Api/WebsocketsService.ts @@ -1,3 +1,4 @@ +import { isErrorResponse } from '@standardnotes/responses' import { UserRolesChangedEvent } from '@standardnotes/domain-events' import { AbstractService, InternalEventBusInterface, StorageKey } from '@standardnotes/services' import { WebSocketApiServiceInterface } from '@standardnotes/api' @@ -72,7 +73,7 @@ export class SNWebSocketsService extends AbstractService { try { const response = await this.webSocketApiService.createConnectionToken() - if (response.data.error) { + if (isErrorResponse(response)) { console.error(response.data.error) return undefined diff --git a/packages/snjs/lib/Services/Api/index.ts b/packages/snjs/lib/Services/Api/index.ts index 3e63ccbf8..da29683d0 100644 --- a/packages/snjs/lib/Services/Api/index.ts +++ b/packages/snjs/lib/Services/Api/index.ts @@ -1,5 +1,5 @@ export * from './ApiService' -export * from './HttpService' +export * from './DeprecatedHttpService' export * from './Paths' export * from '../Session/SessionManager' export * from './WebsocketsService' diff --git a/packages/snjs/lib/Services/Features/FeaturesService.ts b/packages/snjs/lib/Services/Features/FeaturesService.ts index db1718271..ac9a7e473 100644 --- a/packages/snjs/lib/Services/Features/FeaturesService.ts +++ b/packages/snjs/lib/Services/Features/FeaturesService.ts @@ -7,7 +7,7 @@ import { lastElement, isString, } from '@standardnotes/utils' -import { ClientDisplayableError, UserFeaturesResponse } from '@standardnotes/responses' +import { ClientDisplayableError, isErrorResponse } from '@standardnotes/responses' import { ContentType } from '@standardnotes/common' import { RoleName } from '@standardnotes/domain-core' import { FillItemContent, PayloadEmitSource } from '@standardnotes/models' @@ -417,8 +417,8 @@ export class SNFeaturesService if (shouldDownloadRoleBasedFeatures) { const featuresResponse = await this.apiService.getUserFeatures(userUuid) - if (!featuresResponse.error && featuresResponse.data && !this.deinited) { - const features = (featuresResponse as UserFeaturesResponse).data.features + if (!isErrorResponse(featuresResponse) && !this.deinited) { + const features = featuresResponse.data.features await this.didDownloadFeatures(features) } } @@ -747,7 +747,7 @@ export class SNFeaturesService private async performDownloadExternalFeature(url: string): Promise { const response = await this.apiService.downloadFeatureUrl(url) - if (response.error) { + if (response.data?.error) { await this.alertService.alert(API_MESSAGE_FAILED_DOWNLOADING_EXTENSION) return undefined } diff --git a/packages/snjs/lib/Services/KeyRecovery/KeyRecoveryService.ts b/packages/snjs/lib/Services/KeyRecovery/KeyRecoveryService.ts index 62cc56f01..670471ebe 100644 --- a/packages/snjs/lib/Services/KeyRecovery/KeyRecoveryService.ts +++ b/packages/snjs/lib/Services/KeyRecovery/KeyRecoveryService.ts @@ -18,7 +18,7 @@ import { SNApiService } from '@Lib/Services/Api/ApiService' import { ContentType } from '@standardnotes/common' import { ItemManager } from '../Items/ItemManager' import { removeFromArray, Uuids } from '@standardnotes/utils' -import { ClientDisplayableError, KeyParamsResponse } from '@standardnotes/responses' +import { ClientDisplayableError, isErrorResponse } from '@standardnotes/responses' import { AlertService, AbstractService, @@ -283,7 +283,7 @@ export class SNKeyRecoveryService extends AbstractService { const accountsBeforeRequest = await this.getSettingsBasedListedAccounts() const response = await this.apiService.registerForListedAccount() - if (response.error) { + if (isErrorResponse(response)) { return undefined } const MaxAttempts = 4 @@ -99,11 +99,12 @@ export class ListedService extends AbstractService implements ListedClientInterf const response = (await this.httpSerivce.getAbsolute(url).catch((error) => { console.error(error) })) as ListedAccountInfoResponse - if (!response || response.error || !response.data || isString(response.data)) { + + if (!response || response.data?.error || !response.data || isString(response.data)) { return undefined } - return response.data + return response } private async getSettingsBasedListedAccounts(): Promise { diff --git a/packages/snjs/lib/Services/Session/SessionManager.ts b/packages/snjs/lib/Services/Session/SessionManager.ts index c8f906c9e..b5991aefb 100644 --- a/packages/snjs/lib/Services/Session/SessionManager.ts +++ b/packages/snjs/lib/Services/Session/SessionManager.ts @@ -28,16 +28,28 @@ import { SessionRefreshedData, } from '@standardnotes/services' import { Base64String } from '@standardnotes/sncrypto-common' -import { ClientDisplayableError, SessionBody } from '@standardnotes/responses' +import { + ClientDisplayableError, + SessionBody, + ErrorTag, + HttpResponse, + isErrorResponse, + SessionListEntry, + User, + AvailableSubscriptions, + KeyParamsResponse, + SignInResponse, + ChangeCredentialsResponse, + SessionListResponse, + HttpSuccessResponse, +} from '@standardnotes/responses' import { CopyPayloadWithContentOverride } from '@standardnotes/models' -import { isNullOrUndefined } from '@standardnotes/utils' import { LegacySession, MapperInterface, Session, SessionToken } from '@standardnotes/domain-core' import { KeyParamsFromApiResponse, SNRootKeyParams, SNRootKey, CreateNewRootKey } from '@standardnotes/encryption' -import * as Responses from '@standardnotes/responses' import { Subscription } from '@standardnotes/security' import * as Common from '@standardnotes/common' -import { RemoteSession, RawStorageValue } from './Sessions/Types' +import { RawStorageValue } from './Sessions/Types' import { ShareToken } from './ShareToken' import { SNApiService } from '../Api/ApiService' import { DiskStorageService } from '../Storage/DiskStorageService' @@ -48,8 +60,6 @@ import { ChallengeService } from '../Challenge' import { ApiCallError, ErrorMessage, - ErrorTag, - HttpErrorResponseBody, HttpServiceInterface, UserApiServiceInterface, UserRegistrationResponseBody, @@ -76,7 +86,7 @@ export class SNSessionManager extends AbstractService implements SessionsClientInterface, InternalEventHandlerInterface { - private user?: Responses.User + private user?: User private isSessionRenewChallengePresented = false private session?: Session | LegacySession @@ -120,7 +130,7 @@ export class SNSessionManager super.deinit() } - private setUser(user?: Responses.User) { + private setUser(user?: User) { this.user = user this.apiService.setUser(user) } @@ -167,10 +177,10 @@ export class SNSessionManager } public offline() { - return isNullOrUndefined(this.apiService.getSession()) + return this.apiService.getSession() == undefined } - public getUser(): Responses.User | undefined { + public getUser(): User | undefined { return this.user } @@ -187,7 +197,7 @@ export class SNSessionManager } public getSureUser() { - return this.user as Responses.User + return this.user as User } public getSession() { @@ -213,7 +223,7 @@ export class SNSessionManager public async reauthenticateInvalidSession( cancelable = true, - onResponse?: (response: Responses.HttpResponse) => void, + onResponse?: (response: HttpResponse) => void, ): Promise { if (this.isSessionRenewChallengePresented) { return @@ -241,16 +251,16 @@ export class SNSessionManager const email = challengeResponse.values[0].value as string const password = challengeResponse.values[1].value as string const currentKeyParams = this.protocolService.getAccountKeyParams() - const signInResult = await this.signIn( + const { response } = await this.signIn( email, password, false, this.diskStorageService.isEphemeralSession(), currentKeyParams?.version, ) - if (signInResult.response.error) { + if (isErrorResponse(response)) { this.challengeService.setValidationStatusForChallenge(challenge, challengeResponse!.values[1], false) - onResponse?.(signInResult.response) + onResponse?.(response) } else { resolve() this.challengeService.completeChallenge(challenge) @@ -263,26 +273,26 @@ export class SNSessionManager }) } - public async getSubscription(): Promise { + public async getSubscription(): Promise { const result = await this.apiService.getSubscription(this.getSureUser().uuid) - if (result.error) { - return ClientDisplayableError.FromError(result.error) + if (isErrorResponse(result)) { + return ClientDisplayableError.FromError(result.data?.error) } - const subscription = (result as Responses.GetSubscriptionResponse).data!.subscription! + const subscription = result.data.subscription return subscription } - public async getAvailableSubscriptions(): Promise { + public async getAvailableSubscriptions(): Promise { const response = await this.apiService.getAvailableSubscriptions() - if (response.error) { - return ClientDisplayableError.FromError(response.error) + if (isErrorResponse(response)) { + return ClientDisplayableError.FromError(response.data.error) } - return (response as Responses.GetAvailableSubscriptionsResponse).data! + return response.data } private async promptForU2FVerification(username: string): Promise | undefined> { @@ -361,7 +371,7 @@ export class SNSessionManager const registerResponse = await this.userApiService.register({ email, serverPassword, keyParams, ephemeral }) if ('error' in registerResponse.data) { - throw new ApiCallError((registerResponse.data as HttpErrorResponseBody).error.message) + throw new ApiCallError(registerResponse.data.error.message) } await this.handleAuthentication({ @@ -376,37 +386,37 @@ export class SNSessionManager private async retrieveKeyParams(dto: { email: string - mfaKeyPath?: string mfaCode?: string authenticatorResponse?: Record }): Promise<{ keyParams?: SNRootKeyParams - response: Responses.KeyParamsResponse | Responses.HttpResponse - mfaKeyPath?: string + response: HttpResponse mfaCode?: string }> { const response = await this.apiService.getAccountKeyParams(dto) - if (response.error || isNullOrUndefined(response.data)) { + if (isErrorResponse(response) || !response.data) { if (dto.mfaCode) { await this.alertService.alert(SignInStrings.IncorrectMfa) } - if ([ErrorTag.U2FRequired, ErrorTag.MfaRequired].includes(response.error?.tag as ErrorTag)) { - const isU2FRequired = response.error?.tag === ErrorTag.U2FRequired + const error = isErrorResponse(response) ? response.data.error : undefined + + if (response.data && [ErrorTag.U2FRequired, ErrorTag.MfaRequired].includes(error?.tag as ErrorTag)) { + const isU2FRequired = error?.tag === ErrorTag.U2FRequired const result = isU2FRequired ? await this.promptForU2FVerification(dto.email) : await this.promptForMfaValue() if (!result) { return { response: this.apiService.createErrorResponse( SignInStrings.SignInCanceledMissingMfa, - Responses.StatusCode.CanceledMfa, + undefined, + ErrorTag.ClientCanceledMfa, ), } } return this.retrieveKeyParams({ email: dto.email, - mfaKeyPath: isU2FRequired ? undefined : response.error?.payload?.mfa_key, mfaCode: isU2FRequired ? undefined : (result as string), authenticatorResponse: isU2FRequired ? (result as Record) : undefined, }) @@ -415,13 +425,13 @@ export class SNSessionManager } } /** Make sure to use client value for identifier/email */ - const keyParams = KeyParamsFromApiResponse(response as Responses.KeyParamsResponse, dto.email) + const keyParams = KeyParamsFromApiResponse(response.data, dto.email) if (!keyParams || !keyParams.version) { return { response: this.apiService.createErrorResponse(API_MESSAGE_FALLBACK_LOGIN_FAIL), } } - return { keyParams, response, mfaKeyPath: dto.mfaKeyPath, mfaCode: dto.mfaCode } + return { keyParams, response, mfaCode: dto.mfaCode } } public async signIn( @@ -433,9 +443,9 @@ export class SNSessionManager ): Promise { const result = await this.performSignIn(email, password, strict, ephemeral, minAllowedVersion) if ( - result.response.error && - result.response.error.status !== Responses.StatusCode.LocalValidationError && - result.response.error.status !== Responses.StatusCode.CanceledMfa + isErrorResponse(result.response) && + result.response.data.error.tag !== ErrorTag.ClientValidationError && + result.response.data.error.tag !== ErrorTag.ClientCanceledMfa ) { const cleanedEmail = cleanedEmailString(email) if (cleanedEmail !== email) { @@ -461,7 +471,7 @@ export class SNSessionManager const paramsResult = await this.retrieveKeyParams({ email, }) - if (paramsResult.response.error) { + if (isErrorResponse(paramsResult.response)) { return { response: paramsResult.response, } @@ -512,7 +522,7 @@ export class SNSessionManager minAllowedVersion = this.protocolService.getLatestVersion() } - if (!isNullOrUndefined(minAllowedVersion)) { + if (minAllowedVersion != undefined) { if (!Common.leftVersionGreaterThanOrEqualToRight(keyParams.version, minAllowedVersion)) { return { response: this.apiService.createErrorResponse(StrictSignInFailed(keyParams.version, minAllowedVersion)), @@ -521,6 +531,7 @@ export class SNSessionManager } const rootKey = await this.protocolService.computeRootKey(password, keyParams) const signInResponse = await this.bypassChecksAndSignInWithRootKey(email, rootKey, ephemeral) + return { response: signInResponse, } @@ -530,13 +541,14 @@ export class SNSessionManager email: string, rootKey: SNRootKey, ephemeral = false, - ): Promise { + ): Promise> { const { wrappingKey, canceled } = await this.challengeService.getWrappingKeyIfApplicable() if (canceled) { return this.apiService.createErrorResponse( SignInStrings.PasscodeRequired, - Responses.StatusCode.LocalValidationError, + undefined, + ErrorTag.ClientValidationError, ) } @@ -546,18 +558,18 @@ export class SNSessionManager ephemeral, }) - if (signInResponse.error || !signInResponse.data) { + if (!signInResponse.data || isErrorResponse(signInResponse)) { return signInResponse } - const updatedKeyParams = (signInResponse as Responses.SignInResponse).data.key_params + const updatedKeyParams = signInResponse.data.key_params const expandedRootKey = new SNRootKey( CopyPayloadWithContentOverride(rootKey.payload, { keyParams: updatedKeyParams || rootKey.keyParams.getPortableValue(), }), ) - await this.handleSuccessAuthResponse(signInResponse as Responses.SignInResponse, expandedRootKey, wrappingKey) + await this.handleSuccessAuthResponse(signInResponse, expandedRootKey, wrappingKey) return signInResponse } @@ -577,59 +589,54 @@ export class SNSessionManager newEmail: parameters.newEmail, }) - return this.processChangeCredentialsResponse( - response as Responses.ChangeCredentialsResponse, - parameters.newRootKey, - parameters.wrappingKey, - ) + return this.processChangeCredentialsResponse(response, parameters.newRootKey, parameters.wrappingKey) } - public async getSessionsList(): Promise< - (Responses.HttpResponse & { data: RemoteSession[] }) | Responses.HttpResponse - > { + public async getSessionsList(): Promise> { const response = await this.apiService.getSessionsList() - if (response.error || isNullOrUndefined(response.data)) { + + if (isErrorResponse(response)) { return response } - ;( - response as Responses.HttpResponse & { - data: RemoteSession[] - } - ).data = (response as Responses.SessionListResponse).data - .map((session) => ({ - ...session, - updated_at: new Date(session.updated_at), - })) - .sort((s1: RemoteSession, s2: RemoteSession) => (s1.updated_at < s2.updated_at ? 1 : -1)) + + response.data = response.data.sort((s1: SessionListEntry, s2: SessionListEntry) => { + return new Date(s1.updated_at) < new Date(s2.updated_at) ? 1 : -1 + }) + return response } - public async revokeSession(sessionId: UuidString): Promise { - const response = await this.apiService.deleteSession(sessionId) - return response + public async revokeSession(sessionId: UuidString): Promise> { + return this.apiService.deleteSession(sessionId) } public async revokeAllOtherSessions(): Promise { const response = await this.getSessionsList() - if (response.error != undefined || response.data == undefined) { - throw new Error(response.error?.message ?? API_MESSAGE_GENERIC_SYNC_FAIL) + if (isErrorResponse(response) || !response.data) { + const error = isErrorResponse(response) ? response.data?.error : undefined + throw new Error(error?.message ?? API_MESSAGE_GENERIC_SYNC_FAIL) } - const sessions = response.data as RemoteSession[] - const otherSessions = sessions.filter((session) => !session.current) + + const otherSessions = response.data.filter((session) => !session.current) await Promise.all(otherSessions.map((session) => this.revokeSession(session.uuid))) } private async processChangeCredentialsResponse( - response: Responses.ChangeCredentialsResponse, + response: HttpResponse, newRootKey: SNRootKey, wrappingKey?: SNRootKey, ): Promise { - if (!response.error && response.data) { - await this.handleSuccessAuthResponse(response as Responses.ChangeCredentialsResponse, newRootKey, wrappingKey) + if (isErrorResponse(response)) { + return { + response: response, + } } + + await this.handleSuccessAuthResponse(response, newRootKey, wrappingKey) + return { response: response, - keyParams: (response as Responses.ChangeCredentialsResponse).data?.key_params, + keyParams: response.data?.key_params, } } @@ -690,7 +697,7 @@ export class SNSessionManager private async populateSession( rootKey: SNRootKey, - user: Responses.User, + user: User, session: Session | LegacySession, host: string, wrappingKey?: SNRootKey, @@ -734,17 +741,17 @@ export class SNSessionManager * @deprecated use handleAuthentication instead */ private async handleSuccessAuthResponse( - response: Responses.SignInResponse | Responses.ChangeCredentialsResponse, + response: HttpSuccessResponse, rootKey: SNRootKey, wrappingKey?: SNRootKey, ) { const { data } = response - const user = data.user as Responses.User + const user = data.user const isLegacyJwtResponse = data.token != undefined if (isLegacyJwtResponse) { const sessionOrError = LegacySession.create(data.token as string) - if (!sessionOrError.isFailed()) { + if (!sessionOrError.isFailed() && user) { await this.populateSession(rootKey, user, sessionOrError.getValue(), this.apiService.getHost(), wrappingKey) } } else if (data.session) { @@ -755,7 +762,7 @@ export class SNSessionManager data.session.refresh_expiration, data.session.readonly_access, ) - if (session !== null) { + if (session !== null && user) { await this.populateSession(rootKey, user, session, this.apiService.getHost(), wrappingKey) } } diff --git a/packages/snjs/lib/Services/Session/Sessions/Types.ts b/packages/snjs/lib/Services/Session/Sessions/Types.ts index 6fea67bc5..53b376a0d 100644 --- a/packages/snjs/lib/Services/Session/Sessions/Types.ts +++ b/packages/snjs/lib/Services/Session/Sessions/Types.ts @@ -11,10 +11,3 @@ export type RawSessionPayload = { } export type RawStorageValue = RawJwtPayload | RawSessionPayload - -export type RemoteSession = { - uuid: string - updated_at: Date - device_info: string - current: boolean -} diff --git a/packages/snjs/lib/Services/Settings/SettingsGateway.ts b/packages/snjs/lib/Services/Settings/SettingsGateway.ts index 495a4bb1e..227a12841 100644 --- a/packages/snjs/lib/Services/Settings/SettingsGateway.ts +++ b/packages/snjs/lib/Services/Settings/SettingsGateway.ts @@ -1,7 +1,7 @@ import { SettingsList } from './SettingsList' import { SettingName, SensitiveSettingName, SubscriptionSettingName } from '@standardnotes/settings' import { API_MESSAGE_INVALID_SESSION } from '@standardnotes/services' -import { StatusCode, User } from '@standardnotes/responses' +import { HttpStatusCode, isErrorResponse, User } from '@standardnotes/responses' import { SettingsServerInterface } from './SettingsServerInterface' /** @@ -31,30 +31,29 @@ export class SettingsGateway { } async listSettings() { - const { error, data } = await this.settingsApi.listSettings(this.userUuid) + const response = await this.settingsApi.listSettings(this.userUuid) - if (error != undefined) { - throw new Error(error.message) + if (isErrorResponse(response)) { + throw new Error(response.data?.error.message) } - if (data == undefined || data.settings == undefined) { + if (response.data == undefined || response.data.settings == undefined) { return new SettingsList([]) } - const settings: SettingsList = new SettingsList(data.settings) + const settings: SettingsList = new SettingsList(response.data.settings) return settings } async getSetting(name: SettingName): Promise { const response = await this.settingsApi.getSetting(this.userUuid, name) - // Backend responds with 400 when setting doesn't exist - if (response.status === StatusCode.HttpBadRequest) { + if (response.status === HttpStatusCode.BadRequest) { return undefined } - if (response.error != undefined) { - throw new Error(response.error.message) + if (isErrorResponse(response)) { + throw new Error(response.data?.error.message) } return response?.data?.setting?.value ?? undefined @@ -63,12 +62,12 @@ export class SettingsGateway { async getSubscriptionSetting(name: SubscriptionSettingName): Promise { const response = await this.settingsApi.getSubscriptionSetting(this.userUuid, name) - if (response.status === StatusCode.HttpBadRequest) { + if (response.status === HttpStatusCode.BadRequest) { return undefined } - if (response.error != undefined) { - throw new Error(response.error.message) + if (isErrorResponse(response)) { + throw new Error(response.data?.error.message) } return response?.data?.setting?.value ?? undefined @@ -77,29 +76,28 @@ export class SettingsGateway { async getDoesSensitiveSettingExist(name: SensitiveSettingName): Promise { const response = await this.settingsApi.getSetting(this.userUuid, name) - // Backend responds with 400 when setting doesn't exist - if (response.status === StatusCode.HttpBadRequest) { + if (response.status === HttpStatusCode.BadRequest) { return false } - if (response.error != undefined) { - throw new Error(response.error.message) + if (isErrorResponse(response)) { + throw new Error(response.data?.error.message) } return response.data?.success ?? false } async updateSetting(name: SettingName, payload: string, sensitive: boolean): Promise { - const { error } = await this.settingsApi.updateSetting(this.userUuid, name, payload, sensitive) - if (error != undefined) { - throw new Error(error.message) + const response = await this.settingsApi.updateSetting(this.userUuid, name, payload, sensitive) + if (isErrorResponse(response)) { + throw new Error(response.data?.error.message) } } async deleteSetting(name: SettingName): Promise { - const { error } = await this.settingsApi.deleteSetting(this.userUuid, name) - if (error != undefined) { - throw new Error(error.message) + const response = await this.settingsApi.deleteSetting(this.userUuid, name) + if (isErrorResponse(response)) { + throw new Error(response.data?.error.message) } } diff --git a/packages/snjs/lib/Services/Settings/SettingsServerInterface.ts b/packages/snjs/lib/Services/Settings/SettingsServerInterface.ts index 3056e1821..3c05dde89 100644 --- a/packages/snjs/lib/Services/Settings/SettingsServerInterface.ts +++ b/packages/snjs/lib/Services/Settings/SettingsServerInterface.ts @@ -1,24 +1,25 @@ import { DeleteSettingResponse, GetSettingResponse, + HttpResponse, ListSettingsResponse, UpdateSettingResponse, } from '@standardnotes/responses' import { UuidString } from '@Lib/Types/UuidString' export interface SettingsServerInterface { - listSettings(userUuid: UuidString): Promise + listSettings(userUuid: UuidString): Promise> updateSetting( userUuid: UuidString, settingName: string, settingValue: string, sensitive: boolean, - ): Promise + ): Promise> - getSetting(userUuid: UuidString, settingName: string): Promise + getSetting(userUuid: UuidString, settingName: string): Promise> - getSubscriptionSetting(userUuid: UuidString, settingName: string): Promise + getSubscriptionSetting(userUuid: UuidString, settingName: string): Promise> - deleteSetting(userUuid: UuidString, settingName: string): Promise + deleteSetting(userUuid: UuidString, settingName: string): Promise> } diff --git a/packages/snjs/lib/Services/Sync/Account/Operation.ts b/packages/snjs/lib/Services/Sync/Account/Operation.ts index cacabdf2f..6d621c2d6 100644 --- a/packages/snjs/lib/Services/Sync/Account/Operation.ts +++ b/packages/snjs/lib/Services/Sync/Account/Operation.ts @@ -3,7 +3,6 @@ import { arrayByDifference, nonSecureRandomIdentifier, subtractFromArray } from import { ServerSyncResponse } from '@Lib/Services/Sync/Account/Response' import { ResponseSignalReceiver, SyncSignal } from '@Lib/Services/Sync/Signals' import { SNApiService } from '../../Api/ApiService' -import { RawSyncResponse } from '@standardnotes/responses' export const SyncUpDownLimit = 150 @@ -56,12 +55,7 @@ export class AccountSyncOperation { }) const payloads = this.popPayloads(this.upLimit) - const rawResponse = (await this.apiService.sync( - payloads, - this.lastSyncToken, - this.paginationToken, - this.downLimit, - )) as RawSyncResponse + const rawResponse = await this.apiService.sync(payloads, this.lastSyncToken, this.paginationToken, this.downLimit) const response = new ServerSyncResponse(rawResponse) this.responses.push(response) diff --git a/packages/snjs/lib/Services/Sync/Account/Response.ts b/packages/snjs/lib/Services/Sync/Account/Response.ts index b11c36081..3732520f4 100644 --- a/packages/snjs/lib/Services/Sync/Account/Response.ts +++ b/packages/snjs/lib/Services/Sync/Account/Response.ts @@ -2,7 +2,9 @@ import { ApiEndpointParam, ConflictParams, ConflictType, - Error, + HttpError, + HttpResponse, + isErrorResponse, RawSyncResponse, ServerItemResponse, } from '@standardnotes/responses' @@ -12,24 +14,31 @@ import { ServerSyncSavedContextualPayload, FilteredServerItem, } from '@standardnotes/models' -import { deepFreeze, isNullOrUndefined } from '@standardnotes/utils' +import { deepFreeze } from '@standardnotes/utils' export class ServerSyncResponse { - public readonly rawResponse: RawSyncResponse public readonly savedPayloads: ServerSyncSavedContextualPayload[] public readonly retrievedPayloads: FilteredServerItem[] public readonly uuidConflictPayloads: FilteredServerItem[] public readonly dataConflictPayloads: FilteredServerItem[] public readonly rejectedPayloads: FilteredServerItem[] - constructor(rawResponse: RawSyncResponse) { + private successResponseData: RawSyncResponse | undefined + + constructor(public rawResponse: HttpResponse) { this.rawResponse = rawResponse - this.savedPayloads = FilterDisallowedRemotePayloadsAndMap(rawResponse.data?.saved_items || []).map((rawItem) => { - return CreateServerSyncSavedPayload(rawItem) - }) + if (!isErrorResponse(rawResponse)) { + this.successResponseData = rawResponse.data + } - this.retrievedPayloads = FilterDisallowedRemotePayloadsAndMap(rawResponse.data?.retrieved_items || []) + this.savedPayloads = FilterDisallowedRemotePayloadsAndMap(this.successResponseData?.saved_items || []).map( + (rawItem) => { + return CreateServerSyncSavedPayload(rawItem) + }, + ) + + this.retrievedPayloads = FilterDisallowedRemotePayloadsAndMap(this.successResponseData?.retrieved_items || []) this.dataConflictPayloads = FilterDisallowedRemotePayloadsAndMap(this.rawDataConflictItems) @@ -40,8 +49,8 @@ export class ServerSyncResponse { deepFreeze(this) } - public get error(): Error | undefined { - return this.rawResponse.error || this.rawResponse.data?.error + public get error(): HttpError | undefined { + return isErrorResponse(this.rawResponse) ? this.rawResponse.data?.error : undefined } public get status(): number { @@ -49,11 +58,11 @@ export class ServerSyncResponse { } public get lastSyncToken(): string | undefined { - return this.rawResponse.data?.[ApiEndpointParam.LastSyncToken] + return this.successResponseData?.[ApiEndpointParam.LastSyncToken] } public get paginationToken(): string | undefined { - return this.rawResponse.data?.[ApiEndpointParam.PaginationToken] + return this.successResponseData?.[ApiEndpointParam.PaginationToken] } public get numberOfItemsInvolved(): number { @@ -75,7 +84,7 @@ export class ServerSyncResponse { return conflict.type === ConflictType.UuidConflict }) .map((conflict) => { - return conflict.unsaved_item || (conflict.item as ServerItemResponse) + return conflict.unsaved_item || conflict.item! }) } @@ -85,7 +94,7 @@ export class ServerSyncResponse { return conflict.type === ConflictType.ConflictingData }) .map((conflict) => { - return conflict.server_item || (conflict.item as ServerItemResponse) + return conflict.server_item || conflict.item! }) } @@ -99,17 +108,17 @@ export class ServerSyncResponse { ) }) .map((conflict) => { - return conflict.unsaved_item as ServerItemResponse + return conflict.unsaved_item! }) } private get rawConflictObjects(): ConflictParams[] { - const conflicts = this.rawResponse.data?.conflicts || [] - const legacyConflicts = this.rawResponse.data?.unsaved || [] + const conflicts = this.successResponseData?.conflicts || [] + const legacyConflicts = this.successResponseData?.unsaved || [] return conflicts.concat(legacyConflicts) } public get hasError(): boolean { - return !isNullOrUndefined(this.rawResponse.error) + return this.error != undefined } } diff --git a/packages/snjs/lib/index.ts b/packages/snjs/lib/index.ts index 92d8f264a..2fcd3fcd7 100644 --- a/packages/snjs/lib/index.ts +++ b/packages/snjs/lib/index.ts @@ -13,7 +13,10 @@ export * from '@standardnotes/encryption' export * from '@standardnotes/features' export * from '@standardnotes/files' export * from '@standardnotes/models' + export * from '@standardnotes/responses' +export { ErrorTag } from '@standardnotes/responses' + export * from '@standardnotes/services' export * from '@standardnotes/settings' export * from '@standardnotes/utils' diff --git a/packages/snjs/mocha/auth.test.js b/packages/snjs/mocha/auth.test.js index c4e0c77c8..d120e491b 100644 --- a/packages/snjs/mocha/auth.test.js +++ b/packages/snjs/mocha/auth.test.js @@ -68,7 +68,7 @@ describe('basic auth', function () { this.application = await Factory.signOutApplicationAndReturnNew(this.application) const response = await this.application.signIn(this.email, this.password, undefined, undefined, undefined, true) expect(response).to.be.ok - expect(response.error).to.not.be.ok + expect(response.data.error).to.not.be.ok expect(await this.application.protocolService.getRootKey()).to.be.ok }).timeout(20000) @@ -78,7 +78,7 @@ describe('basic auth', function () { this.application = await Factory.signOutApplicationAndReturnNew(this.application) const response = await this.application.signIn(this.email, this.password, undefined, undefined, undefined, true) expect(response).to.be.ok - expect(response.error).to.not.be.ok + expect(response.data.error).to.not.be.ok expect(await this.application.protocolService.getRootKey()).to.be.ok let error @@ -110,7 +110,7 @@ describe('basic auth', function () { (async () => { const response = await this.application.signIn(this.email, this.password, undefined, undefined, undefined, true) expect(response).to.be.ok - expect(response.error).to.not.be.ok + expect(response.data.error).to.not.be.ok expect(await this.application.protocolService.getRootKey()).to.be.ok })(), (async () => { @@ -157,12 +157,12 @@ describe('basic auth', function () { let response = await this.application.signIn(this.email, 'wrong password', undefined, undefined, undefined, true) expect(response).to.have.property('status', 401) - expect(response.error).to.be.ok + expect(response.data.error).to.be.ok response = await this.application.signIn(this.email, this.password, undefined, undefined, undefined, true) expect(response.status).to.equal(200) - expect(response).to.not.haveOwnProperty('error') + expect(response.data).to.not.haveOwnProperty('error') }).timeout(20000) it('server retrieved key params should use our client inputted value for identifier', async function () { @@ -203,7 +203,7 @@ describe('basic auth', function () { this.application = await Factory.signOutApplicationAndReturnNew(this.application) const response = await this.application.signIn(uppercase, this.password, undefined, undefined, undefined, true) expect(response).to.be.ok - expect(response.error).to.not.be.ok + expect(response.data.error).to.not.be.ok expect(await this.application.protocolService.getRootKey()).to.be.ok }).timeout(20000) @@ -219,7 +219,7 @@ describe('basic auth', function () { this.application = await Factory.signOutApplicationAndReturnNew(this.application) const response = await this.application.signIn(withspace, this.password, undefined, undefined, undefined, true) expect(response).to.be.ok - expect(response.error).to.not.be.ok + expect(response.data.error).to.not.be.ok expect(await this.application.protocolService.getRootKey()).to.be.ok }).timeout(20000) @@ -228,7 +228,7 @@ describe('basic auth', function () { this.application = await Factory.signOutApplicationAndReturnNew(this.application) const response = await this.application.signIn(this.email, 'wrongpassword', undefined, undefined, undefined, true) expect(response).to.be.ok - expect(response.error).to.be.ok + expect(response.data.error).to.be.ok expect(await this.application.protocolService.getRootKey()).to.not.be.ok }).timeout(20000) @@ -337,7 +337,7 @@ describe('basic auth', function () { const signinResponse = await this.application.signIn(this.email, newPassword, undefined, undefined, undefined, true) expect(signinResponse).to.be.ok - expect(signinResponse.error).to.not.be.ok + expect(signinResponse.data.error).to.not.be.ok expect(await this.application.protocolService.getRootKey()).to.be.ok @@ -420,7 +420,7 @@ describe('basic auth', function () { ) expect(signinResponse).to.be.ok - expect(signinResponse.error).to.not.be.ok + expect(signinResponse.data.error).to.not.be.ok expect(await this.application.protocolService.getRootKey()).to.be.ok } }).timeout(80000) diff --git a/packages/snjs/mocha/session.test.js b/packages/snjs/mocha/session.test.js index 1943db02a..20825f4f9 100644 --- a/packages/snjs/mocha/session.test.js +++ b/packages/snjs/mocha/session.test.js @@ -172,8 +172,8 @@ describe('server session', function () { Factory.ignoreChallenges(this.application) const syncResponse = await this.application.apiService.sync([]) expect(syncResponse.status).to.equal(401) - expect(syncResponse.error.tag).to.equal('invalid-auth') - expect(syncResponse.error.message).to.equal('Invalid login credentials.') + expect(syncResponse.data.error.tag).to.equal('invalid-auth') + expect(syncResponse.data.error.message).to.equal('Invalid login credentials.') }) it('sign out request should be performed successfully and terminate session with expired access token', async function () { @@ -194,8 +194,8 @@ describe('server session', function () { Factory.ignoreChallenges(this.application) const syncResponse = await this.application.apiService.sync([]) expect(syncResponse.status).to.equal(401) - expect(syncResponse.error.tag).to.equal('invalid-auth') - expect(syncResponse.error.message).to.equal('Invalid login credentials.') + expect(syncResponse.data.error.tag).to.equal('invalid-auth') + expect(syncResponse.data.error.message).to.equal('Invalid login credentials.') }) it('change email request should be successful with a valid access token', async function () { @@ -207,8 +207,7 @@ describe('server session', function () { const newEmail = UuidGenerator.GenerateUuid() const changeEmailResponse = await application.changeEmail(newEmail, password) - expect(changeEmailResponse.status).to.equal(200) - expect(changeEmailResponse.data.user).to.be.ok + expect(changeEmailResponse.error).to.not.be.ok application = await Factory.signOutApplicationAndReturnNew(application) const loginResponse = await Factory.loginToApplication({ @@ -277,8 +276,7 @@ describe('server session', function () { const changePasswordResponse = await this.application.changePassword(this.password, this.newPassword) - expect(changePasswordResponse.status).to.equal(200) - expect(changePasswordResponse.data.user).to.be.ok + expect(changePasswordResponse.error).to.not.be.ok this.application = await Factory.signOutApplicationAndReturnNew(this.application) const loginResponse = await Factory.loginToApplication({ @@ -305,8 +303,7 @@ describe('server session', function () { const changePasswordResponse = await this.application.changePassword(this.password, this.newPassword) - expect(changePasswordResponse).to.be.ok - expect(changePasswordResponse.status).to.equal(200) + expect(changePasswordResponse.error).to.not.be.ok this.application = await Factory.signOutApplicationAndReturnNew(this.application) const loginResponse = await Factory.loginToApplication({ @@ -393,8 +390,8 @@ describe('server session', function () { const refreshSessionResponse = await this.application.apiService.refreshSession() expect(refreshSessionResponse.status).to.equal(400) - expect(refreshSessionResponse.error.tag).to.equal('expired-refresh-token') - expect(refreshSessionResponse.error.message).to.equal('The refresh token has expired.') + expect(refreshSessionResponse.data.error.tag).to.equal('expired-refresh-token') + expect(refreshSessionResponse.data.error.message).to.equal('The refresh token has expired.') /* The access token and refresh token should be expired up to this point. @@ -403,8 +400,8 @@ describe('server session', function () { Factory.ignoreChallenges(this.application) const syncResponse = await this.application.apiService.sync([]) expect(syncResponse.status).to.equal(401) - expect(syncResponse.error.tag).to.equal('invalid-auth') - expect(syncResponse.error.message).to.equal('Invalid login credentials.') + expect(syncResponse.data.error.tag).to.equal('invalid-auth') + expect(syncResponse.data.error.message).to.equal('Invalid login credentials.') }) it('should fail when renewing a session with an invalid refresh token', async function () { @@ -428,8 +425,8 @@ describe('server session', function () { const refreshSessionResponse = await this.application.apiService.refreshSession() expect(refreshSessionResponse.status).to.equal(400) - expect(refreshSessionResponse.error.tag).to.equal('invalid-refresh-token') - expect(refreshSessionResponse.error.message).to.equal('The refresh token is not valid.') + expect(refreshSessionResponse.data.error.tag).to.equal('invalid-refresh-token') + expect(refreshSessionResponse.data.error.message).to.equal('The refresh token is not valid.') // Access token should remain valid. const syncResponse = await this.application.apiService.sync([]) @@ -446,10 +443,10 @@ describe('server session', function () { const refreshPromise = this.application.apiService.refreshSession() const syncResponse = await this.application.apiService.sync([]) - expect(syncResponse.error).to.be.ok + expect(syncResponse.data.error).to.be.ok const errorMessage = 'Your account session is being renewed with the server. Please try your request again.' - expect(syncResponse.error.message).to.be.equal(errorMessage) + expect(syncResponse.data.error.message).to.be.equal(errorMessage) /** Wait for finish so that test cleans up properly */ await refreshPromise }) diff --git a/packages/web/src/javascripts/Components/AccountMenu/SignIn.tsx b/packages/web/src/javascripts/Components/AccountMenu/SignIn.tsx index 00f3c73ac..282d9c42b 100644 --- a/packages/web/src/javascripts/Components/AccountMenu/SignIn.tsx +++ b/packages/web/src/javascripts/Components/AccountMenu/SignIn.tsx @@ -12,6 +12,7 @@ import Icon from '@/Components/Icon/Icon' import IconButton from '@/Components/Button/IconButton' import AdvancedOptions from './AdvancedOptions' import HorizontalSeparator from '../Shared/HorizontalSeparator' +import { isErrorResponse } from '@standardnotes/snjs' type Props = { viewControllerManager: ViewControllerManager @@ -96,9 +97,9 @@ const SignInPane: FunctionComponent = ({ application, viewControllerManag application .signIn(email, password, isStrictSignin, isEphemeral, shouldMergeLocal) - .then((res) => { - if (res.error) { - throw new Error(res.error.message) + .then((response) => { + if (isErrorResponse(response)) { + throw new Error(response.data?.error.message) } viewControllerManager.accountMenuController.closeAccountMenu() }) diff --git a/packages/web/src/javascripts/Components/PurchaseFlow/Panes/SignIn.tsx b/packages/web/src/javascripts/Components/PurchaseFlow/Panes/SignIn.tsx index 30e7fae76..4f3296db3 100644 --- a/packages/web/src/javascripts/Components/PurchaseFlow/Panes/SignIn.tsx +++ b/packages/web/src/javascripts/Components/PurchaseFlow/Panes/SignIn.tsx @@ -7,6 +7,7 @@ import { ChangeEventHandler, FunctionComponent, useEffect, useRef, useState } fr import FloatingLabelInput from '@/Components/Input/FloatingLabelInput' import { isEmailValid } from '@/Utils' import { BlueDotIcon, CircleIcon, DiamondIcon } from '@standardnotes/icons' +import { isErrorResponse } from '@standardnotes/snjs' type Props = { viewControllerManager: ViewControllerManager @@ -70,8 +71,8 @@ const SignIn: FunctionComponent = ({ viewControllerManager, application } try { const response = await application.signIn(email, password) - if (response.error || response.data?.error) { - throw new Error(response.error?.message || response.data?.error?.message) + if (isErrorResponse(response)) { + throw new Error(response.data.error?.message) } else { viewControllerManager.purchaseFlowController.closePurchaseFlow() viewControllerManager.purchaseFlowController.openPurchaseFlow() diff --git a/packages/web/src/javascripts/Components/SessionsModal/SessionsModal.tsx b/packages/web/src/javascripts/Components/SessionsModal/SessionsModal.tsx index 72c8a128a..576eed9ec 100644 --- a/packages/web/src/javascripts/Components/SessionsModal/SessionsModal.tsx +++ b/packages/web/src/javascripts/Components/SessionsModal/SessionsModal.tsx @@ -1,5 +1,5 @@ import { ViewControllerManager } from '@/Controllers/ViewControllerManager' -import { SNApplication, SessionStrings, UuidString, isNullOrUndefined, RemoteSession } from '@standardnotes/snjs' +import { SNApplication, SessionStrings, UuidString, SessionListEntry, isErrorResponse } from '@standardnotes/snjs' import { FunctionComponent, useState, useEffect, useRef, useMemo, useCallback } from 'react' import { Alert } from '@reach/alert' import { AlertDialog, AlertDialogDescription, AlertDialogLabel } from '@reach/alert-dialog' @@ -11,7 +11,7 @@ import Icon from '../Icon/Icon' import Modal, { ModalAction } from '../Modal/Modal' import ModalOverlay from '../Modal/ModalOverlay' -type Session = RemoteSession & { +type Session = SessionListEntry & { revoking?: true } @@ -26,18 +26,20 @@ function useSessions( useEffect(() => { ;(async () => { setRefreshing(true) + const response = await application.getSessions() - if ('error' in response || isNullOrUndefined(response.data)) { - if (response.error?.message) { - setErrorMessage(response.error.message) + if (isErrorResponse(response)) { + if (response.data?.error?.message) { + setErrorMessage(response.data?.error.message) } else { setErrorMessage('An unknown error occured while loading sessions.') } } else { - const sessions = response.data as RemoteSession[] + const sessions = response.data as SessionListEntry[] setSessions(sessions) setErrorMessage('') } + setRefreshing(false) })().catch(console.error) }, [application, lastRefreshDate]) @@ -60,13 +62,11 @@ function useSessions( setSessions(sessionsDuringRevoke) const response = await responsePromise - if (isNullOrUndefined(response)) { + if (!response) { setSessions(sessionsBeforeRevoke) - } else if ('error' in response) { - if (response.error?.message) { - setErrorMessage(response.error?.message) - } else { - setErrorMessage('An unknown error occured while revoking the session.') + } else if (isErrorResponse(response)) { + if (response.data?.error.message) { + setErrorMessage(response.data?.error.message || 'An unknown error occured while revoking the session.') } setSessions(sessionsBeforeRevoke) } else { @@ -145,7 +145,7 @@ const SessionsModalContent: FunctionComponent<{ Current session ) : ( <> -

Signed in on {formatter.format(session.updated_at)}

+

Signed in on {formatter.format(new Date(session.updated_at))}