Partiall upgrade packages/client

This commit is contained in:
Jerko Steiner 2019-09-15 18:29:55 +07:00
parent fea568b58a
commit 30d1f1fcd4
26 changed files with 147 additions and 199 deletions

View File

@ -29,6 +29,11 @@ rules:
delimiter: none
singleline:
delimiter: comma
'@typescript-eslint/no-unused-vars':
- warn
- vars: all
args: none
ignoreRestSiblings: true
'@typescript-eslint/explicit-function-return-type': off
'@typescript-eslint/no-non-null-assertion': off
'@typescript-eslint/no-use-before-define': off

View File

@ -1,18 +0,0 @@
import { TStateSelector } from '@rondo.dev/redux'
import { Connector } from '../redux'
import { Crumb } from './Crumb'
import { CrumbsActions } from './CrumbsActions'
import { ICrumbsState } from './CrumbsReducer'
export class CrumbsConnector extends Connector<ICrumbsState> {
protected readonly breadcrumbsActions = new CrumbsActions()
connect<State>(getLocalState: TStateSelector<State, ICrumbsState>) {
return this.wrap(
getLocalState,
state => state,
dispatch => ({}),
Crumb,
)
}
}

View File

@ -5,7 +5,7 @@ import {TestUtils} from '../test-utils'
const t = new TestUtils()
describe('CrumbsConnector', () => {
describe('configrueCrumbs', () => {
const createTestCase = () => t.withProvider({
reducers: {Crumbs: Feature.Crumbs},
@ -23,7 +23,7 @@ describe('CrumbsConnector', () => {
current: 'Three',
},
})
.withComponent(select => new Feature.CrumbsConnector().connect(select))
.withComponent(select => Feature.configureCrumbs(select))
.withJSX(Component => <MemoryRouter><Component /></MemoryRouter>)
describe('render', () => {

View File

@ -0,0 +1,14 @@
import { pack, TStateSelector } from '@rondo.dev/redux'
import { Crumb } from './Crumb'
import { ICrumbsState } from './CrumbsReducer'
export function configureCrumbs<State>(
getLocalState: TStateSelector<State, ICrumbsState>,
) {
return pack(
getLocalState,
state => state,
dispatch => ({}),
Crumb,
)
}

View File

@ -1,6 +1,6 @@
export * from './configureCrumbs'
export * from './Crumb'
export * from './CrumbsActions'
export * from './CrumbsConnector'
export * from './CrumbsReducer'
export * from './HistoryCrumbs'
export * from './ICrumbLink'

View File

@ -1,11 +1,10 @@
import { IAPIDef } from '@rondo.dev/common'
import { APIDef } from '@rondo.dev/common'
import { HTTPClientMock } from '@rondo.dev/http-client'
import { getError } from '@rondo.dev/test-utils'
import React from 'react'
import ReactDOM from 'react-dom'
import T from 'react-dom/test-utils'
import { MemoryRouter } from 'react-router-dom'
import { TestUtils } from '../test-utils'
import { TestUtils, TestContainer } from '../test-utils'
import * as Feature from './'
import { configureRegister } from './configureRegister'
@ -13,7 +12,7 @@ const test = new TestUtils()
describe('configureRegister', () => {
const http = new HTTPClientMock<IAPIDef>()
const http = new HTTPClientMock<APIDef>()
const loginActions = new Feature.LoginActions(http)
const createTestProvider = () => test.withProvider({
@ -45,7 +44,7 @@ describe('configureRegister', () => {
}
const onSuccess = jest.fn()
let node: Element
let component: React.Component
let component: TestContainer
beforeEach(() => {
http.mockAdd({
method: 'post',
@ -85,8 +84,7 @@ describe('configureRegister', () => {
.value,
)
.toEqual('')
node = ReactDOM.findDOMNode(component) as Element
expect(node.innerHTML).toMatch(/<a href="\/">/)
expect(component.ref.current!.innerHTML).toMatch(/<a href="\/">/)
})
it('sets the error message on failure', async () => {

View File

@ -1,7 +1,7 @@
import React from 'react'
import {IPendingAction} from '@rondo.dev/redux'
import {PendingAction} from '@rondo.dev/redux'
export interface IComponentProps<Data> {
export interface ComponentProps<Data> {
onSubmit: () => void
onChange: (name: string, value: string) => void
// TODO clear data on successful submission. This is important to prevent
@ -9,29 +9,29 @@ export interface IComponentProps<Data> {
data: Data
}
export interface IFormHOCProps<Data> {
onSubmit: (props: Data) => IPendingAction<any, any>
export interface FormHOCProps<Data> {
onSubmit: (props: Data) => PendingAction<unknown, string>
// TODO figure out what would happen if the underlying child component
// would have the same required property as the HOC, like onSuccess?
onSuccess?: () => void
clearOnSuccess?: boolean
}
export interface IFormHOCState<Data> {
export interface FormHOCState<Data> {
error: string
data: Data
}
export function withForm<Data, Props extends IComponentProps<Data>>(
export function withForm<Data, Props extends ComponentProps<Data>>(
Component: React.ComponentType<Props>,
initialState: Data,
) {
type OtherProps = Pick<Props,
Exclude<keyof Props, keyof IComponentProps<Data>>>
type T = IFormHOCProps<Data> & OtherProps
Exclude<keyof Props, keyof ComponentProps<Data>>>
type T = FormHOCProps<Data> & OtherProps
return class FormHOC extends React.PureComponent<T, IFormHOCState<Data>> {
return class FormHOC extends React.PureComponent<T, FormHOCState<Data>> {
constructor(props: T) {
super(props)
this.state = {
@ -78,7 +78,9 @@ export function withForm<Data, Props extends IComponentProps<Data>>(
// https://github.com/Microsoft/TypeScript/issues/28938
return (
<Component
{...otherProps as any}
{
...otherProps as any // eslint-disable-line
}
data={this.state}
onSubmit={this.handleSubmit}
onChange={this.handleChange}

View File

@ -1,58 +0,0 @@
import {TStateSelector} from '@rondo.dev/redux'
import {connect, Omit} from 'react-redux'
import {Dispatch} from 'redux'
import {ComponentType} from 'react'
/**
* Helps isolate the component along with actions and reducer from the global
* application state.
*
* The connect() function requires a state selector, which can be used to
* select a slice of the current state to the component, which will be passed
* on to `mapStateToProps()`.
*
* Classes that extend Connector can provide dependencies in the constructor
* and then bind them to dispatch in mapDispatchToProps. This is useful to
* build components which do not depend on a "global" singletons. For example,
* the Actions class might depend on the HTTPClient class, and then it becomes
* easy to mock it during tests, or swap out different dependencies for
* different applications.
*/
export abstract class Connector<LocalState> {
/**
* Connects a component using redux. The `selectState` method is used to
* select a subset of state to map to the component.
*
* It returns a component with `any` props. Ideally this could be changed to
* required props.
*
* https://stackoverflow.com/questions/54277411
*/
abstract connect<State>(
selectState: TStateSelector<State, LocalState>,
): ComponentType<any>
protected wrap<
State,
Props,
StateProps extends Partial<Props>,
DispatchProps extends Partial<Props>,
>(
getLocalState: TStateSelector<State, LocalState>,
mapStateToProps: (state: LocalState) => StateProps,
mapDispatchToProps: (dispatch: Dispatch) => DispatchProps,
Component: React.ComponentType<Props>,
): ComponentType<
Omit<Props, keyof Props & (keyof StateProps | keyof DispatchProps)>
> {
return connect(
(state: State) => {
const l = getLocalState(state)
return mapStateToProps(l)
},
mapDispatchToProps,
)(Component as any) as any
}
}

View File

@ -1 +0,0 @@
export * from './Connector'

View File

@ -1,4 +1,4 @@
export interface IClientConfig {
export interface ClientConfig {
readonly appName: string
readonly baseUrl: string
readonly csrfToken: string

View File

@ -1,30 +1,27 @@
import { createBrowserHistory } from 'history'
import React from 'react'
import ReactDOM from 'react-dom'
import {Action} from 'redux'
import {IAPIDef} from '@rondo.dev/common'
import {IClientConfig} from './IClientConfig'
import {IHTTPClient, HTTPClient} from '@rondo.dev/http-client'
import {IRenderer} from './IRenderer'
import {Provider} from 'react-redux'
import {Router} from 'react-router-dom'
import {Store} from 'redux'
import {createBrowserHistory} from 'history'
import { Provider } from 'react-redux'
import { Router } from 'react-router-dom'
import { Store } from 'redux'
import { ClientConfig } from './ClientConfig'
import { Renderer } from './Renderer'
export interface IClientRendererParams<Props> {
export interface ClientRendererParams<Props> {
readonly RootComponent: React.ComponentType<Props>
readonly target?: HTMLElement
readonly hydrate: boolean // TODO make this better
}
export class ClientRenderer<Props>
implements IRenderer<Props> {
constructor(readonly params: IClientRendererParams<Props>) {}
implements Renderer<Props> {
constructor(readonly params: ClientRendererParams<Props>) {}
render<State>(
url: string,
store: Store<State>,
props: Props,
config: IClientConfig,
config: ClientConfig,
) {
const {
RootComponent,

View File

@ -1,12 +0,0 @@
import {IAPIDef} from '@rondo.dev/common'
import {IClientConfig} from './IClientConfig'
import {Store} from 'redux'
export interface IRenderer<Props> {
render<State>(
url: string,
store: Store<State>,
props: Props,
config: IClientConfig,
): any
}

View File

@ -0,0 +1,11 @@
import { Store } from 'redux'
import { ClientConfig } from './ClientConfig'
export interface Renderer<Props> {
render<State>(
url: string,
store: Store<State>,
props: Props,
config: ClientConfig,
): unknown
}

View File

@ -8,6 +8,10 @@ import { Store } from 'redux'
import { IClientConfig } from './IClientConfig'
import { IRenderer } from './IRenderer'
interface ComponentWithFetchData {
fetchData(): Promise<unknown>
}
export class ServerRenderer<Props> implements IRenderer<Props> {
constructor(
readonly RootComponent: React.ComponentType<Props>,
@ -17,7 +21,7 @@ export class ServerRenderer<Props> implements IRenderer<Props> {
store: Store<State>,
props: Props,
config: IClientConfig,
host: string = '',
host = '',
headers: Record<string, string> = {},
) {
const {RootComponent} = this
@ -39,7 +43,7 @@ export class ServerRenderer<Props> implements IRenderer<Props> {
await ssrPrepass(element, async (el, component) => {
if (component && 'fetchData' in component) {
await (component as any).fetchData()
await (component as ComponentWithFetchData).fetchData()
}
})
const stream = renderToNodeStream(element)

View File

@ -1,4 +1,4 @@
export * from './ClientRenderer'
export * from './IClientConfig'
export * from './IRenderer'
export * from './ClientConfig'
export * from './Renderer'
export * from './isClientSide'

View File

@ -1,6 +1,10 @@
interface MockServerSide {
__MOCK_SERVER_SIDE__?: boolean
}
export function isClientSide() {
return typeof window !== 'undefined' &&
typeof window.document !== 'undefined' &&
typeof window.document.createElement === 'function' &&
typeof (window as any).__MOCK_SERVER_SIDE__ === 'undefined'
typeof (window as MockServerSide).__MOCK_SERVER_SIDE__ === 'undefined'
}

View File

@ -3,23 +3,27 @@ import React from 'react'
import { FaCheck, FaEdit, FaPlusSquare } from 'react-icons/fa'
import { TeamActions, Team } from '@rondo.dev/common'
export type TTeamEditorProps = {
interface AddTeamProps {
type: 'add'
onAddTeam: TeamActions['create']
} | {
}
interface UpdateTeamProps {
type: 'update'
onUpdateTeam: TeamActions['update']
team: Team
}
export interface ITeamEditorState {
export type TTeamEditorProps = AddTeamProps | UpdateTeamProps
export interface TeamEditorState {
// TODO use redux state for errors!
error: string
name: string
}
export class TeamEditor
extends React.PureComponent<TTeamEditorProps, ITeamEditorState> {
extends React.PureComponent<TTeamEditorProps, TeamEditorState> {
constructor(props: TTeamEditorProps) {
super(props)
this.state = {
@ -33,7 +37,7 @@ extends React.PureComponent<TTeamEditorProps, ITeamEditorState> {
componentWillReceiveProps(nextProps: TTeamEditorProps) {
if (nextProps.type === 'update') {
const {team} = nextProps
if (team !== (this.props as any).team) {
if (team !== (this.props as UpdateTeamProps).team) {
this.setState({
name: this.getName(team),
})

View File

@ -1,24 +1,24 @@
import { TReadonlyRecord, Team, TeamActions } from '@rondo.dev/common'
import { ReadonlyRecord, Team, TeamActions } from '@rondo.dev/common'
import { Button, Panel, PanelBlock, PanelHeading } from 'bloomer'
import React from 'react'
import { FaEdit, FaPlus, FaTimes } from 'react-icons/fa'
import { Link } from 'react-router-dom'
export interface ITeamListProps {
export interface TeamListProps {
ListButtons?: React.ComponentType<{team: Team}>
teamsById: TReadonlyRecord<number, Team>
teamsById: ReadonlyRecord<number, Team>
teamIds: ReadonlyArray<number>
onAddTeam: TeamActions['create']
onRemoveTeam: TeamActions['remove']
}
export interface ITeamProps {
export interface TeamProps {
ListButtons?: React.ComponentType<{team: Team}>
team: Team
onRemoveTeam: TeamActions['remove']
}
export class TeamRow extends React.PureComponent<ITeamProps> {
export class TeamRow extends React.PureComponent<TeamProps> {
handleRemove = async () => {
const {onRemoveTeam, team: {id}} = this.props
await onRemoveTeam({id}).payload
@ -53,7 +53,7 @@ export class TeamRow extends React.PureComponent<ITeamProps> {
}
}
export class TeamList extends React.PureComponent<ITeamListProps> {
export class TeamList extends React.PureComponent<TeamListProps> {
render() {
const {teamIds, teamsById} = this.props

View File

@ -1,4 +1,4 @@
import { IUserInTeam, TReadonlyRecord, TeamActions, UserActions, Team } from '@rondo.dev/common'
import { UserInTeam, ReadonlyRecord, TeamActions, UserActions, Team } from '@rondo.dev/common'
import { Panel, PanelBlock, PanelHeading } from 'bloomer'
import { History, Location } from 'history'
import React from 'react'
@ -8,24 +8,24 @@ import { TeamEditor } from './TeamEditor'
import { TeamList } from './TeamList'
import { TeamUserList } from './TeamUserList'
export interface ITeamManagerProps {
export interface TeamManagerProps {
history: History
location: Location
match: Match<any>
match: Match<any> // eslint-disable-line
ListButtons?: React.ComponentType<{team: Team}>
teamActions: TeamActions
findUserByEmail: UserActions['findUserByEmail']
teamsById: TReadonlyRecord<number, Team>
teamsById: ReadonlyRecord<number, Team>
teamIds: ReadonlyArray<number>
userKeysByTeamId: TReadonlyRecord<number, ReadonlyArray<string>>
usersByKey: TReadonlyRecord<string, IUserInTeam>
userKeysByTeamId: ReadonlyRecord<number, ReadonlyArray<string>>
usersByKey: ReadonlyRecord<string, UserInTeam>
}
export class TeamManager extends React.PureComponent<ITeamManagerProps> {
export class TeamManager extends React.PureComponent<TeamManagerProps> {
async componentDidMount() {
await this.props.teamActions.find()
}

View File

@ -1,18 +1,18 @@
import { indexBy, Team as _Team, IUserInTeam, TReadonlyRecord, without, TeamActions } from '@rondo.dev/common'
import { indexBy, Team as _Team, UserInTeam, ReadonlyRecord, without, TeamActions } from '@rondo.dev/common'
import { createReducer } from '@rondo.dev/jsonrpc'
export interface ITeamState {
export interface TeamState {
readonly loading: number
readonly error: string
readonly teamIds: ReadonlyArray<number>
readonly teamsById: TReadonlyRecord<number, _Team>
readonly teamsById: ReadonlyRecord<number, _Team>
readonly userKeysByTeamId: TReadonlyRecord<number, ReadonlyArray<string>>
readonly usersByKey: TReadonlyRecord<string, IUserInTeam>
readonly userKeysByTeamId: ReadonlyRecord<number, ReadonlyArray<string>>
readonly usersByKey: ReadonlyRecord<string, UserInTeam>
}
const defaultState: ITeamState = {
const defaultState: TeamState = {
loading: 0,
error: '',
@ -104,7 +104,7 @@ export const Team = createReducer('teamService', defaultState)
.reduce((obj, userInTeam) => {
obj[getUserKey(userInTeam)] = userInTeam
return obj
}, {} as Record<string, IUserInTeam>)
}, {} as Record<string, UserInTeam>)
return {
userKeysByTeamId: {

View File

@ -1,11 +1,11 @@
import { IUser, IUserInTeam, TReadonlyRecord, TeamActions, UserActions, Team } from '@rondo.dev/common'
import { User, UserInTeam, ReadonlyRecord, TeamActions, UserActions, Team } from '@rondo.dev/common'
import { Button, Control, Heading, Help, Input, Panel, PanelBlock, PanelHeading } from 'bloomer'
import React from 'react'
import { FaCheck, FaTimes, FaUser } from 'react-icons/fa'
const EMPTY_ARRAY: ReadonlyArray<string> = []
export interface ITeamUsersProps {
export interface TeamUsersProps {
// fetchMyTeams: () => void,
fetchUsersInTeam: TeamActions['findUsers']
findUserByEmail: UserActions['findUserByEmail']
@ -14,29 +14,29 @@ export interface ITeamUsersProps {
onRemoveUser: TeamActions['removeUser']
team: Team
userKeysByTeamId: TReadonlyRecord<number, ReadonlyArray<string>>
usersByKey: TReadonlyRecord<string, IUserInTeam>
userKeysByTeamId: ReadonlyRecord<number, ReadonlyArray<string>>
usersByKey: ReadonlyRecord<string, UserInTeam>
}
export interface ITeamUserProps {
export interface TeamUserProps {
onRemoveUser: (
params: {userId: number, teamId: number, roleId: number}) => void
user: IUserInTeam
user: UserInTeam
}
export interface IAddUserProps {
export interface AddUserProps {
onAddUser: TeamActions['addUser']
onSearchUser: UserActions['findUserByEmail']
teamId: number
}
export interface IAddUserState {
export interface AddUserState {
error: string
email: string
user?: IUser
user?: User
}
export class TeamUser extends React.PureComponent<ITeamUserProps> {
export class TeamUser extends React.PureComponent<TeamUserProps> {
handleRemoveUser = async () => {
const {onRemoveUser, user} = this.props
await onRemoveUser({...user, roleId: 1})
@ -65,8 +65,8 @@ export class TeamUser extends React.PureComponent<ITeamUserProps> {
}
}
export class AddUser extends React.PureComponent<IAddUserProps, IAddUserState> {
constructor(props: IAddUserProps) {
export class AddUser extends React.PureComponent<AddUserProps, AddUserState> {
constructor(props: AddUserProps) {
super(props)
this.state = {
error: '',
@ -131,10 +131,10 @@ export class AddUser extends React.PureComponent<IAddUserProps, IAddUserState> {
}
}
export class TeamUserList extends React.PureComponent<ITeamUsersProps> {
export class TeamUserList extends React.PureComponent<TeamUsersProps> {
async componentDidMount() {
await this.fetchUsersInTeam(this.props.team.id)
} async componentWillReceiveProps(nextProps: ITeamUsersProps) {
} async componentWillReceiveProps(nextProps: TeamUsersProps) {
const {team} = nextProps
if (team.id !== this.props.team.id) {
this.fetchUsersInTeam(team.id)

View File

@ -1,4 +1,4 @@
import { ITeamService, ITeamUsers, IUserService, Team, TeamActions, TeamServiceMethods, UserActions, UserServiceMethods } from '@rondo.dev/common'
import { TeamService, TeamUsers, UserService, Team, TeamActions, TeamServiceMethods, UserActions, UserServiceMethods } from '@rondo.dev/common'
import { createActions } from '@rondo.dev/jsonrpc'
import createClientMock from '@rondo.dev/jsonrpc/lib/createClientMock'
import { getError } from '@rondo.dev/test-utils'
@ -17,9 +17,9 @@ describe('TeamConnector', () => {
}
const [teamClient, teamClientMock] =
createClientMock<ITeamService>(TeamServiceMethods)
const [userClient, userClientMock] =
createClientMock<IUserService>(UserServiceMethods)
createClientMock<TeamService>(TeamServiceMethods)
const [userClient] =
createClientMock<UserService>(UserServiceMethods)
let teamActions!: TeamActions
let userActions!: UserActions
beforeEach(() => {
@ -57,7 +57,7 @@ describe('TeamConnector', () => {
userTeams: [],
}]
const users: ITeamUsers = {
const users: TeamUsers = {
teamId: 123,
usersInTeam: [{
teamId: 123,
@ -111,7 +111,6 @@ describe('TeamConnector', () => {
})
it('displays an error', async () => {
const error = {error: 'An error'}
teamClientMock.create.mockRejectedValue(new Error('Test Error'))
const {render} = createTestProvider()
const {node, waitForActions} = render({

View File

@ -1,6 +1,6 @@
/* eslint @typescript-eslint/no-explicit-any: 0 */
import React from 'react'
import ReactDOM from 'react-dom'
import T from 'react-dom/test-utils'
import {createStore, TStateSelector, WaitMiddleware} from '@rondo.dev/redux'
import {Provider} from 'react-redux'
import {
@ -10,20 +10,18 @@ import {
Reducer,
ReducersMapObject,
combineReducers,
Store as ReduxStore,
Unsubscribe,
} from 'redux'
import { format } from 'util'
interface IRenderParams<State, LocalState> {
interface RenderParams<State, LocalState> {
reducers: ReducersMapObject<State, any>
select: TStateSelector<State, LocalState>
// getComponent: (
// select: TStateSelector<State, LocalState>) => React.ComponentType<Props>,
// customJSX?: (
// Component: React.ComponentType<Props>,
// props: Props,
// ) => JSX.Element
}
export class TestContainer extends React.Component<{}> {
ref = React.createRef<HTMLDivElement>()
render() {
return <div ref={this.ref}>{this.props.children}</div>
}
}
export class TestUtils {
@ -34,9 +32,10 @@ export class TestUtils {
render(jsx: JSX.Element) {
const $div = document.createElement('div')
ReactDOM.render(<TestContainer>{jsx}</TestContainer>, $div)
const component = ReactDOM.render(
<div>{jsx}</div>, $div) as unknown as React.Component<any>
const node = (ReactDOM.findDOMNode(component) as Element).children[0]
<div>{jsx}</div>, $div) as unknown as TestContainer
const node = component.ref.current!
return {
component,
node,
@ -55,7 +54,7 @@ export class TestUtils {
* method to render the connected component with a `Provider`.
*/
withProvider<State, LocalState, A extends Action<any> = AnyAction>(
params: IRenderParams<State, LocalState>,
params: RenderParams<State, LocalState>,
) {
const {reducers, select} = params
@ -102,7 +101,7 @@ export class TestUtils {
return {
...result,
async waitForActions(timeout = 2000) {
await waitMiddleware.waitForRecorded(recorder)
await waitMiddleware.waitForRecorded(recorder, timeout)
},
}
}
@ -112,7 +111,7 @@ export class TestUtils {
return self
}
const self: ISelf<
const self: Self<
Props, typeof store, typeof Component, CreateJSX
> = {
render,
@ -128,14 +127,14 @@ export class TestUtils {
}
}
interface ISelf<Props, Store, Component, CreateJSX> {
interface Self<Props, Store, Component, CreateJSX> {
render: (props: Props) => {
component: React.Component<any>
component: TestContainer
node: Element
waitForActions(timeout?: number): Promise<void>
}
store: Store
Component: Component
withJSX: (localCreateJSX: CreateJSX)
=> ISelf<Props, Store, Component, CreateJSX>
=> Self<Props, Store, Component, CreateJSX>
}

View File

@ -4,7 +4,7 @@ declare module 'react-ssr-prepass' {
export type Visitor = (
element: ReactElement,
instance?: Component,
) => void | Promise<any>
) => void | Promise<unknown>
function ssrPrepass(node: ReactElement, visitor?: Visitor): Promise<void>

View File

@ -1,10 +1,10 @@
export * from './HTTPClient'
export * from './HTTPClientMock'
export * from './Headers'
export * from './HTTPClient'
export * from './HTTPClientMock'
export * from './Request'
export * from './RequestParams'
export * from './RequestQuery'
export * from './Response'
export * from './SimpleHTTPClient'
export * from './TypedRequestParams'
export * from './URLFormatter'

View File

@ -2,7 +2,7 @@ import { Logger } from '@rondo.dev/logger'
import express, { ErrorRequestHandler, Request, Response, Router } from 'express'
import { createError, ErrorResponse, isRPCError } from './error'
import { IDEMPOTENT_METHOD_REGEX } from './idempotent'
import { createRpcService, ERROR_METHOD_NOT_FOUND, ERROR_SERVER, IRequest, SuccessResponse } from './jsonrpc'
import { createRpcService, ERROR_METHOD_NOT_FOUND, ERROR_SERVER, Request as RPCRequest, SuccessResponse } from './jsonrpc'
import { FunctionPropertyNames } from './types'
export type TGetContext<Context> = (req: Request) => Promise<Context> | Context
@ -16,13 +16,13 @@ export interface RPCReturnType {
router(): Router
}
export interface InvocationDetails<A extends IRequest, Context> {
export interface InvocationDetails<A extends RPCRequest, Context> {
context: Context
path: string
request: A
}
async function defaultHook<A extends IRequest, R, Context>(
async function defaultHook<A extends RPCRequest, R, Context>(
details: InvocationDetails<A, Context>,
invoke: () => Promise<R>,
): Promise<R> {
@ -33,7 +33,7 @@ async function defaultHook<A extends IRequest, R, Context>(
export function jsonrpc<Context>(
getContext: TGetContext<Context>,
logger: Logger,
hook: <A extends IRequest, R>(
hook: <A extends RPCRequest, R>(
details: InvocationDetails<A, Context>,
invoke: (request?: A) => Promise<R>) => Promise<R> = defaultHook,
idempotentMethodRegex = IDEMPOTENT_METHOD_REGEX,