feat(api): add websocket api definitions
This commit is contained in:
@@ -10,10 +10,10 @@ module.exports = {
|
||||
},
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
branches: 17,
|
||||
functions: 43,
|
||||
lines: 46,
|
||||
statements: 46
|
||||
branches: 20,
|
||||
functions: 66,
|
||||
lines: 63,
|
||||
statements: 63
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -32,7 +32,8 @@
|
||||
"eslint": "^8.23.0",
|
||||
"eslint-plugin-prettier": "*",
|
||||
"jest": "^28.1.2",
|
||||
"ts-jest": "^28.0.5"
|
||||
"ts-jest": "^28.0.5",
|
||||
"typescript": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@standardnotes/common": "^1.32.0",
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export enum WebSocketApiOperations {
|
||||
CreatingConnectionToken,
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import { WebSocketConnectionTokenResponse } from '../../Response'
|
||||
|
||||
import { WebSocketServerInterface } from '../../Server/WebSocket/WebSocketServerInterface'
|
||||
import { WebSocketApiOperations } from './WebSocketApiOperations'
|
||||
|
||||
import { WebSocketApiService } from './WebSocketApiService'
|
||||
|
||||
describe('WebSocketApiService', () => {
|
||||
let webSocketServer: WebSocketServerInterface
|
||||
|
||||
const createService = () => new WebSocketApiService(webSocketServer)
|
||||
|
||||
beforeEach(() => {
|
||||
webSocketServer = {} as jest.Mocked<WebSocketServerInterface>
|
||||
webSocketServer.createConnectionToken = jest.fn().mockReturnValue({
|
||||
data: { token: 'foobar' },
|
||||
} as jest.Mocked<WebSocketConnectionTokenResponse>)
|
||||
})
|
||||
|
||||
it('should create a websocket connection token', async () => {
|
||||
const response = await createService().createConnectionToken()
|
||||
|
||||
expect(response).toEqual({
|
||||
data: {
|
||||
token: 'foobar',
|
||||
},
|
||||
})
|
||||
expect(webSocketServer.createConnectionToken).toHaveBeenCalledWith({})
|
||||
})
|
||||
|
||||
it('should not create a token if it is already creating', async () => {
|
||||
const service = createService()
|
||||
Object.defineProperty(service, 'operationsInProgress', {
|
||||
get: () => new Map([[WebSocketApiOperations.CreatingConnectionToken, true]]),
|
||||
})
|
||||
|
||||
let error = null
|
||||
try {
|
||||
await service.createConnectionToken()
|
||||
} catch (caughtError) {
|
||||
error = caughtError
|
||||
}
|
||||
|
||||
expect(error).not.toBeNull()
|
||||
})
|
||||
|
||||
it('should not create a token if the server fails', async () => {
|
||||
webSocketServer.createConnectionToken = jest.fn().mockImplementation(() => {
|
||||
throw new Error('Oops')
|
||||
})
|
||||
|
||||
let error = null
|
||||
try {
|
||||
await createService().createConnectionToken()
|
||||
} catch (caughtError) {
|
||||
error = caughtError
|
||||
}
|
||||
|
||||
expect(error).not.toBeNull()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,33 @@
|
||||
import { ErrorMessage } from '../../Error/ErrorMessage'
|
||||
import { ApiCallError } from '../../Error/ApiCallError'
|
||||
|
||||
import { WebSocketApiServiceInterface } from './WebSocketApiServiceInterface'
|
||||
import { WebSocketApiOperations } from './WebSocketApiOperations'
|
||||
import { WebSocketServerInterface } from '../../Server'
|
||||
import { WebSocketConnectionTokenResponse } from '../../Response'
|
||||
|
||||
export class WebSocketApiService implements WebSocketApiServiceInterface {
|
||||
private operationsInProgress: Map<WebSocketApiOperations, boolean>
|
||||
|
||||
constructor(private webSocketServer: WebSocketServerInterface) {
|
||||
this.operationsInProgress = new Map()
|
||||
}
|
||||
|
||||
async createConnectionToken(): Promise<WebSocketConnectionTokenResponse> {
|
||||
if (this.operationsInProgress.get(WebSocketApiOperations.CreatingConnectionToken)) {
|
||||
throw new ApiCallError(ErrorMessage.GenericInProgress)
|
||||
}
|
||||
|
||||
this.operationsInProgress.set(WebSocketApiOperations.CreatingConnectionToken, true)
|
||||
|
||||
try {
|
||||
const response = await this.webSocketServer.createConnectionToken({})
|
||||
|
||||
this.operationsInProgress.set(WebSocketApiOperations.CreatingConnectionToken, false)
|
||||
|
||||
return response
|
||||
} catch (error) {
|
||||
throw new ApiCallError(ErrorMessage.GenericFail)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { WebSocketConnectionTokenResponse } from '../../Response'
|
||||
|
||||
export interface WebSocketApiServiceInterface {
|
||||
createConnectionToken(): Promise<WebSocketConnectionTokenResponse>
|
||||
}
|
||||
@@ -3,3 +3,5 @@ export * from './Subscription/SubscriptionApiService'
|
||||
export * from './Subscription/SubscriptionApiServiceInterface'
|
||||
export * from './User/UserApiService'
|
||||
export * from './User/UserApiServiceInterface'
|
||||
export * from './WebSocket/WebSocketApiService'
|
||||
export * from './WebSocket/WebSocketApiServiceInterface'
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export type WebSocketConnectionTokenRequestParams = {
|
||||
[additionalParam: string]: unknown
|
||||
}
|
||||
@@ -5,3 +5,4 @@ export * from './Subscription/SubscriptionInviteDeclineRequestParams'
|
||||
export * from './Subscription/SubscriptionInviteListRequestParams'
|
||||
export * from './Subscription/SubscriptionInviteRequestParams'
|
||||
export * from './User/UserRegistrationRequestParams'
|
||||
export * from './WebSocket/WebSocketConnectionTokenRequestParams'
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
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<WebSocketConnectionTokenResponseBody, HttpErrorResponseBody>
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export type WebSocketConnectionTokenResponseBody = {
|
||||
token: string
|
||||
}
|
||||
@@ -10,3 +10,5 @@ export * from './Subscription/SubscriptionInviteResponse'
|
||||
export * from './Subscription/SubscriptionInviteResponseBody'
|
||||
export * from './User/UserRegistrationResponse'
|
||||
export * from './User/UserRegistrationResponseBody'
|
||||
export * from './WebSocket/WebSocketConnectionTokenResponse'
|
||||
export * from './WebSocket/WebSocketConnectionTokenResponseBody'
|
||||
|
||||
9
packages/api/src/Domain/Server/WebSocket/Paths.ts
Normal file
9
packages/api/src/Domain/Server/WebSocket/Paths.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
const TokenPaths = {
|
||||
createConnectionToken: '/v1/sockets/tokens',
|
||||
}
|
||||
|
||||
export const Paths = {
|
||||
v1: {
|
||||
...TokenPaths,
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { HttpServiceInterface } from '../../Http'
|
||||
import { WebSocketConnectionTokenResponse } from '../../Response'
|
||||
|
||||
import { WebSocketServer } from './WebSocketServer'
|
||||
|
||||
describe('WebSocketServer', () => {
|
||||
let httpService: HttpServiceInterface
|
||||
|
||||
const createServer = () => new WebSocketServer(httpService)
|
||||
|
||||
beforeEach(() => {
|
||||
httpService = {} as jest.Mocked<HttpServiceInterface>
|
||||
httpService.post = jest.fn().mockReturnValue({
|
||||
data: { token: 'foobar' },
|
||||
} as jest.Mocked<WebSocketConnectionTokenResponse>)
|
||||
})
|
||||
|
||||
it('should create a websocket connection token', async () => {
|
||||
const response = await createServer().createConnectionToken({})
|
||||
|
||||
expect(response).toEqual({
|
||||
data: {
|
||||
token: 'foobar',
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
17
packages/api/src/Domain/Server/WebSocket/WebSocketServer.ts
Normal file
17
packages/api/src/Domain/Server/WebSocket/WebSocketServer.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { HttpServiceInterface } from '../../Http/HttpServiceInterface'
|
||||
import { WebSocketConnectionTokenRequestParams } from '../../Request/WebSocket/WebSocketConnectionTokenRequestParams'
|
||||
import { WebSocketConnectionTokenResponse } from '../../Response/WebSocket/WebSocketConnectionTokenResponse'
|
||||
import { Paths } from './Paths'
|
||||
import { WebSocketServerInterface } from './WebSocketServerInterface'
|
||||
|
||||
export class WebSocketServer implements WebSocketServerInterface {
|
||||
constructor(private httpService: HttpServiceInterface) {}
|
||||
|
||||
async createConnectionToken(
|
||||
params: WebSocketConnectionTokenRequestParams,
|
||||
): Promise<WebSocketConnectionTokenResponse> {
|
||||
const response = await this.httpService.post(Paths.v1.createConnectionToken, params)
|
||||
|
||||
return response as WebSocketConnectionTokenResponse
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { WebSocketConnectionTokenRequestParams } from '../../Request/WebSocket/WebSocketConnectionTokenRequestParams'
|
||||
import { WebSocketConnectionTokenResponse } from '../../Response/WebSocket/WebSocketConnectionTokenResponse'
|
||||
|
||||
export interface WebSocketServerInterface {
|
||||
createConnectionToken(params: WebSocketConnectionTokenRequestParams): Promise<WebSocketConnectionTokenResponse>
|
||||
}
|
||||
@@ -2,3 +2,5 @@ export * from './Subscription/SubscriptionServer'
|
||||
export * from './Subscription/SubscriptionServerInterface'
|
||||
export * from './User/UserServer'
|
||||
export * from './User/UserServerInterface'
|
||||
export * from './WebSocket/WebSocketServer'
|
||||
export * from './WebSocket/WebSocketServerInterface'
|
||||
|
||||
Reference in New Issue
Block a user