Skip to content

Commit c165694

Browse files
committed
feat: add ability to pass event map generic to Provider.createEmitter
1 parent 8401a0d commit c165694

File tree

6 files changed

+415
-46
lines changed

6 files changed

+415
-46
lines changed

.changeset/odd-carpets-sort.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"ox": patch
3+
---
4+
5+
Added ability to pass custom event map to `Provider.createEmitter`.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"ox": patch
3+
---
4+
5+
Added ability to pass `schema` to `RpcRequest.createStore`

src/core/Provider.ts

Lines changed: 49 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,6 @@ import type * as RpcSchema from './RpcSchema.js'
88

99
/** Options for a {@link ox#Provider.Provider}. */
1010
export type Options = {
11-
/**
12-
* Whether to include event functions (`on`, `removeListener`) on the Provider.
13-
*
14-
* @default true
15-
*/
16-
includeEvents?: boolean | undefined
1711
/**
1812
* RPC Schema to use for the Provider's `request` function.
1913
* See {@link ox#RpcSchema.(from:function)} for more.
@@ -26,6 +20,7 @@ export type Options = {
2620
/** Root type for an EIP-1193 Provider. */
2721
export type Provider<
2822
options extends Options | undefined = undefined,
23+
eventMap extends boolean | Record<string, unknown> = false,
2924
///
3025
_schema extends RpcSchema.Generic = options extends {
3126
schema: infer schema extends RpcSchema.Generic
@@ -35,16 +30,17 @@ export type Provider<
3530
> = Compute<
3631
{
3732
request: RequestFn<_schema>
38-
} & (options extends { includeEvents: true } | undefined
39-
? {
40-
on: EventListenerFn
41-
removeListener: EventListenerFn
42-
}
43-
: {})
33+
} & (
34+
| (eventMap extends true ? Emitter<EventMap> : never)
35+
| (eventMap extends false ? Partial<Emitter<EventMap>> : never)
36+
| (eventMap extends Record<string, unknown> ? Emitter<eventMap> : never)
37+
)
4438
>
4539

4640
/** Type for an EIP-1193 Provider's event emitter. */
47-
export type Emitter = Compute<EventEmitter<EventMap>>
41+
export type Emitter<
42+
eventMap extends Record<string, unknown> | undefined = undefined,
43+
> = Compute<EventEmitter<EventMap<eventMap>>>
4844

4945
/** EIP-1193 Provider's `request` function. */
5046
export type RequestFn<schema extends RpcSchema.Generic = RpcSchema.Generic> = <
@@ -53,12 +49,6 @@ export type RequestFn<schema extends RpcSchema.Generic = RpcSchema.Generic> = <
5349
parameters: RpcSchema_internal.ExtractRequestOpaque<schema, methodName>,
5450
) => Promise<RpcSchema.ExtractReturnType<schema, methodName>>
5551

56-
/** Type for an EIP-1193 Provider's event listener functions (`on`, `removeListener`, etc). */
57-
export type EventListenerFn = <event extends keyof EventMap>(
58-
event: event,
59-
listener: EventMap[event],
60-
) => void
61-
6252
export type ConnectInfo = {
6353
chainId: string
6454
}
@@ -81,13 +71,15 @@ export class ProviderRpcError extends Error {
8171
}
8272
}
8373

84-
export type EventMap = {
74+
export type EventMap<
75+
eventMap extends Record<string, unknown> | undefined = undefined,
76+
> = {
8577
accountsChanged: (accounts: readonly Address.Address[]) => void
8678
chainChanged: (chainId: string) => void
8779
connect: (connectInfo: ConnectInfo) => void
8880
disconnect: (error: ProviderRpcError) => void
8981
message: (message: Message) => void
90-
}
82+
} & (eventMap extends Record<string, unknown> ? eventMap : {})
9183

9284
/** The user rejected the request. */
9385
export class UserRejectedRequestError extends ProviderRpcError {
@@ -293,8 +285,10 @@ export class AtomicityNotSupportedError extends ProviderRpcError {
293285
*
294286
* @returns An event emitter.
295287
*/
296-
export function createEmitter(): Emitter {
297-
const emitter = new EventEmitter<EventMap>()
288+
export function createEmitter<
289+
eventMap extends Record<string, unknown> = Record<string, unknown>,
290+
>(): Emitter<eventMap> {
291+
const emitter = new EventEmitter<EventMap<eventMap>>()
298292

299293
return {
300294
get eventNames() {
@@ -476,23 +470,18 @@ export declare namespace createEmitter {
476470
* @returns An typed EIP-1193 Provider.
477471
*/
478472
export function from<
479-
const provider extends Provider | unknown,
480-
options extends Options | undefined = undefined,
473+
options extends Options | undefined,
474+
//
475+
provider extends from.Value<options> | undefined = undefined,
481476
>(
482-
provider: provider | Provider<{ schema: RpcSchema.Generic }>,
477+
provider: provider | from.Value<options> | undefined,
483478
options?: options | Options,
484-
): Provider<options>
479+
): from.ReturnType<options, provider>
485480
// eslint-disable-next-line jsdoc/require-jsdoc
486-
export function from(provider: any, options: Options = {}): Provider<Options> {
487-
const { includeEvents = true } = options
481+
export function from(provider: any, _options: Options = {}): Provider {
488482
if (!provider) throw new IsUndefinedError()
489483
return {
490-
...(includeEvents
491-
? {
492-
on: provider.on?.bind(provider),
493-
removeListener: provider.removeListener?.bind(provider),
494-
}
495-
: {}),
484+
...provider,
496485
async request(args) {
497486
try {
498487
const result = await provider.request(args)
@@ -511,6 +500,31 @@ export function from(provider: any, options: Options = {}): Provider<Options> {
511500
}
512501

513502
export declare namespace from {
503+
type Value<options extends Options | undefined = undefined> = Partial<
504+
Emitter<any>
505+
> & {
506+
request: (
507+
parameters: options extends {
508+
schema: infer schema extends RpcSchema.Generic
509+
}
510+
? schema['Request']
511+
: RpcSchema.Generic['Request'],
512+
) => unknown
513+
}
514+
515+
type ReturnType<
516+
options extends Options | undefined = Options | undefined,
517+
provider extends from.Value<options> | undefined =
518+
| from.Value<options>
519+
| undefined,
520+
> = Omit<provider, 'request'> & {
521+
request: RequestFn<
522+
options extends { schema: infer schema extends RpcSchema.Generic }
523+
? schema
524+
: RpcSchema.Default
525+
>
526+
}
527+
514528
type ErrorType = IsUndefinedError | Errors.GlobalErrorType
515529
}
516530

src/core/RpcRequest.ts

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,25 @@ export type RpcRequest<schema extends RpcSchema.Generic = RpcSchema.Generic> =
1717
>
1818

1919
/** JSON-RPC request store type. */
20-
export type Store<schema extends RpcSchema.Generic = RpcSchema.Default> =
20+
export type Store<schema extends RpcSchema.Generic | undefined = undefined> =
2121
Compute<{
2222
prepare: <methodName extends RpcSchema.MethodNameGeneric>(
2323
parameters: Compute<
24-
RpcSchema_internal.ExtractRequestOpaque<schema, methodName>
24+
schema extends RpcSchema.Generic
25+
? RpcSchema.ExtractRequest<schema, methodName>
26+
: RpcSchema_internal.ExtractRequestOpaque<
27+
RpcSchema.Default,
28+
methodName
29+
>
2530
>,
26-
) => Compute<RpcRequest<RpcSchema.ExtractItem<schema, methodName>>>
31+
) => Compute<
32+
RpcRequest<
33+
RpcSchema.ExtractItem<
34+
schema extends RpcSchema.Generic ? schema : RpcSchema.Default,
35+
methodName
36+
>
37+
>
38+
>
2739
readonly id: number
2840
}>
2941

@@ -58,12 +70,12 @@ export type Store<schema extends RpcSchema.Generic = RpcSchema.Default> =
5870
* @example
5971
* ### Type-safe Custom Schemas
6072
*
61-
* It is possible to define your own type-safe schema by using the {@link ox#RpcSchema.From} type.
73+
* It is possible to define your own type-safe schema by using {@link ox#RpcSchema.from}.
6274
*
6375
* ```ts twoslash
6476
* import { RpcSchema, RpcRequest } from 'ox'
6577
*
66-
* type Schema = RpcSchema.From<{ // [!code focus]
78+
* const schema = RpcSchema.from<{ // [!code focus]
6779
* Request: { // [!code focus]
6880
* method: 'eth_foobar' // [!code focus]
6981
* params: [number] // [!code focus]
@@ -75,9 +87,9 @@ export type Store<schema extends RpcSchema.Generic = RpcSchema.Default> =
7587
* params: [string] // [!code focus]
7688
* } // [!code focus]
7789
* ReturnType: string // [!code focus]
78-
* }> // [!code focus]
90+
* }>() // [!code focus]
7991
*
80-
* const store = RpcRequest.createStore<Schema>() // [!code focus]
92+
* const store = RpcRequest.createStore({ schema }) // [!code focus]
8193
*
8294
* const request = store.prepare({
8395
* method: 'eth_foobar', // [!code focus]
@@ -90,8 +102,8 @@ export type Store<schema extends RpcSchema.Generic = RpcSchema.Default> =
90102
* @returns The request store
91103
*/
92104
export function createStore<
93-
schema extends RpcSchema.Generic = RpcSchema.Default,
94-
>(options: createStore.Options = {}): createStore.ReturnType<schema> {
105+
schema extends RpcSchema.Generic | undefined = undefined,
106+
>(options: createStore.Options<schema> = {}): createStore.ReturnType<schema> {
95107
let id = options.id ?? 0
96108
return {
97109
prepare(options) {
@@ -107,12 +119,14 @@ export function createStore<
107119
}
108120

109121
export declare namespace createStore {
110-
type Options = {
122+
type Options<schema extends RpcSchema.Generic | undefined = undefined> = {
111123
/** The initial request ID. */
112124
id?: number
125+
/** RPC Schema to use for the request store. */
126+
schema?: schema | RpcSchema.Generic | undefined
113127
}
114128

115-
type ReturnType<schema extends RpcSchema.Generic = RpcSchema.Default> =
129+
type ReturnType<schema extends RpcSchema.Generic | undefined = undefined> =
116130
Store<schema>
117131

118132
type ErrorType = Errors.GlobalErrorType

0 commit comments

Comments
 (0)