nydus-client 5.0.0 → 5.1.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/dist/index.d.ts +5 -0
- package/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/package.json +14 -16
package/dist/index.d.ts
CHANGED
|
@@ -81,6 +81,11 @@ type NydusEvents = {
|
|
|
81
81
|
}) => void;
|
|
82
82
|
/** Fired when a general error occurs. */
|
|
83
83
|
error: (err: Error) => void;
|
|
84
|
+
/**
|
|
85
|
+
* Fired when the server returns a 403 on connect. The client will not continue attempting
|
|
86
|
+
* to reconnect after this.
|
|
87
|
+
*/
|
|
88
|
+
unauthorized: () => void;
|
|
84
89
|
/** Fired when the connection attempt times out. */
|
|
85
90
|
connect_timeout: () => void;
|
|
86
91
|
/** Fired when the reconnection attempts exceeded the maximum allowed without success. */
|
package/dist/index.js
CHANGED
|
@@ -218,10 +218,15 @@ var NydusClient = class extends TypedEventEmitter {
|
|
|
218
218
|
onError(err) {
|
|
219
219
|
this.clearConnectTimer();
|
|
220
220
|
if (isTransportError(err) && err.message === "xhr poll error") {
|
|
221
|
-
|
|
221
|
+
if (err.description === 403) {
|
|
222
|
+
this.skipReconnect = true;
|
|
223
|
+
this.emit("unauthorized");
|
|
224
|
+
} else {
|
|
225
|
+
this.onClose("error", err);
|
|
226
|
+
}
|
|
222
227
|
return;
|
|
223
228
|
}
|
|
224
|
-
if (this.skipReconnect && isTransportError(err) && err.description && err.description.message && /closed before the connection (was|is) established/.test(err.description.message)) {
|
|
229
|
+
if (this.skipReconnect && isTransportError(err) && err.description && typeof err.description !== "number" && err.description.message && /closed before the connection (was|is) established/.test(err.description.message)) {
|
|
225
230
|
return;
|
|
226
231
|
}
|
|
227
232
|
this.emit("error", err);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../index.ts","../typed-emitter.ts"],"sourcesContent":["import Backoff from 'backo2'\nimport { Socket as EngineIoSocket, SocketOptions as EngineIoSocketOptions } from 'engine.io-client'\nimport { nanoid } from 'nanoid'\nimport {\n decode,\n encode,\n MessageType,\n NydusErrorMessage,\n NydusPublishMessage,\n NydusResultMessage,\n protocolVersion,\n} from 'nydus-protocol'\nimport ruta from 'ruta3'\nimport { TypedEventEmitter } from './typed-emitter'\n\nexport { protocolVersion }\n\nexport interface NydusClientOptions extends EngineIoSocketOptions {\n /**\n * How long before a connection attempt should be considered failed. Optional, will not timeout\n * if not specified.\n */\n connectTimeout?: number\n /** How many times to attempt to reconnect before giving up. */\n reconnectionAttempts: number\n /**\n * How long to wait before attempting to reconnect, in milliseconds. This time will be backed off\n * if successive attempts fail.\n */\n reconnectionDelay: number\n /**\n * The maximum amount of time to wait before attempting to reconnect, in milliseconds, when backed\n * off. */\n reconnectionDelayMax: number\n /**\n * How much to jitter reconnection attempts, to avoid all clients connecting at once. This value\n * should be between 0 and 1.\n */\n reconnectionJitter: number\n}\n\ninterface ExpandedSocket extends Omit<EngineIoSocket, 'readyState'> {\n readonly readyState: string\n}\n\ninterface TransportError extends Error {\n readonly type: 'TransportError'\n readonly description: Error\n}\n\nfunction isTransportError(err: Error): err is TransportError {\n return (err as any).type === 'TransportError'\n}\n\nexport interface RouteInfo {\n route: string\n params: Record<string, string>\n splats: string[]\n}\n\nexport type RouteHandler = (routeInfo: RouteInfo, data: any) => void\n\ntype NydusEvents = {\n /** Fired when the connection succeeds. */\n connect: () => void\n /** Fired when the connection has been closed */\n disconnect: (reason: string, details?: Error) => void\n /** Fired when a reconnect attempt is being initiated. */\n reconnecting: (attempts: number) => void\n /** Fired when a publish occurred that wasn't handled by any registered routes. */\n unhandled: (published: { path: string; data: any }) => void\n\n /** Fired when a general error occurs. */\n error: (err: Error) => void\n /** Fired when the connection attempt times out. */\n\n connect_timeout: () => void\n /** Fired when the reconnection attempts exceeded the maximum allowed without success. */\n\n reconnect_failed: () => void\n /** Fired when the connection attempt failed. */\n\n connect_failed: () => void\n}\n\nexport class InvokeError extends Error {\n readonly status: number\n readonly body: any\n\n constructor(message: string, status: number, body?: any) {\n super(message)\n this.status = status\n this.body = body\n }\n}\n\ntype PromiseCompleters = { resolve: (value: unknown) => void; reject: (reason: any) => void }\n\nexport class NydusClient extends TypedEventEmitter<NydusEvents> {\n readonly host: string\n readonly opts: Partial<NydusClientOptions>\n conn: ExpandedSocket | null = null\n\n private outstanding = new Map<string, PromiseCompleters>()\n private router = ruta<RouteHandler>()\n private backoff: Backoff\n\n private backoffTimer: ReturnType<typeof setTimeout> | null = null\n private connectTimer: ReturnType<typeof setTimeout> | null = null\n\n private wasOpened = false\n private skipReconnect = false\n private disconnectingPromise: Promise<void> | undefined = undefined\n private disconnectingResolver: (() => void) | undefined = undefined\n\n constructor(host: string, opts: Partial<NydusClientOptions> = {}) {\n super()\n this.host = host\n this.opts = opts\n\n this.opts.reconnectionAttempts = this.opts.reconnectionAttempts || Infinity\n this.backoff = new Backoff({\n min: opts.reconnectionDelay || 1000,\n max: opts.reconnectionDelayMax || 10000,\n jitter: opts.reconnectionJitter || 0.5,\n })\n }\n\n // One of: opening, open, closing, closed.\n get readyState() {\n return this.conn != null ? this.conn.readyState : 'closed'\n }\n\n private doConnect() {\n if (this.opts.connectTimeout) {\n this.connectTimer = setTimeout(() => {\n this.emit('connect_timeout')\n this.disconnect()\n this.skipReconnect = false\n this.onClose('connect timeout')\n }, this.opts.connectTimeout)\n }\n\n this.conn = new EngineIoSocket(this.host, this.opts) as unknown as ExpandedSocket\n this.conn\n .on('open', this.onOpen.bind(this))\n .on('message', data => this.onMessage(data as string))\n .on('close', this.onClose.bind(this) as any)\n .on('error', this.onError.bind(this) as any)\n }\n\n // Connect to the server. If already connected, this will be a no-op.\n connect() {\n if (this.conn) {\n // If the socket is closing, wait for it to close before connecting again\n if (this.conn.readyState === 'closing') {\n this.disconnectingPromise!.then(() => {\n this.connect()\n }).catch(_err => {})\n }\n return\n }\n\n this.skipReconnect = false\n this.wasOpened = false\n this.doConnect()\n }\n\n reconnect() {\n if (this.conn || this.skipReconnect || this.backoffTimer) {\n return\n }\n\n if (this.backoff.attempts >= this.opts.reconnectionAttempts!) {\n this.backoff.reset()\n this.emit('reconnect_failed')\n return\n }\n\n this.backoffTimer = setTimeout(() => {\n this.backoffTimer = null\n this.emit('reconnecting', this.backoff.attempts)\n\n if (this.skipReconnect || this.conn) return\n\n this.doConnect()\n }, this.backoff.duration())\n }\n\n // Disconnect from the server. If not already connected, this will be a no-op.\n disconnect() {\n this.skipReconnect = true\n if (this.backoffTimer) {\n clearTimeout(this.backoffTimer)\n this.backoffTimer = null\n }\n\n if (!this.conn) return\n\n if (!this.disconnectingPromise) {\n this.disconnectingPromise = new Promise<void>(resolve => {\n this.disconnectingResolver = resolve\n }).catch(_err => {})\n }\n\n this.conn.close()\n }\n\n /**\n * Registers a handler function to respond to PUBLISHes to paths matching a specified pattern.\n * Handlers are normal functions of the form:\n * `function({ route, params, splats }, data)`\n *\n * PUBLISHes that don't match a route will be emitted as an 'unhandled' event on this object,\n * which can be useful to track in development mode.\n */\n registerRoute(pathPattern: string, handler: RouteHandler) {\n this.router.addRoute(pathPattern, handler)\n }\n\n private onPublish({ path, data }: NydusPublishMessage<any>) {\n const route = this.router.match(path)\n if (!route) {\n this.emit('unhandled', { path, data })\n return\n }\n\n route.action({ route: route.route, params: route.params, splats: route.splats }, data)\n }\n\n /**\n * Invoke a remote method on the server, specified via a path. Optionally, data can be specified\n * to send along with the call (will be JSON encoded). A Promise will be returned, resolved or\n * rejected with the result or error (respectively) from the server.\n */\n invoke(path: string, data?: any) {\n const id = nanoid()\n return new Promise((resolve, reject) => {\n if (!this.conn) {\n reject(new Error('Not connected'))\n return\n }\n\n this.outstanding.set(id, { resolve, reject })\n this.conn.send(encode(MessageType.Invoke, data, id, path), undefined)\n })\n .catch(err => {\n // Convert error-like objects back to Errors\n if (err.message && err.status) {\n const converted = new InvokeError(err.message, err.status, err.body)\n throw converted\n }\n\n throw err\n })\n .finally(() => this.outstanding.delete(id))\n }\n\n private onInvokeResponse({ type, id, data }: NydusResultMessage<any> | NydusErrorMessage<any>) {\n const p = this.outstanding.get(id)\n if (!p) {\n this.emit('error', new Error('Unknown invoke id'))\n return\n }\n\n p[type === MessageType.Result ? 'resolve' : 'reject'](data)\n }\n\n private onOpen() {\n this.clearConnectTimer()\n this.wasOpened = true\n this.backoff.reset()\n this.emit('connect')\n }\n\n private onMessage(msg: string) {\n const decoded = decode(msg)\n switch (decoded.type) {\n case MessageType.ParserError:\n this.conn?.close() // will cause a call to _onClose\n break\n case MessageType.Welcome:\n if (decoded.data !== protocolVersion) {\n this.emit(\n 'error',\n new Error('Server has incompatible protocol version: ' + protocolVersion),\n )\n this.conn?.close()\n }\n break\n case MessageType.Result:\n case MessageType.Error:\n this.onInvokeResponse(decoded)\n break\n case MessageType.Publish:\n this.onPublish(decoded)\n break\n }\n }\n\n private onClose(reason: string, details?: Error) {\n this.clearConnectTimer()\n this.conn = null\n\n if (this.disconnectingResolver) {\n this.disconnectingResolver()\n this.disconnectingResolver = undefined\n this.disconnectingPromise = undefined\n }\n\n if (!this.wasOpened) {\n this.emit('connect_failed')\n this.reconnect()\n // Sockets can emit 'close' even if the connection was never actually opened. Don't emit emits\n // upstream in that case, since they're rather unnecessary\n return\n }\n\n this.emit('disconnect', reason, details)\n this.outstanding.clear()\n this.wasOpened = false\n this.reconnect()\n }\n\n private onError(err: Error | TransportError) {\n this.clearConnectTimer()\n if (isTransportError(err) && err.message === 'xhr poll error') {\n this.onClose('error', err)\n return\n }\n if (\n this.skipReconnect &&\n isTransportError(err) &&\n err.description &&\n err.description.message &&\n /closed before the connection (was|is) established/.test(err.description.message)\n ) {\n // ws sometimes throws errors if you disconnect a socket that was in the process of\n // reconnecting. Since the disconnect was requested (_skipReconnect is true), this seems\n // spurious, so we just ignore it\n return\n }\n\n this.emit('error', err)\n }\n\n clearConnectTimer() {\n if (this.connectTimer) {\n clearTimeout(this.connectTimer)\n this.connectTimer = null\n }\n }\n}\n\nexport default function createClient(host: string, opts?: Partial<NydusClientOptions>) {\n return new NydusClient(host, opts)\n}\n","import { EventEmitter } from 'events'\nimport { DefaultListener, TypedEmitter } from 'tiny-typed-emitter'\n\nexport type EventMap = DefaultListener\n\n/**\n * A typed version of the normal node EventEmitter class, such that emitted/handled events and\n * their associated parameters can be type-checked properly.\n *\n * This uses typed-emitter under the hood, it just makes it easier to extend.\n *\n * Example:\n * ```\n * type FooEvents = {\n * bar: (message: string) => void\n * baz: (count: number, ...extras: any[]) => void\n * }\n *\n * class Foo extends TypedEventEmitter<FooEvents> {\n * constructor() {\n * super()\n * }\n *\n * test() {\n * this.emit('bar', 'hello world')\n * this.emit('baz', 5, 'extra', 'stuff', 'to', 'pass', 27)\n * }\n * }\n * ```\n */\nexport abstract class TypedEventEmitter<T extends EventMap> extends (EventEmitter as {\n new <T extends EventMap>(): TypedEmitter<T>\n})<T> {\n constructor() {\n // NOTE(tec27): No idea why eslint thinks super isn't a constructor here, I assume it's failing\n // to parse things properly in some way\n // eslint-disable-next-line constructor-super\n super()\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../index.ts","../typed-emitter.ts"],"sourcesContent":["import Backoff from 'backo2'\nimport { Socket as EngineIoSocket, SocketOptions as EngineIoSocketOptions } from 'engine.io-client'\nimport { nanoid } from 'nanoid'\nimport {\n decode,\n encode,\n MessageType,\n NydusErrorMessage,\n NydusPublishMessage,\n NydusResultMessage,\n protocolVersion,\n} from 'nydus-protocol'\nimport ruta from 'ruta3'\nimport { TypedEventEmitter } from './typed-emitter'\n\nexport { protocolVersion }\n\nexport interface NydusClientOptions extends EngineIoSocketOptions {\n /**\n * How long before a connection attempt should be considered failed. Optional, will not timeout\n * if not specified.\n */\n connectTimeout?: number\n /** How many times to attempt to reconnect before giving up. */\n reconnectionAttempts: number\n /**\n * How long to wait before attempting to reconnect, in milliseconds. This time will be backed off\n * if successive attempts fail.\n */\n reconnectionDelay: number\n /**\n * The maximum amount of time to wait before attempting to reconnect, in milliseconds, when backed\n * off. */\n reconnectionDelayMax: number\n /**\n * How much to jitter reconnection attempts, to avoid all clients connecting at once. This value\n * should be between 0 and 1.\n */\n reconnectionJitter: number\n}\n\ninterface ExpandedSocket extends Omit<EngineIoSocket, 'readyState'> {\n readonly readyState: string\n}\n\ninterface TransportError extends Error {\n readonly type: 'TransportError'\n readonly description: Error | number\n}\n\nfunction isTransportError(err: Error): err is TransportError {\n return (err as any).type === 'TransportError'\n}\n\nexport interface RouteInfo {\n route: string\n params: Record<string, string>\n splats: string[]\n}\n\nexport type RouteHandler = (routeInfo: RouteInfo, data: any) => void\n\ntype NydusEvents = {\n /** Fired when the connection succeeds. */\n connect: () => void\n /** Fired when the connection has been closed */\n disconnect: (reason: string, details?: Error) => void\n /** Fired when a reconnect attempt is being initiated. */\n reconnecting: (attempts: number) => void\n /** Fired when a publish occurred that wasn't handled by any registered routes. */\n unhandled: (published: { path: string; data: any }) => void\n\n /** Fired when a general error occurs. */\n error: (err: Error) => void\n\n /**\n * Fired when the server returns a 403 on connect. The client will not continue attempting\n * to reconnect after this.\n */\n unauthorized: () => void\n\n /** Fired when the connection attempt times out. */\n connect_timeout: () => void\n\n /** Fired when the reconnection attempts exceeded the maximum allowed without success. */\n reconnect_failed: () => void\n\n /** Fired when the connection attempt failed. */\n connect_failed: () => void\n}\n\nexport class InvokeError extends Error {\n readonly status: number\n readonly body: any\n\n constructor(message: string, status: number, body?: any) {\n super(message)\n this.status = status\n this.body = body\n }\n}\n\ntype PromiseCompleters = { resolve: (value: unknown) => void; reject: (reason: any) => void }\n\nexport class NydusClient extends TypedEventEmitter<NydusEvents> {\n readonly host: string\n readonly opts: Partial<NydusClientOptions>\n conn: ExpandedSocket | null = null\n\n private outstanding = new Map<string, PromiseCompleters>()\n private router = ruta<RouteHandler>()\n private backoff: Backoff\n\n private backoffTimer: ReturnType<typeof setTimeout> | null = null\n private connectTimer: ReturnType<typeof setTimeout> | null = null\n\n private wasOpened = false\n private skipReconnect = false\n private disconnectingPromise: Promise<void> | undefined = undefined\n private disconnectingResolver: (() => void) | undefined = undefined\n\n constructor(host: string, opts: Partial<NydusClientOptions> = {}) {\n super()\n this.host = host\n this.opts = opts\n\n this.opts.reconnectionAttempts = this.opts.reconnectionAttempts || Infinity\n this.backoff = new Backoff({\n min: opts.reconnectionDelay || 1000,\n max: opts.reconnectionDelayMax || 10000,\n jitter: opts.reconnectionJitter || 0.5,\n })\n }\n\n // One of: opening, open, closing, closed.\n get readyState() {\n return this.conn != null ? this.conn.readyState : 'closed'\n }\n\n private doConnect() {\n if (this.opts.connectTimeout) {\n this.connectTimer = setTimeout(() => {\n this.emit('connect_timeout')\n this.disconnect()\n this.skipReconnect = false\n this.onClose('connect timeout')\n }, this.opts.connectTimeout)\n }\n\n this.conn = new EngineIoSocket(this.host, this.opts) as unknown as ExpandedSocket\n this.conn\n .on('open', this.onOpen.bind(this))\n .on('message', data => this.onMessage(data as string))\n .on('close', this.onClose.bind(this) as any)\n .on('error', this.onError.bind(this) as any)\n }\n\n // Connect to the server. If already connected, this will be a no-op.\n connect() {\n if (this.conn) {\n // If the socket is closing, wait for it to close before connecting again\n if (this.conn.readyState === 'closing') {\n this.disconnectingPromise!.then(() => {\n this.connect()\n }).catch(_err => {})\n }\n return\n }\n\n this.skipReconnect = false\n this.wasOpened = false\n this.doConnect()\n }\n\n reconnect() {\n if (this.conn || this.skipReconnect || this.backoffTimer) {\n return\n }\n\n if (this.backoff.attempts >= this.opts.reconnectionAttempts!) {\n this.backoff.reset()\n this.emit('reconnect_failed')\n return\n }\n\n this.backoffTimer = setTimeout(() => {\n this.backoffTimer = null\n this.emit('reconnecting', this.backoff.attempts)\n\n if (this.skipReconnect || this.conn) return\n\n this.doConnect()\n }, this.backoff.duration())\n }\n\n // Disconnect from the server. If not already connected, this will be a no-op.\n disconnect() {\n this.skipReconnect = true\n if (this.backoffTimer) {\n clearTimeout(this.backoffTimer)\n this.backoffTimer = null\n }\n\n if (!this.conn) return\n\n if (!this.disconnectingPromise) {\n this.disconnectingPromise = new Promise<void>(resolve => {\n this.disconnectingResolver = resolve\n }).catch(_err => {})\n }\n\n this.conn.close()\n }\n\n /**\n * Registers a handler function to respond to PUBLISHes to paths matching a specified pattern.\n * Handlers are normal functions of the form:\n * `function({ route, params, splats }, data)`\n *\n * PUBLISHes that don't match a route will be emitted as an 'unhandled' event on this object,\n * which can be useful to track in development mode.\n */\n registerRoute(pathPattern: string, handler: RouteHandler) {\n this.router.addRoute(pathPattern, handler)\n }\n\n private onPublish({ path, data }: NydusPublishMessage<any>) {\n const route = this.router.match(path)\n if (!route) {\n this.emit('unhandled', { path, data })\n return\n }\n\n route.action({ route: route.route, params: route.params, splats: route.splats }, data)\n }\n\n /**\n * Invoke a remote method on the server, specified via a path. Optionally, data can be specified\n * to send along with the call (will be JSON encoded). A Promise will be returned, resolved or\n * rejected with the result or error (respectively) from the server.\n */\n invoke(path: string, data?: any) {\n const id = nanoid()\n return new Promise((resolve, reject) => {\n if (!this.conn) {\n reject(new Error('Not connected'))\n return\n }\n\n this.outstanding.set(id, { resolve, reject })\n this.conn.send(encode(MessageType.Invoke, data, id, path), undefined)\n })\n .catch(err => {\n // Convert error-like objects back to Errors\n if (err.message && err.status) {\n const converted = new InvokeError(err.message, err.status, err.body)\n throw converted\n }\n\n throw err\n })\n .finally(() => this.outstanding.delete(id))\n }\n\n private onInvokeResponse({ type, id, data }: NydusResultMessage<any> | NydusErrorMessage<any>) {\n const p = this.outstanding.get(id)\n if (!p) {\n this.emit('error', new Error('Unknown invoke id'))\n return\n }\n\n p[type === MessageType.Result ? 'resolve' : 'reject'](data)\n }\n\n private onOpen() {\n this.clearConnectTimer()\n this.wasOpened = true\n this.backoff.reset()\n this.emit('connect')\n }\n\n private onMessage(msg: string) {\n const decoded = decode(msg)\n switch (decoded.type) {\n case MessageType.ParserError:\n this.conn?.close() // will cause a call to _onClose\n break\n case MessageType.Welcome:\n if (decoded.data !== protocolVersion) {\n this.emit(\n 'error',\n new Error('Server has incompatible protocol version: ' + protocolVersion),\n )\n this.conn?.close()\n }\n break\n case MessageType.Result:\n case MessageType.Error:\n this.onInvokeResponse(decoded)\n break\n case MessageType.Publish:\n this.onPublish(decoded)\n break\n }\n }\n\n private onClose(reason: string, details?: Error) {\n this.clearConnectTimer()\n this.conn = null\n\n if (this.disconnectingResolver) {\n this.disconnectingResolver()\n this.disconnectingResolver = undefined\n this.disconnectingPromise = undefined\n }\n\n if (!this.wasOpened) {\n this.emit('connect_failed')\n this.reconnect()\n // Sockets can emit 'close' even if the connection was never actually opened. Don't emit emits\n // upstream in that case, since they're rather unnecessary\n return\n }\n\n this.emit('disconnect', reason, details)\n this.outstanding.clear()\n this.wasOpened = false\n this.reconnect()\n }\n\n private onError(err: Error | TransportError) {\n this.clearConnectTimer()\n if (isTransportError(err) && err.message === 'xhr poll error') {\n if (err.description === 403) {\n this.skipReconnect = true\n this.emit('unauthorized')\n } else {\n this.onClose('error', err)\n }\n return\n }\n if (\n this.skipReconnect &&\n isTransportError(err) &&\n err.description &&\n typeof err.description !== 'number' &&\n err.description.message &&\n /closed before the connection (was|is) established/.test(err.description.message)\n ) {\n // ws sometimes throws errors if you disconnect a socket that was in the process of\n // reconnecting. Since the disconnect was requested (_skipReconnect is true), this seems\n // spurious, so we just ignore it\n return\n }\n\n this.emit('error', err)\n }\n\n clearConnectTimer() {\n if (this.connectTimer) {\n clearTimeout(this.connectTimer)\n this.connectTimer = null\n }\n }\n}\n\nexport default function createClient(host: string, opts?: Partial<NydusClientOptions>) {\n return new NydusClient(host, opts)\n}\n","import { EventEmitter } from 'events'\nimport { DefaultListener, TypedEmitter } from 'tiny-typed-emitter'\n\nexport type EventMap = DefaultListener\n\n/**\n * A typed version of the normal node EventEmitter class, such that emitted/handled events and\n * their associated parameters can be type-checked properly.\n *\n * This uses typed-emitter under the hood, it just makes it easier to extend.\n *\n * Example:\n * ```\n * type FooEvents = {\n * bar: (message: string) => void\n * baz: (count: number, ...extras: any[]) => void\n * }\n *\n * class Foo extends TypedEventEmitter<FooEvents> {\n * constructor() {\n * super()\n * }\n *\n * test() {\n * this.emit('bar', 'hello world')\n * this.emit('baz', 5, 'extra', 'stuff', 'to', 'pass', 27)\n * }\n * }\n * ```\n */\nexport abstract class TypedEventEmitter<T extends EventMap> extends (EventEmitter as {\n new <T extends EventMap>(): TypedEmitter<T>\n})<T> {\n constructor() {\n // NOTE(tec27): No idea why eslint thinks super isn't a constructor here, I assume it's failing\n // to parse things properly in some way\n // eslint-disable-next-line constructor-super\n super()\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nydus-client",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"description": "WebSocket client library for the nydus protocol, a simple RPC/PubSub protocol.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -37,33 +37,31 @@
|
|
|
37
37
|
"engine.io-client": "^6.6.3",
|
|
38
38
|
"nanoid": "^5.1.5",
|
|
39
39
|
"nydus-protocol": "^3.0.0",
|
|
40
|
-
"prettier-plugin-organize-imports": "^4.1.0",
|
|
41
40
|
"ruta3": "^2.0.1",
|
|
42
41
|
"tiny-typed-emitter": "^2.1.0"
|
|
43
42
|
},
|
|
44
43
|
"devDependencies": {
|
|
45
44
|
"@eslint/eslintrc": "^3.3.1",
|
|
46
|
-
"@eslint/js": "^9.
|
|
47
|
-
"@swc/core": "^1.
|
|
45
|
+
"@eslint/js": "^9.32.0",
|
|
46
|
+
"@swc/core": "^1.13.2",
|
|
48
47
|
"@types/backo2": "^1.0.4",
|
|
49
48
|
"@types/chai": "^5.2.2",
|
|
50
49
|
"@types/chai-as-promised": "^8.0.2",
|
|
51
|
-
"@types/engine.io-client": "^6.0.0",
|
|
52
50
|
"@types/mocha": "^10.0.10",
|
|
53
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
54
|
-
"@typescript-eslint/parser": "^8.
|
|
55
|
-
"chai": "^5.2.
|
|
51
|
+
"@typescript-eslint/eslint-plugin": "^8.38.0",
|
|
52
|
+
"@typescript-eslint/parser": "^8.38.0",
|
|
53
|
+
"chai": "^5.2.1",
|
|
56
54
|
"chai-as-promised": "^8.0.1",
|
|
57
|
-
"
|
|
58
|
-
"eslint": "^
|
|
59
|
-
"eslint-
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"mocha": "^11.6.0",
|
|
55
|
+
"eslint": "^9.32.0",
|
|
56
|
+
"eslint-config-prettier": "^10.1.8",
|
|
57
|
+
"eslint-plugin-prettier": "^5.5.3",
|
|
58
|
+
"globals": "^16.3.0",
|
|
59
|
+
"mocha": "^11.7.1",
|
|
63
60
|
"nydus": "^5.0.2",
|
|
64
|
-
"prettier": "^3.
|
|
61
|
+
"prettier": "^3.6.2",
|
|
62
|
+
"prettier-plugin-organize-imports": "^4.2.0",
|
|
65
63
|
"tsup": "^8.5.0",
|
|
66
|
-
"tsx": "^4.
|
|
64
|
+
"tsx": "^4.20.3",
|
|
67
65
|
"typescript": "^5.8.3"
|
|
68
66
|
},
|
|
69
67
|
"scripts": {
|