@nmtjs/client 0.5.3 → 0.6.1

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/lib/client.ts DELETED
@@ -1,140 +0,0 @@
1
- import { type BaseClientFormat, ErrorCode } from '@nmtjs/common'
2
-
3
- import type { TServiceContract } from '@nmtjs/contract'
4
- import { ClientError } from './common.ts'
5
- import type { ClientTransport } from './transport.ts'
6
- import type { ClientCallOptions } from './types.ts'
7
- import * as utils from './utils.ts'
8
-
9
- export type ClientOptions = {
10
- defaultTimeout: number
11
- debug?: boolean
12
- }
13
-
14
- export type ClientServices = Record<string, TServiceContract>
15
-
16
- export abstract class Client extends utils.EventEmitter {
17
- protected transport!: ClientTransport
18
- protected format!: BaseClientFormat
19
-
20
- auth?: string
21
-
22
- private ids = {
23
- call: 0,
24
- stream: 0,
25
- }
26
-
27
- constructor(
28
- protected readonly options: ClientOptions,
29
- protected services: string[],
30
- ) {
31
- super()
32
- if (!options.defaultTimeout) options.defaultTimeout = 15000
33
- }
34
-
35
- useTransport<T extends new (...args: any[]) => ClientTransport>(
36
- transportClass: T,
37
- ...options: ConstructorParameters<T>
38
- ) {
39
- this.transport = new transportClass(...options)
40
- this.transport.client = Object.freeze({
41
- services: this.services,
42
- format: this.format,
43
- auth: this.auth,
44
- })
45
- this.checkTransport(this.transport)
46
- return this as Omit<this, 'useTransport'>
47
- }
48
-
49
- useFormat(format: BaseClientFormat) {
50
- this.format = format
51
- return this as Omit<this, 'useFormat'>
52
- }
53
-
54
- async connect() {
55
- await this.transport.connect()
56
- }
57
-
58
- async disconnect() {
59
- await this.transport.disconnect()
60
- }
61
-
62
- async reconnect() {
63
- await this.disconnect()
64
- await this.connect()
65
- }
66
-
67
- protected checkTransport(transport: ClientTransport) {}
68
-
69
- protected createCaller(
70
- service: string,
71
- procedure: string,
72
- {
73
- timeout = this.options.defaultTimeout,
74
- transformInput,
75
- transformOutput,
76
- }: {
77
- timeout?: number
78
- transformInput?: (input: any) => any
79
- transformOutput?: (output: any) => any
80
- } = {},
81
- ) {
82
- return async (payload: any, options: ClientCallOptions = {}) => {
83
- const { signal } = options
84
-
85
- const abortSignal = signal
86
- ? AbortSignal.any([signal, AbortSignal.timeout(timeout)])
87
- : AbortSignal.timeout(timeout)
88
-
89
- const callId = ++this.ids.call
90
-
91
- if (this.options.debug) {
92
- console.groupCollapsed(`RPC [${callId}] ${service}/${procedure}`)
93
- console.log(payload)
94
- console.groupEnd()
95
- }
96
-
97
- const callExecution = this.transport
98
- .rpc({
99
- callId,
100
- service,
101
- procedure,
102
- payload: transformInput ? transformInput(payload) : payload,
103
- signal: abortSignal,
104
- })
105
- .then((result) => {
106
- if (result.success) return result.value
107
- throw new ClientError(
108
- result.error.code,
109
- result.error.message,
110
- result.error.data,
111
- )
112
- })
113
-
114
- const callTimeout = utils.forAborted(abortSignal).catch(() => {
115
- const error = new ClientError(ErrorCode.RequestTimeout)
116
- return Promise.reject(error)
117
- })
118
-
119
- try {
120
- const response = await Promise.race([callTimeout, callExecution])
121
-
122
- if (this.options.debug) {
123
- console.groupCollapsed(`RPC [${callId}] Success`)
124
- console.log(response)
125
- console.groupEnd()
126
- }
127
-
128
- return transformOutput ? transformOutput(response) : response
129
- } catch (error) {
130
- if (this.options.debug) {
131
- console.groupCollapsed(`RPC [${callId}] Error`)
132
- console.log(error)
133
- console.groupEnd()
134
- }
135
-
136
- throw error
137
- }
138
- }
139
- }
140
- }
package/lib/stream.ts DELETED
@@ -1,72 +0,0 @@
1
- import type { ApiBlob, ApiBlobMetadata } from '@nmtjs/common'
2
- import type { AnyFn } from './utils.ts'
3
-
4
- export class ClientUpStream {
5
- readonly reader: ReadableStreamBYOBReader
6
-
7
- constructor(
8
- readonly id: number,
9
- readonly blob: ApiBlob,
10
- ) {
11
- if (this.blob.source instanceof ReadableStream === false)
12
- throw new Error('Blob source is not a ReadableStream')
13
- this.reader = this.blob.source.getReader({ mode: 'byob' })
14
- }
15
- }
16
-
17
- export type ClientDownStreamBlob = {
18
- readonly metadata: ApiBlobMetadata
19
- readonly stream: ReadableStream<Uint8Array>
20
- }
21
-
22
- export type ClientDownStreamWrapper = {
23
- writer: WritableStreamDefaultWriter
24
- blob: ClientDownStreamBlob
25
- }
26
-
27
- export const createClientDownStream = (
28
- metadata: ApiBlobMetadata,
29
- pull: AnyFn,
30
- ): ClientDownStreamWrapper => {
31
- let bytes = 0
32
-
33
- const { readable, writable } = new TransformStream<Uint8Array, Uint8Array>(
34
- {
35
- start: () => pull,
36
- transform(chunk, controller) {
37
- if (metadata.size !== -1) {
38
- bytes += chunk.byteLength
39
- if (bytes > metadata.size) {
40
- const error = new Error('Stream size exceeded')
41
- controller.error(error)
42
- } else {
43
- try {
44
- controller.enqueue(chunk)
45
- } catch (error) {
46
- console.error(error)
47
- }
48
- }
49
- } else {
50
- controller.enqueue(chunk)
51
- }
52
- },
53
- },
54
- { highWaterMark: 1 },
55
- )
56
-
57
- const writer = writable.getWriter()
58
-
59
- const blob: ClientDownStreamBlob = {
60
- get metadata() {
61
- return metadata
62
- },
63
- get stream() {
64
- return readable
65
- },
66
- }
67
-
68
- return {
69
- blob,
70
- writer,
71
- }
72
- }
@@ -1,12 +0,0 @@
1
- import { EventEmitter, type EventMap } from './utils.ts'
2
-
3
- export class Subscription<
4
- Events extends EventMap = EventMap,
5
- > extends EventEmitter<Events> {
6
- constructor(
7
- readonly key: string,
8
- readonly unsubscribe: () => void,
9
- ) {
10
- super()
11
- }
12
- }
package/lib/transport.ts DELETED
@@ -1,40 +0,0 @@
1
- import type { BaseClientFormat } from '@nmtjs/common'
2
- import { EventEmitter, type EventMap } from './utils.ts'
3
-
4
- export type ClientTransportRpcCall = {
5
- service: string
6
- procedure: string
7
- callId: number
8
- payload: any
9
- signal: AbortSignal
10
- }
11
-
12
- export type ClientTransportRpcResult =
13
- | {
14
- success: false
15
- error: { code: string; message?: string; data?: any }
16
- }
17
- | {
18
- success: true
19
- value: any
20
- }
21
-
22
- export abstract class ClientTransport<
23
- T extends EventMap = EventMap,
24
- > extends EventEmitter<
25
- T & { event: [service: string, event: string, payload: any] }
26
- > {
27
- abstract type: string
28
-
29
- client!: {
30
- readonly services: string[]
31
- readonly format: BaseClientFormat
32
- readonly auth?: string
33
- }
34
-
35
- abstract connect(): Promise<void>
36
- abstract disconnect(): Promise<void>
37
- abstract rpc(
38
- params: ClientTransportRpcCall,
39
- ): Promise<ClientTransportRpcResult>
40
- }
package/lib/utils.ts DELETED
@@ -1,65 +0,0 @@
1
- export type AnyFn = (...args: any[]) => any
2
-
3
- export type EventMap = { [K: string]: any[] }
4
-
5
- export function forAborted(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
- /**
19
- * Very simple node-like event emitter wrapper around EventTarget
20
- *
21
- * @todo add errors and promise rejections handling
22
- */
23
- export class EventEmitter<
24
- Events extends EventMap = EventMap,
25
- EventNames extends Extract<keyof Events, string> = Extract<
26
- keyof Events,
27
- string
28
- >,
29
- > {
30
- #target = new EventTarget()
31
- #listeners = new Map<AnyFn, AnyFn>()
32
-
33
- on<E extends EventNames>(
34
- event: E | (Object & string),
35
- listener: (...args: Events[E]) => void,
36
- options?: AddEventListenerOptions,
37
- ) {
38
- const wrapper = (event) => listener(...event.detail)
39
- this.#listeners.set(listener, wrapper)
40
- this.#target.addEventListener(event, wrapper, options)
41
- return () => this.#target.removeEventListener(event, wrapper)
42
- }
43
-
44
- once<E extends EventNames>(
45
- event: E | (Object & string),
46
- listener: (...args: Events[E]) => void,
47
- ) {
48
- return this.on(event, listener, { once: true })
49
- }
50
-
51
- off(event: EventNames | (Object & string), listener: AnyFn) {
52
- const wrapper = this.#listeners.get(listener)
53
- if (wrapper) this.#target.removeEventListener(event, wrapper)
54
- }
55
-
56
- emit<E extends EventNames | (Object & string)>(
57
- event: E,
58
- ...args: E extends EventEmitter ? Events[E] : any[]
59
- ) {
60
- return this.#target.dispatchEvent(new CustomEvent(event, { detail: args }))
61
- }
62
- }
63
-
64
- export const once = (ee: EventEmitter, event: string) =>
65
- new Promise((resolve) => ee.once(event, resolve))
File without changes