@nmtjs/client 0.15.3 → 0.16.0-beta.2

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 +65 -0
  2. package/dist/client.js +98 -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 +36 -83
  11. package/dist/core.js +315 -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 +564 -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 +218 -0
  42. package/src/clients/runtime.ts +93 -79
  43. package/src/clients/static.ts +46 -38
  44. package/src/core.ts +408 -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 +778 -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/type": "0.15.3",
24
- "@nmtjs/contract": "0.15.3",
25
- "@nmtjs/protocol": "0.15.3",
26
- "@nmtjs/common": "0.15.3"
23
+ "@nmtjs/contract": "0.16.0-beta.2",
24
+ "@nmtjs/type": "0.16.0-beta.2",
25
+ "@nmtjs/common": "0.16.0-beta.2",
26
+ "@nmtjs/protocol": "0.16.0-beta.2"
27
27
  },
28
28
  "devDependencies": {
29
- "@nmtjs/tests-integration": "0.15.3",
30
- "@nmtjs/type": "0.15.3",
31
- "@nmtjs/contract": "0.15.3",
32
- "@nmtjs/common": "0.15.3",
33
- "@nmtjs/protocol": "0.15.3"
29
+ "@nmtjs/tests-integration": "0.16.0-beta.2",
30
+ "@nmtjs/type": "0.16.0-beta.2",
31
+ "@nmtjs/contract": "0.16.0-beta.2",
32
+ "@nmtjs/common": "0.16.0-beta.2",
33
+ "@nmtjs/protocol": "0.16.0-beta.2"
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.3",
41
+ "version": "0.16.0-beta.2",
42
42
  "scripts": {
43
43
  "clean-build": "rm -rf ./dist"
44
44
  }
package/src/client.ts ADDED
@@ -0,0 +1,218 @@
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
+ autoConnect?: boolean
34
+ timeout?: number
35
+ plugins?: ClientPlugin[]
36
+ safe?: SafeCall
37
+ }
38
+
39
+ export type BaseClientOptions<
40
+ RouterContract extends TAnyRouterContract = TAnyRouterContract,
41
+ SafeCall extends boolean = false,
42
+ > = ClientOptions<RouterContract, SafeCall>
43
+
44
+ export interface ClientCallersFactory<
45
+ Routes extends AnyResolvedContractRouter,
46
+ SafeCall extends boolean,
47
+ > {
48
+ call: ClientCallers<Routes, SafeCall, false>
49
+ stream: ClientCallers<Routes, SafeCall, true>
50
+ }
51
+
52
+ type ClientRoutes<
53
+ RouterContract extends TAnyRouterContract,
54
+ InputTypeProvider extends TypeProvider,
55
+ OutputTypeProvider extends TypeProvider,
56
+ > = ResolveAPIRouterRoutes<
57
+ RouterContract,
58
+ InputTypeProvider,
59
+ OutputTypeProvider
60
+ >
61
+
62
+ export class Client<
63
+ TransportFactory extends ClientTransportFactory<
64
+ any,
65
+ any
66
+ > = ClientTransportFactory<any, any>,
67
+ RouterContract extends TAnyRouterContract = TAnyRouterContract,
68
+ SafeCall extends boolean = false,
69
+ InputTypeProvider extends TypeProvider = TypeProvider,
70
+ OutputTypeProvider extends TypeProvider = TypeProvider,
71
+ > {
72
+ _!: {
73
+ routes: ResolveAPIRouterRoutes<
74
+ RouterContract,
75
+ InputTypeProvider,
76
+ OutputTypeProvider
77
+ >
78
+ safe: SafeCall
79
+ }
80
+
81
+ readonly core: ClientCore
82
+ protected readonly rpcLayer: RpcLayerApi
83
+ protected readonly streamLayer: StreamLayerApi
84
+ protected readonly pingLayer: PingLayerApi
85
+ protected readonly transformer: BaseClientTransformer
86
+
87
+ readonly call: ClientCallers<
88
+ ClientRoutes<RouterContract, InputTypeProvider, OutputTypeProvider>,
89
+ SafeCall,
90
+ false
91
+ >
92
+ readonly stream: ClientCallers<
93
+ ClientRoutes<RouterContract, InputTypeProvider, OutputTypeProvider>,
94
+ SafeCall,
95
+ true
96
+ >
97
+
98
+ readonly on: ClientCore['on']
99
+ readonly once: ClientCore['once']
100
+ readonly off: ClientCore['off']
101
+
102
+ constructor(
103
+ readonly options: ClientOptions<RouterContract, SafeCall>,
104
+ readonly transportFactory: TransportFactory,
105
+ readonly transportOptions: TransportFactory extends ClientTransportFactory<
106
+ any,
107
+ infer Options
108
+ >
109
+ ? Options
110
+ : never,
111
+ transformer: BaseClientTransformer,
112
+ buildCallers: (rpc: RpcLayerApi) => { call: unknown; stream: unknown },
113
+ ) {
114
+ this.transformer = transformer
115
+
116
+ const transport = this.transportFactory(
117
+ { protocol: this.options.protocol, format: this.options.format },
118
+ this.transportOptions,
119
+ )
120
+
121
+ const coreOptions: ClientCoreOptions = {
122
+ protocol: this.options.protocol,
123
+ format: this.options.format,
124
+ application: this.options.application,
125
+ autoConnect: this.options.autoConnect,
126
+ }
127
+
128
+ this.core = new ClientCore(coreOptions, transport)
129
+ this.streamLayer = createStreamLayer(this.core)
130
+ this.rpcLayer = createRpcLayer(this.core, this.streamLayer, transformer, {
131
+ timeout: this.options.timeout,
132
+ safe: this.options.safe,
133
+ })
134
+ this.pingLayer = createPingLayer(this.core)
135
+
136
+ this.core.setMessageContextFactory(() => ({
137
+ encoder: this.core.format,
138
+ decoder: this.core.format,
139
+ transport: {
140
+ send: (buffer) => {
141
+ this.core.send(buffer).catch(noopFn)
142
+ },
143
+ },
144
+ streamId: () => this.streamLayer.getStreamId(),
145
+ addClientStream: (blob) => this.streamLayer.addClientStream(blob),
146
+ addServerStream: (streamId, metadata) =>
147
+ this.streamLayer.createServerBlobStream(streamId, metadata),
148
+ }))
149
+
150
+ this.core.initPlugins(this.options.plugins, {
151
+ core: this.core,
152
+ ping: this.pingLayer,
153
+ })
154
+
155
+ const callers = buildCallers(this.rpcLayer)
156
+ this.call = callers.call as ClientCallers<
157
+ ClientRoutes<RouterContract, InputTypeProvider, OutputTypeProvider>,
158
+ SafeCall,
159
+ false
160
+ >
161
+ this.stream = callers.stream as ClientCallers<
162
+ ClientRoutes<RouterContract, InputTypeProvider, OutputTypeProvider>,
163
+ SafeCall,
164
+ true
165
+ >
166
+
167
+ this.on = this.core.on.bind(this.core)
168
+ this.once = this.core.once.bind(this.core)
169
+ this.off = this.core.off.bind(this.core)
170
+ }
171
+
172
+ get state(): ConnectionState {
173
+ return this.core.state
174
+ }
175
+
176
+ get transportType() {
177
+ return this.core.transportType
178
+ }
179
+
180
+ get lastDisconnectReason() {
181
+ return this.core.lastDisconnectReason
182
+ }
183
+
184
+ get auth() {
185
+ return this.core.auth
186
+ }
187
+
188
+ set auth(value: any) {
189
+ this.core.auth = value
190
+ }
191
+
192
+ isDisposed() {
193
+ return this.core.isDisposed()
194
+ }
195
+
196
+ connect() {
197
+ return this.core.connect()
198
+ }
199
+
200
+ disconnect() {
201
+ return this.core.disconnect()
202
+ }
203
+
204
+ ping(timeout: number, signal?: AbortSignal) {
205
+ return this.pingLayer.ping(timeout, signal)
206
+ }
207
+
208
+ blob(
209
+ source: Blob | ReadableStream | string | AsyncIterable<Uint8Array>,
210
+ metadata?: ProtocolBlobMetadata,
211
+ ) {
212
+ return ProtocolBlob.from(source, metadata)
213
+ }
214
+
215
+ dispose() {
216
+ this.core.dispose()
217
+ }
218
+ }
@@ -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
  }