@nmtjs/client 0.16.0-beta.1 → 0.16.0-beta.10

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.
@@ -1,10 +1,16 @@
1
- import type { ProtocolBlob, ProtocolBlobMetadata } from '@nmtjs/protocol'
2
1
  import type {
3
- ProtocolClientBlobStream,
4
- ProtocolServerBlobConsumer,
5
- } from '@nmtjs/protocol/client'
2
+ ProtocolBlob,
3
+ ProtocolBlobInterface,
4
+ ProtocolBlobMetadata,
5
+ } from '@nmtjs/protocol'
6
+ import type { ProtocolClientBlobStream } from '@nmtjs/protocol/client'
6
7
  import { MAX_UINT32, noopFn } from '@nmtjs/common'
7
- import { ClientMessageType, kBlobKey, ServerMessageType } from '@nmtjs/protocol'
8
+ import {
9
+ ClientMessageType,
10
+ createProtocolBlobReference,
11
+ getProtocolBlobStreamId,
12
+ ServerMessageType,
13
+ } from '@nmtjs/protocol'
8
14
  import { ProtocolServerBlobStream } from '@nmtjs/protocol/client'
9
15
 
10
16
  import type { ClientCore } from '../core.ts'
@@ -23,44 +29,36 @@ export interface StreamLayerApi {
23
29
  readonly serverStreams: ServerStreams
24
30
  getStreamId: () => number
25
31
  addClientStream: (blob: ProtocolBlob) => ProtocolClientBlobStream
26
- createServerBlobStream: (
32
+ createServerBlob: (
27
33
  streamId: number,
28
34
  metadata: ProtocolBlobMetadata,
29
- ) => ProtocolServerBlobConsumer
30
- addServerBlobStream: (metadata: ProtocolBlobMetadata) => {
35
+ ) => ProtocolBlobInterface
36
+ addServerBlobStream: (
37
+ metadata: ProtocolBlobMetadata,
38
+ options?: {
39
+ start?: (
40
+ stream: ProtocolServerBlobStream,
41
+ options?: { signal?: AbortSignal },
42
+ ) => void
43
+ },
44
+ ) => {
45
+ blob: ProtocolBlobInterface
31
46
  streamId: number
32
47
  stream: ProtocolServerBlobStream
33
48
  }
34
- }
35
-
36
- export const createServerBlobConsumer = (
37
- metadata: ProtocolBlobMetadata,
38
- subscribe: (options?: { signal?: AbortSignal }) => ProtocolServerBlobStream,
39
- ): ProtocolServerBlobConsumer => {
40
- const consumer = ((options?: { signal?: AbortSignal }) =>
41
- subscribe(options)) as ProtocolServerBlobConsumer
42
-
43
- Object.defineProperties(consumer, {
44
- metadata: {
45
- configurable: false,
46
- enumerable: true,
47
- writable: false,
48
- value: metadata,
49
- },
50
- [kBlobKey]: {
51
- configurable: false,
52
- enumerable: false,
53
- writable: false,
54
- value: true,
55
- },
56
- })
57
-
58
- return consumer
49
+ consumeServerBlob: (
50
+ blob: ProtocolBlobInterface,
51
+ options?: { signal?: AbortSignal },
52
+ ) => ProtocolServerBlobStream
59
53
  }
60
54
 
61
55
  export const createStreamLayer = (core: ClientCore): StreamLayerApi => {
62
56
  const clientStreams = new ClientStreams()
63
- const serverStreams = new ServerStreams()
57
+ const serverStreams = new ServerStreams<ProtocolServerBlobStream>()
58
+ const serverBlobInitializers = new Map<
59
+ number,
60
+ (options?: { signal?: AbortSignal }) => void
61
+ >()
64
62
 
65
63
  let streamId = 0
66
64
 
@@ -77,10 +75,29 @@ export const createStreamLayer = (core: ClientCore): StreamLayerApi => {
77
75
  return clientStreams.add(blob.source, id, blob.metadata)
78
76
  }
79
77
 
80
- const createServerBlobStream = (
81
- id: number,
82
- metadata: ProtocolBlobMetadata,
83
- ) => {
78
+ const abortServerBlob = (streamId: number, reason?: unknown) => {
79
+ if (core.messageContext) {
80
+ core.emitStreamEvent({
81
+ direction: 'outgoing',
82
+ streamType: 'server_blob',
83
+ action: 'abort',
84
+ streamId,
85
+ reason: toReasonString(reason),
86
+ })
87
+
88
+ const buffer = core.protocol.encodeMessage(
89
+ core.messageContext,
90
+ ClientMessageType.ServerStreamAbort,
91
+ { streamId, reason: toReasonString(reason) },
92
+ )
93
+
94
+ core.send(buffer).catch(noopFn)
95
+ }
96
+
97
+ void serverStreams.abort(streamId).catch(noopFn)
98
+ }
99
+
100
+ const createServerBlob = (id: number, metadata: ProtocolBlobMetadata) => {
84
101
  const stream = new ProtocolServerBlobStream(metadata, {
85
102
  pull: () => {
86
103
  if (!core.messageContext) return
@@ -102,6 +119,7 @@ export const createStreamLayer = (core: ClientCore): StreamLayerApi => {
102
119
  core.send(buffer).catch(noopFn)
103
120
  },
104
121
  close: () => {
122
+ serverBlobInitializers.delete(id)
105
123
  serverStreams.remove(id)
106
124
  },
107
125
  readableStrategy: { highWaterMark: 0 },
@@ -109,43 +127,64 @@ export const createStreamLayer = (core: ClientCore): StreamLayerApi => {
109
127
 
110
128
  serverStreams.add(id, stream)
111
129
 
112
- return createServerBlobConsumer(metadata, ({ signal } = {}) => {
113
- if (signal) {
114
- signal.addEventListener(
115
- 'abort',
116
- () => {
117
- if (!core.messageContext) return
130
+ return createProtocolBlobReference(id, metadata)
131
+ }
118
132
 
119
- core.emitStreamEvent({
120
- direction: 'outgoing',
121
- streamType: 'server_blob',
122
- action: 'abort',
123
- streamId: id,
124
- reason: toReasonString(signal.reason),
125
- })
133
+ const addServerBlobStream = (
134
+ metadata: ProtocolBlobMetadata,
135
+ options?: {
136
+ start?: (
137
+ stream: ProtocolServerBlobStream,
138
+ options?: { signal?: AbortSignal },
139
+ ) => void
140
+ },
141
+ ) => {
142
+ const id = getStreamId()
143
+ const stream = new ProtocolServerBlobStream(metadata)
144
+ serverStreams.add(id, stream)
126
145
 
127
- const buffer = core.protocol.encodeMessage(
128
- core.messageContext,
129
- ClientMessageType.ServerStreamAbort,
130
- { streamId: id, reason: toReasonString(signal.reason) },
131
- )
146
+ if (options?.start) {
147
+ let started = false
148
+ serverBlobInitializers.set(id, (subscriptionOptions) => {
149
+ if (started) return
150
+ started = true
151
+ options.start?.(stream, subscriptionOptions)
152
+ })
153
+ }
132
154
 
133
- core.send(buffer).catch(noopFn)
134
- void serverStreams.abort(id).catch(noopFn)
135
- },
136
- { once: true },
137
- )
138
- }
155
+ return {
156
+ blob: createProtocolBlobReference(id, metadata),
157
+ streamId: id,
158
+ stream,
159
+ }
160
+ }
161
+
162
+ const consumeServerBlob = (
163
+ blob: ProtocolBlobInterface,
164
+ options?: { signal?: AbortSignal },
165
+ ) => {
166
+ const id = getProtocolBlobStreamId(blob)
167
+ const stream = serverStreams.get(id)
139
168
 
169
+ if (options?.signal?.aborted) {
170
+ abortServerBlob(id, options.signal.reason)
140
171
  return stream
141
- })
142
- }
172
+ }
143
173
 
144
- const addServerBlobStream = (metadata: ProtocolBlobMetadata) => {
145
- const id = getStreamId()
146
- const stream = new ProtocolServerBlobStream(metadata)
147
- serverStreams.add(id, stream)
148
- return { streamId: id, stream }
174
+ if (options?.signal) {
175
+ options.signal.addEventListener(
176
+ 'abort',
177
+ () => {
178
+ abortServerBlob(id, options.signal?.reason)
179
+ },
180
+ { once: true },
181
+ )
182
+ }
183
+
184
+ serverBlobInitializers.get(id)?.(options)
185
+ serverBlobInitializers.delete(id)
186
+
187
+ return stream
149
188
  }
150
189
 
151
190
  core.on('message', (message: any) => {
@@ -161,6 +200,7 @@ export const createStreamLayer = (core: ClientCore): StreamLayerApi => {
161
200
  void serverStreams.push(message.streamId, message.chunk)
162
201
  break
163
202
  case ServerMessageType.ServerStreamEnd:
203
+ serverBlobInitializers.delete(message.streamId)
164
204
  core.emitStreamEvent({
165
205
  direction: 'incoming',
166
206
  streamType: 'server_blob',
@@ -170,6 +210,7 @@ export const createStreamLayer = (core: ClientCore): StreamLayerApi => {
170
210
  void serverStreams.end(message.streamId)
171
211
  break
172
212
  case ServerMessageType.ServerStreamAbort:
213
+ serverBlobInitializers.delete(message.streamId)
173
214
  core.emitStreamEvent({
174
215
  direction: 'incoming',
175
216
  streamType: 'server_blob',
@@ -264,6 +305,7 @@ export const createStreamLayer = (core: ClientCore): StreamLayerApi => {
264
305
  core.on('disconnected', (reason) => {
265
306
  void clientStreams.clear(reason).catch(noopFn)
266
307
  void serverStreams.clear(reason).catch(noopFn)
308
+ serverBlobInitializers.clear()
267
309
  })
268
310
 
269
311
  return {
@@ -271,7 +313,8 @@ export const createStreamLayer = (core: ClientCore): StreamLayerApi => {
271
313
  serverStreams,
272
314
  getStreamId,
273
315
  addClientStream,
274
- createServerBlobStream,
316
+ createServerBlob,
275
317
  addServerBlobStream,
318
+ consumeServerBlob,
276
319
  }
277
320
  }
package/src/types.ts CHANGED
@@ -1,11 +1,7 @@
1
1
  import type { CallTypeProvider, OneOf, TypeProvider } from '@nmtjs/common'
2
2
  import type { TAnyProcedureContract, TAnyRouterContract } from '@nmtjs/contract'
3
- import type { ProtocolBlobInterface } from '@nmtjs/protocol'
4
- import type {
5
- ProtocolError,
6
- ProtocolServerBlobConsumer,
7
- } from '@nmtjs/protocol/client'
8
- import type { BaseTypeAny, PlainType, t } from '@nmtjs/type'
3
+ import type { ProtocolError } from '@nmtjs/protocol/client'
4
+ import type { BaseTypeAny, t } from '@nmtjs/type'
9
5
 
10
6
  export const ResolvedType: unique symbol = Symbol('ResolvedType')
11
7
  export type ResolvedType = typeof ResolvedType
@@ -25,12 +21,6 @@ export type BlobSubscriptionOptions = { signal?: AbortSignal }
25
21
 
26
22
  export type StreamSubscriptionOptions = Partial<StreamCallOptions>
27
23
 
28
- export type ClientOutputType<T> = T extends ProtocolBlobInterface
29
- ? ProtocolServerBlobConsumer
30
- : T extends { [PlainType]?: true }
31
- ? { [K in keyof Omit<T, PlainType>]: ClientOutputType<T[K]> }
32
- : T
33
-
34
24
  export interface StaticInputContractTypeProvider extends TypeProvider {
35
25
  output: this['input'] extends BaseTypeAny
36
26
  ? t.infer.decode.input<this['input']>
@@ -45,13 +35,13 @@ export interface RuntimeInputContractTypeProvider extends TypeProvider {
45
35
 
46
36
  export interface StaticOutputContractTypeProvider extends TypeProvider {
47
37
  output: this['input'] extends BaseTypeAny
48
- ? ClientOutputType<t.infer.encodeRaw.output<this['input']>>
38
+ ? t.infer.encode.output<this['input']>
49
39
  : never
50
40
  }
51
41
 
52
42
  export interface RuntimeOutputContractTypeProvider extends TypeProvider {
53
43
  output: this['input'] extends BaseTypeAny
54
- ? ClientOutputType<t.infer.decodeRaw.output<this['input']>>
44
+ ? t.infer.decode.output<this['input']>
55
45
  : never
56
46
  }
57
47