Add T prefix for all type defs
This commit is contained in:
parent
db96b95522
commit
264f5aba60
@ -1,6 +0,0 @@
|
||||
import {IAction} from './IAction'
|
||||
|
||||
export type GetAction<MyTypes, T extends string> =
|
||||
MyTypes extends IAction<infer U, T>
|
||||
? MyTypes
|
||||
: never
|
||||
@ -1,6 +0,0 @@
|
||||
import {IAsyncAction} from './IAsyncAction'
|
||||
|
||||
export type GetPendingAction<MyTypes, T extends string> =
|
||||
MyTypes extends IAsyncAction<infer U, T> & {status: 'pending'}
|
||||
? MyTypes
|
||||
: never
|
||||
@ -1,6 +0,0 @@
|
||||
import {IAsyncAction} from './IAsyncAction'
|
||||
|
||||
export type GetResolvedAction<MyTypes, T extends string> =
|
||||
MyTypes extends IAsyncAction<infer U, T> & {status: 'resolved'}
|
||||
? MyTypes
|
||||
: never
|
||||
@ -2,9 +2,9 @@ import {IPendingAction} from './IPendingAction'
|
||||
import {IResolvedAction} from './IResolvedAction'
|
||||
import {IRejectedAction} from './IRejectedAction'
|
||||
|
||||
export type IAsyncStatus = 'pending' | 'resolved' | 'rejected'
|
||||
export type TAsyncStatus = 'pending' | 'resolved' | 'rejected'
|
||||
|
||||
export type IAsyncAction<T, ActionType extends string> =
|
||||
export type TAsyncAction<T, ActionType extends string> =
|
||||
IPendingAction<T, ActionType>
|
||||
| IResolvedAction<T, ActionType>
|
||||
| IRejectedAction<ActionType>
|
||||
6
packages/client/src/actions/TGetAction.ts
Normal file
6
packages/client/src/actions/TGetAction.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import {IAction} from './IAction'
|
||||
|
||||
export type TGetAction<ActionTypes, T extends string> =
|
||||
ActionTypes extends IAction<infer U, T>
|
||||
? ActionTypes
|
||||
: never
|
||||
6
packages/client/src/actions/TGetPendingAction.ts
Normal file
6
packages/client/src/actions/TGetPendingAction.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import {TAsyncAction} from './TAsyncAction'
|
||||
|
||||
export type TGetPendingAction<MyTypes, T extends string> =
|
||||
MyTypes extends TAsyncAction<infer U, T> & {status: 'pending'}
|
||||
? MyTypes
|
||||
: never
|
||||
6
packages/client/src/actions/TGetResolvedAction.ts
Normal file
6
packages/client/src/actions/TGetResolvedAction.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import {TAsyncAction} from './TAsyncAction'
|
||||
|
||||
export type TGetResolvedAction<MyTypes, T extends string> =
|
||||
MyTypes extends TAsyncAction<infer U, T> & {status: 'resolved'}
|
||||
? MyTypes
|
||||
: never
|
||||
@ -1,9 +1,9 @@
|
||||
export * from './GetAction'
|
||||
export * from './GetResolvedAction'
|
||||
export * from './GetPendingAction'
|
||||
export * from './IAction'
|
||||
export * from './IAsyncAction'
|
||||
export * from './IPendingAction'
|
||||
export * from './IRejectedAction'
|
||||
export * from './IResolvedAction'
|
||||
export * from './PendingAction'
|
||||
export * from './TAsyncAction'
|
||||
export * from './TGetAction'
|
||||
export * from './TGetPendingAction'
|
||||
export * from './TGetResolvedAction'
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import {createCRUDActions} from './CRUDActions'
|
||||
import React from 'react'
|
||||
import {AnyAction} from 'redux'
|
||||
import {CRUDReducer, ICRUDMethod} from './'
|
||||
import {CRUDReducer, TCRUDMethod} from './'
|
||||
import {HTTPClientMock, TestUtils, getError} from '../test-utils'
|
||||
import {IMethod} from '@rondo/common'
|
||||
import {TMethod} from '@rondo/common'
|
||||
import {IPendingAction} from '../actions'
|
||||
|
||||
describe('CRUD', () => {
|
||||
@ -100,7 +100,7 @@ describe('CRUD', () => {
|
||||
})
|
||||
|
||||
function dispatch(
|
||||
method: ICRUDMethod,
|
||||
method: TCRUDMethod,
|
||||
action: IPendingAction<unknown, string>,
|
||||
) {
|
||||
store.dispatch(action)
|
||||
@ -109,13 +109,13 @@ describe('CRUD', () => {
|
||||
return action
|
||||
}
|
||||
|
||||
function getUrl(method: ICRUDMethod) {
|
||||
function getUrl(method: TCRUDMethod) {
|
||||
return method === 'save' || method === 'findMany'
|
||||
? '/one/1/two'
|
||||
: '/one/1/two/2'
|
||||
}
|
||||
|
||||
function getHTTPMethod(method: ICRUDMethod): IMethod {
|
||||
function getHTTPMethod(method: TCRUDMethod): TMethod {
|
||||
switch (method) {
|
||||
case 'save':
|
||||
return 'post'
|
||||
@ -131,7 +131,7 @@ describe('CRUD', () => {
|
||||
|
||||
describe('Promise rejections', () => {
|
||||
const testCases: Array<{
|
||||
method: ICRUDMethod
|
||||
method: TCRUDMethod
|
||||
params: any
|
||||
}> = [{
|
||||
method: 'findOne',
|
||||
@ -203,7 +203,7 @@ describe('CRUD', () => {
|
||||
const entity = {id: 100, name: 'test'}
|
||||
|
||||
const testCases: Array<{
|
||||
method: ICRUDMethod
|
||||
method: TCRUDMethod
|
||||
params: any
|
||||
body?: any
|
||||
response: any
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
import {ICRUDAction} from './ICRUDAction'
|
||||
import {ICRUDMethod} from './ICRUDMethod'
|
||||
import {TCRUDAction} from './TCRUDAction'
|
||||
import {TCRUDMethod} from './TCRUDMethod'
|
||||
import {IHTTPClient, ITypedRequestParams} from '../http'
|
||||
import {IRoutes, Filter, OnlyDefined} from '@rondo/common'
|
||||
import {IRoutes, TFilter, TOnlyDefined} from '@rondo/common'
|
||||
|
||||
export type Optional<T> = T extends {} ? T : undefined
|
||||
|
||||
type Action<T, ActionType extends string, Method extends ICRUDMethod> =
|
||||
Filter<ICRUDAction<T, ActionType>, {method: Method, status: 'pending'}>
|
||||
type TAction<T, ActionType extends string, Method extends TCRUDMethod> =
|
||||
TFilter<TCRUDAction<T, ActionType>, {method: Method, status: 'pending'}>
|
||||
|
||||
export class SaveActionCreator<
|
||||
T extends IRoutes,
|
||||
@ -20,10 +18,10 @@ export class SaveActionCreator<
|
||||
readonly type: ActionType,
|
||||
) {}
|
||||
|
||||
save = (params: OnlyDefined<{
|
||||
save = (params: TOnlyDefined<{
|
||||
body: T[Route]['post']['body'],
|
||||
params: T[Route]['post']['params'],
|
||||
}>): Action<T[Route]['post']['response'], ActionType, 'save'> => {
|
||||
}>): TAction<T[Route]['post']['response'], ActionType, 'save'> => {
|
||||
const p = params as any
|
||||
return {
|
||||
payload: this.http.post(this.route, p.body, p.params),
|
||||
@ -46,10 +44,10 @@ export class FindOneActionCreator<
|
||||
readonly type: ActionType,
|
||||
) {}
|
||||
|
||||
findOne = (params: OnlyDefined<{
|
||||
query: Optional<T[Route]['get']['query']>,
|
||||
findOne = (params: TOnlyDefined<{
|
||||
query: T[Route]['get']['query'],
|
||||
params: T[Route]['get']['params'],
|
||||
}>): Action<T[Route]['get']['response'], ActionType, 'findOne'> => {
|
||||
}>): TAction<T[Route]['get']['response'], ActionType, 'findOne'> => {
|
||||
const p = params as any
|
||||
return {
|
||||
payload: this.http.get(this.route, p.query, p.params),
|
||||
@ -73,10 +71,10 @@ export class UpdateActionCreator<
|
||||
readonly type: ActionType,
|
||||
) {}
|
||||
|
||||
update = (params: OnlyDefined<{
|
||||
update = (params: TOnlyDefined<{
|
||||
body: T[Route]['put']['body'],
|
||||
params: T[Route]['put']['params'],
|
||||
}>): Action<T[Route]['put']['response'], ActionType, 'update'> => {
|
||||
}>): TAction<T[Route]['put']['response'], ActionType, 'update'> => {
|
||||
const p = params as any
|
||||
return {
|
||||
payload: this.http.put(this.route, p.body, p.params),
|
||||
@ -100,10 +98,10 @@ export class RemoveActionCreator<
|
||||
readonly type: ActionType,
|
||||
) {}
|
||||
|
||||
remove = (params: OnlyDefined<{
|
||||
body: Optional<T[Route]['delete']['body']>,
|
||||
remove = (params: TOnlyDefined<{
|
||||
body: T[Route]['delete']['body'],
|
||||
params: T[Route]['delete']['params'],
|
||||
}>): Action<T[Route]['delete']['response'], ActionType, 'remove'> => {
|
||||
}>): TAction<T[Route]['delete']['response'], ActionType, 'remove'> => {
|
||||
const p = params as any
|
||||
return {
|
||||
payload: this.http.delete(this.route, p.body, p.params),
|
||||
@ -126,8 +124,8 @@ export class FindManyActionCreator<
|
||||
readonly type: ActionType,
|
||||
) {}
|
||||
|
||||
findMany = (params: OnlyDefined<{
|
||||
query: Optional<T[Route]['get']['query']>,
|
||||
findMany = (params: TOnlyDefined<{
|
||||
query: T[Route]['get']['query'],
|
||||
params: T[Route]['get']['params'],
|
||||
}>): {
|
||||
payload: Promise<T[Route]['get']['response']>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import {IAction, IResolvedAction} from '../actions'
|
||||
import {ICRUDAction} from './ICRUDAction'
|
||||
import {ICRUDMethod} from './ICRUDMethod'
|
||||
import {indexBy, without, Filter} from '@rondo/common'
|
||||
import {TCRUDAction} from './TCRUDAction'
|
||||
import {TCRUDMethod} from './TCRUDMethod'
|
||||
import {indexBy, without, TFilter} from '@rondo/common'
|
||||
|
||||
export interface ICRUDEntity {
|
||||
readonly id: number
|
||||
@ -65,7 +65,7 @@ export class CRUDReducer<
|
||||
|
||||
handleRejected = (
|
||||
state: ICRUDState<T>,
|
||||
method: ICRUDMethod,
|
||||
method: TCRUDMethod,
|
||||
error: Error,
|
||||
): ICRUDState<T> => {
|
||||
return {
|
||||
@ -82,7 +82,7 @@ export class CRUDReducer<
|
||||
|
||||
handleLoading = (
|
||||
state: ICRUDState<T>,
|
||||
method: ICRUDMethod,
|
||||
method: TCRUDMethod,
|
||||
): ICRUDState<T> => {
|
||||
return {
|
||||
...state,
|
||||
@ -163,7 +163,7 @@ export class CRUDReducer<
|
||||
|
||||
reduce = (
|
||||
state: ICRUDState<T> | undefined,
|
||||
action: ICRUDAction<T, ActionType>,
|
||||
action: TCRUDAction<T, ActionType>,
|
||||
): ICRUDState<T> => {
|
||||
const {defaultState} = this
|
||||
state = state || defaultState
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
import {IAsyncAction} from '../actions'
|
||||
import {ICRUDMethod} from './ICRUDMethod'
|
||||
|
||||
export type ICRUDSaveAction<T, ActionType extends string> =
|
||||
IAsyncAction<T, ActionType> & {method: Extract<ICRUDMethod, 'save'>}
|
||||
|
||||
export type ICRUDUpdateAction<T, ActionType extends string> =
|
||||
IAsyncAction<T, ActionType> & {method: Extract<ICRUDMethod, 'update'>}
|
||||
|
||||
export type ICRUDRemoveAction<T, ActionType extends string> =
|
||||
IAsyncAction<T, ActionType> & {method: Extract<ICRUDMethod, 'remove'>}
|
||||
|
||||
export type ICRUDFindOneAction<T, ActionType extends string> =
|
||||
IAsyncAction<T, ActionType> & {method: Extract<ICRUDMethod, 'findOne'>}
|
||||
|
||||
export type ICRUDFindManyAction<T, ActionType extends string> =
|
||||
IAsyncAction<T[], ActionType> & {method: Extract<ICRUDMethod, 'findMany'>}
|
||||
|
||||
export type ICRUDAction<T, ActionType extends string> =
|
||||
ICRUDSaveAction<T, ActionType>
|
||||
| ICRUDUpdateAction<T, ActionType>
|
||||
| ICRUDRemoveAction<T, ActionType>
|
||||
| ICRUDFindOneAction<T, ActionType>
|
||||
| ICRUDFindManyAction<T, ActionType>
|
||||
@ -1 +0,0 @@
|
||||
export type ICRUDMethod = 'save' | 'update' | 'findOne' | 'findMany' | 'remove'
|
||||
24
packages/client/src/crud/TCRUDAction.ts
Normal file
24
packages/client/src/crud/TCRUDAction.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import {TAsyncAction} from '../actions'
|
||||
import {TCRUDMethod} from './TCRUDMethod'
|
||||
|
||||
export type TCRUDSaveAction<T, ActionType extends string> =
|
||||
TAsyncAction<T, ActionType> & {method: Extract<TCRUDMethod, 'save'>}
|
||||
|
||||
export type TCRUDUpdateAction<T, ActionType extends string> =
|
||||
TAsyncAction<T, ActionType> & {method: Extract<TCRUDMethod, 'update'>}
|
||||
|
||||
export type TCRUDRemoveAction<T, ActionType extends string> =
|
||||
TAsyncAction<T, ActionType> & {method: Extract<TCRUDMethod, 'remove'>}
|
||||
|
||||
export type TCRUDFindOneAction<T, ActionType extends string> =
|
||||
TAsyncAction<T, ActionType> & {method: Extract<TCRUDMethod, 'findOne'>}
|
||||
|
||||
export type TCRUDFindManyAction<T, ActionType extends string> =
|
||||
TAsyncAction<T[], ActionType> & {method: Extract<TCRUDMethod, 'findMany'>}
|
||||
|
||||
export type TCRUDAction<T, ActionType extends string> =
|
||||
TCRUDSaveAction<T, ActionType>
|
||||
| TCRUDUpdateAction<T, ActionType>
|
||||
| TCRUDRemoveAction<T, ActionType>
|
||||
| TCRUDFindOneAction<T, ActionType>
|
||||
| TCRUDFindManyAction<T, ActionType>
|
||||
1
packages/client/src/crud/TCRUDMethod.ts
Normal file
1
packages/client/src/crud/TCRUDMethod.ts
Normal file
@ -0,0 +1 @@
|
||||
export type TCRUDMethod = 'save' | 'update' | 'findOne' | 'findMany' | 'remove'
|
||||
@ -1,4 +1,4 @@
|
||||
export * from './CRUDActions'
|
||||
export * from './CRUDReducer'
|
||||
export * from './ICRUDAction'
|
||||
export * from './ICRUDMethod'
|
||||
export * from './TCRUDAction'
|
||||
export * from './TCRUDMethod'
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import {GetAction, IAction} from '../actions'
|
||||
import {TGetAction, IAction} from '../actions'
|
||||
|
||||
export interface ICrumbLink {
|
||||
name: string
|
||||
@ -10,10 +10,10 @@ export interface ICrumbs {
|
||||
current: string
|
||||
}
|
||||
|
||||
export type CrumbsActionType =
|
||||
export type TCrumbsAction =
|
||||
IAction<ICrumbs, 'BREADCRUMBS_SET'>
|
||||
|
||||
type Action<T extends string> = GetAction<CrumbsActionType, T>
|
||||
type Action<T extends string> = TGetAction<TCrumbsAction, T>
|
||||
|
||||
export class CrumbsActions {
|
||||
setCrumbs(breadcrumbs: ICrumbs): Action<'BREADCRUMBS_SET'> {
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import {Crumb} from './Crumb'
|
||||
import {Connector, IStateSelector} from '../redux'
|
||||
import {Connector, TStateSelector} from '../redux'
|
||||
import {ICrumbsState} from './CrumbsReducer'
|
||||
import {CrumbsActions} from './CrumbsActions'
|
||||
|
||||
export class CrumbsConnector extends Connector<ICrumbsState> {
|
||||
protected readonly breadcrumbsActions = new CrumbsActions()
|
||||
|
||||
connect<State>(getLocalState: IStateSelector<State, ICrumbsState>) {
|
||||
connect<State>(getLocalState: TStateSelector<State, ICrumbsState>) {
|
||||
return this.wrap(
|
||||
getLocalState,
|
||||
state => state,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import {ICrumbs, CrumbsActionType} from './CrumbsActions'
|
||||
import {ICrumbs, TCrumbsAction} from './CrumbsActions'
|
||||
|
||||
export interface ICrumbsState extends ICrumbs {
|
||||
}
|
||||
@ -8,7 +8,7 @@ const defaultState: ICrumbsState = {
|
||||
current: 'Home',
|
||||
}
|
||||
|
||||
export function Crumbs(state = defaultState, action: CrumbsActionType)
|
||||
export function Crumbs(state = defaultState, action: TCrumbsAction)
|
||||
: ICrumbsState {
|
||||
switch (action.type) {
|
||||
case 'BREADCRUMBS_SET':
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import axios from 'axios'
|
||||
import {IHTTPClient} from './IHTTPClient'
|
||||
import {IHeader} from './IHeader'
|
||||
import {IMethod, IRoutes, URLFormatter} from '@rondo/common'
|
||||
import {TMethod, IRoutes, URLFormatter} from '@rondo/common'
|
||||
import {IRequest} from './IRequest'
|
||||
import {IResponse} from './IResponse'
|
||||
import {ITypedRequestParams} from './ITypedRequestParams'
|
||||
@ -31,7 +31,7 @@ export class HTTPClient<T extends IRoutes> implements IHTTPClient<T> {
|
||||
|
||||
async request<
|
||||
P extends keyof T & string,
|
||||
M extends IMethod,
|
||||
M extends TMethod,
|
||||
>(params: ITypedRequestParams<T, P, M>): Promise<T[P][M]['response']> {
|
||||
|
||||
const url = this.formatter.format(params.path, params.params)
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import {IMethod, IRoutes} from '@rondo/common'
|
||||
import {TMethod, IRoutes} from '@rondo/common'
|
||||
import {ITypedRequestParams} from './ITypedRequestParams'
|
||||
|
||||
export interface IHTTPClient<T extends IRoutes> {
|
||||
request<
|
||||
P extends keyof T & string,
|
||||
M extends IMethod,
|
||||
M extends TMethod,
|
||||
>(params: ITypedRequestParams<T, P, M>): Promise<T[P][M]['response']>
|
||||
|
||||
get<P extends keyof T & string>(
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import {IMethod} from '@rondo/common'
|
||||
import {TMethod} from '@rondo/common'
|
||||
|
||||
export interface IRequest {
|
||||
method: IMethod,
|
||||
method: TMethod,
|
||||
url: string,
|
||||
params?: {[key: string]: any},
|
||||
data?: any,
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import {IRoutes, IMethod} from '@rondo/common'
|
||||
import {IRoutes, TMethod} from '@rondo/common'
|
||||
|
||||
export interface ITypedRequestParams<
|
||||
T extends IRoutes,
|
||||
P extends keyof T & string,
|
||||
M extends IMethod,
|
||||
M extends TMethod,
|
||||
> {
|
||||
method: M,
|
||||
path: P,
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import {GetAction, IAsyncAction, IAction, PendingAction} from '../actions'
|
||||
import {TGetAction, TAsyncAction, IAction, PendingAction} from '../actions'
|
||||
import {IAPIDef, ICredentials, INewUser, IUser} from '@rondo/common'
|
||||
import {IHTTPClient} from '../http/IHTTPClient'
|
||||
|
||||
export type LoginActionType =
|
||||
IAsyncAction<IUser, 'LOGIN'>
|
||||
| IAsyncAction<unknown, 'LOGIN_LOGOUT'>
|
||||
| IAsyncAction<IUser, 'LOGIN_REGISTER'>
|
||||
export type TLoginAction =
|
||||
TAsyncAction<IUser, 'LOGIN'>
|
||||
| TAsyncAction<unknown, 'LOGIN_LOGOUT'>
|
||||
| TAsyncAction<IUser, 'LOGIN_REGISTER'>
|
||||
| IAction<{redirectTo: string}, 'LOGIN_REDIRECT_SET'>
|
||||
|
||||
type Action<T extends string> = GetAction<LoginActionType, T>
|
||||
type TAction<T extends string> = TGetAction<TLoginAction, T>
|
||||
|
||||
export class LoginActions {
|
||||
constructor(protected readonly http: IHTTPClient<IAPIDef>) {}
|
||||
@ -34,7 +34,7 @@ export class LoginActions {
|
||||
)
|
||||
}
|
||||
|
||||
setRedirectTo = (redirectTo: string): Action<'LOGIN_REDIRECT_SET'> => {
|
||||
setRedirectTo = (redirectTo: string): TAction<'LOGIN_REDIRECT_SET'> => {
|
||||
return {
|
||||
payload: {redirectTo},
|
||||
type: 'LOGIN_REDIRECT_SET',
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import {Connector} from '../redux/Connector'
|
||||
import {ICredentials} from '@rondo/common'
|
||||
import {ILoginState} from './LoginReducer'
|
||||
import {IStateSelector} from '../redux'
|
||||
import {TStateSelector} from '../redux'
|
||||
import {LoginActions} from './LoginActions'
|
||||
import {LoginForm} from './LoginForm'
|
||||
import {bindActionCreators} from 'redux'
|
||||
@ -18,7 +18,7 @@ export class LoginConnector extends Connector<ILoginState> {
|
||||
super()
|
||||
}
|
||||
|
||||
connect<State>(getLocalState: IStateSelector<State, ILoginState>) {
|
||||
connect<State>(getLocalState: TStateSelector<State, ILoginState>) {
|
||||
return this.wrap(
|
||||
getLocalState,
|
||||
state => ({
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import {IUser} from '@rondo/common'
|
||||
import {LoginActionType} from './LoginActions'
|
||||
import {TLoginAction} from './LoginActions'
|
||||
|
||||
export interface ILoginState {
|
||||
readonly error: string
|
||||
@ -17,7 +17,7 @@ const defaultState: ILoginState = {
|
||||
|
||||
export function Login(
|
||||
state = defaultState,
|
||||
action: LoginActionType,
|
||||
action: TLoginAction,
|
||||
): ILoginState {
|
||||
switch (action.type) {
|
||||
// sync actions
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import {Connector} from '../redux/Connector'
|
||||
import {INewUser} from '@rondo/common'
|
||||
import {ILoginState} from './LoginReducer'
|
||||
import {IStateSelector} from '../redux'
|
||||
import {TStateSelector} from '../redux'
|
||||
import {LoginActions} from './LoginActions'
|
||||
import {RegisterForm} from './RegisterForm'
|
||||
import {bindActionCreators} from 'redux'
|
||||
@ -20,7 +20,7 @@ export class RegisterConnector extends Connector<ILoginState> {
|
||||
super()
|
||||
}
|
||||
|
||||
connect<State>(getLocalState: IStateSelector<State, ILoginState>) {
|
||||
connect<State>(getLocalState: TStateSelector<State, ILoginState>) {
|
||||
return this.wrap(
|
||||
getLocalState,
|
||||
state => ({
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import {IStateSelector} from './IStateSelector'
|
||||
import {TStateSelector} from './TStateSelector'
|
||||
import {connect, Omit} from 'react-redux'
|
||||
import {Dispatch} from 'redux'
|
||||
import {ComponentType} from 'react'
|
||||
@ -30,7 +30,7 @@ export abstract class Connector<LocalState> {
|
||||
* https://stackoverflow.com/questions/54277411
|
||||
*/
|
||||
abstract connect<State>(
|
||||
selectState: IStateSelector<State, LocalState>,
|
||||
selectState: TStateSelector<State, LocalState>,
|
||||
): ComponentType<any>
|
||||
|
||||
protected wrap<
|
||||
@ -39,7 +39,7 @@ export abstract class Connector<LocalState> {
|
||||
StateProps extends Partial<Props>,
|
||||
DispatchProps extends Partial<Props>,
|
||||
>(
|
||||
getLocalState: IStateSelector<State, LocalState>,
|
||||
getLocalState: TStateSelector<State, LocalState>,
|
||||
mapStateToProps: (state: LocalState) => StateProps,
|
||||
mapDispatchToProps: (dispatch: Dispatch) => DispatchProps,
|
||||
Component: React.ComponentType<Props>,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Select and return a part of the state
|
||||
*/
|
||||
export type IStateSelector<GlobalState, StateSlice>
|
||||
export type TStateSelector<GlobalState, StateSlice>
|
||||
= (state: GlobalState) => StateSlice
|
||||
@ -1,2 +1,2 @@
|
||||
export * from './Connector'
|
||||
export * from './IStateSelector'
|
||||
export * from './TStateSelector'
|
||||
|
||||
@ -3,13 +3,13 @@ import ReactDOM from 'react-dom'
|
||||
import {Action} from 'redux'
|
||||
import {IClientConfig} from './IClientConfig'
|
||||
import {IRenderer} from './IRenderer'
|
||||
import {IStoreFactory} from './IStoreFactory'
|
||||
import {TStoreFactory} from './TStoreFactory'
|
||||
import {Provider} from 'react-redux'
|
||||
import {Router} from 'react-router-dom'
|
||||
import {createBrowserHistory} from 'history'
|
||||
|
||||
export interface IClientRendererParams<State, A extends Action> {
|
||||
readonly createStore: IStoreFactory<State, A | any>,
|
||||
readonly createStore: TStoreFactory<State, A | any>,
|
||||
readonly RootComponent: React.ComponentType<{config: IClientConfig}>,
|
||||
readonly target?: HTMLElement
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ import React from 'react'
|
||||
import {Action} from 'redux'
|
||||
import {IClientConfig} from './IClientConfig'
|
||||
import {IRenderer} from './IRenderer'
|
||||
import {IStoreFactory} from './IStoreFactory'
|
||||
import {TStoreFactory} from './TStoreFactory'
|
||||
import {Provider} from 'react-redux'
|
||||
import {StaticRouterContext} from 'react-router'
|
||||
import {StaticRouter} from 'react-router-dom'
|
||||
@ -10,7 +10,7 @@ import {renderToNodeStream} from 'react-dom/server'
|
||||
|
||||
export class ServerRenderer<State, A extends Action> implements IRenderer {
|
||||
constructor(
|
||||
readonly createStore: IStoreFactory<State, A | any>,
|
||||
readonly createStore: TStoreFactory<State, A | any>,
|
||||
readonly RootComponent: React.ComponentType<{config: IClientConfig}>,
|
||||
) {}
|
||||
render(url: string, config: IClientConfig, state?: any) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import {Action, Store} from 'redux'
|
||||
|
||||
// TODO maybe Store should also be typed
|
||||
export type IStoreFactory<State, A extends Action> =
|
||||
export type TStoreFactory<State, A extends Action> =
|
||||
(state?: State) => Store<State, A | any>
|
||||
@ -1,5 +1,5 @@
|
||||
export * from './ClientRenderer'
|
||||
export * from './IClientConfig'
|
||||
export * from './IRenderer'
|
||||
export * from './IStoreFactory'
|
||||
export * from './TStoreFactory'
|
||||
export * from './isClientSide'
|
||||
|
||||
@ -1,19 +1,19 @@
|
||||
import {IAPIDef} from '@rondo/common'
|
||||
import {GetPendingAction, IAsyncAction, PendingAction} from '../actions'
|
||||
import {TGetPendingAction, TAsyncAction, PendingAction} from '../actions'
|
||||
import {IHTTPClient} from '../http/IHTTPClient'
|
||||
import {ITeam, IUser, IUserInTeam} from '@rondo/common'
|
||||
|
||||
export type TeamActionType =
|
||||
IAsyncAction<ITeam[], 'TEAMS'>
|
||||
| IAsyncAction<ITeam, 'TEAM_CREATE'>
|
||||
| IAsyncAction<ITeam, 'TEAM_UPDATE'>
|
||||
| IAsyncAction<{id: number}, 'TEAM_REMOVE'>
|
||||
| IAsyncAction<IUserInTeam, 'TEAM_USER_ADD'>
|
||||
| IAsyncAction<{userId: number, teamId: number}, 'TEAM_USER_REMOVE'>
|
||||
| IAsyncAction<{teamId: number, usersInTeam: IUserInTeam[]}, 'TEAM_USERS'>
|
||||
| IAsyncAction<IUser | undefined, 'TEAM_USER_FIND'>
|
||||
export type TTeamAction =
|
||||
TAsyncAction<ITeam[], 'TEAMS'>
|
||||
| TAsyncAction<ITeam, 'TEAM_CREATE'>
|
||||
| TAsyncAction<ITeam, 'TEAM_UPDATE'>
|
||||
| TAsyncAction<{id: number}, 'TEAM_REMOVE'>
|
||||
| TAsyncAction<IUserInTeam, 'TEAM_USER_ADD'>
|
||||
| TAsyncAction<{userId: number, teamId: number}, 'TEAM_USER_REMOVE'>
|
||||
| TAsyncAction<{teamId: number, usersInTeam: IUserInTeam[]}, 'TEAM_USERS'>
|
||||
| TAsyncAction<IUser | undefined, 'TEAM_USER_FIND'>
|
||||
|
||||
type Action<T extends string> = GetPendingAction<TeamActionType, T>
|
||||
type Action<T extends string> = TGetPendingAction<TTeamAction, T>
|
||||
|
||||
export class TeamActions {
|
||||
constructor(protected readonly http: IHTTPClient<IAPIDef>) {}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import {Connector} from '../redux/Connector'
|
||||
import {IStateSelector} from '../redux'
|
||||
import {TStateSelector} from '../redux'
|
||||
import {ITeamState} from './TeamReducer'
|
||||
import {TeamActions} from './TeamActions'
|
||||
import {TeamManager} from './TeamManager'
|
||||
@ -11,7 +11,7 @@ export class TeamConnector extends Connector<ITeamState> {
|
||||
super()
|
||||
}
|
||||
|
||||
connect<State>(getLocalState: IStateSelector<State, ITeamState>) {
|
||||
connect<State>(getLocalState: TStateSelector<State, ITeamState>) {
|
||||
const Component = this.wrap(
|
||||
getLocalState,
|
||||
state => ({
|
||||
|
||||
@ -4,7 +4,7 @@ import {ITeam} from '@rondo/common'
|
||||
import {TeamActions} from './TeamActions'
|
||||
import {FaPlusSquare, FaCheck, FaEdit} from 'react-icons/fa'
|
||||
|
||||
export type ITeamEditorProps = {
|
||||
export type TTeamEditorProps = {
|
||||
type: 'add'
|
||||
onAddTeam: TeamActions['createTeam']
|
||||
} | {
|
||||
@ -20,8 +20,8 @@ export interface ITeamEditorState {
|
||||
}
|
||||
|
||||
export class TeamEditor
|
||||
extends React.PureComponent<ITeamEditorProps, ITeamEditorState> {
|
||||
constructor(props: ITeamEditorProps) {
|
||||
extends React.PureComponent<TTeamEditorProps, ITeamEditorState> {
|
||||
constructor(props: TTeamEditorProps) {
|
||||
super(props)
|
||||
this.state = {
|
||||
error: '',
|
||||
@ -31,7 +31,7 @@ extends React.PureComponent<ITeamEditorProps, ITeamEditorState> {
|
||||
getName(team?: ITeam) {
|
||||
return team ? team.name : ''
|
||||
}
|
||||
componentWillReceiveProps(nextProps: ITeamEditorProps) {
|
||||
componentWillReceiveProps(nextProps: TTeamEditorProps) {
|
||||
if (nextProps.type === 'update') {
|
||||
const {team} = nextProps
|
||||
if (team !== (this.props as any).team) {
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import React from 'react'
|
||||
import {Button, Panel, PanelHeading, PanelBlock} from 'bloomer'
|
||||
import {FaPlus, FaEdit, FaTimes} from 'react-icons/fa'
|
||||
import {ITeam, ReadonlyRecord} from '@rondo/common'
|
||||
import {ITeam, TReadonlyRecord} from '@rondo/common'
|
||||
import {Link} from 'react-router-dom'
|
||||
import {TeamActions} from './TeamActions'
|
||||
import {TeamEditor} from './TeamEditor'
|
||||
|
||||
export interface ITeamListProps {
|
||||
teamsById: ReadonlyRecord<number, ITeam>,
|
||||
teamsById: TReadonlyRecord<number, ITeam>,
|
||||
teamIds: ReadonlyArray<number>,
|
||||
onAddTeam: TeamActions['createTeam']
|
||||
onRemoveTeam: TeamActions['removeTeam']
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
import {History, Location} from 'history'
|
||||
import {ITeam, IUserInTeam, ReadonlyRecord} from '@rondo/common'
|
||||
import {ITeam, IUserInTeam, TReadonlyRecord} from '@rondo/common'
|
||||
import {Panel, PanelBlock, PanelHeading} from 'bloomer'
|
||||
import {Route, Switch} from 'react-router-dom'
|
||||
import {TeamActions} from './TeamActions'
|
||||
@ -24,11 +24,11 @@ export interface ITeamManagerProps {
|
||||
fetchUsersInTeam: TeamActions['fetchUsersInTeam']
|
||||
findUserByEmail: TeamActions['findUserByEmail']
|
||||
|
||||
teamsById: ReadonlyRecord<number, ITeam>
|
||||
teamsById: TReadonlyRecord<number, ITeam>
|
||||
teamIds: ReadonlyArray<number>
|
||||
|
||||
userKeysByTeamId: ReadonlyRecord<number, ReadonlyArray<string>>
|
||||
usersByKey: ReadonlyRecord<string, IUserInTeam>
|
||||
userKeysByTeamId: TReadonlyRecord<number, ReadonlyArray<string>>
|
||||
usersByKey: TReadonlyRecord<string, IUserInTeam>
|
||||
}
|
||||
|
||||
export class TeamManager extends React.PureComponent<ITeamManagerProps> {
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
import {
|
||||
ITeam, IUserInTeam, ReadonlyRecord, indexBy, without,
|
||||
ITeam, IUserInTeam, TReadonlyRecord, indexBy, without,
|
||||
} from '@rondo/common'
|
||||
import {TeamActionType} from './TeamActions'
|
||||
import {GetResolvedAction} from '../actions'
|
||||
import {TTeamAction} from './TeamActions'
|
||||
import {TGetResolvedAction} from '../actions'
|
||||
|
||||
export interface ITeamState {
|
||||
readonly error: string
|
||||
|
||||
readonly teamIds: ReadonlyArray<number>
|
||||
readonly teamsById: ReadonlyRecord<number, ITeam>
|
||||
readonly teamsById: TReadonlyRecord<number, ITeam>
|
||||
|
||||
readonly userKeysByTeamId: ReadonlyRecord<number, ReadonlyArray<string>>
|
||||
readonly usersByKey: ReadonlyRecord<string, IUserInTeam>
|
||||
readonly userKeysByTeamId: TReadonlyRecord<number, ReadonlyArray<string>>
|
||||
readonly usersByKey: TReadonlyRecord<string, IUserInTeam>
|
||||
}
|
||||
|
||||
const defaultState: ITeamState = {
|
||||
@ -26,7 +26,7 @@ const defaultState: ITeamState = {
|
||||
|
||||
function removeUser(
|
||||
state: ITeamState,
|
||||
action: GetResolvedAction<TeamActionType, 'TEAM_USER_REMOVE'>,
|
||||
action: TGetResolvedAction<TTeamAction, 'TEAM_USER_REMOVE'>,
|
||||
) {
|
||||
|
||||
const {payload} = action
|
||||
@ -52,7 +52,7 @@ function getUserKey(userInTeam: {userId: number, teamId: number}) {
|
||||
return `${userInTeam.teamId}_${userInTeam.userId}`
|
||||
}
|
||||
|
||||
export function Team(state = defaultState, action: TeamActionType): ITeamState {
|
||||
export function Team(state = defaultState, action: TTeamAction): ITeamState {
|
||||
switch (action.status) {
|
||||
case 'pending':
|
||||
return state
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import {ITeam, IUser, IUserInTeam, ReadonlyRecord} from '@rondo/common'
|
||||
import {ITeam, IUser, IUserInTeam, TReadonlyRecord} from '@rondo/common'
|
||||
import {TeamActions} from './TeamActions'
|
||||
import {FaUser, FaCheck, FaTimes} from 'react-icons/fa'
|
||||
|
||||
@ -18,8 +18,8 @@ export interface ITeamUsersProps {
|
||||
onRemoveUser: TeamActions['removeUser']
|
||||
|
||||
team: ITeam
|
||||
userKeysByTeamId: ReadonlyRecord<number, ReadonlyArray<string>>
|
||||
usersByKey: ReadonlyRecord<string, IUserInTeam>
|
||||
userKeysByTeamId: TReadonlyRecord<number, ReadonlyArray<string>>
|
||||
usersByKey: TReadonlyRecord<string, IUserInTeam>
|
||||
}
|
||||
|
||||
export interface ITeamUserProps {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import T from 'react-dom/test-utils'
|
||||
import {IStateSelector} from '../redux'
|
||||
import {TStateSelector} from '../redux'
|
||||
import {Provider} from 'react-redux'
|
||||
import {createStore} from '../store'
|
||||
import {
|
||||
@ -15,9 +15,9 @@ import {
|
||||
|
||||
interface IRenderParams<State, LocalState> {
|
||||
reducers: ReducersMapObject<State, any>
|
||||
select: IStateSelector<State, LocalState>
|
||||
select: TStateSelector<State, LocalState>
|
||||
// getComponent: (
|
||||
// select: IStateSelector<State, LocalState>) => React.ComponentType<Props>,
|
||||
// select: TStateSelector<State, LocalState>) => React.ComponentType<Props>,
|
||||
// customJSX?: (
|
||||
// Component: React.ComponentType<Props>,
|
||||
// props: Props,
|
||||
@ -65,7 +65,7 @@ export class TestUtils {
|
||||
}
|
||||
|
||||
const withComponent = <Props extends {}>(
|
||||
getComponent: (select: IStateSelector<State, LocalState>) =>
|
||||
getComponent: (select: TStateSelector<State, LocalState>) =>
|
||||
React.ComponentType<Props>,
|
||||
) => {
|
||||
const Component = getComponent(select)
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
export type IMethod = 'get'
|
||||
export type TMethod = 'get'
|
||||
| 'post'
|
||||
| 'put'
|
||||
| 'delete'
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
export type ReadonlyRecord<K extends string | number | symbol, V> =
|
||||
Readonly<Record<K, V>>
|
||||
@ -9,7 +9,6 @@ export * from './IUser'
|
||||
export * from './IUser'
|
||||
export * from './IUserInTeam'
|
||||
export * from './IUserTeam'
|
||||
export * from './ReadonlyRecord'
|
||||
export * from './URLFormatter'
|
||||
export * from './indexBy'
|
||||
export * from './types'
|
||||
|
||||
@ -1,22 +1,25 @@
|
||||
/**
|
||||
* transform unknown into undefined
|
||||
*/
|
||||
export type Optional<T> = T extends {} ? T : undefined
|
||||
export type TOptional<T> = T extends {} ? T : undefined
|
||||
|
||||
export type NonUndefinedPropertyNames<T> = {
|
||||
export type TNonUndefinedPropertyNames<T> = {
|
||||
[K in keyof T]: T[K] extends undefined ? never: K
|
||||
}[keyof T]
|
||||
|
||||
export type OnlyRequired<T> = Pick<T, NonUndefinedPropertyNames<T>>
|
||||
export type TOnlyRequired<T> = Pick<T, TNonUndefinedPropertyNames<T>>
|
||||
|
||||
export type NonUnknownPropertyNames<T> = {
|
||||
export type TNonUnknownPropertyNames<T> = {
|
||||
[K in keyof T]: T[K] extends {} ? K : never
|
||||
}[keyof T]
|
||||
|
||||
export type OnlyDefined<T> = Pick<T, NonUnknownPropertyNames<T>>
|
||||
export type TOnlyDefined<T> = Pick<T, TNonUnknownPropertyNames<T>>
|
||||
|
||||
/**
|
||||
* Remove types from T that are not assignable to U
|
||||
* https://www.typescriptlang.org/docs/handbook/advanced-types.html
|
||||
*/
|
||||
export type Filter<T, U> = T extends U ? T : never
|
||||
export type TFilter<T, U> = T extends U ? T : never
|
||||
|
||||
export type TReadonlyRecord<K extends string | number | symbol, V> =
|
||||
Readonly<Record<K, V>>
|
||||
|
||||
@ -8,12 +8,12 @@ import {
|
||||
Repository,
|
||||
} from 'typeorm'
|
||||
|
||||
export type IConnectionGetter = () => Connection
|
||||
export type TConnectionGetter = () => Connection
|
||||
|
||||
export class TransactionManager implements ITransactionManager {
|
||||
constructor(
|
||||
readonly ns: Namespace,
|
||||
readonly getConnection: IConnectionGetter,
|
||||
readonly getConnection: TConnectionGetter,
|
||||
) {}
|
||||
|
||||
getEntityManager = (): EntityManager => {
|
||||
|
||||
@ -17,10 +17,10 @@ export function pad(text: string, n: number, trim: boolean) {
|
||||
return text
|
||||
}
|
||||
|
||||
export type ILogLevel = 'error' | 'warn' | 'info' | 'debug' | 'verbose' | 'off'
|
||||
export type TLogLevel = 'error' | 'warn' | 'info' | 'debug' | 'verbose' | 'off'
|
||||
|
||||
export interface IEnabledLoggers {
|
||||
readonly [key: string]: ILogLevel
|
||||
readonly [key: string]: TLogLevel
|
||||
}
|
||||
|
||||
export interface IParams {
|
||||
@ -48,9 +48,9 @@ export class LoggerFactory implements ILoggerFactory {
|
||||
} = {}) {
|
||||
const enabledLoggers = logs.split(',').reduce((logConfig, log) => {
|
||||
const [key, value] = log.split(':')
|
||||
logConfig[key] = (value || 'info') as ILogLevel
|
||||
logConfig[key] = (value || 'info') as TLogLevel
|
||||
return logConfig
|
||||
}, {} as {[key: string]: ILogLevel})
|
||||
}, {} as {[key: string]: TLogLevel})
|
||||
|
||||
const params = opts.split(',').reduce((o, key) => {
|
||||
o[key] = true
|
||||
@ -70,7 +70,7 @@ export class LoggerFactory implements ILoggerFactory {
|
||||
this.getCorrelationId = () => ''
|
||||
}
|
||||
|
||||
getLoggerLevel(name: string): ILogLevel {
|
||||
getLoggerLevel(name: string): TLogLevel {
|
||||
const {enabledLoggers} = this.options
|
||||
const disabled = !!enabledLoggers['-' + name]
|
||||
if (disabled) {
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import {Authenticator as A, Passport} from 'passport'
|
||||
import {IUserService} from '../services'
|
||||
import {Strategy as LocalStrategy} from 'passport-local'
|
||||
import {IHandler} from './IHandler'
|
||||
import {THandler} from './THandler'
|
||||
import {IMiddleware} from './IMiddleware'
|
||||
|
||||
export class Authenticator implements IMiddleware {
|
||||
|
||||
protected readonly passport: A
|
||||
readonly handle: IHandler[]
|
||||
readonly handle: THandler[]
|
||||
|
||||
constructor(protected readonly userService: IUserService) {
|
||||
this.passport = new Passport() as any
|
||||
@ -22,7 +22,7 @@ export class Authenticator implements IMiddleware {
|
||||
]
|
||||
}
|
||||
|
||||
withLogInPromise: IHandler = (req, res, next) => {
|
||||
withLogInPromise: THandler = (req, res, next) => {
|
||||
req.logInPromise = (user) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
req.logIn(user, err => {
|
||||
@ -72,7 +72,7 @@ export class Authenticator implements IMiddleware {
|
||||
.catch(done)
|
||||
}
|
||||
|
||||
authenticate(strategy: string | string[]): IHandler {
|
||||
authenticate(strategy: string | string[]): THandler {
|
||||
return (req, res, next) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.passport.authenticate(strategy, (err: Error, user, info) => {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import Csurf from 'csurf'
|
||||
import {IHandler} from './IHandler'
|
||||
import {THandler} from './THandler'
|
||||
import {IMiddleware} from './IMiddleware'
|
||||
import {UrlWithStringQuery} from 'url'
|
||||
|
||||
@ -9,7 +9,7 @@ export interface ICSRFParams {
|
||||
}
|
||||
|
||||
export class CSRFMiddleware implements IMiddleware {
|
||||
readonly handle: IHandler
|
||||
readonly handle: THandler
|
||||
|
||||
constructor(readonly params: ICSRFParams) {
|
||||
this.handle = Csurf({
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import {IErrorHandler} from './IErrorHandler'
|
||||
import {TErrorHandler} from './TErrorHandler'
|
||||
import {ILogger} from '../logger/ILogger'
|
||||
import {IMiddleware} from './IMiddleware'
|
||||
import {ValidationError} from '../validator'
|
||||
@ -6,7 +6,7 @@ import {ValidationError} from '../validator'
|
||||
export class ErrorApiHandler implements IMiddleware {
|
||||
constructor(readonly logger: ILogger) {}
|
||||
|
||||
handle: IErrorHandler = (err, req, res, next) => {
|
||||
handle: TErrorHandler = (err, req, res, next) => {
|
||||
this.logger.error('%s An API error occurred: %s',
|
||||
req.correlationId, err.stack)
|
||||
const statusCode = this.getStatus(err)
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import {IMiddleware} from './IMiddleware'
|
||||
import {IErrorHandler} from './IErrorHandler'
|
||||
import {ILogger} from '../logger/ILogger'
|
||||
import {IMiddleware} from './IMiddleware'
|
||||
import {TErrorHandler} from './TErrorHandler'
|
||||
|
||||
export class ErrorPageHandler implements IMiddleware {
|
||||
constructor(readonly logger: ILogger) {}
|
||||
|
||||
handle: IErrorHandler = (err, req, res, next) => {
|
||||
handle: TErrorHandler = (err, req, res, next) => {
|
||||
this.logger.error(
|
||||
'%s An error occurred: %s',
|
||||
req.correlationId, err.stack)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import {IHandler} from './IHandler'
|
||||
import {IErrorHandler} from './IErrorHandler'
|
||||
import {THandler} from './THandler'
|
||||
import {TErrorHandler} from './TErrorHandler'
|
||||
|
||||
export interface IMiddleware {
|
||||
handle: IHandler | IHandler[] | IErrorHandler
|
||||
handle: THandler | THandler[] | TErrorHandler
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import {IHandler} from './IHandler'
|
||||
import {THandler} from './THandler'
|
||||
import {ILogger} from '../logger/ILogger'
|
||||
import {IMiddleware} from './IMiddleware'
|
||||
import shortid from 'shortid'
|
||||
@ -6,7 +6,7 @@ import shortid from 'shortid'
|
||||
export class RequestLogger implements IMiddleware {
|
||||
constructor(protected readonly logger: ILogger) {}
|
||||
|
||||
handle: IHandler = (req, res, next) => {
|
||||
handle: THandler = (req, res, next) => {
|
||||
const start = Date.now()
|
||||
req.correlationId = shortid.generate()
|
||||
res.on('finish', () => {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import ExpressSession from 'express-session'
|
||||
import {IHandler} from './IHandler'
|
||||
import {THandler} from './THandler'
|
||||
import {IMiddleware} from './IMiddleware'
|
||||
import {ISession} from '../session/ISession'
|
||||
import {ITransactionManager} from '../database/ITransactionManager'
|
||||
@ -15,7 +15,7 @@ export interface ISessionOptions {
|
||||
}
|
||||
|
||||
export class SessionMiddleware implements IMiddleware {
|
||||
readonly handle: IHandler
|
||||
readonly handle: THandler
|
||||
|
||||
constructor(readonly params: ISessionOptions) {
|
||||
this.handle = ExpressSession({
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import {Request, Response, NextFunction} from 'express'
|
||||
|
||||
export type IErrorHandler =
|
||||
export type TErrorHandler =
|
||||
(err: Error, req: Request, res: Response, next: NextFunction) => any
|
||||
@ -1,3 +1,3 @@
|
||||
import {Request, Response, NextFunction} from 'express'
|
||||
|
||||
export type IHandler = (req: Request, res: Response, next: NextFunction) => any
|
||||
export type THandler = (req: Request, res: Response, next: NextFunction) => any
|
||||
@ -1,4 +1,4 @@
|
||||
import {Request, Response, NextFunction} from 'express'
|
||||
|
||||
export type IPromiseHandler<T> =
|
||||
export type TPromiseHandler<T> =
|
||||
(req: Request, res: Response, next: NextFunction) => Promise<T>
|
||||
@ -1,6 +1,6 @@
|
||||
import shortid from 'shortid'
|
||||
import {IMiddleware} from './IMiddleware'
|
||||
import {IHandler} from './IHandler'
|
||||
import {THandler} from './THandler'
|
||||
import {Namespace} from 'cls-hooked'
|
||||
|
||||
export const CORRELATION_ID = 'CORRELATION_ID'
|
||||
@ -8,7 +8,7 @@ export const CORRELATION_ID = 'CORRELATION_ID'
|
||||
export class Transaction implements IMiddleware {
|
||||
constructor(readonly ns: Namespace) {}
|
||||
|
||||
handle: IHandler = (req, res, next) => {
|
||||
handle: THandler = (req, res, next) => {
|
||||
const {ns} = this
|
||||
ns.bindEmitter(req)
|
||||
ns.bindEmitter(res)
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import createError from 'http-errors'
|
||||
import {Request} from 'express'
|
||||
import {IHandler} from './IHandler'
|
||||
import {THandler} from './THandler'
|
||||
|
||||
const isLoggedIn = (req: Request) => !!(req as any).user
|
||||
|
||||
export const ensureLoggedInApi: IHandler = (req, res, next) => {
|
||||
export const ensureLoggedInApi: THandler = (req, res, next) => {
|
||||
if (!isLoggedIn(req)) {
|
||||
next(createError(401))
|
||||
return
|
||||
@ -12,7 +12,7 @@ export const ensureLoggedInApi: IHandler = (req, res, next) => {
|
||||
next()
|
||||
}
|
||||
|
||||
export const ensureLoggedInSite = (redirectTo: string): IHandler => {
|
||||
export const ensureLoggedInSite = (redirectTo: string): THandler => {
|
||||
return function _ensureLoggedInSite(req, res, next) {
|
||||
if (!isLoggedIn(req)) {
|
||||
res.redirect(redirectTo)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import {IHandler} from './IHandler'
|
||||
import {IPromiseHandler} from './IPromiseHandler'
|
||||
import {THandler} from './THandler'
|
||||
import {TPromiseHandler} from './TPromiseHandler'
|
||||
|
||||
export function handlePromise<T>(endpoint: IPromiseHandler<T>): IHandler {
|
||||
export function handlePromise<T>(endpoint: TPromiseHandler<T>): THandler {
|
||||
return (req, res, next) => {
|
||||
const promise = endpoint(req, res, next)
|
||||
promise
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
export * from './Authenticator'
|
||||
export * from './CSRFMiddleware'
|
||||
export * from './ensureLoggedIn'
|
||||
export * from './ErrorApiHandler'
|
||||
export * from './ErrorPageHandler'
|
||||
export * from './handlePromise'
|
||||
export * from './IErrorHandler'
|
||||
export * from './IHandler'
|
||||
export * from './IMiddleware'
|
||||
export * from './IPromiseHandler'
|
||||
export * from './RequestLogger'
|
||||
export * from './SessionMiddleware'
|
||||
export * from './TErrorHandler'
|
||||
export * from './THandler'
|
||||
export * from './TPromiseHandler'
|
||||
export * from './Transaction'
|
||||
export * from './ensureLoggedIn'
|
||||
export * from './handlePromise'
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import express from 'express'
|
||||
import {IRoutes, IMethod} from '@rondo/common'
|
||||
import {ITypedHandler} from './ITypedHandler'
|
||||
import {IRoutes, TMethod} from '@rondo/common'
|
||||
import {TTypedHandler} from './TTypedHandler'
|
||||
|
||||
export class AsyncRouter<R extends IRoutes> {
|
||||
readonly router: express.Router
|
||||
@ -11,18 +11,18 @@ export class AsyncRouter<R extends IRoutes> {
|
||||
this.use = this.router.use.bind(this.router) as any
|
||||
}
|
||||
|
||||
protected addRoute<M extends IMethod, P extends keyof R & string>(
|
||||
protected addRoute<M extends TMethod, P extends keyof R & string>(
|
||||
method: M,
|
||||
path: P,
|
||||
handler: ITypedHandler<R, P, M>,
|
||||
handler: TTypedHandler<R, P, M>,
|
||||
) {
|
||||
const addRoute = this.router[method].bind(this.router as any)
|
||||
|
||||
addRoute(path, this.wrapHandler(handler))
|
||||
}
|
||||
|
||||
protected wrapHandler<M extends IMethod, P extends keyof R & string>(
|
||||
handler: ITypedHandler<R, P, M>,
|
||||
protected wrapHandler<M extends TMethod, P extends keyof R & string>(
|
||||
handler: TTypedHandler<R, P, M>,
|
||||
): express.RequestHandler {
|
||||
return (req, res, next) => {
|
||||
handler(req, res, next)
|
||||
@ -35,43 +35,43 @@ export class AsyncRouter<R extends IRoutes> {
|
||||
|
||||
get<P extends keyof R & string>(
|
||||
path: P,
|
||||
handler: ITypedHandler<R, P, 'get'>,
|
||||
handler: TTypedHandler<R, P, 'get'>,
|
||||
) {
|
||||
this.addRoute('get', path, handler)
|
||||
}
|
||||
|
||||
post<P extends keyof R & string>(
|
||||
path: P,
|
||||
handler: ITypedHandler<R, P, 'post'>,
|
||||
handler: TTypedHandler<R, P, 'post'>,
|
||||
) {
|
||||
this.addRoute('post', path, handler)
|
||||
}
|
||||
|
||||
put<P extends keyof R & string>(
|
||||
path: P, handler: ITypedHandler<R, P, 'put'>,
|
||||
path: P, handler: TTypedHandler<R, P, 'put'>,
|
||||
) {
|
||||
this.addRoute('put', path, handler)
|
||||
}
|
||||
|
||||
delete<P extends keyof R & string>(
|
||||
path: P, handler: ITypedHandler<R, P, 'delete'>) {
|
||||
path: P, handler: TTypedHandler<R, P, 'delete'>) {
|
||||
this.addRoute('delete', path, handler)
|
||||
}
|
||||
|
||||
head<P extends keyof R & string>(
|
||||
path: P,
|
||||
handler: ITypedHandler<R, P, 'head'>,
|
||||
handler: TTypedHandler<R, P, 'head'>,
|
||||
) {
|
||||
this.addRoute('head', path, handler)
|
||||
}
|
||||
|
||||
options<P extends keyof R & string>(
|
||||
path: P, handler: ITypedHandler<R, P, 'options'>) {
|
||||
path: P, handler: TTypedHandler<R, P, 'options'>) {
|
||||
this.addRoute('options', path, handler)
|
||||
}
|
||||
|
||||
patch<P extends keyof R & string>(
|
||||
path: P, handler: ITypedHandler<R, P, 'patch'>) {
|
||||
path: P, handler: TTypedHandler<R, P, 'patch'>) {
|
||||
this.addRoute('patch', path, handler)
|
||||
}
|
||||
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import express from 'express'
|
||||
import {IRoutes, IMethod} from '@rondo/common'
|
||||
import {IRoutes, TMethod} from '@rondo/common'
|
||||
import {ITypedRequest} from './ITypedRequest'
|
||||
|
||||
export type ITypedHandler<
|
||||
export type TTypedHandler<
|
||||
R extends IRoutes,
|
||||
P extends keyof R,
|
||||
M extends IMethod
|
||||
M extends TMethod
|
||||
> = (
|
||||
req: ITypedRequest<R[P][M]>,
|
||||
res: express.Response,
|
||||
@ -1,16 +1,16 @@
|
||||
import express from 'express'
|
||||
import {AsyncRouter} from './AsyncRouter'
|
||||
import {IRoutes, IMethod} from '@rondo/common'
|
||||
import {IRoutes, TMethod} from '@rondo/common'
|
||||
import {ITransactionManager} from '../database/ITransactionManager'
|
||||
import {ITypedHandler} from './ITypedHandler'
|
||||
import {TTypedHandler} from './TTypedHandler'
|
||||
|
||||
export class TransactionalRouter<R extends IRoutes> extends AsyncRouter<R> {
|
||||
constructor(readonly transactionManager: ITransactionManager) {
|
||||
super()
|
||||
}
|
||||
|
||||
protected wrapHandler<M extends IMethod, P extends keyof R & string>(
|
||||
handler: ITypedHandler<R, P, M>,
|
||||
protected wrapHandler<M extends TMethod, P extends keyof R & string>(
|
||||
handler: TTypedHandler<R, P, M>,
|
||||
): express.RequestHandler {
|
||||
return async (req, res, next) => {
|
||||
await this.transactionManager
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
export * from './AsyncRouter'
|
||||
export * from './ITypedHandler'
|
||||
export * from './TTypedHandler'
|
||||
export * from './ITypedRequest'
|
||||
export * from './TransactionalRouter'
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import {IHandler} from '../middleware/IHandler'
|
||||
import {THandler} from '../middleware/THandler'
|
||||
import {AsyncRouter} from '../router'
|
||||
import {IRoutes} from '@rondo/common'
|
||||
|
||||
export abstract class BaseRoute<T extends IRoutes> {
|
||||
readonly handle: IHandler
|
||||
readonly handle: THandler
|
||||
|
||||
constructor(protected readonly t: AsyncRouter<T>) {
|
||||
this.handle = t.router
|
||||
|
||||
@ -9,11 +9,11 @@ type CallbackErr = (err?: any) => void
|
||||
export interface ISessionStoreOptions<S extends ISession> {
|
||||
readonly ttl: number
|
||||
readonly cleanup: number
|
||||
readonly getRepository: IRepositoryFactory<S>
|
||||
readonly getRepository: TRepositoryFactory<S>
|
||||
buildSession(sessionData: SessionData, session: ISession): S
|
||||
}
|
||||
|
||||
export type IRepositoryFactory<T> = () => Repository<T>
|
||||
export type TRepositoryFactory<T> = () => Repository<T>
|
||||
|
||||
// TODO casting as any because TypeScript complains. Looks like this is a
|
||||
// bug in TypeScript 3.2.2
|
||||
@ -22,7 +22,7 @@ export type IRepositoryFactory<T> = () => Repository<T>
|
||||
// https://github.com/Microsoft/TypeScript/issues/21592
|
||||
export class SessionStore<S extends ISession> extends Store {
|
||||
|
||||
protected readonly getRepository: IRepositoryFactory<S>
|
||||
protected readonly getRepository: TRepositoryFactory<S>
|
||||
|
||||
constructor(
|
||||
protected readonly options: ISessionStoreOptions<S>,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import supertest from 'supertest'
|
||||
import {
|
||||
IMethod,
|
||||
TMethod,
|
||||
IRoutes,
|
||||
URLFormatter,
|
||||
} from '@rondo/common'
|
||||
@ -13,7 +13,7 @@ interface ITest extends Omit<Omit<supertest.Test, 'then'>, 'catch'> {}
|
||||
interface IResponse<
|
||||
R extends IRoutes,
|
||||
P extends keyof R,
|
||||
M extends IMethod,
|
||||
M extends TMethod,
|
||||
> extends supertest.Response {
|
||||
body: R[P][M]['response']
|
||||
header: {[key: string]: string}
|
||||
@ -22,7 +22,7 @@ interface IResponse<
|
||||
interface IRequest<
|
||||
R extends IRoutes,
|
||||
P extends keyof R,
|
||||
M extends IMethod,
|
||||
M extends TMethod,
|
||||
> extends ITest, Promise<IResponse<R, P, M>> {
|
||||
send(value: R[P][M]['body'] | string): this
|
||||
expect(status: number, body?: any): this
|
||||
@ -37,7 +37,7 @@ interface IRequest<
|
||||
interface IRequestOptions<
|
||||
R extends IRoutes,
|
||||
P extends keyof R,
|
||||
M extends IMethod,
|
||||
M extends TMethod,
|
||||
> {
|
||||
params?: R[P][M]['params'],
|
||||
query?: R[P][M]['query'],
|
||||
@ -62,7 +62,7 @@ export class RequestTester<R extends IRoutes> {
|
||||
return this
|
||||
}
|
||||
|
||||
request<M extends IMethod, P extends keyof R & string>(
|
||||
request<M extends TMethod, P extends keyof R & string>(
|
||||
method: M, path: P, options: IRequestOptions<R, P, 'post'> = {},
|
||||
)
|
||||
: IRequest<R, P, M> {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user