Skip to content

DX improvments by adding typehints #356

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions src/connector/connector.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
import { Channel, PresenceChannel } from './../channel';

type CustomConnector = new (options: Options) => Connector;

type Broadcaster = 'socket.io' | 'pusher' | 'null' | CustomConnector

export interface Options {
auth?: {
headers: Record<string, string>
},
userAuthentication?: {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haven't set up fields that are isn't actually referenced in this package. For service specific options the user can import typing from the service's package and use an intersection of types.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact authEndpoint for example is deprecated in pusher.

endpoint?: string,
headers?: Record<string, string>,
},
broadcaster?: Broadcaster,
csrfToken?: string | null,
bearerToken?: string | null,
[K: string]: unknown
}

export abstract class Connector {
/**
* Default connector options.
*/
private _defaultOptions: any = {
private _defaultOptions: Options = {
auth: {
headers: {},
},
Expand All @@ -29,15 +47,15 @@ export abstract class Connector {
/**
* Create a new class instance.
*/
constructor(options: any) {
constructor(options: Options) {
this.setOptions(options);
this.connect();
}

/**
* Merge the custom options with the defaults.
*/
protected setOptions(options: any): any {
protected setOptions(options: Options): any {
this.options = Object.assign(this._defaultOptions, options);

let token = this.csrfToken();
Expand Down Expand Up @@ -83,6 +101,11 @@ export abstract class Connector {
*/
abstract connect(): void;

/**
* Listen for an event on a channel instance.
*/
abstract listen(name: string, event: string, callback: CallableFunction): Channel;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to have been present in all supplied connectors and this would be a basic requirement/naming for any different provider's connector.


/**
* Get a channel instance by name.
*/
Expand Down
7 changes: 7 additions & 0 deletions src/connector/null-connector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ export class NullConnector extends Connector {
return new NullPrivateChannel();
}

/**
* Get a private encrypted channel instance by name.
*/
encryptedPrivateChannel(name: string): NullPrivateChannel {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added so it's has better feature parity with the pusher connector.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what the socket.io equivalent...

return this.privateChannel(name);
}

/**
* Get a presence channel instance by name.
*/
Expand Down
2 changes: 1 addition & 1 deletion src/connector/socketio-connector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export class SocketIoConnector extends Connector {
/**
* Listen for an event on a channel instance.
*/
listen(name: string, event: string, callback: Function): SocketIoChannel {
listen(name: string, event: string, callback: CallableFunction): SocketIoChannel {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

has better typing when it comes to call, bind, apply

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can update the rest of the package to CallableFunction if desired.

return this.channel(name).listen(event, callback);
}

Expand Down
23 changes: 15 additions & 8 deletions src/echo.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
import { Channel, PresenceChannel } from './channel';
import { PusherConnector, SocketIoConnector, NullConnector } from './connector';
import type { Connector, Options } from './connector';

interface EchoOptions extends Options {
withoutInterceptors?: boolean;
}

/**
* This class is the primary API for interacting with broadcasting.
*/
export default class Echo {
export default class Echo<O extends Record<PropertyKey, unknown>> {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

user can pass in the typings from providers such as pusher

/**
* The broadcasting connector.
*/
connector: any;
connector: Connector;

/**
* The Echo options.
*/
options: any;
options: EchoOptions & O;

/**
* Create a new class instance.
*/
constructor(options: any) {
constructor(options: EchoOptions & O) {
this.options = options;
this.connect();

Expand Down Expand Up @@ -46,6 +51,8 @@ export default class Echo {
this.connector = new NullConnector(this.options);
} else if (typeof this.options.broadcaster == 'function') {
this.connector = new this.options.broadcaster(this.options);
} else {
throw new Error('Broadcaster option not set when initialising Echo.');
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit nicer than the user calling a method on undefined as the connector has not been set.

}
}

Expand Down Expand Up @@ -95,7 +102,7 @@ export default class Echo {
* Get a private encrypted channel instance by name.
*/
encryptedPrivate(channel: string): Channel {
return this.connector.encryptedPrivateChannel(channel);
return (this.connector as NullConnector | PusherConnector).encryptedPrivateChannel(channel);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why this is here socket.io connector is not implementing it. (The user can always just access echo.connector)

}

/**
Expand All @@ -106,8 +113,8 @@ export default class Echo {
}

/**
* Register 3rd party request interceptiors. These are used to automatically
* send a connections socket id to a Laravel app with a X-Socket-Id header.
* Register 3rd party request interceptors. These are used to automatically
* send a connections socket id to a Laravel app with an X-Socket-Id header.
*/
registerInterceptors(): void {
if (typeof Vue === 'function' && Vue.http) {
Expand Down Expand Up @@ -179,4 +186,4 @@ export default class Echo {
/**
* Export channel classes for TypeScript.
*/
export { Channel, PresenceChannel };
export { Channel, PresenceChannel, EchoOptions };