@nmtjs/client 0.15.0-beta.2 → 0.15.0-beta.20

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.
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export * from './core.ts'
2
+ export * from './events.ts'
3
+ export * from './transformers.ts'
4
+ export * from './transport.ts'
5
+ export * from './types.ts'
package/src/streams.ts ADDED
@@ -0,0 +1,131 @@
1
+ import type { ProtocolBlobMetadata } from '@nmtjs/protocol'
2
+ import type { ProtocolServerStreamInterface } from '@nmtjs/protocol/client'
3
+ import { ProtocolClientBlobStream } from '@nmtjs/protocol/client'
4
+
5
+ export class ClientStreams {
6
+ readonly #collection = new Map<number, ProtocolClientBlobStream>()
7
+
8
+ get size() {
9
+ return this.#collection.size
10
+ }
11
+
12
+ get(streamId: number) {
13
+ const stream = this.#collection.get(streamId)
14
+ if (!stream) throw new Error('Stream not found')
15
+ return stream
16
+ }
17
+
18
+ add(
19
+ source: ReadableStream,
20
+ streamId: number,
21
+ metadata: ProtocolBlobMetadata,
22
+ ) {
23
+ const stream = new ProtocolClientBlobStream(source, streamId, metadata)
24
+ this.#collection.set(streamId, stream)
25
+ return stream
26
+ }
27
+
28
+ remove(streamId: number) {
29
+ this.#collection.delete(streamId)
30
+ }
31
+
32
+ async abort(streamId: number, reason?: string) {
33
+ const stream = this.#collection.get(streamId)
34
+ if (!stream) return // Stream already cleaned up
35
+ await stream.abort(reason)
36
+ this.remove(streamId)
37
+ }
38
+
39
+ pull(streamId: number, size: number) {
40
+ const stream = this.get(streamId)
41
+ return stream.read(size)
42
+ }
43
+
44
+ async end(streamId: number) {
45
+ await this.get(streamId).end()
46
+ this.remove(streamId)
47
+ }
48
+
49
+ async clear(reason?: string) {
50
+ if (reason) {
51
+ const abortPromises = [...this.#collection.values()].map((stream) =>
52
+ stream.abort(reason),
53
+ )
54
+ await Promise.all(abortPromises)
55
+ }
56
+ this.#collection.clear()
57
+ }
58
+ }
59
+
60
+ export class ServerStreams<
61
+ T extends ProtocolServerStreamInterface = ProtocolServerStreamInterface,
62
+ > {
63
+ readonly #collection = new Map<number, T>()
64
+ readonly #writers = new Map<number, WritableStreamDefaultWriter>()
65
+
66
+ get size() {
67
+ return this.#collection.size
68
+ }
69
+
70
+ has(streamId: number) {
71
+ return this.#collection.has(streamId)
72
+ }
73
+
74
+ get(streamId: number) {
75
+ const stream = this.#collection.get(streamId)
76
+ if (!stream) throw new Error('Stream not found')
77
+ return stream
78
+ }
79
+
80
+ add(streamId: number, stream: T) {
81
+ this.#collection.set(streamId, stream)
82
+ this.#writers.set(
83
+ streamId,
84
+ stream.writable.getWriter() as WritableStreamDefaultWriter,
85
+ )
86
+ return stream
87
+ }
88
+
89
+ remove(streamId: number) {
90
+ this.#collection.delete(streamId)
91
+ this.#writers.delete(streamId)
92
+ }
93
+
94
+ async abort(streamId: number) {
95
+ if (this.has(streamId)) {
96
+ const writer = this.#writers.get(streamId)
97
+ if (writer) {
98
+ await writer.abort()
99
+ writer.releaseLock()
100
+ }
101
+ this.remove(streamId)
102
+ }
103
+ }
104
+
105
+ async push(streamId: number, chunk: ArrayBufferView) {
106
+ const writer = this.#writers.get(streamId)
107
+ if (writer) {
108
+ return await writer.write(chunk)
109
+ }
110
+ }
111
+
112
+ async end(streamId: number) {
113
+ const writer = this.#writers.get(streamId)
114
+ if (writer) {
115
+ await writer.close()
116
+ writer.releaseLock()
117
+ }
118
+ this.remove(streamId)
119
+ }
120
+
121
+ async clear(reason?: string) {
122
+ if (reason) {
123
+ const abortPromises = [...this.#writers.values()].map((writer) =>
124
+ writer.abort(reason).finally(() => writer.releaseLock()),
125
+ )
126
+ await Promise.allSettled(abortPromises)
127
+ }
128
+ this.#collection.clear()
129
+ this.#writers.clear()
130
+ }
131
+ }
@@ -0,0 +1,8 @@
1
+ export class BaseClientTransformer {
2
+ encode(_procedure: string, payload: any) {
3
+ return payload
4
+ }
5
+ decode(_procedure: string, payload: any) {
6
+ return payload
7
+ }
8
+ }
@@ -0,0 +1,71 @@
1
+ import type {
2
+ ConnectionType,
3
+ ProtocolBlobMetadata,
4
+ ProtocolVersion,
5
+ } from '@nmtjs/protocol'
6
+ import type { BaseClientFormat } from '@nmtjs/protocol/client'
7
+
8
+ export type ClientTransportMessageOptions = {
9
+ signal?: AbortSignal
10
+ _stream_response?: boolean
11
+ }
12
+
13
+ export interface ClientTransportStartParams {
14
+ auth?: string
15
+ application?: string
16
+ onMessage: (message: ArrayBufferView) => any
17
+ onConnect: () => any
18
+ onDisconnect: (reason: 'client' | 'server' | (string & {})) => any
19
+ }
20
+
21
+ export interface ClientTransportRpcParams {
22
+ format: BaseClientFormat
23
+ auth?: string
24
+ application?: string
25
+ }
26
+
27
+ export type ClientCallResponse =
28
+ | { type: 'rpc'; result: ArrayBufferView }
29
+ | { type: 'rpc_stream'; stream: ReadableStream<ArrayBufferView> }
30
+ | {
31
+ type: 'blob'
32
+ metadata: ProtocolBlobMetadata
33
+ source: ReadableStream<ArrayBufferView>
34
+ }
35
+
36
+ export type ClientTransport<T extends ConnectionType = ConnectionType> =
37
+ T extends ConnectionType.Bidirectional
38
+ ? {
39
+ type: ConnectionType.Bidirectional
40
+ connect(params: ClientTransportStartParams): Promise<void>
41
+ disconnect(): Promise<void>
42
+ send(
43
+ message: ArrayBufferView,
44
+ options: ClientTransportMessageOptions,
45
+ ): Promise<void>
46
+ }
47
+ : {
48
+ type: ConnectionType.Unidirectional
49
+ connect?(params: ClientTransportStartParams): Promise<void>
50
+ disconnect?(): Promise<void>
51
+ call(
52
+ client: {
53
+ format: BaseClientFormat
54
+ auth?: string
55
+ application?: string
56
+ },
57
+ rpc: { callId: number; procedure: string; payload: any },
58
+ options: ClientTransportMessageOptions,
59
+ ): Promise<ClientCallResponse>
60
+ }
61
+
62
+ export interface ClientTransportParams {
63
+ protocol: ProtocolVersion
64
+ format: BaseClientFormat
65
+ }
66
+
67
+ export type ClientTransportFactory<
68
+ Type extends ConnectionType,
69
+ Options = unknown,
70
+ Transport extends ClientTransport<Type> = ClientTransport<Type>,
71
+ > = (params: ClientTransportParams, options: Options) => Transport
package/src/types.ts ADDED
@@ -0,0 +1,129 @@
1
+ import type { CallTypeProvider, OneOf, TypeProvider } from '@nmtjs/common'
2
+ import type { TAnyProcedureContract, TAnyRouterContract } from '@nmtjs/contract'
3
+ import type { ProtocolBlobInterface } from '@nmtjs/protocol'
4
+ import type {
5
+ ProtocolError,
6
+ ProtocolServerBlobStream,
7
+ } from '@nmtjs/protocol/client'
8
+ import type { BaseTypeAny, PlainType, t } from '@nmtjs/type'
9
+
10
+ export const ResolvedType: unique symbol = Symbol('ResolvedType')
11
+ export type ResolvedType = typeof ResolvedType
12
+
13
+ export type ClientCallOptions = {
14
+ timeout?: number
15
+ signal?: AbortSignal
16
+ /**
17
+ * @internal
18
+ */
19
+ _stream_response?: boolean
20
+ }
21
+
22
+ export type ClientOutputType<T> = T extends ProtocolBlobInterface
23
+ ? (options?: { signal?: AbortSignal }) => ProtocolServerBlobStream
24
+ : T extends { [PlainType]?: true }
25
+ ? { [K in keyof Omit<T, PlainType>]: ClientOutputType<T[K]> }
26
+ : T
27
+
28
+ export interface StaticInputContractTypeProvider extends TypeProvider {
29
+ output: this['input'] extends BaseTypeAny
30
+ ? t.infer.decode.input<this['input']>
31
+ : never
32
+ }
33
+
34
+ export interface RuntimeInputContractTypeProvider extends TypeProvider {
35
+ output: this['input'] extends BaseTypeAny
36
+ ? t.infer.encode.input<this['input']>
37
+ : never
38
+ }
39
+
40
+ export interface StaticOutputContractTypeProvider extends TypeProvider {
41
+ output: this['input'] extends BaseTypeAny
42
+ ? ClientOutputType<t.infer.encodeRaw.output<this['input']>>
43
+ : never
44
+ }
45
+
46
+ export interface RuntimeOutputContractTypeProvider extends TypeProvider {
47
+ output: this['input'] extends BaseTypeAny
48
+ ? ClientOutputType<t.infer.decodeRaw.output<this['input']>>
49
+ : never
50
+ }
51
+
52
+ export type AnyResolvedContractProcedure = {
53
+ [ResolvedType]: 'procedure'
54
+ contract: TAnyProcedureContract
55
+ stream: boolean
56
+ input: any
57
+ output: any
58
+ }
59
+
60
+ export type AnyResolvedContractRouter = {
61
+ [ResolvedType]: 'router'
62
+ [key: string]: AnyResolvedContractProcedure | AnyResolvedContractRouter
63
+ }
64
+
65
+ export type ResolveAPIRouterRoutes<
66
+ T extends TAnyRouterContract,
67
+ InputTypeProvider extends TypeProvider = TypeProvider,
68
+ OutputTypeProvider extends TypeProvider = TypeProvider,
69
+ > = { [ResolvedType]: 'router' } & {
70
+ [K in keyof T['routes']]: T['routes'][K] extends TAnyProcedureContract
71
+ ? {
72
+ [ResolvedType]: 'procedure'
73
+ contract: T['routes'][K]
74
+ stream: T['routes'][K]['stream'] extends true ? true : false
75
+ input: CallTypeProvider<InputTypeProvider, T['routes'][K]['input']>
76
+ output: T['routes'][K]['stream'] extends true
77
+ ? AsyncIterable<
78
+ CallTypeProvider<OutputTypeProvider, T['routes'][K]['output']>
79
+ >
80
+ : CallTypeProvider<OutputTypeProvider, T['routes'][K]['output']>
81
+ }
82
+ : T['routes'][K] extends TAnyRouterContract
83
+ ? ResolveAPIRouterRoutes<
84
+ T['routes'][K],
85
+ InputTypeProvider,
86
+ OutputTypeProvider
87
+ >
88
+ : never
89
+ }
90
+
91
+ export type ResolveContract<
92
+ C extends TAnyRouterContract = TAnyRouterContract,
93
+ InputTypeProvider extends TypeProvider = TypeProvider,
94
+ OutputTypeProvider extends TypeProvider = TypeProvider,
95
+ > = ResolveAPIRouterRoutes<C, InputTypeProvider, OutputTypeProvider>
96
+
97
+ export type ClientCaller<
98
+ Procedure extends AnyResolvedContractProcedure,
99
+ SafeCall extends boolean,
100
+ > = (
101
+ ...args: Procedure['input'] extends t.NeverType
102
+ ? [data?: undefined, options?: Partial<ClientCallOptions>]
103
+ : undefined extends t.infer.encode.input<Procedure['contract']['input']>
104
+ ? [data?: Procedure['input'], options?: Partial<ClientCallOptions>]
105
+ : [data: Procedure['input'], options?: Partial<ClientCallOptions>]
106
+ ) => SafeCall extends true
107
+ ? Promise<OneOf<[{ result: Procedure['output'] }, { error: ProtocolError }]>>
108
+ : Promise<Procedure['output']>
109
+
110
+ type OmitType<T extends object, E> = {
111
+ [K in keyof T as T[K] extends E ? never : K]: T[K]
112
+ }
113
+
114
+ export type ClientCallers<
115
+ Resolved extends AnyResolvedContractRouter,
116
+ SafeCall extends boolean,
117
+ Stream extends boolean,
118
+ > = OmitType<
119
+ {
120
+ [K in keyof Resolved]: Resolved[K] extends AnyResolvedContractProcedure
121
+ ? Stream extends (Resolved[K]['stream'] extends true ? true : false)
122
+ ? ClientCaller<Resolved[K], SafeCall>
123
+ : never
124
+ : Resolved[K] extends AnyResolvedContractRouter
125
+ ? ClientCallers<Resolved[K], SafeCall, Stream>
126
+ : never
127
+ },
128
+ never
129
+ >