@nmtjs/client 0.15.2 → 0.16.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/client.d.ts +64 -0
  2. package/dist/client.js +97 -0
  3. package/dist/client.js.map +1 -0
  4. package/dist/clients/runtime.d.ts +6 -12
  5. package/dist/clients/runtime.js +58 -57
  6. package/dist/clients/runtime.js.map +1 -1
  7. package/dist/clients/static.d.ts +4 -9
  8. package/dist/clients/static.js +20 -20
  9. package/dist/clients/static.js.map +1 -1
  10. package/dist/core.d.ts +33 -83
  11. package/dist/core.js +305 -690
  12. package/dist/core.js.map +1 -1
  13. package/dist/events.d.ts +0 -1
  14. package/dist/events.js +74 -11
  15. package/dist/events.js.map +1 -1
  16. package/dist/index.d.ts +4 -0
  17. package/dist/index.js +4 -0
  18. package/dist/index.js.map +1 -1
  19. package/dist/layers/ping.d.ts +6 -0
  20. package/dist/layers/ping.js +65 -0
  21. package/dist/layers/ping.js.map +1 -0
  22. package/dist/layers/rpc.d.ts +19 -0
  23. package/dist/layers/rpc.js +521 -0
  24. package/dist/layers/rpc.js.map +1 -0
  25. package/dist/layers/streams.d.ts +20 -0
  26. package/dist/layers/streams.js +194 -0
  27. package/dist/layers/streams.js.map +1 -0
  28. package/dist/plugins/browser.js +28 -9
  29. package/dist/plugins/browser.js.map +1 -1
  30. package/dist/plugins/heartbeat.js +10 -10
  31. package/dist/plugins/heartbeat.js.map +1 -1
  32. package/dist/plugins/index.d.ts +1 -1
  33. package/dist/plugins/index.js +0 -1
  34. package/dist/plugins/index.js.map +1 -1
  35. package/dist/plugins/reconnect.js +11 -94
  36. package/dist/plugins/reconnect.js.map +1 -1
  37. package/dist/plugins/types.d.ts +27 -11
  38. package/dist/transport.d.ts +49 -31
  39. package/dist/types.d.ts +21 -5
  40. package/package.json +10 -10
  41. package/src/client.ts +216 -0
  42. package/src/clients/runtime.ts +93 -79
  43. package/src/clients/static.ts +46 -38
  44. package/src/core.ts +394 -901
  45. package/src/events.ts +113 -14
  46. package/src/index.ts +4 -0
  47. package/src/layers/ping.ts +99 -0
  48. package/src/layers/rpc.ts +725 -0
  49. package/src/layers/streams.ts +277 -0
  50. package/src/plugins/browser.ts +39 -9
  51. package/src/plugins/heartbeat.ts +10 -10
  52. package/src/plugins/index.ts +8 -1
  53. package/src/plugins/reconnect.ts +12 -119
  54. package/src/plugins/types.ts +30 -13
  55. package/src/transport.ts +75 -46
  56. package/src/types.ts +33 -8
package/dist/types.d.ts CHANGED
@@ -1,21 +1,28 @@
1
1
  import type { CallTypeProvider, OneOf, TypeProvider } from '@nmtjs/common';
2
2
  import type { TAnyProcedureContract, TAnyRouterContract } from '@nmtjs/contract';
3
3
  import type { ProtocolBlobInterface } from '@nmtjs/protocol';
4
- import type { ProtocolError, ProtocolServerBlobStream } from '@nmtjs/protocol/client';
4
+ import type { ProtocolError, ProtocolServerBlobConsumer } from '@nmtjs/protocol/client';
5
5
  import type { BaseTypeAny, PlainType, t } from '@nmtjs/type';
6
6
  export declare const ResolvedType: unique symbol;
7
7
  export type ResolvedType = typeof ResolvedType;
8
- export type ClientCallOptions = {
8
+ export type RpcCallOptions = {
9
9
  timeout?: number;
10
10
  signal?: AbortSignal;
11
+ };
12
+ export type StreamCallOptions = RpcCallOptions & {
13
+ autoReconnect?: boolean;
14
+ };
15
+ export type ClientCallOptions = StreamCallOptions & {
11
16
  /**
12
17
  * @internal
13
18
  */
14
19
  _stream_response?: boolean;
15
20
  };
16
- export type ClientOutputType<T> = T extends ProtocolBlobInterface ? (options?: {
21
+ export type BlobSubscriptionOptions = {
17
22
  signal?: AbortSignal;
18
- }) => ProtocolServerBlobStream : T extends {
23
+ };
24
+ export type StreamSubscriptionOptions = Partial<StreamCallOptions>;
25
+ export type ClientOutputType<T> = T extends ProtocolBlobInterface ? ProtocolServerBlobConsumer : T extends {
19
26
  [PlainType]?: true;
20
27
  } ? {
21
28
  [K in keyof Omit<T, PlainType>]: ClientOutputType<T[K]>;
@@ -55,7 +62,16 @@ export type ResolveAPIRouterRoutes<T extends TAnyRouterContract, InputTypeProvid
55
62
  } : T['routes'][K] extends TAnyRouterContract ? ResolveAPIRouterRoutes<T['routes'][K], InputTypeProvider, OutputTypeProvider> : never;
56
63
  };
57
64
  export type ResolveContract<C extends TAnyRouterContract = TAnyRouterContract, InputTypeProvider extends TypeProvider = TypeProvider, OutputTypeProvider extends TypeProvider = TypeProvider> = ResolveAPIRouterRoutes<C, InputTypeProvider, OutputTypeProvider>;
58
- export type ClientCaller<Procedure extends AnyResolvedContractProcedure, SafeCall extends boolean> = (...args: Procedure['input'] extends t.NeverType ? [data?: undefined, options?: Partial<ClientCallOptions>] : undefined extends t.infer.encode.input<Procedure['contract']['input']> ? [data?: Procedure['input'], options?: Partial<ClientCallOptions>] : [data: Procedure['input'], options?: Partial<ClientCallOptions>]) => SafeCall extends true ? Promise<OneOf<[{
65
+ export type ClientCaller<Procedure extends AnyResolvedContractProcedure, SafeCall extends boolean> = (...args: Procedure['input'] extends t.NeverType ? [
66
+ data?: undefined,
67
+ options?: Partial<Procedure['stream'] extends true ? StreamCallOptions : RpcCallOptions>
68
+ ] : undefined extends t.infer.encode.input<Procedure['contract']['input']> ? [
69
+ data?: Procedure['input'],
70
+ options?: Partial<Procedure['stream'] extends true ? StreamCallOptions : RpcCallOptions>
71
+ ] : [
72
+ data: Procedure['input'],
73
+ options?: Partial<Procedure['stream'] extends true ? StreamCallOptions : RpcCallOptions>
74
+ ]) => SafeCall extends true ? Promise<OneOf<[{
59
75
  result: Procedure['output'];
60
76
  }, {
61
77
  error: ProtocolError;
package/package.json CHANGED
@@ -20,17 +20,17 @@
20
20
  }
21
21
  },
22
22
  "peerDependencies": {
23
- "@nmtjs/contract": "0.15.2",
24
- "@nmtjs/type": "0.15.2",
25
- "@nmtjs/protocol": "0.15.2",
26
- "@nmtjs/common": "0.15.2"
23
+ "@nmtjs/type": "0.16.0-beta.1",
24
+ "@nmtjs/contract": "0.16.0-beta.1",
25
+ "@nmtjs/common": "0.16.0-beta.1",
26
+ "@nmtjs/protocol": "0.16.0-beta.1"
27
27
  },
28
28
  "devDependencies": {
29
- "@nmtjs/tests-integration": "0.15.2",
30
- "@nmtjs/type": "0.15.2",
31
- "@nmtjs/contract": "0.15.2",
32
- "@nmtjs/common": "0.15.2",
33
- "@nmtjs/protocol": "0.15.2"
29
+ "@nmtjs/tests-integration": "0.16.0-beta.1",
30
+ "@nmtjs/common": "0.16.0-beta.1",
31
+ "@nmtjs/type": "0.16.0-beta.1",
32
+ "@nmtjs/protocol": "0.16.0-beta.1",
33
+ "@nmtjs/contract": "0.16.0-beta.1"
34
34
  },
35
35
  "files": [
36
36
  "dist",
@@ -38,7 +38,7 @@
38
38
  "LICENSE.md",
39
39
  "README.md"
40
40
  ],
41
- "version": "0.15.2",
41
+ "version": "0.16.0-beta.1",
42
42
  "scripts": {
43
43
  "clean-build": "rm -rf ./dist"
44
44
  }
package/src/client.ts ADDED
@@ -0,0 +1,216 @@
1
+ import type { TypeProvider } from '@nmtjs/common'
2
+ import type { TAnyRouterContract } from '@nmtjs/contract'
3
+ import type { ProtocolBlobMetadata, ProtocolVersion } from '@nmtjs/protocol'
4
+ import type { BaseClientFormat } from '@nmtjs/protocol/client'
5
+ import { noopFn } from '@nmtjs/common'
6
+ import { ProtocolBlob } from '@nmtjs/protocol'
7
+
8
+ import type { ClientCoreOptions, ConnectionState } from './core.ts'
9
+ import type { PingLayerApi } from './layers/ping.ts'
10
+ import type { RpcLayerApi } from './layers/rpc.ts'
11
+ import type { StreamLayerApi } from './layers/streams.ts'
12
+ import type { ClientPlugin } from './plugins/types.ts'
13
+ import type { BaseClientTransformer } from './transformers.ts'
14
+ import type { ClientTransportFactory } from './transport.ts'
15
+ import type {
16
+ AnyResolvedContractRouter,
17
+ ClientCallers,
18
+ ResolveAPIRouterRoutes,
19
+ } from './types.ts'
20
+ import { ClientCore } from './core.ts'
21
+ import { createPingLayer } from './layers/ping.ts'
22
+ import { createRpcLayer } from './layers/rpc.ts'
23
+ import { createStreamLayer } from './layers/streams.ts'
24
+
25
+ export interface ClientOptions<
26
+ RouterContract extends TAnyRouterContract = TAnyRouterContract,
27
+ SafeCall extends boolean = false,
28
+ > {
29
+ contract: RouterContract
30
+ protocol: ProtocolVersion
31
+ format: BaseClientFormat
32
+ application?: string
33
+ timeout?: number
34
+ plugins?: ClientPlugin[]
35
+ safe?: SafeCall
36
+ }
37
+
38
+ export type BaseClientOptions<
39
+ RouterContract extends TAnyRouterContract = TAnyRouterContract,
40
+ SafeCall extends boolean = false,
41
+ > = ClientOptions<RouterContract, SafeCall>
42
+
43
+ export interface ClientCallersFactory<
44
+ Routes extends AnyResolvedContractRouter,
45
+ SafeCall extends boolean,
46
+ > {
47
+ call: ClientCallers<Routes, SafeCall, false>
48
+ stream: ClientCallers<Routes, SafeCall, true>
49
+ }
50
+
51
+ type ClientRoutes<
52
+ RouterContract extends TAnyRouterContract,
53
+ InputTypeProvider extends TypeProvider,
54
+ OutputTypeProvider extends TypeProvider,
55
+ > = ResolveAPIRouterRoutes<
56
+ RouterContract,
57
+ InputTypeProvider,
58
+ OutputTypeProvider
59
+ >
60
+
61
+ export class Client<
62
+ TransportFactory extends ClientTransportFactory<
63
+ any,
64
+ any
65
+ > = ClientTransportFactory<any, any>,
66
+ RouterContract extends TAnyRouterContract = TAnyRouterContract,
67
+ SafeCall extends boolean = false,
68
+ InputTypeProvider extends TypeProvider = TypeProvider,
69
+ OutputTypeProvider extends TypeProvider = TypeProvider,
70
+ > {
71
+ _!: {
72
+ routes: ResolveAPIRouterRoutes<
73
+ RouterContract,
74
+ InputTypeProvider,
75
+ OutputTypeProvider
76
+ >
77
+ safe: SafeCall
78
+ }
79
+
80
+ readonly core: ClientCore
81
+ protected readonly rpcLayer: RpcLayerApi
82
+ protected readonly streamLayer: StreamLayerApi
83
+ protected readonly pingLayer: PingLayerApi
84
+ protected readonly transformer: BaseClientTransformer
85
+
86
+ readonly call: ClientCallers<
87
+ ClientRoutes<RouterContract, InputTypeProvider, OutputTypeProvider>,
88
+ SafeCall,
89
+ false
90
+ >
91
+ readonly stream: ClientCallers<
92
+ ClientRoutes<RouterContract, InputTypeProvider, OutputTypeProvider>,
93
+ SafeCall,
94
+ true
95
+ >
96
+
97
+ readonly on: ClientCore['on']
98
+ readonly once: ClientCore['once']
99
+ readonly off: ClientCore['off']
100
+
101
+ constructor(
102
+ readonly options: ClientOptions<RouterContract, SafeCall>,
103
+ readonly transportFactory: TransportFactory,
104
+ readonly transportOptions: TransportFactory extends ClientTransportFactory<
105
+ any,
106
+ infer Options
107
+ >
108
+ ? Options
109
+ : never,
110
+ transformer: BaseClientTransformer,
111
+ buildCallers: (rpc: RpcLayerApi) => { call: unknown; stream: unknown },
112
+ ) {
113
+ this.transformer = transformer
114
+
115
+ const transport = this.transportFactory(
116
+ { protocol: this.options.protocol, format: this.options.format },
117
+ this.transportOptions,
118
+ )
119
+
120
+ const coreOptions: ClientCoreOptions = {
121
+ protocol: this.options.protocol,
122
+ format: this.options.format,
123
+ application: this.options.application,
124
+ }
125
+
126
+ this.core = new ClientCore(coreOptions, transport)
127
+ this.streamLayer = createStreamLayer(this.core)
128
+ this.rpcLayer = createRpcLayer(this.core, this.streamLayer, transformer, {
129
+ timeout: this.options.timeout,
130
+ safe: this.options.safe,
131
+ })
132
+ this.pingLayer = createPingLayer(this.core)
133
+
134
+ this.core.setMessageContextFactory(() => ({
135
+ encoder: this.core.format,
136
+ decoder: this.core.format,
137
+ transport: {
138
+ send: (buffer) => {
139
+ this.core.send(buffer).catch(noopFn)
140
+ },
141
+ },
142
+ streamId: () => this.streamLayer.getStreamId(),
143
+ addClientStream: (blob) => this.streamLayer.addClientStream(blob),
144
+ addServerStream: (streamId, metadata) =>
145
+ this.streamLayer.createServerBlobStream(streamId, metadata),
146
+ }))
147
+
148
+ this.core.initPlugins(this.options.plugins, {
149
+ core: this.core,
150
+ ping: this.pingLayer,
151
+ })
152
+
153
+ const callers = buildCallers(this.rpcLayer)
154
+ this.call = callers.call as ClientCallers<
155
+ ClientRoutes<RouterContract, InputTypeProvider, OutputTypeProvider>,
156
+ SafeCall,
157
+ false
158
+ >
159
+ this.stream = callers.stream as ClientCallers<
160
+ ClientRoutes<RouterContract, InputTypeProvider, OutputTypeProvider>,
161
+ SafeCall,
162
+ true
163
+ >
164
+
165
+ this.on = this.core.on.bind(this.core)
166
+ this.once = this.core.once.bind(this.core)
167
+ this.off = this.core.off.bind(this.core)
168
+ }
169
+
170
+ get state(): ConnectionState {
171
+ return this.core.state
172
+ }
173
+
174
+ get transportType() {
175
+ return this.core.transportType
176
+ }
177
+
178
+ get lastDisconnectReason() {
179
+ return this.core.lastDisconnectReason
180
+ }
181
+
182
+ get auth() {
183
+ return this.core.auth
184
+ }
185
+
186
+ set auth(value: any) {
187
+ this.core.auth = value
188
+ }
189
+
190
+ isDisposed() {
191
+ return this.core.isDisposed()
192
+ }
193
+
194
+ connect() {
195
+ return this.core.connect()
196
+ }
197
+
198
+ disconnect() {
199
+ return this.core.disconnect()
200
+ }
201
+
202
+ ping(timeout: number, signal?: AbortSignal) {
203
+ return this.pingLayer.ping(timeout, signal)
204
+ }
205
+
206
+ blob(
207
+ source: Blob | ReadableStream | string | AsyncIterable<Uint8Array>,
208
+ metadata?: ProtocolBlobMetadata,
209
+ ) {
210
+ return ProtocolBlob.from(source, metadata)
211
+ }
212
+
213
+ dispose() {
214
+ this.core.dispose()
215
+ }
216
+ }
@@ -5,44 +5,111 @@ import type {
5
5
  } from '@nmtjs/contract'
6
6
  import { IsProcedureContract, IsRouterContract } from '@nmtjs/contract'
7
7
 
8
- import type { BaseClientOptions } from '../core.ts'
8
+ import type { BaseClientOptions } from '../client.ts'
9
+ import type { RpcLayerApi } from '../layers/rpc.ts'
9
10
  import type { ClientTransportFactory } from '../transport.ts'
10
11
  import type {
11
- ClientCallers,
12
12
  ClientCallOptions,
13
13
  RuntimeInputContractTypeProvider,
14
14
  RuntimeOutputContractTypeProvider,
15
15
  } from '../types.ts'
16
- import { BaseClient } from '../core.ts'
16
+ import { Client } from '../client.ts'
17
17
 
18
18
  export class RuntimeContractTransformer {
19
19
  #procedures = new Map<string, TAnyProcedureContract>()
20
20
 
21
21
  constructor(router: TAnyRouterContract) {
22
- const registerProcedures = (r: TRouteContract, path: string[] = []) => {
23
- if (IsRouterContract(r)) {
24
- for (const [key, route] of Object.entries(r.routes)) {
25
- registerProcedures(route, [...path, key])
22
+ const registerProcedures = (route: TRouteContract, path: string[] = []) => {
23
+ if (IsRouterContract(route)) {
24
+ for (const [key, child] of Object.entries(route.routes)) {
25
+ registerProcedures(child, [...path, key])
26
26
  }
27
- } else if (IsProcedureContract(r)) {
28
- const fullName = [...path].join('/')
29
- this.#procedures.set(fullName, r)
27
+ return
28
+ }
29
+
30
+ if (IsProcedureContract(route)) {
31
+ this.#procedures.set(path.join('/'), route)
30
32
  }
31
33
  }
34
+
32
35
  registerProcedures(router)
33
36
  }
34
37
 
35
- encode(_procedure: string, payload: any) {
36
- const procedure = this.#procedures.get(_procedure)
37
- if (!procedure) throw new Error(`Procedure not found: ${_procedure}`)
38
- return procedure.input.encode(payload)
38
+ encode(procedure: string, payload: any) {
39
+ const contract = this.#procedures.get(procedure)
40
+ if (!contract) throw new Error(`Procedure not found: ${procedure}`)
41
+ return contract.input.encode(payload)
42
+ }
43
+
44
+ decode(procedure: string, payload: any) {
45
+ const contract = this.#procedures.get(procedure)
46
+ if (!contract) throw new Error(`Procedure not found: ${procedure}`)
47
+ return contract.output.decode(payload)
39
48
  }
49
+ }
50
+
51
+ const assignNested = (
52
+ root: Record<string, any>,
53
+ name: string,
54
+ value: unknown,
55
+ ) => {
56
+ const parts = name.split('/')
57
+ let current = root
58
+
59
+ for (let i = 0; i < parts.length; i++) {
60
+ const part = parts[i]
61
+ if (i === parts.length - 1) {
62
+ current[part] = value
63
+ } else {
64
+ current[part] = current[part] ?? Object.create(null)
65
+ current = current[part]
66
+ }
67
+ }
68
+ }
69
+
70
+ const buildRuntimeCallers = (
71
+ rpc: RpcLayerApi,
72
+ contract: TAnyRouterContract,
73
+ ) => {
74
+ const procedures = new Map<string, TAnyProcedureContract>()
75
+
76
+ const resolveProcedures = (
77
+ router: TAnyRouterContract,
78
+ path: string[] = [],
79
+ ) => {
80
+ for (const [key, route] of Object.entries(router.routes)) {
81
+ if (IsRouterContract(route)) {
82
+ resolveProcedures(route, [...path, key])
83
+ } else if (IsProcedureContract(route)) {
84
+ procedures.set([...path, key].join('/'), route)
85
+ }
86
+ }
87
+ }
88
+
89
+ resolveProcedures(contract)
90
+
91
+ const callers: Record<string, any> = Object.create(null)
92
+ const streams: Record<string, any> = Object.create(null)
93
+
94
+ for (const [name, procedure] of procedures) {
95
+ const invoke = (
96
+ payload?: unknown,
97
+ options?: Partial<ClientCallOptions>,
98
+ ) => {
99
+ return rpc.call(name, payload, {
100
+ ...options,
101
+ _stream_response: !!procedure.stream,
102
+ })
103
+ }
40
104
 
41
- decode(_procedure: string, payload: any) {
42
- const procedure = this.#procedures.get(_procedure)
43
- if (!procedure) throw new Error(`Procedure not found: ${_procedure}`)
44
- return procedure.output.decode(payload)
105
+ if (procedure.stream) {
106
+ assignNested(streams, name, invoke)
107
+ } else {
108
+ assignNested(callers, name, invoke)
109
+ }
45
110
  }
111
+
112
+ return { call: callers, stream: streams }
46
113
  }
47
114
 
48
115
  export class RuntimeClient<
@@ -52,18 +119,13 @@ export class RuntimeClient<
52
119
  >,
53
120
  RouterContract extends TAnyRouterContract = TAnyRouterContract,
54
121
  SafeCall extends boolean = false,
55
- > extends BaseClient<
122
+ > extends Client<
56
123
  Transport,
57
124
  RouterContract,
58
125
  SafeCall,
59
126
  RuntimeInputContractTypeProvider,
60
127
  RuntimeOutputContractTypeProvider
61
128
  > {
62
- protected readonly transformer: RuntimeContractTransformer
63
-
64
- readonly #procedures = new Map<string, TAnyProcedureContract>()
65
- readonly #callers!: ClientCallers<this['_']['routes'], SafeCall, boolean>
66
-
67
129
  constructor(
68
130
  options: BaseClientOptions<RouterContract, SafeCall>,
69
131
  transport: Transport,
@@ -74,60 +136,12 @@ export class RuntimeClient<
74
136
  ? Options
75
137
  : never,
76
138
  ) {
77
- super(options, transport, transportOptions)
78
-
79
- this.resolveProcedures(this.options.contract)
80
- this.transformer = new RuntimeContractTransformer(this.options.contract)
81
- this.#callers = this.buildCallers()
82
- }
83
-
84
- override get call(): ClientCallers<this['_']['routes'], SafeCall, false> {
85
- return this.#callers as any
86
- }
87
-
88
- override get stream(): ClientCallers<this['_']['routes'], SafeCall, true> {
89
- return this.#callers as any
90
- }
91
-
92
- protected resolveProcedures(router: TAnyRouterContract, path: string[] = []) {
93
- for (const [key, route] of Object.entries(router.routes)) {
94
- if (IsRouterContract(route)) {
95
- this.resolveProcedures(route, [...path, key])
96
- } else if (IsProcedureContract(route)) {
97
- const fullName = [...path, key].join('/')
98
- this.#procedures.set(fullName, route)
99
- }
100
- }
101
- }
102
-
103
- protected buildCallers(): ClientCallers<
104
- this['_']['routes'],
105
- SafeCall,
106
- boolean
107
- > {
108
- const callers: Record<string, any> = Object.create(null)
109
-
110
- for (const [name, { stream }] of this.#procedures) {
111
- const parts = name.split('/')
112
- let current = callers
113
- for (let i = 0; i < parts.length; i++) {
114
- const part = parts[i]
115
- if (i === parts.length - 1) {
116
- current[part] = (
117
- payload?: unknown,
118
- options?: Partial<ClientCallOptions>,
119
- ) =>
120
- this._call(name, payload, {
121
- ...options,
122
- _stream_response: !!stream,
123
- })
124
- } else {
125
- current[part] = current[part] ?? Object.create(null)
126
- current = current[part]
127
- }
128
- }
129
- }
130
-
131
- return callers as ClientCallers<this['_']['routes'], SafeCall, boolean>
139
+ super(
140
+ options,
141
+ transport,
142
+ transportOptions,
143
+ new RuntimeContractTransformer(options.contract),
144
+ (rpc) => buildRuntimeCallers(rpc, options.contract),
145
+ )
132
146
  }
133
147
  }
@@ -1,16 +1,48 @@
1
1
  import type { TAnyRouterContract } from '@nmtjs/contract'
2
2
 
3
- import type { BaseClientOptions } from '../core.ts'
3
+ import type { BaseClientOptions } from '../client.ts'
4
+ import type { RpcLayerApi } from '../layers/rpc.ts'
4
5
  import type { ClientTransportFactory } from '../transport.ts'
5
6
  import type {
6
- ClientCallers,
7
7
  ClientCallOptions,
8
8
  StaticInputContractTypeProvider,
9
9
  StaticOutputContractTypeProvider,
10
10
  } from '../types.ts'
11
- import { BaseClient } from '../core.ts'
11
+ import { Client } from '../client.ts'
12
12
  import { BaseClientTransformer } from '../transformers.ts'
13
13
 
14
+ const buildStaticCallers = (
15
+ rpc: RpcLayerApi,
16
+ isStream: boolean,
17
+ path: string[] = [],
18
+ ): Record<string, unknown> => {
19
+ const createProxy = <T>(
20
+ target: Record<string, unknown>,
21
+ current: string[],
22
+ ) => {
23
+ return new Proxy(target, {
24
+ get: (obj, prop) => {
25
+ if (prop === 'then') return obj
26
+
27
+ const nextPath = [...current, String(prop)]
28
+ const caller = (
29
+ payload?: unknown,
30
+ options?: Partial<ClientCallOptions>,
31
+ ) => {
32
+ return rpc.call(nextPath.join('/'), payload, {
33
+ ...options,
34
+ _stream_response: isStream || options?._stream_response,
35
+ })
36
+ }
37
+
38
+ return createProxy(caller as any, nextPath)
39
+ },
40
+ }) as T
41
+ }
42
+
43
+ return createProxy(Object.create(null), path)
44
+ }
45
+
14
46
  export class StaticClient<
15
47
  Transport extends ClientTransportFactory<any, any> = ClientTransportFactory<
16
48
  any,
@@ -18,15 +50,13 @@ export class StaticClient<
18
50
  >,
19
51
  RouterContract extends TAnyRouterContract = TAnyRouterContract,
20
52
  SafeCall extends boolean = false,
21
- > extends BaseClient<
53
+ > extends Client<
22
54
  Transport,
23
55
  RouterContract,
24
56
  SafeCall,
25
57
  StaticInputContractTypeProvider,
26
58
  StaticOutputContractTypeProvider
27
59
  > {
28
- protected readonly transformer: BaseClientTransformer
29
-
30
60
  constructor(
31
61
  options: BaseClientOptions<RouterContract, SafeCall>,
32
62
  transport: Transport,
@@ -37,37 +67,15 @@ export class StaticClient<
37
67
  ? Options
38
68
  : never,
39
69
  ) {
40
- super(options, transport, transportOptions)
41
- this.transformer = new BaseClientTransformer()
42
- }
43
-
44
- override get call(): ClientCallers<this['_']['routes'], SafeCall, false> {
45
- return this.createProxy(Object.create(null), false)
46
- }
47
-
48
- override get stream(): ClientCallers<this['_']['routes'], SafeCall, true> {
49
- return this.createProxy(Object.create(null), true)
50
- }
51
-
52
- protected createProxy<T>(
53
- target: Record<string, unknown>,
54
- isStream: boolean,
55
- path: string[] = [],
56
- ) {
57
- return new Proxy(target, {
58
- get: (obj, prop) => {
59
- if (prop === 'then') return obj
60
- const newPath = [...path, String(prop)]
61
- const caller = (
62
- payload?: unknown,
63
- options?: Partial<ClientCallOptions>,
64
- ) =>
65
- this._call(newPath.join('/'), payload, {
66
- ...options,
67
- _stream_response: isStream || options?._stream_response,
68
- })
69
- return this.createProxy(caller as any, isStream, newPath)
70
- },
71
- }) as T
70
+ super(
71
+ options,
72
+ transport,
73
+ transportOptions,
74
+ new BaseClientTransformer(),
75
+ (rpc) => ({
76
+ call: buildStaticCallers(rpc, false),
77
+ stream: buildStaticCallers(rpc, true),
78
+ }),
79
+ )
72
80
  }
73
81
  }