@nmtjs/protocol 0.6.0
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/LICENSE.md +7 -0
- package/README.md +9 -0
- package/dist/client/events.js +41 -0
- package/dist/client/events.js.map +1 -0
- package/dist/client/format.js +2 -0
- package/dist/client/format.js.map +1 -0
- package/dist/client/index.js +4 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/protocol.js +311 -0
- package/dist/client/protocol.js.map +1 -0
- package/dist/client/stream.js +99 -0
- package/dist/client/stream.js.map +1 -0
- package/dist/common/binary.js +25 -0
- package/dist/common/binary.js.map +1 -0
- package/dist/common/blob.js +42 -0
- package/dist/common/blob.js.map +1 -0
- package/dist/common/enums.js +44 -0
- package/dist/common/enums.js.map +1 -0
- package/dist/common/index.js +4 -0
- package/dist/common/index.js.map +1 -0
- package/dist/common/types.js +1 -0
- package/dist/common/types.js.map +1 -0
- package/dist/server/api.js +1 -0
- package/dist/server/api.js.map +1 -0
- package/dist/server/connection.js +21 -0
- package/dist/server/connection.js.map +1 -0
- package/dist/server/constants.js +1 -0
- package/dist/server/constants.js.map +1 -0
- package/dist/server/format.js +48 -0
- package/dist/server/format.js.map +1 -0
- package/dist/server/index.js +10 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/injectables.js +22 -0
- package/dist/server/injectables.js.map +1 -0
- package/dist/server/protocol.js +293 -0
- package/dist/server/protocol.js.map +1 -0
- package/dist/server/registry.js +19 -0
- package/dist/server/registry.js.map +1 -0
- package/dist/server/stream.js +30 -0
- package/dist/server/stream.js.map +1 -0
- package/dist/server/transport.js +7 -0
- package/dist/server/transport.js.map +1 -0
- package/dist/server/utils.js +10 -0
- package/dist/server/utils.js.map +1 -0
- package/lib/client/events.ts +66 -0
- package/lib/client/format.ts +22 -0
- package/lib/client/index.ts +4 -0
- package/lib/client/protocol.ts +440 -0
- package/lib/client/stream.ts +116 -0
- package/lib/common/binary.ts +60 -0
- package/lib/common/blob.ts +70 -0
- package/lib/common/enums.ts +46 -0
- package/lib/common/index.ts +4 -0
- package/lib/common/types.ts +64 -0
- package/lib/server/api.ts +47 -0
- package/lib/server/connection.ts +57 -0
- package/lib/server/constants.ts +4 -0
- package/lib/server/format.ts +107 -0
- package/lib/server/index.ts +10 -0
- package/lib/server/injectables.ts +51 -0
- package/lib/server/protocol.ts +422 -0
- package/lib/server/registry.ts +24 -0
- package/lib/server/stream.ts +43 -0
- package/lib/server/transport.ts +36 -0
- package/lib/server/utils.ts +22 -0
- package/package.json +39 -0
- package/tsconfig.json +3 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// TODO: get rid of lib DOM somehow...
|
|
2
|
+
/// <reference lib="dom" />
|
|
3
|
+
|
|
4
|
+
const utf8decoder = new TextDecoder()
|
|
5
|
+
const utf8encoder = new TextEncoder()
|
|
6
|
+
|
|
7
|
+
export type BinaryTypes = {
|
|
8
|
+
Int8: number
|
|
9
|
+
Int16: number
|
|
10
|
+
Int32: number
|
|
11
|
+
Uint8: number
|
|
12
|
+
Uint16: number
|
|
13
|
+
Uint32: number
|
|
14
|
+
Float32: number
|
|
15
|
+
Float64: number
|
|
16
|
+
BigInt64: bigint
|
|
17
|
+
BigUint64: bigint
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const encodeNumber = <T extends keyof BinaryTypes>(
|
|
21
|
+
value: BinaryTypes[T],
|
|
22
|
+
type: T,
|
|
23
|
+
littleEndian = false,
|
|
24
|
+
) => {
|
|
25
|
+
const bytesNeeded = globalThis[`${type}Array`].BYTES_PER_ELEMENT
|
|
26
|
+
const ab = new ArrayBuffer(bytesNeeded)
|
|
27
|
+
const dv = new DataView(ab)
|
|
28
|
+
dv[`set${type}`](0, value as never, littleEndian)
|
|
29
|
+
return ab
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const decodeNumber = <T extends keyof BinaryTypes>(
|
|
33
|
+
buffer: ArrayBuffer,
|
|
34
|
+
type: T,
|
|
35
|
+
offset = 0,
|
|
36
|
+
littleEndian = false,
|
|
37
|
+
): BinaryTypes[T] => {
|
|
38
|
+
const view = new DataView(buffer)
|
|
39
|
+
return view[`get${type}`](offset, littleEndian) as BinaryTypes[T]
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const encodeText = (text: string) =>
|
|
43
|
+
new Uint8Array(utf8encoder.encode(text)).buffer as ArrayBuffer
|
|
44
|
+
|
|
45
|
+
export const decodeText = (buffer: Parameters<typeof utf8decoder.decode>[0]) =>
|
|
46
|
+
utf8decoder.decode(buffer)
|
|
47
|
+
|
|
48
|
+
export const concat = (...buffers: ArrayBuffer[]) => {
|
|
49
|
+
const totalLength = buffers.reduce(
|
|
50
|
+
(acc, buffer) => acc + buffer.byteLength,
|
|
51
|
+
0,
|
|
52
|
+
)
|
|
53
|
+
const view = new Uint8Array(totalLength)
|
|
54
|
+
let offset = 0
|
|
55
|
+
for (const buffer of buffers) {
|
|
56
|
+
view.set(new Uint8Array(buffer), offset)
|
|
57
|
+
offset += buffer.byteLength
|
|
58
|
+
}
|
|
59
|
+
return view.buffer
|
|
60
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export type ProtocolBlobMetadata = {
|
|
2
|
+
type: string
|
|
3
|
+
size: number
|
|
4
|
+
filename?: string
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface ProtocolBlobInterface {
|
|
8
|
+
readonly metadata: ProtocolBlobMetadata
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class ProtocolBlob implements ProtocolBlobInterface {
|
|
12
|
+
public readonly metadata: ProtocolBlobMetadata
|
|
13
|
+
public readonly source: any
|
|
14
|
+
|
|
15
|
+
constructor(
|
|
16
|
+
source: any,
|
|
17
|
+
size = -1,
|
|
18
|
+
type = 'application/octet-stream',
|
|
19
|
+
filename?: string,
|
|
20
|
+
) {
|
|
21
|
+
if (size < -1 || size === 0) throw new Error('Blob size is invalid')
|
|
22
|
+
|
|
23
|
+
this.source = source
|
|
24
|
+
this.metadata = {
|
|
25
|
+
size,
|
|
26
|
+
type,
|
|
27
|
+
filename,
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static from(
|
|
32
|
+
source: any,
|
|
33
|
+
metadata: {
|
|
34
|
+
size?: number
|
|
35
|
+
type?: string
|
|
36
|
+
filename?: string
|
|
37
|
+
} = {},
|
|
38
|
+
) {
|
|
39
|
+
let _source: any = undefined
|
|
40
|
+
|
|
41
|
+
if (source instanceof globalThis.ReadableStream) {
|
|
42
|
+
_source = source
|
|
43
|
+
} else if ('File' in globalThis && source instanceof globalThis.File) {
|
|
44
|
+
_source = source.stream()
|
|
45
|
+
metadata.size = source.size
|
|
46
|
+
metadata.filename = source.name
|
|
47
|
+
} else if (source instanceof globalThis.Blob) {
|
|
48
|
+
_source = source.stream()
|
|
49
|
+
metadata.size = source.size
|
|
50
|
+
} else if (typeof source === 'string') {
|
|
51
|
+
const blob = new Blob([source])
|
|
52
|
+
_source = blob.stream()
|
|
53
|
+
metadata.size = blob.size
|
|
54
|
+
metadata.type = metadata.type || 'text/plain'
|
|
55
|
+
} else if (source instanceof globalThis.ArrayBuffer) {
|
|
56
|
+
const blob = new Blob([source])
|
|
57
|
+
_source = blob.stream()
|
|
58
|
+
metadata.size = blob.size
|
|
59
|
+
} else {
|
|
60
|
+
_source = source
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return new ProtocolBlob(
|
|
64
|
+
_source,
|
|
65
|
+
metadata.size,
|
|
66
|
+
metadata.type,
|
|
67
|
+
metadata.filename,
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export enum ClientMessageType {
|
|
2
|
+
Rpc = 10,
|
|
3
|
+
RpcAbort = 11,
|
|
4
|
+
RpcStreamAbort = 12,
|
|
5
|
+
|
|
6
|
+
ClientStreamPush = 20,
|
|
7
|
+
ClientStreamEnd = 21,
|
|
8
|
+
ClientStreamAbort = 22,
|
|
9
|
+
ServerStreamAbort = 23,
|
|
10
|
+
ServerStreamPull = 24,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export enum ServerMessageType {
|
|
14
|
+
Event = 1,
|
|
15
|
+
|
|
16
|
+
RpcResponse = 10,
|
|
17
|
+
RpcStreamResponse = 11,
|
|
18
|
+
RpcStreamChunk = 12,
|
|
19
|
+
RpcStreamAbort = 13,
|
|
20
|
+
|
|
21
|
+
ServerStreamPush = 20,
|
|
22
|
+
ServerStreamEnd = 21,
|
|
23
|
+
ServerStreamAbort = 22,
|
|
24
|
+
ClientStreamAbort = 23,
|
|
25
|
+
ClientStreamPull = 24,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export enum TransportType {
|
|
29
|
+
Bidirectional = 'Bidirectional',
|
|
30
|
+
Unidirectional = 'Unidirectional',
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export enum ErrorCode {
|
|
34
|
+
ValidationError = 'ValidationError',
|
|
35
|
+
BadRequest = 'BadRequest',
|
|
36
|
+
NotFound = 'NotFound',
|
|
37
|
+
Forbidden = 'Forbidden',
|
|
38
|
+
Unauthorized = 'Unauthorized',
|
|
39
|
+
InternalServerError = 'InternalServerError',
|
|
40
|
+
NotAcceptable = 'NotAcceptable',
|
|
41
|
+
RequestTimeout = 'RequestTimeout',
|
|
42
|
+
GatewayTimeout = 'GatewayTimeout',
|
|
43
|
+
ServiceUnavailable = 'ServiceUnavailable',
|
|
44
|
+
ClientRequestError = 'ClientRequestError',
|
|
45
|
+
ConnectionError = 'ConnectionError',
|
|
46
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ProtocolServerBlobStream } from '../client/stream.ts'
|
|
2
|
+
import type {
|
|
3
|
+
ProtocolBlob,
|
|
4
|
+
ProtocolBlobInterface,
|
|
5
|
+
ProtocolBlobMetadata,
|
|
6
|
+
} from './blob.ts'
|
|
7
|
+
|
|
8
|
+
export type ProtocolRPC = {
|
|
9
|
+
callId: number
|
|
10
|
+
namespace: string
|
|
11
|
+
procedure: string
|
|
12
|
+
payload: any
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type ProtocolRPCResponse =
|
|
16
|
+
| {
|
|
17
|
+
callId: number
|
|
18
|
+
error: any
|
|
19
|
+
payload?: never
|
|
20
|
+
}
|
|
21
|
+
| {
|
|
22
|
+
callId: number
|
|
23
|
+
payload: any
|
|
24
|
+
error?: never
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface EncodeRPCContext {
|
|
28
|
+
getStream: (id: number) => any
|
|
29
|
+
addStream: (blob: ProtocolBlob) => {
|
|
30
|
+
id: number
|
|
31
|
+
metadata: ProtocolBlobMetadata
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface DecodeRPCContext {
|
|
36
|
+
getStream: (id: number) => any
|
|
37
|
+
addStream: (id: number, metadata: ProtocolBlobMetadata) => any
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface BaseClientDecoder {
|
|
41
|
+
decode(buffer: ArrayBuffer): any
|
|
42
|
+
decodeRPC(buffer: ArrayBuffer, context: DecodeRPCContext): ProtocolRPCResponse
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface BaseClientEncoder {
|
|
46
|
+
encode(data: any): ArrayBuffer
|
|
47
|
+
encodeRPC(rpc: ProtocolRPC, context: EncodeRPCContext): ArrayBuffer
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type InputType<T> = T extends any[]
|
|
51
|
+
? InputType<T[number]>[]
|
|
52
|
+
: T extends ProtocolBlobInterface
|
|
53
|
+
? ProtocolBlob
|
|
54
|
+
: T extends object
|
|
55
|
+
? { [K in keyof T]: InputType<T[K]> }
|
|
56
|
+
: T
|
|
57
|
+
|
|
58
|
+
export type OutputType<T> = T extends any[]
|
|
59
|
+
? OutputType<T[number]>[]
|
|
60
|
+
: T extends ProtocolBlobInterface
|
|
61
|
+
? ProtocolServerBlobStream
|
|
62
|
+
: T extends object
|
|
63
|
+
? { [K in keyof T]: OutputType<T[K]> }
|
|
64
|
+
: T
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Container } from '@nmtjs/core'
|
|
2
|
+
import type { Hook } from '@nmtjs/core'
|
|
3
|
+
import type { Connection } from './connection.ts'
|
|
4
|
+
|
|
5
|
+
export type ProtocolApiCallOptions = {
|
|
6
|
+
connection: Connection
|
|
7
|
+
namespace: string
|
|
8
|
+
procedure: string
|
|
9
|
+
container: Container
|
|
10
|
+
payload: any
|
|
11
|
+
signal: AbortSignal
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type ProtocolAnyIterable<T> =
|
|
15
|
+
| (() => AsyncGenerator<T>)
|
|
16
|
+
// | (() => Generator<T>)
|
|
17
|
+
| AsyncIterable<T>
|
|
18
|
+
// | Iterable<T>
|
|
19
|
+
|
|
20
|
+
export interface ProtocolApiCallBaseResult {
|
|
21
|
+
output: unknown
|
|
22
|
+
}
|
|
23
|
+
export interface ProtocolApiCallSubscriptionResult
|
|
24
|
+
extends ProtocolApiCallBaseResult {
|
|
25
|
+
subscription: never
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ProtocolApiCallIterableResult
|
|
29
|
+
extends ProtocolApiCallBaseResult {
|
|
30
|
+
iterable: ProtocolAnyIterable<unknown>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type ProtocolApiCallResult =
|
|
34
|
+
| ProtocolApiCallBaseResult
|
|
35
|
+
| ProtocolApiCallSubscriptionResult
|
|
36
|
+
| ProtocolApiCallIterableResult
|
|
37
|
+
|
|
38
|
+
export interface ProtocolApi {
|
|
39
|
+
call(options: ProtocolApiCallOptions): Promise<ProtocolApiCallResult>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
declare module '@nmtjs/core' {
|
|
43
|
+
export interface HookType {
|
|
44
|
+
[Hook.OnConnect]: (connection: Connection) => any
|
|
45
|
+
[Hook.OnDisconnect]: (connection: Connection) => any
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto'
|
|
2
|
+
// import type { TAnyEventContract } from '@nmtjs/contract'
|
|
3
|
+
import type { InteractivePromise } from '@nmtjs/common'
|
|
4
|
+
import type { Container } from '@nmtjs/core'
|
|
5
|
+
import type { ProtocolApiCallResult } from './api.ts'
|
|
6
|
+
import type { BaseServerDecoder, BaseServerEncoder } from './format.ts'
|
|
7
|
+
import type { ProtocolClientStream, ProtocolServerStream } from './stream.ts'
|
|
8
|
+
|
|
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
|
+
export type ConnectionOptions<Data = unknown> = {
|
|
21
|
+
id?: string
|
|
22
|
+
data: Data
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class Connection<Data = unknown> {
|
|
26
|
+
readonly id: string
|
|
27
|
+
readonly data: Data
|
|
28
|
+
|
|
29
|
+
constructor(options: ConnectionOptions<Data>) {
|
|
30
|
+
this.id = options.id ?? randomUUID()
|
|
31
|
+
this.data = options.data
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type ConnectionCall<T = unknown> = InteractivePromise<T> & {
|
|
36
|
+
abort: AbortController['abort']
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export class ConnectionContext {
|
|
40
|
+
streamId = 1
|
|
41
|
+
calls = new Map<number, ConnectionCall<ProtocolApiCallResult>>()
|
|
42
|
+
clientStreams = new Map<number, ProtocolClientStream>()
|
|
43
|
+
serverStreams = new Map<number, ProtocolServerStream>()
|
|
44
|
+
container: Container
|
|
45
|
+
format: {
|
|
46
|
+
encoder: BaseServerEncoder
|
|
47
|
+
decoder: BaseServerDecoder
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
constructor(
|
|
51
|
+
container: ConnectionContext['container'],
|
|
52
|
+
format: ConnectionContext['format'],
|
|
53
|
+
) {
|
|
54
|
+
this.container = container
|
|
55
|
+
this.format = format
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { type Pattern, match } from '@nmtjs/core'
|
|
2
|
+
import type {
|
|
3
|
+
DecodeRPCContext,
|
|
4
|
+
EncodeRPCContext,
|
|
5
|
+
ProtocolRPC,
|
|
6
|
+
ProtocolRPCResponse,
|
|
7
|
+
} from '../common/types.ts'
|
|
8
|
+
|
|
9
|
+
export interface BaseServerDecoder {
|
|
10
|
+
accept: Pattern[]
|
|
11
|
+
decode(buffer: ArrayBuffer): any
|
|
12
|
+
decodeRPC(buffer: ArrayBuffer, context: DecodeRPCContext): ProtocolRPC
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface BaseServerEncoder {
|
|
16
|
+
contentType: string
|
|
17
|
+
encode(data: any): ArrayBuffer
|
|
18
|
+
encodeRPC(rpc: ProtocolRPCResponse, context: EncodeRPCContext): ArrayBuffer
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export abstract class BaseServerFormat
|
|
22
|
+
implements BaseServerDecoder, BaseServerEncoder
|
|
23
|
+
{
|
|
24
|
+
abstract accept: Pattern[]
|
|
25
|
+
abstract contentType: string
|
|
26
|
+
|
|
27
|
+
abstract encode(data: any): ArrayBuffer
|
|
28
|
+
abstract encodeRPC(
|
|
29
|
+
rpc: ProtocolRPCResponse,
|
|
30
|
+
context: EncodeRPCContext,
|
|
31
|
+
): ArrayBuffer
|
|
32
|
+
abstract decode(buffer: ArrayBuffer): any
|
|
33
|
+
abstract decodeRPC(
|
|
34
|
+
buffer: ArrayBuffer,
|
|
35
|
+
context: DecodeRPCContext,
|
|
36
|
+
): ProtocolRPC
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const parseContentTypes = (types: string) => {
|
|
40
|
+
if (types === '*/*') return ['*/*']
|
|
41
|
+
return types
|
|
42
|
+
.split(',')
|
|
43
|
+
.map((t) => {
|
|
44
|
+
const [type, ...rest] = t.split(';')
|
|
45
|
+
const params = new Map(
|
|
46
|
+
rest.map((p) =>
|
|
47
|
+
p
|
|
48
|
+
.trim()
|
|
49
|
+
.split('=')
|
|
50
|
+
.slice(0, 2)
|
|
51
|
+
.map((p) => p.trim()),
|
|
52
|
+
) as [string, string][],
|
|
53
|
+
)
|
|
54
|
+
return {
|
|
55
|
+
type,
|
|
56
|
+
q: params.has('q') ? Number.parseFloat(params.get('q')!) : 1,
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
.sort((a, b) => {
|
|
60
|
+
if (a.type === '*/*') return 1
|
|
61
|
+
if (b.type === '*/*') return -1
|
|
62
|
+
return b.q - a.q ? -1 : 1
|
|
63
|
+
})
|
|
64
|
+
.map((t) => t.type)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export class Format {
|
|
68
|
+
decoders = new Map<Pattern, BaseServerDecoder>()
|
|
69
|
+
encoders = new Map<Pattern, BaseServerEncoder>()
|
|
70
|
+
|
|
71
|
+
constructor(formats: BaseServerFormat[]) {
|
|
72
|
+
for (const format of formats) {
|
|
73
|
+
this.encoders.set(format.contentType, format)
|
|
74
|
+
for (const acceptType of format.accept) {
|
|
75
|
+
this.decoders.set(acceptType, format)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
supportsDecoder(contentType: string, throwIfUnsupported = false) {
|
|
81
|
+
return this.supports(this.decoders, contentType, throwIfUnsupported)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
supportsEncoder(contentType: string, throwIfUnsupported = false) {
|
|
85
|
+
return this.supports(this.encoders, contentType, throwIfUnsupported)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private supports<T extends BaseServerEncoder | BaseServerDecoder>(
|
|
89
|
+
formats: Map<Pattern, T>,
|
|
90
|
+
contentType: string,
|
|
91
|
+
throwIfUnsupported = false,
|
|
92
|
+
): T | null {
|
|
93
|
+
// TODO: Use node:utils.MIMEType (not implemented yet in Deno and Bun yet)
|
|
94
|
+
const types = parseContentTypes(contentType)
|
|
95
|
+
|
|
96
|
+
for (const type of types) {
|
|
97
|
+
for (const [pattern, format] of formats) {
|
|
98
|
+
if (type === '*/*' || match(type, pattern)) return format
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (throwIfUnsupported)
|
|
103
|
+
throw new Error(`No supported format found: ${contentType}`)
|
|
104
|
+
|
|
105
|
+
return null
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from './api.ts'
|
|
2
|
+
export * from './connection.ts'
|
|
3
|
+
export * from './constants.ts'
|
|
4
|
+
export * from './injectables.ts'
|
|
5
|
+
export * from './format.ts'
|
|
6
|
+
export * from './protocol.ts'
|
|
7
|
+
export * from './registry.ts'
|
|
8
|
+
export * from './stream.ts'
|
|
9
|
+
export * from './transport.ts'
|
|
10
|
+
export * from './utils.ts'
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Scope,
|
|
3
|
+
createFactoryInjectable,
|
|
4
|
+
createLazyInjectable,
|
|
5
|
+
} from '@nmtjs/core'
|
|
6
|
+
|
|
7
|
+
const connection = createLazyInjectable<unknown, Scope.Connection>(
|
|
8
|
+
Scope.Connection,
|
|
9
|
+
'RPC connection',
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
const connectionData = createLazyInjectable<unknown, Scope.Connection>(
|
|
13
|
+
Scope.Connection,
|
|
14
|
+
"RPC connection's data",
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
const transportStopSignal = createLazyInjectable<AbortSignal>(
|
|
18
|
+
Scope.Global,
|
|
19
|
+
'Transport stop signal',
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
const rpcClientAbortSignal = createLazyInjectable<AbortSignal, Scope.Call>(
|
|
23
|
+
Scope.Call,
|
|
24
|
+
'RPC client abort signal',
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
const rpcTimeoutSignal = createLazyInjectable<AbortSignal, Scope.Call>(
|
|
28
|
+
Scope.Call,
|
|
29
|
+
'RPC timeout signal',
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
const rpcAbortSignal = createFactoryInjectable(
|
|
33
|
+
{
|
|
34
|
+
dependencies: {
|
|
35
|
+
rpcTimeoutSignal,
|
|
36
|
+
rpcClientAbortSignal,
|
|
37
|
+
transportStopSignal,
|
|
38
|
+
},
|
|
39
|
+
factory: (ctx) => AbortSignal.any(Object.values(ctx)),
|
|
40
|
+
},
|
|
41
|
+
'Any RPC abort signal',
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
export const ProtocolInjectables = {
|
|
45
|
+
connection,
|
|
46
|
+
connectionData,
|
|
47
|
+
transportStopSignal,
|
|
48
|
+
rpcClientAbortSignal,
|
|
49
|
+
rpcTimeoutSignal,
|
|
50
|
+
rpcAbortSignal,
|
|
51
|
+
} as const
|