@nmtjs/protocol 0.6.0 → 0.6.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.
- package/dist/client/events.js +3 -16
- package/dist/client/events.js.map +1 -1
- package/dist/client/protocol.js +68 -57
- package/dist/client/protocol.js.map +1 -1
- package/dist/client/stream.js +2 -3
- package/dist/client/stream.js.map +1 -1
- package/dist/server/api.js.map +1 -1
- package/dist/server/connection.js +1 -0
- package/dist/server/connection.js.map +1 -1
- package/dist/server/protocol.js +26 -8
- package/dist/server/protocol.js.map +1 -1
- package/lib/client/events.ts +4 -16
- package/lib/client/protocol.ts +108 -68
- package/lib/client/stream.ts +12 -5
- package/lib/server/api.ts +1 -2
- package/lib/server/connection.ts +1 -12
- package/lib/server/protocol.ts +30 -7
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../lib/server/protocol.ts"],"sourcesContent":["import { type Callback, createPromise, defer, throwError } from '@nmtjs/common'\nimport { type Container, Hook, type Logger, Scope } from '@nmtjs/core'\nimport { concat, decodeNumber, encodeNumber } from '../common/binary.ts'\nimport type { ProtocolBlob, ProtocolBlobMetadata } from '../common/blob.ts'\nimport { ErrorCode, ServerMessageType } from '../common/enums.ts'\nimport type { ProtocolRPC } from '../common/types.ts'\nimport type { ProtocolApi, ProtocolApiCallResult } from './api.ts'\nimport {\n Connection,\n ConnectionContext,\n type ConnectionOptions,\n} from './connection.ts'\nimport type { Format } from './format.ts'\nimport type { ProtocolRegistry } from './registry.ts'\nimport { ProtocolClientStream, ProtocolServerStream } from './stream.ts'\nimport type { Transport } from './transport.ts'\nimport { type ResolveFormatParams, getFormat } from './utils.ts'\n\nexport class ProtocolError extends Error {\n code: string\n data?: any\n\n constructor(code: string, message?: string, data?: any) {\n super(message)\n this.code = code\n this.data = data\n }\n\n get message() {\n return `${this.code} ${super.message}`\n }\n\n toString() {\n return `${this.code} ${this.message}`\n }\n\n toJSON() {\n return {\n code: this.code,\n message: this.message,\n data: this.data,\n }\n }\n}\n\nexport class ProtocolConnections {\n readonly #collection = new Map<\n string,\n {\n connection: Connection\n context: ConnectionContext\n transport: Transport\n }\n >()\n\n constructor(\n private readonly application: {\n logger: Logger\n registry: ProtocolRegistry\n format: Format\n container: Container\n },\n ) {}\n\n get(connectionId: string) {\n const connection = this.#collection.get(connectionId)\n if (!connection) throwError('Connection not found')\n return connection\n }\n\n async add<T>(\n transport: Transport<any>,\n options: ConnectionOptions<T>,\n params: ResolveFormatParams,\n ) {\n const connection = new Connection(options)\n const format = getFormat(this.application.format, params)\n const container = this.application.container.fork(Scope.Connection)\n const context = new ConnectionContext(container, format)\n\n this.#collection.set(connection.id, { connection, context, transport })\n\n await this.application.registry.hooks.call(\n Hook.OnConnect,\n { concurrent: false },\n connection,\n )\n\n return { connection, context }\n }\n\n async remove(connectionId: string) {\n const { connection, context } = this.get(connectionId)\n\n this.application.registry.hooks.call(\n Hook.OnDisconnect,\n { concurrent: true },\n connection,\n )\n\n this.#collection.delete(connectionId)\n\n const { calls, serverStreams, clientStreams, container } = context\n\n for (const call of calls.values()) {\n call.reject(new Error('Connection closed'))\n }\n\n for (const stream of clientStreams.values()) {\n stream.destroy(new Error('Connection closed'))\n }\n\n for (const stream of serverStreams.values()) {\n stream.destroy(new Error('Connection closed'))\n }\n\n try {\n await container.dispose()\n } catch (error) {\n this.application.logger.error(\n { error, connection },\n 'Error during closing connection',\n )\n }\n }\n}\n\nexport class ProtocolClientStreams {\n constructor(private readonly connections: ProtocolConnections) {}\n\n get(connectionId: string, streamId: number) {\n const { context } = this.connections.get(connectionId)\n const { clientStreams } = context\n const stream = clientStreams.get(streamId) ?? throwError('Stream not found')\n return stream\n }\n\n remove(connectionId: string, streamId: number) {\n const { context } = this.connections.get(connectionId)\n const { clientStreams } = context\n clientStreams.get(streamId) || throwError('Stream not found')\n clientStreams.delete(streamId)\n }\n\n add(\n connectionId: string,\n streamId: number,\n metadata: ProtocolBlobMetadata,\n read: Callback,\n ) {\n const { context } = this.connections.get(connectionId)\n const { clientStreams } = context\n const stream = new ProtocolClientStream(streamId, metadata, { read })\n clientStreams.set(streamId, stream)\n return stream\n }\n\n push(connectionId: string, streamId: number, chunk: ArrayBuffer) {\n const stream = this.get(connectionId, streamId)\n stream.push(Buffer.from(chunk))\n }\n\n end(connectionId: string, streamId: number) {\n const stream = this.get(connectionId, streamId)\n stream.push(null)\n this.remove(connectionId, streamId)\n }\n\n abort(connectionId: string, streamId: number, error = new Error('Aborted')) {\n const stream = this.get(connectionId, streamId)\n stream.destroy(error)\n this.remove(connectionId, streamId)\n }\n}\n\nexport class ProtocolServerStreams {\n constructor(private readonly connections: ProtocolConnections) {}\n\n get(connectionId: string, streamId: number) {\n const { context } = this.connections.get(connectionId)\n const { serverStreams } = context\n const stream = serverStreams.get(streamId) ?? throwError('Stream not found')\n return stream\n }\n\n add(connectionId: string, streamId: number, blob: ProtocolBlob) {\n const { context } = this.connections.get(connectionId)\n const { serverStreams } = context\n const stream = new ProtocolServerStream(streamId, blob)\n serverStreams.set(streamId, stream)\n return stream\n }\n\n remove(connectionId: string, streamId: number) {\n const { context } = this.connections.get(connectionId)\n const { serverStreams } = context\n serverStreams.has(streamId) || throwError('Stream not found')\n serverStreams.delete(streamId)\n }\n\n pull(connectionId: string, streamId: number) {\n const stream = this.get(connectionId, streamId)\n stream.resume()\n }\n\n abort(connectionId: string, streamId: number, error = new Error('Aborted')) {\n const stream = this.get(connectionId, streamId)\n stream.destroy(error)\n this.remove(connectionId, streamId)\n }\n}\n\nexport class Protocol {\n readonly connections: ProtocolConnections\n readonly clientStreams: ProtocolClientStreams\n readonly serverStreams: ProtocolServerStreams\n\n constructor(\n protected readonly application: {\n logger: Logger\n format: Format\n container: Container\n registry: ProtocolRegistry\n api: ProtocolApi\n },\n ) {\n this.connections = new ProtocolConnections(this.application)\n this.clientStreams = new ProtocolClientStreams(this.connections)\n this.serverStreams = new ProtocolServerStreams(this.connections)\n }\n\n async call(\n connectionId: string,\n rpc: ProtocolRPC,\n params: { signal?: AbortSignal } = {},\n ) {\n const { connection, context, transport } =\n this.connections.get(connectionId)\n const { calls, format } = context\n const { callId, namespace, procedure, payload } = rpc\n const abortController = new AbortController()\n const signal = params.signal\n ? AbortSignal.any([params.signal, abortController.signal])\n : abortController.signal\n\n const call = Object.assign(createPromise<ProtocolApiCallResult>(), {\n abort: () => abortController.abort(),\n })\n\n calls.set(callId, call)\n call.promise.finally(() => calls.delete(callId))\n\n const callIdEncoded = encodeNumber(callId, 'Uint32')\n const container = context.container.fork(Scope.Call)\n\n try {\n const response = await this.application.api.call({\n connection,\n container,\n namespace,\n payload,\n procedure,\n signal,\n })\n\n const responseEncoded = format.encoder.encodeRPC(\n {\n callId,\n payload: response.output,\n },\n {\n addStream: (blob) => {\n const id = context.streamId++\n const stream = this.serverStreams.add(connectionId, id, blob)\n stream.on('data', (chunk) => {\n stream.pause()\n transport.send(\n connection,\n ServerMessageType.ServerStreamPush,\n concat(\n encodeNumber(id, 'Uint32'),\n Buffer.from(chunk).buffer as ArrayBuffer,\n ),\n )\n })\n stream.on('error', (err) => {\n transport.send(\n connection,\n ServerMessageType.ServerStreamAbort,\n encodeNumber(id, 'Uint32'),\n )\n })\n stream.on('end', () => {\n transport.send(\n connection,\n ServerMessageType.ServerStreamEnd,\n encodeNumber(id, 'Uint32'),\n )\n })\n return stream\n },\n getStream: (id) => {\n return this.clientStreams.get(connectionId, id)\n },\n },\n )\n\n if ('subscription' in response) {\n throwError('Unimplemented')\n } else if ('iterable' in response) {\n transport.send(\n connection,\n ServerMessageType.RpcStreamResponse,\n responseEncoded,\n )\n try {\n const iterable =\n typeof response.iterable === 'function'\n ? response.iterable()\n : response.iterable\n for await (const chunk of iterable) {\n const chunkEncoded = format.encoder.encode(chunk)\n transport.send(\n connection,\n ServerMessageType.RpcStreamChunk,\n concat(callIdEncoded, chunkEncoded),\n )\n }\n } catch (error) {\n this.application.logger.error(error)\n transport.send(\n connection,\n ServerMessageType.RpcStreamAbort,\n callIdEncoded,\n )\n }\n } else {\n transport.send(\n connection,\n ServerMessageType.RpcResponse,\n responseEncoded,\n )\n }\n } catch (error) {\n if (error instanceof ProtocolError === false) {\n this.application.logger.error(\n { error, connection },\n 'Error during RPC call',\n )\n\n // biome-ignore lint/suspicious/noCatchAssign:\n error = new ProtocolError(\n ErrorCode.InternalServerError,\n 'Internal server error',\n )\n }\n\n const payload = format.encoder.encodeRPC(\n { callId, error },\n {\n addStream(blob) {\n throwError('Cannot handle stream for error response')\n },\n getStream(id) {\n throwError('Cannot handle stream for error response')\n },\n },\n )\n transport.send(connection, ServerMessageType.RpcResponse, payload)\n } finally {\n container.dispose().catch((error) => {\n this.application.logger.error(\n { error, connection },\n \"Error during disposing connection's container\",\n )\n })\n }\n }\n\n async callRaw(\n connectionId: string,\n buffer: ArrayBuffer,\n params: { signal?: AbortSignal } = {},\n ) {\n const { connection, context, transport } =\n this.connections.get(connectionId)\n\n const { format } = context\n\n const rpc = format.decoder.decodeRPC(buffer, {\n addStream: (id, metadata) => {\n return this.clientStreams.add(connectionId, id, metadata, (size) => {\n transport.send(\n connection,\n ServerMessageType.ClientStreamPull,\n concat(encodeNumber(id, 'Uint32'), encodeNumber(size, 'Uint32')),\n )\n })\n },\n getStream: (id) => {\n return this.serverStreams.get(connectionId, id)\n },\n })\n\n return await this.call(connectionId, rpc, params)\n }\n\n callAbort(connectionId: string, callId: number) {\n const { context } = this.connections.get(connectionId)\n const call = context.calls.get(callId) ?? throwError('Call not found')\n call.abort()\n }\n\n callAbortRaw(connectionId: string, buffer: ArrayBuffer) {\n const callId = decodeNumber(buffer, 'Uint32')\n return this.callAbort(connectionId, callId)\n }\n\n notify(connectionId: string, event, payload) {\n throw Error('Unimplemented')\n }\n}\n"],"names":["createPromise","throwError","Hook","Scope","concat","decodeNumber","encodeNumber","ErrorCode","ServerMessageType","Connection","ConnectionContext","ProtocolClientStream","ProtocolServerStream","getFormat","ProtocolError","Error","code","data","constructor","message","toString","toJSON","ProtocolConnections","application","Map","get","connectionId","connection","add","transport","options","params","format","container","fork","context","set","id","registry","hooks","call","OnConnect","concurrent","remove","OnDisconnect","delete","calls","serverStreams","clientStreams","values","reject","stream","destroy","dispose","error","logger","ProtocolClientStreams","connections","streamId","metadata","read","push","chunk","Buffer","from","end","abort","ProtocolServerStreams","blob","has","pull","resume","Protocol","rpc","callId","namespace","procedure","payload","abortController","AbortController","signal","AbortSignal","any","Object","assign","promise","finally","callIdEncoded","Call","response","api","responseEncoded","encoder","encodeRPC","output","addStream","on","pause","send","ServerStreamPush","buffer","err","ServerStreamAbort","ServerStreamEnd","getStream","RpcStreamResponse","iterable","chunkEncoded","encode","RpcStreamChunk","RpcStreamAbort","RpcResponse","InternalServerError","catch","callRaw","decoder","decodeRPC","size","ClientStreamPull","callAbort","callAbortRaw","notify","event"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../lib/server/protocol.ts"],"sourcesContent":["import { type Callback, createPromise, defer, throwError } from '@nmtjs/common'\nimport { type Container, Hook, type Logger, Scope } from '@nmtjs/core'\nimport { concat, decodeNumber, encodeNumber } from '../common/binary.ts'\nimport type { ProtocolBlob, ProtocolBlobMetadata } from '../common/blob.ts'\nimport { ErrorCode, ServerMessageType } from '../common/enums.ts'\nimport type { ProtocolRPC } from '../common/types.ts'\nimport type { ProtocolApi, ProtocolApiCallResult } from './api.ts'\nimport {\n Connection,\n ConnectionContext,\n type ConnectionOptions,\n} from './connection.ts'\nimport type { Format } from './format.ts'\nimport type { ProtocolRegistry } from './registry.ts'\nimport { ProtocolClientStream, ProtocolServerStream } from './stream.ts'\nimport type { Transport } from './transport.ts'\nimport { type ResolveFormatParams, getFormat } from './utils.ts'\n\nexport class ProtocolError extends Error {\n code: string\n data?: any\n\n constructor(code: string, message?: string, data?: any) {\n super(message)\n this.code = code\n this.data = data\n }\n\n get message() {\n return `${this.code} ${super.message}`\n }\n\n toString() {\n return `${this.code} ${this.message}`\n }\n\n toJSON() {\n return {\n code: this.code,\n message: this.message,\n data: this.data,\n }\n }\n}\n\nexport class ProtocolConnections {\n readonly #collection = new Map<\n string,\n {\n connection: Connection\n context: ConnectionContext\n transport: Transport\n }\n >()\n\n constructor(\n private readonly application: {\n logger: Logger\n registry: ProtocolRegistry\n format: Format\n container: Container\n },\n ) {}\n\n get(connectionId: string) {\n const connection = this.#collection.get(connectionId)\n if (!connection) throwError('Connection not found')\n return connection\n }\n\n async add<T>(\n transport: Transport<any>,\n options: ConnectionOptions<T>,\n params: ResolveFormatParams,\n ) {\n const connection = new Connection(options)\n const format = getFormat(this.application.format, params)\n const container = this.application.container.fork(Scope.Connection)\n const context = new ConnectionContext(container, format)\n\n this.#collection.set(connection.id, { connection, context, transport })\n\n await this.application.registry.hooks.call(\n Hook.OnConnect,\n { concurrent: false },\n connection,\n )\n\n return { connection, context }\n }\n\n async remove(connectionId: string) {\n const { connection, context } = this.get(connectionId)\n\n this.application.registry.hooks.call(\n Hook.OnDisconnect,\n { concurrent: true },\n connection,\n )\n\n this.#collection.delete(connectionId)\n\n const { calls, serverStreams, clientStreams, rpcStreams, container } =\n context\n\n for (const call of calls.values()) {\n call.reject(new Error('Connection closed'))\n }\n\n for (const stream of clientStreams.values()) {\n stream.destroy(new Error('Connection closed'))\n }\n\n for (const stream of serverStreams.values()) {\n stream.destroy(new Error('Connection closed'))\n }\n\n for (const stream of rpcStreams.values()) {\n stream.abort(new Error('Connection closed'))\n }\n\n try {\n await container.dispose()\n } catch (error) {\n this.application.logger.error(\n { error, connection },\n 'Error during closing connection',\n )\n }\n }\n}\n\nexport class ProtocolClientStreams {\n constructor(private readonly connections: ProtocolConnections) {}\n\n get(connectionId: string, streamId: number) {\n const { context } = this.connections.get(connectionId)\n const { clientStreams } = context\n const stream = clientStreams.get(streamId) ?? throwError('Stream not found')\n return stream\n }\n\n remove(connectionId: string, streamId: number) {\n const { context } = this.connections.get(connectionId)\n const { clientStreams } = context\n clientStreams.get(streamId) || throwError('Stream not found')\n clientStreams.delete(streamId)\n }\n\n add(\n connectionId: string,\n streamId: number,\n metadata: ProtocolBlobMetadata,\n read: Callback,\n ) {\n const { context } = this.connections.get(connectionId)\n const { clientStreams } = context\n const stream = new ProtocolClientStream(streamId, metadata, { read })\n clientStreams.set(streamId, stream)\n return stream\n }\n\n push(connectionId: string, streamId: number, chunk: ArrayBuffer) {\n const stream = this.get(connectionId, streamId)\n stream.push(Buffer.from(chunk))\n }\n\n end(connectionId: string, streamId: number) {\n const stream = this.get(connectionId, streamId)\n stream.push(null)\n this.remove(connectionId, streamId)\n }\n\n abort(connectionId: string, streamId: number, error = new Error('Aborted')) {\n const stream = this.get(connectionId, streamId)\n stream.destroy(error)\n this.remove(connectionId, streamId)\n }\n}\n\nexport class ProtocolServerStreams {\n constructor(private readonly connections: ProtocolConnections) {}\n\n get(connectionId: string, streamId: number) {\n const { context } = this.connections.get(connectionId)\n const { serverStreams } = context\n const stream = serverStreams.get(streamId) ?? throwError('Stream not found')\n return stream\n }\n\n add(connectionId: string, streamId: number, blob: ProtocolBlob) {\n const { context } = this.connections.get(connectionId)\n const { serverStreams } = context\n const stream = new ProtocolServerStream(streamId, blob)\n serverStreams.set(streamId, stream)\n return stream\n }\n\n remove(connectionId: string, streamId: number) {\n const { context } = this.connections.get(connectionId)\n const { serverStreams } = context\n serverStreams.has(streamId) || throwError('Stream not found')\n serverStreams.delete(streamId)\n }\n\n pull(connectionId: string, streamId: number) {\n const stream = this.get(connectionId, streamId)\n stream.resume()\n }\n\n abort(connectionId: string, streamId: number, error = new Error('Aborted')) {\n const stream = this.get(connectionId, streamId)\n stream.destroy(error)\n this.remove(connectionId, streamId)\n }\n}\n\nexport class Protocol {\n readonly connections: ProtocolConnections\n readonly clientStreams: ProtocolClientStreams\n readonly serverStreams: ProtocolServerStreams\n\n constructor(\n protected readonly application: {\n logger: Logger\n format: Format\n container: Container\n registry: ProtocolRegistry\n api: ProtocolApi\n },\n ) {\n this.connections = new ProtocolConnections(this.application)\n this.clientStreams = new ProtocolClientStreams(this.connections)\n this.serverStreams = new ProtocolServerStreams(this.connections)\n }\n\n async rpc(\n connectionId: string,\n rpc: ProtocolRPC,\n params: { signal?: AbortSignal } = {},\n ) {\n const { connection, context, transport } =\n this.connections.get(connectionId)\n const { calls, format } = context\n const { callId, namespace, procedure, payload } = rpc\n const abortController = new AbortController()\n const signal = params.signal\n ? AbortSignal.any([params.signal, abortController.signal])\n : abortController.signal\n\n const call = Object.assign(createPromise<ProtocolApiCallResult>(), {\n abort: () => abortController.abort(),\n })\n\n calls.set(callId, call)\n call.promise.finally(() => calls.delete(callId))\n\n const callIdEncoded = encodeNumber(callId, 'Uint32')\n const container = context.container.fork(Scope.Call)\n\n try {\n const response = await this.application.api.call({\n connection,\n container,\n namespace,\n payload,\n procedure,\n signal,\n })\n\n const responseEncoded = format.encoder.encodeRPC(\n {\n callId,\n payload: response.output,\n },\n {\n addStream: (blob) => {\n const id = context.streamId++\n const stream = this.serverStreams.add(connectionId, id, blob)\n stream.on('data', (chunk) => {\n stream.pause()\n transport.send(\n connection,\n ServerMessageType.ServerStreamPush,\n concat(\n encodeNumber(id, 'Uint32'),\n Buffer.from(chunk).buffer as ArrayBuffer,\n ),\n )\n })\n stream.on('error', (err) => {\n transport.send(\n connection,\n ServerMessageType.ServerStreamAbort,\n encodeNumber(id, 'Uint32'),\n )\n })\n stream.on('end', () => {\n transport.send(\n connection,\n ServerMessageType.ServerStreamEnd,\n encodeNumber(id, 'Uint32'),\n )\n })\n return stream\n },\n getStream: (id) => {\n return this.clientStreams.get(connectionId, id)\n },\n },\n )\n\n if ('subscription' in response) {\n throwError('Unimplemented')\n } else if ('iterable' in response) {\n transport.send(\n connection,\n ServerMessageType.RpcStreamResponse,\n responseEncoded,\n )\n try {\n const ab = new AbortController()\n context.rpcStreams.set(callId, ab)\n const iterable =\n typeof response.iterable === 'function'\n ? response.iterable()\n : response.iterable\n for await (const chunk of iterable) {\n if (ab.signal.aborted) break\n const chunkEncoded = format.encoder.encode(chunk)\n transport.send(\n connection,\n ServerMessageType.RpcStreamChunk,\n concat(callIdEncoded, chunkEncoded),\n )\n }\n } catch (error) {\n this.application.logger.error(error)\n transport.send(\n connection,\n ServerMessageType.RpcStreamAbort,\n callIdEncoded,\n )\n } finally {\n context.rpcStreams.delete(callId)\n response.onFinish && defer(response.onFinish)\n }\n } else {\n transport.send(\n connection,\n ServerMessageType.RpcResponse,\n responseEncoded,\n )\n }\n } catch (error) {\n if (error instanceof ProtocolError === false) {\n this.application.logger.error(\n { error, connection },\n 'Error during RPC call',\n )\n\n // biome-ignore lint/suspicious/noCatchAssign:\n error = new ProtocolError(\n ErrorCode.InternalServerError,\n 'Internal server error',\n )\n }\n\n const payload = format.encoder.encodeRPC(\n { callId, error },\n {\n addStream(blob) {\n throwError('Cannot handle stream for error response')\n },\n getStream(id) {\n throwError('Cannot handle stream for error response')\n },\n },\n )\n transport.send(connection, ServerMessageType.RpcResponse, payload)\n } finally {\n container.dispose().catch((error) => {\n this.application.logger.error(\n { error, connection },\n \"Error during disposing connection's container\",\n )\n })\n }\n }\n\n async rpcRaw(\n connectionId: string,\n buffer: ArrayBuffer,\n params: { signal?: AbortSignal } = {},\n ) {\n const { connection, context, transport } =\n this.connections.get(connectionId)\n\n const { format } = context\n\n const rpc = format.decoder.decodeRPC(buffer, {\n addStream: (id, metadata) => {\n return this.clientStreams.add(connectionId, id, metadata, (size) => {\n transport.send(\n connection,\n ServerMessageType.ClientStreamPull,\n concat(encodeNumber(id, 'Uint32'), encodeNumber(size, 'Uint32')),\n )\n })\n },\n getStream: (id) => {\n return this.serverStreams.get(connectionId, id)\n },\n })\n\n return await this.rpc(connectionId, rpc, params)\n }\n\n rpcAbort(connectionId: string, callId: number) {\n const { context } = this.connections.get(connectionId)\n const call = context.calls.get(callId) ?? throwError('Call not found')\n call.abort()\n }\n\n rpcAbortRaw(connectionId: string, buffer: ArrayBuffer) {\n const callId = decodeNumber(buffer, 'Uint32')\n return this.rpcAbort(connectionId, callId)\n }\n\n rpcStreamAbort(connectionId: string, callId: number) {\n const { context } = this.connections.get(connectionId)\n const ab =\n context.rpcStreams.get(callId) ?? throwError('Call stream not found')\n ab.abort()\n }\n\n rpcStreamAbortRaw(connectionId: string, buffer: ArrayBuffer) {\n const callId = decodeNumber(buffer, 'Uint32')\n return this.rpcStreamAbort(connectionId, callId)\n }\n\n notify(connectionId: string, event, payload) {\n throw Error('Unimplemented')\n }\n}\n"],"names":["createPromise","defer","throwError","Hook","Scope","concat","decodeNumber","encodeNumber","ErrorCode","ServerMessageType","Connection","ConnectionContext","ProtocolClientStream","ProtocolServerStream","getFormat","ProtocolError","Error","code","data","constructor","message","toString","toJSON","ProtocolConnections","application","Map","get","connectionId","connection","add","transport","options","params","format","container","fork","context","set","id","registry","hooks","call","OnConnect","concurrent","remove","OnDisconnect","delete","calls","serverStreams","clientStreams","rpcStreams","values","reject","stream","destroy","abort","dispose","error","logger","ProtocolClientStreams","connections","streamId","metadata","read","push","chunk","Buffer","from","end","ProtocolServerStreams","blob","has","pull","resume","Protocol","rpc","callId","namespace","procedure","payload","abortController","AbortController","signal","AbortSignal","any","Object","assign","promise","finally","callIdEncoded","Call","response","api","responseEncoded","encoder","encodeRPC","output","addStream","on","pause","send","ServerStreamPush","buffer","err","ServerStreamAbort","ServerStreamEnd","getStream","RpcStreamResponse","ab","iterable","aborted","chunkEncoded","encode","RpcStreamChunk","RpcStreamAbort","onFinish","RpcResponse","InternalServerError","catch","rpcRaw","decoder","decodeRPC","size","ClientStreamPull","rpcAbort","rpcAbortRaw","rpcStreamAbort","rpcStreamAbortRaw","notify","event"],"mappings":"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"}
|
package/lib/client/events.ts
CHANGED
|
@@ -2,19 +2,6 @@ import type { Callback } from '@nmtjs/common'
|
|
|
2
2
|
|
|
3
3
|
export type EventMap = { [K: string]: any[] }
|
|
4
4
|
|
|
5
|
-
export function untilAborted(signal: AbortSignal) {
|
|
6
|
-
return new Promise((_, reject) => {
|
|
7
|
-
const handler = () => reject(new Error('aborted'))
|
|
8
|
-
const options = { once: true }
|
|
9
|
-
signal.addEventListener('abort', handler, options)
|
|
10
|
-
})
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function onAbort(signal: AbortSignal, listener: () => void) {
|
|
14
|
-
signal.addEventListener('abort', listener, { once: true })
|
|
15
|
-
return () => signal.removeEventListener('abort', listener)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
5
|
/**
|
|
19
6
|
* Very simple node-like event emitter wrapper around EventTarget
|
|
20
7
|
*
|
|
@@ -27,6 +14,10 @@ export class EventEmitter<
|
|
|
27
14
|
string
|
|
28
15
|
>,
|
|
29
16
|
> {
|
|
17
|
+
static once(ee: EventEmitter, event: string) {
|
|
18
|
+
return new Promise((resolve) => ee.once(event, resolve))
|
|
19
|
+
}
|
|
20
|
+
|
|
30
21
|
#target = new EventTarget()
|
|
31
22
|
#listeners = new Map<Callback, Callback>()
|
|
32
23
|
|
|
@@ -61,6 +52,3 @@ export class EventEmitter<
|
|
|
61
52
|
return this.#target.dispatchEvent(new CustomEvent(event, { detail: args }))
|
|
62
53
|
}
|
|
63
54
|
}
|
|
64
|
-
|
|
65
|
-
export const once = (ee: EventEmitter, event: string) =>
|
|
66
|
-
new Promise((resolve) => ee.once(event, resolve))
|
package/lib/client/protocol.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type InteractivePromise,
|
|
3
|
+
createPromise,
|
|
4
|
+
onceAborted,
|
|
5
|
+
} from '@nmtjs/common'
|
|
2
6
|
import { concat, decodeNumber, encodeNumber } from '../common/binary.ts'
|
|
3
7
|
import type { ProtocolBlobMetadata } from '../common/blob.ts'
|
|
4
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
ClientMessageType,
|
|
10
|
+
ErrorCode,
|
|
11
|
+
ServerMessageType,
|
|
12
|
+
} from '../common/enums.ts'
|
|
5
13
|
import type { ProtocolRPC } from '../common/types.ts'
|
|
6
14
|
import { EventEmitter } from './events.ts'
|
|
7
15
|
import type { BaseClientFormat } from './format.ts'
|
|
@@ -151,6 +159,18 @@ export class ProtocolBaseTransformer {
|
|
|
151
159
|
export type ProtocolClientCall = InteractivePromise<any> &
|
|
152
160
|
Pick<ProtocolRPC, 'namespace' | 'procedure'>
|
|
153
161
|
|
|
162
|
+
export type ProtocolBaseClientOptions = {
|
|
163
|
+
transport: ProtocolTransport
|
|
164
|
+
format: BaseClientFormat
|
|
165
|
+
transformer?: ProtocolBaseTransformer
|
|
166
|
+
timeout?: number
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export type ProtocolBaseClientCallOptions = {
|
|
170
|
+
signal?: AbortSignal
|
|
171
|
+
timeout?: number
|
|
172
|
+
}
|
|
173
|
+
|
|
154
174
|
export abstract class ProtocolBaseClient<
|
|
155
175
|
T extends Record<string, Record<string, any>>,
|
|
156
176
|
> extends EventEmitter<
|
|
@@ -164,29 +184,34 @@ export abstract class ProtocolBaseClient<
|
|
|
164
184
|
> {
|
|
165
185
|
readonly #clientStreams: ProtocolClientStreams
|
|
166
186
|
readonly #serverStreams: ProtocolServerStreams
|
|
167
|
-
readonly #
|
|
168
|
-
readonly #
|
|
187
|
+
readonly #rpcStreams: ProtocolServerStreams
|
|
188
|
+
readonly #rpcStreamData = new Map<
|
|
169
189
|
number,
|
|
170
190
|
Pick<ProtocolRPC, 'namespace' | 'procedure'>
|
|
171
191
|
>()
|
|
172
192
|
readonly #calls = new Map<number, ProtocolClientCall>()
|
|
173
193
|
|
|
194
|
+
readonly #transport: ProtocolTransport
|
|
195
|
+
readonly #format: BaseClientFormat
|
|
196
|
+
readonly transformer: ProtocolBaseTransformer = new ProtocolBaseTransformer()
|
|
197
|
+
readonly #timeout: number
|
|
198
|
+
|
|
174
199
|
#callId = 0
|
|
175
200
|
#streamId = 0
|
|
176
201
|
|
|
177
|
-
constructor(
|
|
178
|
-
protected readonly transport: ProtocolTransport,
|
|
179
|
-
protected readonly format: BaseClientFormat,
|
|
180
|
-
protected readonly transformer: ProtocolBaseTransformer = new ProtocolBaseTransformer(),
|
|
181
|
-
) {
|
|
202
|
+
constructor(options: ProtocolBaseClientOptions) {
|
|
182
203
|
super()
|
|
183
204
|
|
|
205
|
+
this.#transport = options.transport
|
|
206
|
+
this.#format = options.format
|
|
207
|
+
this.#timeout = options.timeout ?? 60000
|
|
208
|
+
|
|
184
209
|
this.#clientStreams = new ProtocolClientStreams()
|
|
185
210
|
this.#serverStreams = new ProtocolServerStreams()
|
|
186
|
-
this.#
|
|
211
|
+
this.#rpcStreams = new ProtocolServerStreams()
|
|
187
212
|
|
|
188
|
-
this
|
|
189
|
-
const [namespace, event, payload] = this
|
|
213
|
+
this.#transport.on(`${ServerMessageType.Event}`, (buffer) => {
|
|
214
|
+
const [namespace, event, payload] = this.#format.decode(buffer)
|
|
190
215
|
const name = `${namespace}/${event}`
|
|
191
216
|
const transformed = this.transformer.decodeEvent(
|
|
192
217
|
namespace,
|
|
@@ -196,69 +221,72 @@ export abstract class ProtocolBaseClient<
|
|
|
196
221
|
this.emit(name, transformed)
|
|
197
222
|
})
|
|
198
223
|
|
|
199
|
-
this
|
|
224
|
+
this.#transport.on(`${ServerMessageType.RpcResponse}`, (buffer) => {
|
|
200
225
|
const { call, error, payload } = this.#handleResponse(buffer)
|
|
201
226
|
if (error) call.reject(error)
|
|
202
227
|
else call.resolve(payload)
|
|
203
228
|
})
|
|
204
229
|
|
|
205
|
-
this
|
|
230
|
+
this.#transport.on(`${ServerMessageType.RpcStreamResponse}`, (buffer) => {
|
|
206
231
|
const { call, response, payload, error } = this.#handleResponse(buffer)
|
|
207
232
|
if (error) return call.reject(error)
|
|
208
233
|
console.log('Creating RPC stream', response)
|
|
209
234
|
const stream = new ProtocolServerStream()
|
|
210
|
-
this.#
|
|
211
|
-
this.#
|
|
235
|
+
this.#rpcStreams.add(response.callId, stream)
|
|
236
|
+
this.#rpcStreamData.set(response.callId, {
|
|
212
237
|
namespace: call.namespace,
|
|
213
238
|
procedure: call.procedure,
|
|
214
239
|
})
|
|
215
|
-
call.resolve(
|
|
240
|
+
call.resolve({ payload, stream })
|
|
216
241
|
})
|
|
217
242
|
|
|
218
|
-
this
|
|
219
|
-
|
|
220
|
-
|
|
243
|
+
this.#transport.on(
|
|
244
|
+
`${ServerMessageType.RpcStreamChunk}`,
|
|
245
|
+
async (buffer) => {
|
|
246
|
+
const callId = decodeNumber(buffer, 'Uint32')
|
|
247
|
+
console.log('RPC stream chunk', callId)
|
|
221
248
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
249
|
+
const chunk = buffer.slice(Uint32Array.BYTES_PER_ELEMENT)
|
|
250
|
+
if (chunk.byteLength === 0) {
|
|
251
|
+
this.#rpcStreams.end(callId)
|
|
252
|
+
this.#rpcStreamData.delete(callId)
|
|
253
|
+
} else {
|
|
254
|
+
const call = this.#rpcStreamData.get(callId)
|
|
255
|
+
console.log('RPC stream call', call)
|
|
256
|
+
if (call) {
|
|
257
|
+
const payload = this.#format.decode(chunk)
|
|
258
|
+
console.log('RPC stream payload', payload)
|
|
259
|
+
try {
|
|
260
|
+
const transformed = this.transformer.decodeRPCChunk(
|
|
261
|
+
call.namespace,
|
|
262
|
+
call.procedure,
|
|
263
|
+
payload,
|
|
264
|
+
)
|
|
265
|
+
await this.#rpcStreams.push(callId, transformed)
|
|
266
|
+
} catch (error) {
|
|
267
|
+
this.#send(
|
|
268
|
+
ClientMessageType.RpcStreamAbort,
|
|
269
|
+
encodeNumber(callId, 'Uint32'),
|
|
270
|
+
)
|
|
271
|
+
this.#rpcStreams.remove(callId)
|
|
272
|
+
this.#rpcStreamData.delete(callId)
|
|
273
|
+
}
|
|
246
274
|
}
|
|
247
275
|
}
|
|
248
|
-
}
|
|
249
|
-
|
|
276
|
+
},
|
|
277
|
+
)
|
|
250
278
|
|
|
251
|
-
this
|
|
279
|
+
this.#transport.on(`${ServerMessageType.RpcStreamAbort}`, (buffer) => {
|
|
252
280
|
const callId = decodeNumber(buffer, 'Uint32')
|
|
253
281
|
console.log('RPC stream abort', callId)
|
|
254
282
|
const call = this.#calls.get(callId)
|
|
255
283
|
if (call) {
|
|
256
284
|
this.#serverStreams.end(callId)
|
|
257
|
-
this.#
|
|
285
|
+
this.#rpcStreams.abort(callId)
|
|
258
286
|
}
|
|
259
287
|
})
|
|
260
288
|
|
|
261
|
-
this
|
|
289
|
+
this.#transport.on(
|
|
262
290
|
`${ServerMessageType.ServerStreamPush}`,
|
|
263
291
|
async (buffer) => {
|
|
264
292
|
const streamId = decodeNumber(buffer, 'Uint32')
|
|
@@ -266,12 +294,12 @@ export abstract class ProtocolBaseClient<
|
|
|
266
294
|
console.log('Server stream push', streamId, chunk.byteLength)
|
|
267
295
|
try {
|
|
268
296
|
await this.#serverStreams.push(streamId, chunk)
|
|
269
|
-
this
|
|
297
|
+
this.#send(
|
|
270
298
|
ClientMessageType.ServerStreamPull,
|
|
271
299
|
encodeNumber(streamId, 'Uint32'),
|
|
272
300
|
)
|
|
273
301
|
} catch (error) {
|
|
274
|
-
this
|
|
302
|
+
this.#send(
|
|
275
303
|
ClientMessageType.ServerStreamAbort,
|
|
276
304
|
encodeNumber(streamId, 'Uint32'),
|
|
277
305
|
)
|
|
@@ -280,25 +308,25 @@ export abstract class ProtocolBaseClient<
|
|
|
280
308
|
},
|
|
281
309
|
)
|
|
282
310
|
|
|
283
|
-
this
|
|
311
|
+
this.#transport.on(`${ServerMessageType.ServerStreamEnd}`, (buffer) => {
|
|
284
312
|
const streamId = decodeNumber(buffer, 'Uint32')
|
|
285
313
|
console.log('Server stream end', streamId)
|
|
286
314
|
this.#serverStreams.end(streamId)
|
|
287
315
|
})
|
|
288
316
|
|
|
289
|
-
this
|
|
317
|
+
this.#transport.on(`${ServerMessageType.ServerStreamAbort}`, (buffer) => {
|
|
290
318
|
const streamId = decodeNumber(buffer, 'Uint32')
|
|
291
319
|
console.log('Server stream abort', streamId)
|
|
292
320
|
this.#serverStreams.abort(streamId)
|
|
293
321
|
})
|
|
294
322
|
|
|
295
|
-
this
|
|
323
|
+
this.#transport.on(`${ServerMessageType.ClientStreamAbort}`, (buffer) => {
|
|
296
324
|
const streamId = decodeNumber(buffer, 'Uint32')
|
|
297
325
|
console.log('Client stream abort', streamId)
|
|
298
326
|
this.#clientStreams.abort(streamId)
|
|
299
327
|
})
|
|
300
328
|
|
|
301
|
-
this
|
|
329
|
+
this.#transport.on(
|
|
302
330
|
`${ServerMessageType.ClientStreamPull}`,
|
|
303
331
|
async (buffer) => {
|
|
304
332
|
const streamId = decodeNumber(buffer, 'Uint32')
|
|
@@ -312,51 +340,56 @@ export abstract class ProtocolBaseClient<
|
|
|
312
340
|
try {
|
|
313
341
|
const chunk = await this.#clientStreams.pull(streamId, size)
|
|
314
342
|
if (chunk) {
|
|
315
|
-
this
|
|
343
|
+
this.#send(
|
|
316
344
|
ClientMessageType.ClientStreamPush,
|
|
317
345
|
concat(streamIdEncoded, chunk),
|
|
318
346
|
)
|
|
319
347
|
} else {
|
|
320
|
-
this
|
|
348
|
+
this.#send(ClientMessageType.ClientStreamEnd, streamIdEncoded)
|
|
321
349
|
this.#clientStreams.end(streamId)
|
|
322
350
|
}
|
|
323
351
|
} catch (error) {
|
|
324
352
|
console.error(error)
|
|
325
|
-
this
|
|
353
|
+
this.#send(ClientMessageType.ClientStreamAbort, streamIdEncoded)
|
|
326
354
|
}
|
|
327
355
|
},
|
|
328
356
|
)
|
|
329
357
|
}
|
|
330
358
|
|
|
331
359
|
async connect(auth: any) {
|
|
332
|
-
return await this
|
|
360
|
+
return await this.#transport.connect(auth, this.#format.contentType)
|
|
333
361
|
}
|
|
334
362
|
|
|
335
363
|
async disconnect() {
|
|
336
|
-
return await this
|
|
364
|
+
return await this.#transport.disconnect()
|
|
337
365
|
}
|
|
338
366
|
|
|
339
|
-
|
|
367
|
+
async #send(messageType: ClientMessageType, buffer: ArrayBuffer) {
|
|
340
368
|
console.log(
|
|
341
369
|
'Client transport send',
|
|
342
370
|
ClientMessageType[messageType],
|
|
343
371
|
buffer.byteLength,
|
|
344
372
|
)
|
|
345
|
-
return await this
|
|
373
|
+
return await this.#transport.send(messageType, buffer)
|
|
346
374
|
}
|
|
347
375
|
|
|
348
376
|
protected async _call(
|
|
349
377
|
namespace: string,
|
|
350
378
|
procedure: string,
|
|
351
379
|
payload: any,
|
|
352
|
-
options = {},
|
|
380
|
+
options: ProtocolBaseClientCallOptions = {},
|
|
353
381
|
) {
|
|
382
|
+
const timeoutSignal = AbortSignal.timeout(options.timeout || this.#timeout)
|
|
383
|
+
const signal = options.signal
|
|
384
|
+
? AbortSignal.any([options.signal, timeoutSignal])
|
|
385
|
+
: timeoutSignal
|
|
386
|
+
|
|
354
387
|
const callId = ++this.#callId
|
|
355
388
|
const call = Object.assign(createPromise(), {
|
|
356
389
|
namespace,
|
|
357
390
|
procedure,
|
|
358
391
|
})
|
|
359
|
-
const buffer = this
|
|
392
|
+
const buffer = this.#format.encodeRPC(
|
|
360
393
|
{
|
|
361
394
|
callId,
|
|
362
395
|
namespace,
|
|
@@ -380,20 +413,27 @@ export abstract class ProtocolBaseClient<
|
|
|
380
413
|
},
|
|
381
414
|
)
|
|
382
415
|
|
|
383
|
-
this
|
|
416
|
+
this.#transport.send(ClientMessageType.Rpc, buffer).catch(console.error)
|
|
384
417
|
|
|
385
418
|
this.#calls.set(callId, call)
|
|
386
419
|
|
|
387
|
-
|
|
420
|
+
const onAborted = onceAborted(signal).then(() => {
|
|
421
|
+
if (this.#calls.has(callId)) {
|
|
422
|
+
this.#send(ClientMessageType.RpcAbort, encodeNumber(callId, 'Uint32'))
|
|
423
|
+
}
|
|
424
|
+
throw new ProtocolError(ErrorCode.RequestTimeout, 'Request timeout')
|
|
425
|
+
})
|
|
426
|
+
|
|
427
|
+
return Promise.race([call.promise, onAborted])
|
|
388
428
|
}
|
|
389
429
|
|
|
390
430
|
#handleResponse(buffer: ArrayBuffer) {
|
|
391
431
|
const callStreams: ProtocolServerBlobStream[] = []
|
|
392
|
-
const response = this
|
|
432
|
+
const response = this.#format.decodeRPC(buffer, {
|
|
393
433
|
addStream: (id, metadata) => {
|
|
394
434
|
console.log('Client transport blob stream', id, metadata)
|
|
395
435
|
const stream = new ProtocolServerBlobStream(id, metadata, () => {
|
|
396
|
-
this
|
|
436
|
+
this.#send(
|
|
397
437
|
ClientMessageType.ServerStreamPull,
|
|
398
438
|
encodeNumber(id, 'Uint32'),
|
|
399
439
|
)
|
package/lib/client/stream.ts
CHANGED
|
@@ -22,7 +22,7 @@ export class ProtocolClientBlobStream extends TransformStream<
|
|
|
22
22
|
if (chunk instanceof ArrayBuffer) {
|
|
23
23
|
controller.enqueue(chunk)
|
|
24
24
|
} else if (chunk instanceof Uint8Array) {
|
|
25
|
-
controller.enqueue(chunk.buffer)
|
|
25
|
+
controller.enqueue(chunk.buffer as unknown as ArrayBuffer)
|
|
26
26
|
} else if (typeof chunk === 'string') {
|
|
27
27
|
controller.enqueue(encodeText(chunk))
|
|
28
28
|
} else {
|
|
@@ -61,13 +61,20 @@ export class ProtocolClientBlobStream extends TransformStream<
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
async end() {
|
|
64
|
-
if (!this.writable.locked
|
|
65
|
-
|
|
66
|
-
}
|
|
64
|
+
if (!this.writable.locked) await this.writable.close()
|
|
65
|
+
else await this.writable.abort(new Error('Stream closed'))
|
|
67
66
|
}
|
|
68
67
|
}
|
|
69
68
|
|
|
70
|
-
export
|
|
69
|
+
export interface ProtocolServerStreamInterface<T = any> {
|
|
70
|
+
[Symbol.asyncIterator](): AsyncGenerator<T>
|
|
71
|
+
abort(error?: Error): void
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export class ProtocolServerStream<T = any>
|
|
75
|
+
extends TransformStream<any, T>
|
|
76
|
+
implements ProtocolServerStreamInterface<T>
|
|
77
|
+
{
|
|
71
78
|
#writer: WritableStreamDefaultWriter
|
|
72
79
|
|
|
73
80
|
constructor(start?: Callback) {
|
package/lib/server/api.ts
CHANGED
|
@@ -13,9 +13,7 @@ export type ProtocolApiCallOptions = {
|
|
|
13
13
|
|
|
14
14
|
export type ProtocolAnyIterable<T> =
|
|
15
15
|
| (() => AsyncGenerator<T>)
|
|
16
|
-
// | (() => Generator<T>)
|
|
17
16
|
| AsyncIterable<T>
|
|
18
|
-
// | Iterable<T>
|
|
19
17
|
|
|
20
18
|
export interface ProtocolApiCallBaseResult {
|
|
21
19
|
output: unknown
|
|
@@ -28,6 +26,7 @@ export interface ProtocolApiCallSubscriptionResult
|
|
|
28
26
|
export interface ProtocolApiCallIterableResult
|
|
29
27
|
extends ProtocolApiCallBaseResult {
|
|
30
28
|
iterable: ProtocolAnyIterable<unknown>
|
|
29
|
+
onFinish?: () => void
|
|
31
30
|
}
|
|
32
31
|
|
|
33
32
|
export type ProtocolApiCallResult =
|
package/lib/server/connection.ts
CHANGED
|
@@ -1,22 +1,10 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto'
|
|
2
|
-
// import type { TAnyEventContract } from '@nmtjs/contract'
|
|
3
2
|
import type { InteractivePromise } from '@nmtjs/common'
|
|
4
3
|
import type { Container } from '@nmtjs/core'
|
|
5
4
|
import type { ProtocolApiCallResult } from './api.ts'
|
|
6
5
|
import type { BaseServerDecoder, BaseServerEncoder } from './format.ts'
|
|
7
6
|
import type { ProtocolClientStream, ProtocolServerStream } from './stream.ts'
|
|
8
7
|
|
|
9
|
-
// export type NotifyFn = <T extends TAnyEventContract>(
|
|
10
|
-
// connection: Connection,
|
|
11
|
-
// contract: T,
|
|
12
|
-
// payload: t.infer.input.decoded<T['payload']>,
|
|
13
|
-
// ) => Promise<boolean>
|
|
14
|
-
|
|
15
|
-
// export type ConnectionNotifyFn = (
|
|
16
|
-
// contract: TAnyEventContract,
|
|
17
|
-
// payload: unknown,
|
|
18
|
-
// ) => Promise<boolean>
|
|
19
|
-
|
|
20
8
|
export type ConnectionOptions<Data = unknown> = {
|
|
21
9
|
id?: string
|
|
22
10
|
data: Data
|
|
@@ -41,6 +29,7 @@ export class ConnectionContext {
|
|
|
41
29
|
calls = new Map<number, ConnectionCall<ProtocolApiCallResult>>()
|
|
42
30
|
clientStreams = new Map<number, ProtocolClientStream>()
|
|
43
31
|
serverStreams = new Map<number, ProtocolServerStream>()
|
|
32
|
+
rpcStreams = new Map<number, AbortController>()
|
|
44
33
|
container: Container
|
|
45
34
|
format: {
|
|
46
35
|
encoder: BaseServerEncoder
|