@harelpls/use-pusher
Advanced tools
Comparing version 3.1.3 to 3.2.0
/// <reference types="prop-types" /> | ||
/// <reference types="react" /> | ||
import { AuthOptions, Channel, Options, PresenceChannel } from 'pusher-js'; | ||
import Pusher, { Channel, Options, PresenceChannel } from 'pusher-js'; | ||
export interface PusherContextValues { | ||
client?: any | undefined; | ||
triggerEndpoint?: string; | ||
client?: React.MutableRefObject<Pusher | undefined>; | ||
triggerEndpoint?: string; | ||
} | ||
export interface PusherProviderProps extends Options { | ||
clientKey: string; | ||
cluster: string; | ||
authEndpoint?: string; | ||
auth?: AuthOptions; | ||
triggerEndpoint?: string; | ||
defer?: boolean; | ||
children: React.ReactNode; | ||
value?: any; | ||
clientKey: string; | ||
cluster: 'mt1' | 'us2' | 'us3' | 'eu' | 'ap1' | 'ap2' | 'ap3' | 'ap4'; | ||
triggerEndpoint?: string; | ||
defer?: boolean; | ||
value?: PusherContextValues; | ||
} | ||
export declare const __PusherContext: React.Context<PusherContextValues>; | ||
/** | ||
* Provider for the pusher service in an app | ||
* Provider that creates your pusher instance and provides it to child hooks throughout your app. | ||
* Note, you can pass in value={{}} as a prop if you'd like to override the pusher client passed. | ||
* This is handy when simulating pusher locally, or for testing. | ||
* @param props Config for Pusher client | ||
*/ | ||
export declare function PusherProvider({ clientKey, cluster, triggerEndpoint, authEndpoint, auth, defer, ...props }: PusherProviderProps): JSX.Element; | ||
export declare const PusherProvider: React.FC<PusherProviderProps>; | ||
/** | ||
* Subscribe to channel | ||
* Provides access to the pusher client instance. | ||
* | ||
* @returns a `MutableRefObject<Pusher|undefined>`. The instance is held by a `useRef()` hook. | ||
* @example | ||
* useChannel("my-channel") | ||
* ```javscript | ||
* const { client } = usePusher(); | ||
* client.current.subscribe('my-channel'); | ||
* ``` | ||
*/ | ||
export declare function useChannel(channelName: string): any; | ||
export declare function usePusher(): PusherContextValues; | ||
export declare const NOT_IN_CONTEXT_WARNING = | ||
'No Pusher context. Did you forget to wrap your app in a <PusherProvider />?'; | ||
/** | ||
* Subscribe to a channel | ||
* | ||
* @param channelName The name of the channel you want to subscribe to. | ||
* @typeparam Type of channel you're subscribing to. Can be one of Channel or PresenceChannel. | ||
* @returns Instance of the channel you just subscribed to. | ||
* | ||
* @example | ||
* ```javascript | ||
* const channel = useChannel("my-channel") | ||
* channel.bind('some-event', () => {}) | ||
* ``` | ||
*/ | ||
export declare function useChannel<T extends Channel & PresenceChannel>( | ||
channelName: string | ||
): T | undefined; | ||
/** | ||
* Subscribe to presence channel events and get members back | ||
* | ||
* @param channelName name of presence channel. Should have presence- suffix. | ||
* @param eventName name of event to bind to | ||
* @param onEvent callback to fire when event is called | ||
* @param dependencies dependencies array that onEvent uses | ||
* @param options optional argument to skip events | ||
* @param channelName name of presence the channel. Should have `presence-` suffix. | ||
* @returns Object with `channel`, `members` and `myID` properties. | ||
* | ||
* @example | ||
* const {members} = usePresenceChannel( | ||
* "my-channel", | ||
* "my-event", | ||
* (message) => console.log(message), | ||
* ) | ||
* ```javascript | ||
* const { channel, members, myID } = usePresenceChannel("presence-my-channel"); | ||
* ``` | ||
*/ | ||
export declare function usePresenceChannel(channelName: string): { | ||
channel: PresenceChannel; | ||
members: {}; | ||
myID: any; | ||
export declare function usePresenceChannel( | ||
channelName: string | ||
): { | ||
channel: PresenceChannel | undefined; | ||
members: {}; | ||
myID: any; | ||
}; | ||
@@ -59,84 +77,102 @@ /** | ||
* @param callback Callback to call on a new event | ||
* @param dependencies Dependencies the callback uses. | ||
*/ | ||
export declare function useEvent<D>(channel: Channel | PresenceChannel | undefined, eventName: string, callback: (data?: D) => void, dependencies?: unknown[] | undefined): void; | ||
export declare function useEvent<D>( | ||
channel: Channel | PresenceChannel | undefined, | ||
eventName: string, | ||
callback: (data?: D) => void, | ||
dependencies?: unknown[] | undefined | ||
): void; | ||
/** | ||
* Trigger events hook | ||
* | ||
* @param channel the channel you'd like to trigger clientEvents on. Get this from [[useChannel]] or [[usePresenceChannel]]. | ||
* @typeparam TData shape of the data you're sending with the event. | ||
* @returns A memoized trigger function that will perform client events on the channel. | ||
* @example | ||
* ```javascript | ||
* const channel = useChannel('my-channel'); | ||
* const trigger = useClientTrigger(channel) | ||
* | ||
* const trigger = useTrigger('my-channel'); | ||
* trigger('my-event', {message: 'hello'}); | ||
* const handleClick = () => trigger('some-client-event', {}); | ||
* ``` | ||
*/ | ||
export declare function useTrigger(channelName: string): (eventName: string, data?: any) => Promise<Response>; | ||
export declare function useClientTrigger(channel: Channel | PresenceChannel): (eventName: string, data?: any) => void; | ||
export declare function useClientTrigger<TData = {}>( | ||
channel: Channel | PresenceChannel | ||
): (eventName: string, data: TData) => void; | ||
/** | ||
* Provides access to the pusher client | ||
* Hook to provide a trigger function that calls the server defined in `PusherProviderProps.triggerEndpoint` using `fetch`. | ||
* Any `auth?.headers` in the config object will be passed with the `fetch` call. | ||
* | ||
* @param channelName name of channel to call trigger on | ||
* @typeparam TData shape of the data you're sending with the event | ||
* | ||
* @example | ||
* const {client} = usePusher(); | ||
* client.current.subscribe('my-channel'); | ||
* ```typescript | ||
* const trigger = useTrigger<{message: string}>('my-channel'); | ||
* trigger('my-event', {message: 'hello'}); | ||
* ``` | ||
*/ | ||
export declare function usePusher(): PusherContextValues; | ||
export declare const NOT_IN_CONTEXT_WARNING = "No Pusher context. Did you forget to wrap your app in a <PusherProvider />?"; | ||
export declare function useTrigger<TData = {}>( | ||
channelName: string | ||
): (eventName: string, data?: TData | undefined) => Promise<Response>; | ||
export declare type CallbackSignature = (data: any, metadata?: any) => void; | ||
export declare class PusherChannelMock { | ||
/** Initialize PusherChannelMock with callbacks object. */ | ||
callbacks: { | ||
[name: string]: Function[]; | ||
}; | ||
name: string; | ||
constructor(name?: string); | ||
/** | ||
* Bind callback to an event name. | ||
* @param {String} name - name of the event. | ||
* @param {Function} callback - callback to be called on event. | ||
*/ | ||
bind(name: string, callback: Function): void; | ||
/** | ||
* Unbind callback from an event name. | ||
* @param {String} name - name of the event. | ||
* @param {Function} callback - callback to be called on event. | ||
*/ | ||
unbind(name: string, callback: Function): void; | ||
/** | ||
* Emit event with data. | ||
* @param {String} name - name of the event. | ||
* @param {*} data - data you want to pass in to callback function that gets * called. | ||
*/ | ||
emit(name: string, data?: any, metadata?: any): void; | ||
trigger(): void; | ||
/** Initialize PusherChannelMock with callbacks object. */ | ||
callbacks: { | ||
[name: string]: CallbackSignature[]; | ||
}; | ||
name: string; | ||
constructor(name?: string); | ||
/** | ||
* Bind callback to an event name. | ||
* @param {String} name - name of the event. | ||
* @param {Function} callback - callback to be called on event. | ||
*/ | ||
bind(name: string, callback: CallbackSignature): void; | ||
/** | ||
* Unbind callback from an event name. | ||
* @param {String} name - name of the event. | ||
* @param {Function} callback - callback to be called on event. | ||
*/ | ||
unbind(name: string, callback: CallbackSignature): void; | ||
/** | ||
* Emit event with data. | ||
* @param {String} name - name of the event. | ||
* @param {*} data - data you want to pass in to callback function that gets * called. | ||
*/ | ||
emit(name: string, data?: any, metadata?: any): void; | ||
trigger(): void; | ||
} | ||
export declare class PusherPresenceChannelMock extends PusherChannelMock { | ||
members: any; | ||
myID: any; | ||
constructor(name?: string); | ||
members: any; | ||
myID: any; | ||
constructor(name?: string); | ||
} | ||
export declare class PusherMock { | ||
key: string; | ||
config: Options; | ||
channels: { | ||
[name: string]: PusherChannelMock; | ||
}; | ||
/** Initialize PusherMock with empty channels object. */ | ||
constructor(key: string, config: Options); | ||
/** | ||
* Get channel by its name. | ||
* @param {String} name - name of the channel. | ||
* @returns {PusherChannelMock} PusherChannelMock object that represents channel | ||
*/ | ||
channel(name: string): PusherChannelMock; | ||
/** | ||
* Mock subscribing to a channel. | ||
* @param {String} name - name of the channel. | ||
* @returns {PusherChannelMock} PusherChannelMock object that represents channel | ||
*/ | ||
subscribe(name: string): PusherChannelMock; | ||
/** | ||
* Unsubscribe from a mocked channel. | ||
* @param {String} name - name of the channel. | ||
*/ | ||
unsubscribe(name: string): void; | ||
disconnect(): void; | ||
key: string; | ||
config: Options; | ||
channels: { | ||
[name: string]: PusherChannelMock; | ||
}; | ||
/** Initialize PusherMock with empty channels object. */ | ||
constructor(key: string, config: Options); | ||
/** | ||
* Get channel by its name. | ||
* @param {String} name - name of the channel. | ||
* @returns {PusherChannelMock} PusherChannelMock object that represents channel | ||
*/ | ||
channel(name: string): PusherChannelMock; | ||
/** | ||
* Mock subscribing to a channel. | ||
* @param {String} name - name of the channel. | ||
* @returns {PusherChannelMock} PusherChannelMock object that represents channel | ||
*/ | ||
subscribe(name: string): PusherChannelMock; | ||
/** | ||
* Unsubscribe from a mocked channel. | ||
* @param {String} name - name of the channel. | ||
*/ | ||
unsubscribe(name: string): void; | ||
disconnect(): void; | ||
} | ||
export {}; |
@@ -146,15 +146,16 @@ import React, { useRef, useEffect, useContext, useState, useCallback } from 'react'; | ||
/** | ||
* Provider for the pusher service in an app | ||
* Provider that creates your pusher instance and provides it to child hooks throughout your app. | ||
* Note, you can pass in value={{}} as a prop if you'd like to override the pusher client passed. | ||
* This is handy when simulating pusher locally, or for testing. | ||
* @param props Config for Pusher client | ||
*/ | ||
function PusherProvider(_a) { | ||
var PusherProvider = function PusherProvider(_a) { | ||
var clientKey = _a.clientKey, | ||
cluster = _a.cluster, | ||
triggerEndpoint = _a.triggerEndpoint, | ||
authEndpoint = _a.authEndpoint, | ||
auth = _a.auth, | ||
_b = _a.defer, | ||
defer = _b === void 0 ? false : _b, | ||
props = __rest(_a, ["clientKey", "cluster", "triggerEndpoint", "authEndpoint", "auth", "defer"]); // errors when required props are not passed. | ||
children = _a.children, | ||
props = __rest(_a, ["clientKey", "cluster", "triggerEndpoint", "defer", "children"]); // errors when required props are not passed. | ||
@@ -165,34 +166,25 @@ | ||
var children = props.children, | ||
additionalConfig = __rest(props, ["children"]); | ||
var config = __assign({ | ||
cluster: cluster | ||
}, additionalConfig); | ||
}, props); | ||
if (authEndpoint) config.authEndpoint = authEndpoint; | ||
if (auth) config.auth = auth; | ||
var pusherClientRef = useRef(); // track config for comparison | ||
var previousConfig = useRef(); | ||
var previousConfig = useRef(props); | ||
useEffect(function () { | ||
previousConfig.current = config; | ||
previousConfig.current = props; | ||
}); | ||
useEffect(function () { | ||
// if client exists and options are the same, skip. | ||
if (dequal(previousConfig.current, config) && pusherClientRef.current !== undefined) { | ||
// Skip creation of client if deferring, a value prop is passed, or config props are the same. | ||
if (defer || props.value || dequal(previousConfig.current, props) && pusherClientRef.current !== undefined) { | ||
return; | ||
} // optional defer parameter skips creating the class. | ||
// handy if you want to wait for something async like | ||
// a JWT before creating it. | ||
} // create the client and assign it to the ref | ||
if (!defer) { | ||
pusherClientRef.current = new Pusher(clientKey, config); | ||
} | ||
pusherClientRef.current = new Pusher(clientKey, config); // cleanup | ||
return function () { | ||
return pusherClientRef.current && pusherClientRef.current.disconnect(); | ||
pusherClientRef.current && pusherClientRef.current.disconnect(); | ||
}; | ||
}, [clientKey, config, defer, pusherClientRef]); | ||
}, [clientKey, props, defer, pusherClientRef]); | ||
return React.createElement(PusherContext.Provider, _extends({ | ||
@@ -205,10 +197,13 @@ value: { | ||
}, props)); | ||
} | ||
}; | ||
/** | ||
* Provides access to the pusher client | ||
* Provides access to the pusher client instance. | ||
* | ||
* @returns a `MutableRefObject<Pusher|undefined>`. The instance is held by a `useRef()` hook. | ||
* @example | ||
* const {client} = usePusher(); | ||
* ```javscript | ||
* const { client } = usePusher(); | ||
* client.current.subscribe('my-channel'); | ||
* ``` | ||
*/ | ||
@@ -226,6 +221,13 @@ function usePusher() { | ||
/** | ||
* Subscribe to channel | ||
* Subscribe to a channel | ||
* | ||
* @param channelName The name of the channel you want to subscribe to. | ||
* @typeparam Type of channel you're subscribing to. Can be one of Channel or PresenceChannel. | ||
* @returns Instance of the channel you just subscribed to. | ||
* | ||
* @example | ||
* useChannel("my-channel") | ||
* ```javascript | ||
* const channel = useChannel("my-channel") | ||
* channel.bind('some-event', () => {}) | ||
* ``` | ||
*/ | ||
@@ -241,4 +243,4 @@ function useChannel(channelName) { | ||
return; | ||
var channel = pusherClient.subscribe(channelName); | ||
setChannel(channel); | ||
var pusherChannel = pusherClient.subscribe(channelName); | ||
setChannel(pusherChannel); | ||
}, [channelName, pusherClient]); | ||
@@ -251,18 +253,12 @@ return channel; | ||
* | ||
* @param channelName name of presence channel. Should have presence- suffix. | ||
* @param eventName name of event to bind to | ||
* @param onEvent callback to fire when event is called | ||
* @param dependencies dependencies array that onEvent uses | ||
* @param options optional argument to skip events | ||
* @param channelName name of presence the channel. Should have `presence-` suffix. | ||
* @returns Object with `channel`, `members` and `myID` properties. | ||
* | ||
* @example | ||
* const {members} = usePresenceChannel( | ||
* "my-channel", | ||
* "my-event", | ||
* (message) => console.log(message), | ||
* ) | ||
* ```javascript | ||
* const { channel, members, myID } = usePresenceChannel("presence-my-channel"); | ||
* ``` | ||
*/ | ||
function usePresenceChannel(channelName) { | ||
// errors for missing arguments | ||
invariant_1(channelName, 'channelName required to subscribe to a channel'); | ||
invariant_1(channelName.includes('presence-'), "Presence channels should use prefix 'presence-' in their name. Use the useChannel hook instead."); | ||
@@ -272,41 +268,30 @@ // Get regular channel functionality | ||
var _b = useState(), myID = _b[0], setMyID = _b[1]; | ||
/** | ||
* Get members info on subscription success | ||
*/ | ||
var handleSubscriptionSuccess = useCallback(function (members) { | ||
setMembers(members.members); | ||
setMyID(members.myID); | ||
}, []); | ||
/** | ||
* Add or update member in object. | ||
* @note not using a new Map() here to match pusher-js library. | ||
* @param member member being added | ||
*/ | ||
var handleAdd = useCallback(function (member) { | ||
setMembers(function (previousMembers) { | ||
var _a; | ||
return (__assign(__assign({}, previousMembers), (_a = {}, _a[member.id] = member.info, _a))); | ||
}); | ||
}, []); | ||
/** | ||
* Remove member from the state object. | ||
* @param member Member being removed | ||
*/ | ||
var handleRemove = useCallback(function (member) { | ||
setMembers(function (previousMembers) { | ||
var nextMembers = __assign({}, previousMembers); | ||
delete nextMembers[member.id]; | ||
return nextMembers; | ||
}); | ||
}, []); | ||
/** | ||
* Bind and unbind to membership events | ||
*/ | ||
// bind and unbind member events events on our channel | ||
var channel = useChannel(channelName); | ||
useEffect(function () { | ||
if (channel) { | ||
// Get membership info on successful subscription | ||
var handleSubscriptionSuccess_1 = function (members) { | ||
setMembers(members.members); | ||
setMyID(members.myID); | ||
}; | ||
// add a member to the members object | ||
var handleAdd_1 = function (member) { | ||
setMembers(function (previousMembers) { | ||
var _a; | ||
return (__assign(__assign({}, previousMembers), (_a = {}, _a[member.id] = member.info, _a))); | ||
}); | ||
}; | ||
// remove a member from the members object | ||
var handleRemove_1 = function (member) { | ||
setMembers(function (previousMembers) { | ||
var nextMembers = __assign({}, previousMembers); | ||
delete nextMembers[member.id]; | ||
return nextMembers; | ||
}); | ||
}; | ||
// bind to all member addition/removal events | ||
channel.bind('pusher:subscription_succeeded', handleSubscriptionSuccess); | ||
channel.bind('pusher:member_added', handleAdd); | ||
channel.bind('pusher:member_removed', handleRemove); | ||
channel.bind('pusher:subscription_succeeded', handleSubscriptionSuccess_1); | ||
channel.bind('pusher:member_added', handleAdd_1); | ||
channel.bind('pusher:member_removed', handleRemove_1); | ||
// set any members that already existed on the channel | ||
@@ -317,15 +302,14 @@ if (channel.members) { | ||
} | ||
// cleanup | ||
return function () { | ||
channel.unbind('pusher:subscription_succeeded', handleSubscriptionSuccess_1); | ||
channel.unbind('pusher:member_added', handleAdd_1); | ||
channel.unbind('pusher:member_removed', handleRemove_1); | ||
}; | ||
} | ||
// cleanup | ||
return function () { | ||
if (channel) { | ||
channel.unbind('pusher:subscription_succeeded', handleSubscriptionSuccess); | ||
channel.unbind('pusher:member_added', handleAdd); | ||
channel.unbind('pusher:member_removed', handleRemove); | ||
} | ||
}; | ||
}, [channel, handleSubscriptionSuccess, handleAdd, handleRemove]); | ||
var presenceChannel = channel; | ||
// to make typescript happy. | ||
return function () { }; | ||
}, [channel]); | ||
return { | ||
channel: presenceChannel, | ||
channel: channel, | ||
members: members, | ||
@@ -341,3 +325,2 @@ myID: myID, | ||
* @param callback Callback to call on a new event | ||
* @param dependencies Dependencies the callback uses. | ||
*/ | ||
@@ -359,3 +342,4 @@ function useEvent(channel, eventName, callback, dependencies) { | ||
} | ||
channel.bind(eventName, callback); | ||
else | ||
channel.bind(eventName, callback); | ||
return function () { | ||
@@ -368,31 +352,56 @@ channel.unbind(eventName, callback); | ||
/** | ||
* Trigger events hook | ||
* | ||
* @param channel the channel you'd like to trigger clientEvents on. Get this from [[useChannel]] or [[usePresenceChannel]]. | ||
* @typeparam TData shape of the data you're sending with the event. | ||
* @returns A memoized trigger function that will perform client events on the channel. | ||
* @example | ||
* ```javascript | ||
* const channel = useChannel('my-channel'); | ||
* const trigger = useClientTrigger(channel) | ||
* | ||
* const trigger = useTrigger('my-channel'); | ||
* const handleClick = () => trigger('some-client-event', {}); | ||
* ``` | ||
*/ | ||
function useClientTrigger(channel) { | ||
channel && | ||
invariant_1(channel.name.match(/(private-|presence-)/gi), "Channel provided to useClientTrigger wasn't private or presence channel. Client events only work on these types of channels."); | ||
// memoize trigger so it's not being created every render | ||
var trigger = useCallback(function (eventName, data) { | ||
invariant_1(eventName, 'Must pass event name to trigger a client event.'); | ||
channel && channel.trigger(eventName, data); | ||
}, [channel]); | ||
return trigger; | ||
} | ||
/** | ||
* Hook to provide a trigger function that calls the server defined in `PusherProviderProps.triggerEndpoint` using `fetch`. | ||
* Any `auth?.headers` in the config object will be passed with the `fetch` call. | ||
* | ||
* @param channelName name of channel to call trigger on | ||
* @typeparam TData shape of the data you're sending with the event | ||
* | ||
* @example | ||
* ```typescript | ||
* const trigger = useTrigger<{message: string}>('my-channel'); | ||
* trigger('my-event', {message: 'hello'}); | ||
* ``` | ||
*/ | ||
function useTrigger(channelName) { | ||
var _a = usePusher(), client = _a.client, triggerEndpoint = _a.triggerEndpoint; | ||
// you can't use this if you haven't supplied a triggerEndpoint. | ||
invariant_1(triggerEndpoint, 'No trigger endpoint specified to <PusherProvider />. Cannot trigger an event.'); | ||
// subscribe to the channel we'll be triggering to. | ||
useChannel(channelName); | ||
invariant_1(channelName, "No channel specified to trigger to."); | ||
invariant_1(triggerEndpoint, "No trigger endpoint specified to <PusherProvider />. Cannot trigger an event."); | ||
/** | ||
* Memoized trigger function | ||
*/ | ||
// memoized trigger function to return | ||
var trigger = useCallback(function (eventName, data) { | ||
var fetchOptions = { | ||
method: "POST", | ||
body: JSON.stringify({ channelName: channelName, eventName: eventName, data: data }) | ||
method: 'POST', | ||
body: JSON.stringify({ channelName: channelName, eventName: eventName, data: data }), | ||
}; | ||
if (client.current && client.current.config.auth) { | ||
if (client && client.current && client.current.config.auth) { | ||
fetchOptions.headers = client.current.config.auth.headers; | ||
} | ||
else { | ||
console.warn("No auth parameters supplied to <PusherProvider />. Your events will be unauthenticated."); | ||
console.warn('No auth parameters supplied to <PusherProvider />. Your events will be unauthenticated.'); | ||
} | ||
// forcing triggerEndpoint to exist for TS here | ||
// because invariant will throw during dev | ||
return fetch(triggerEndpoint, fetchOptions); | ||
@@ -403,14 +412,2 @@ }, [client, triggerEndpoint, channelName]); | ||
function useClientTrigger(channel) { | ||
channel && | ||
invariant_1(channel.name.match(/(private-|presence-)/gi), "Channel provided to useClientTrigger wasn't private or presence channel. Client events only work on these types of channels."); | ||
// memoize trigger so it's not being created every render | ||
var trigger = useCallback(function (eventName, data) { | ||
if (data === void 0) { data = {}; } | ||
invariant_1(eventName, 'Must pass event name to trigger a client event.'); | ||
channel && channel.trigger(eventName, data); | ||
}, [channel]); | ||
return trigger; | ||
} | ||
var PusherChannelMock = /** @class */ (function () { | ||
@@ -417,0 +414,0 @@ function PusherChannelMock(name) { |
@@ -1,11 +0,4 @@ | ||
'use strict'; | ||
import React, { useRef, useEffect, useContext, useState, useCallback } from 'react'; | ||
import Pusher from 'pusher-js'; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } | ||
var React = require('react'); | ||
var React__default = _interopDefault(React); | ||
var Pusher = _interopDefault(require('pusher-js')); | ||
function _extends() { | ||
@@ -150,18 +143,19 @@ _extends = Object.assign || function (target) { | ||
var PusherContext = React__default.createContext({}); | ||
var PusherContext = React.createContext({}); | ||
var __PusherContext = PusherContext; | ||
/** | ||
* Provider for the pusher service in an app | ||
* Provider that creates your pusher instance and provides it to child hooks throughout your app. | ||
* Note, you can pass in value={{}} as a prop if you'd like to override the pusher client passed. | ||
* This is handy when simulating pusher locally, or for testing. | ||
* @param props Config for Pusher client | ||
*/ | ||
function PusherProvider(_a) { | ||
var PusherProvider = function PusherProvider(_a) { | ||
var clientKey = _a.clientKey, | ||
cluster = _a.cluster, | ||
triggerEndpoint = _a.triggerEndpoint, | ||
authEndpoint = _a.authEndpoint, | ||
auth = _a.auth, | ||
_b = _a.defer, | ||
defer = _b === void 0 ? false : _b, | ||
props = __rest(_a, ["clientKey", "cluster", "triggerEndpoint", "authEndpoint", "auth", "defer"]); // errors when required props are not passed. | ||
children = _a.children, | ||
props = __rest(_a, ["clientKey", "cluster", "triggerEndpoint", "defer", "children"]); // errors when required props are not passed. | ||
@@ -172,35 +166,26 @@ | ||
var children = props.children, | ||
additionalConfig = __rest(props, ["children"]); | ||
var config = __assign({ | ||
cluster: cluster | ||
}, additionalConfig); | ||
}, props); | ||
if (authEndpoint) config.authEndpoint = authEndpoint; | ||
if (auth) config.auth = auth; | ||
var pusherClientRef = React.useRef(); // track config for comparison | ||
var pusherClientRef = useRef(); // track config for comparison | ||
var previousConfig = React.useRef(); | ||
React.useEffect(function () { | ||
previousConfig.current = config; | ||
var previousConfig = useRef(props); | ||
useEffect(function () { | ||
previousConfig.current = props; | ||
}); | ||
React.useEffect(function () { | ||
// if client exists and options are the same, skip. | ||
if (dequal(previousConfig.current, config) && pusherClientRef.current !== undefined) { | ||
useEffect(function () { | ||
// Skip creation of client if deferring, a value prop is passed, or config props are the same. | ||
if (defer || props.value || dequal(previousConfig.current, props) && pusherClientRef.current !== undefined) { | ||
return; | ||
} // optional defer parameter skips creating the class. | ||
// handy if you want to wait for something async like | ||
// a JWT before creating it. | ||
} // create the client and assign it to the ref | ||
if (!defer) { | ||
pusherClientRef.current = new Pusher(clientKey, config); | ||
} | ||
pusherClientRef.current = new Pusher(clientKey, config); // cleanup | ||
return function () { | ||
return pusherClientRef.current && pusherClientRef.current.disconnect(); | ||
pusherClientRef.current && pusherClientRef.current.disconnect(); | ||
}; | ||
}, [clientKey, config, defer, pusherClientRef]); | ||
return React__default.createElement(PusherContext.Provider, _extends({ | ||
}, [clientKey, props, defer, pusherClientRef]); | ||
return React.createElement(PusherContext.Provider, _extends({ | ||
value: { | ||
@@ -212,14 +197,17 @@ client: pusherClientRef, | ||
}, props)); | ||
} | ||
}; | ||
/** | ||
* Provides access to the pusher client | ||
* Provides access to the pusher client instance. | ||
* | ||
* @returns a `MutableRefObject<Pusher|undefined>`. The instance is held by a `useRef()` hook. | ||
* @example | ||
* const {client} = usePusher(); | ||
* ```javscript | ||
* const { client } = usePusher(); | ||
* client.current.subscribe('my-channel'); | ||
* ``` | ||
*/ | ||
function usePusher() { | ||
var context = React.useContext(__PusherContext); | ||
React.useEffect(function () { | ||
var context = useContext(__PusherContext); | ||
useEffect(function () { | ||
if (!context) | ||
@@ -233,6 +221,13 @@ console.warn(NOT_IN_CONTEXT_WARNING); | ||
/** | ||
* Subscribe to channel | ||
* Subscribe to a channel | ||
* | ||
* @param channelName The name of the channel you want to subscribe to. | ||
* @typeparam Type of channel you're subscribing to. Can be one of Channel or PresenceChannel. | ||
* @returns Instance of the channel you just subscribed to. | ||
* | ||
* @example | ||
* useChannel("my-channel") | ||
* ```javascript | ||
* const channel = useChannel("my-channel") | ||
* channel.bind('some-event', () => {}) | ||
* ``` | ||
*/ | ||
@@ -244,8 +239,8 @@ function useChannel(channelName) { | ||
var pusherClient = client && client.current; | ||
var _a = React.useState(), channel = _a[0], setChannel = _a[1]; | ||
React.useEffect(function () { | ||
var _a = useState(), channel = _a[0], setChannel = _a[1]; | ||
useEffect(function () { | ||
if (!pusherClient) | ||
return; | ||
var channel = pusherClient.subscribe(channelName); | ||
setChannel(channel); | ||
var pusherChannel = pusherClient.subscribe(channelName); | ||
setChannel(pusherChannel); | ||
}, [channelName, pusherClient]); | ||
@@ -258,61 +253,44 @@ return channel; | ||
* | ||
* @param channelName name of presence channel. Should have presence- suffix. | ||
* @param eventName name of event to bind to | ||
* @param onEvent callback to fire when event is called | ||
* @param dependencies dependencies array that onEvent uses | ||
* @param options optional argument to skip events | ||
* @param channelName name of presence the channel. Should have `presence-` suffix. | ||
* @returns Object with `channel`, `members` and `myID` properties. | ||
* | ||
* @example | ||
* const {members} = usePresenceChannel( | ||
* "my-channel", | ||
* "my-event", | ||
* (message) => console.log(message), | ||
* ) | ||
* ```javascript | ||
* const { channel, members, myID } = usePresenceChannel("presence-my-channel"); | ||
* ``` | ||
*/ | ||
function usePresenceChannel(channelName) { | ||
// errors for missing arguments | ||
invariant_1(channelName, 'channelName required to subscribe to a channel'); | ||
invariant_1(channelName.includes('presence-'), "Presence channels should use prefix 'presence-' in their name. Use the useChannel hook instead."); | ||
// Get regular channel functionality | ||
var _a = React.useState({}), members = _a[0], setMembers = _a[1]; | ||
var _b = React.useState(), myID = _b[0], setMyID = _b[1]; | ||
/** | ||
* Get members info on subscription success | ||
*/ | ||
var handleSubscriptionSuccess = React.useCallback(function (members) { | ||
setMembers(members.members); | ||
setMyID(members.myID); | ||
}, []); | ||
/** | ||
* Add or update member in object. | ||
* @note not using a new Map() here to match pusher-js library. | ||
* @param member member being added | ||
*/ | ||
var handleAdd = React.useCallback(function (member) { | ||
setMembers(function (previousMembers) { | ||
var _a; | ||
return (__assign(__assign({}, previousMembers), (_a = {}, _a[member.id] = member.info, _a))); | ||
}); | ||
}, []); | ||
/** | ||
* Remove member from the state object. | ||
* @param member Member being removed | ||
*/ | ||
var handleRemove = React.useCallback(function (member) { | ||
setMembers(function (previousMembers) { | ||
var nextMembers = __assign({}, previousMembers); | ||
delete nextMembers[member.id]; | ||
return nextMembers; | ||
}); | ||
}, []); | ||
/** | ||
* Bind and unbind to membership events | ||
*/ | ||
var _a = useState({}), members = _a[0], setMembers = _a[1]; | ||
var _b = useState(), myID = _b[0], setMyID = _b[1]; | ||
// bind and unbind member events events on our channel | ||
var channel = useChannel(channelName); | ||
React.useEffect(function () { | ||
useEffect(function () { | ||
if (channel) { | ||
// Get membership info on successful subscription | ||
var handleSubscriptionSuccess_1 = function (members) { | ||
setMembers(members.members); | ||
setMyID(members.myID); | ||
}; | ||
// add a member to the members object | ||
var handleAdd_1 = function (member) { | ||
setMembers(function (previousMembers) { | ||
var _a; | ||
return (__assign(__assign({}, previousMembers), (_a = {}, _a[member.id] = member.info, _a))); | ||
}); | ||
}; | ||
// remove a member from the members object | ||
var handleRemove_1 = function (member) { | ||
setMembers(function (previousMembers) { | ||
var nextMembers = __assign({}, previousMembers); | ||
delete nextMembers[member.id]; | ||
return nextMembers; | ||
}); | ||
}; | ||
// bind to all member addition/removal events | ||
channel.bind('pusher:subscription_succeeded', handleSubscriptionSuccess); | ||
channel.bind('pusher:member_added', handleAdd); | ||
channel.bind('pusher:member_removed', handleRemove); | ||
channel.bind('pusher:subscription_succeeded', handleSubscriptionSuccess_1); | ||
channel.bind('pusher:member_added', handleAdd_1); | ||
channel.bind('pusher:member_removed', handleRemove_1); | ||
// set any members that already existed on the channel | ||
@@ -323,15 +301,14 @@ if (channel.members) { | ||
} | ||
// cleanup | ||
return function () { | ||
channel.unbind('pusher:subscription_succeeded', handleSubscriptionSuccess_1); | ||
channel.unbind('pusher:member_added', handleAdd_1); | ||
channel.unbind('pusher:member_removed', handleRemove_1); | ||
}; | ||
} | ||
// cleanup | ||
return function () { | ||
if (channel) { | ||
channel.unbind('pusher:subscription_succeeded', handleSubscriptionSuccess); | ||
channel.unbind('pusher:member_added', handleAdd); | ||
channel.unbind('pusher:member_removed', handleRemove); | ||
} | ||
}; | ||
}, [channel, handleSubscriptionSuccess, handleAdd, handleRemove]); | ||
var presenceChannel = channel; | ||
// to make typescript happy. | ||
return function () { }; | ||
}, [channel]); | ||
return { | ||
channel: presenceChannel, | ||
channel: channel, | ||
members: members, | ||
@@ -347,3 +324,2 @@ myID: myID, | ||
* @param callback Callback to call on a new event | ||
* @param dependencies Dependencies the callback uses. | ||
*/ | ||
@@ -355,3 +331,3 @@ function useEvent(channel, eventName, callback, dependencies) { | ||
// deprecate dependencies | ||
React.useEffect(function () { | ||
useEffect(function () { | ||
if (dependencies) { | ||
@@ -362,7 +338,8 @@ console.warn('The useEvent callback is no longer memoized - dependencies are deprecated and its up to you to memoize the callback if you want to.'); | ||
// bind and unbind events whenever the channel, eventName or callback changes. | ||
React.useEffect(function () { | ||
useEffect(function () { | ||
if (channel === undefined) { | ||
return; | ||
} | ||
channel.bind(eventName, callback); | ||
else | ||
channel.bind(eventName, callback); | ||
return function () { | ||
@@ -375,31 +352,56 @@ channel.unbind(eventName, callback); | ||
/** | ||
* Trigger events hook | ||
* | ||
* @param channel the channel you'd like to trigger clientEvents on. Get this from [[useChannel]] or [[usePresenceChannel]]. | ||
* @typeparam TData shape of the data you're sending with the event. | ||
* @returns A memoized trigger function that will perform client events on the channel. | ||
* @example | ||
* ```javascript | ||
* const channel = useChannel('my-channel'); | ||
* const trigger = useClientTrigger(channel) | ||
* | ||
* const trigger = useTrigger('my-channel'); | ||
* const handleClick = () => trigger('some-client-event', {}); | ||
* ``` | ||
*/ | ||
function useClientTrigger(channel) { | ||
channel && | ||
invariant_1(channel.name.match(/(private-|presence-)/gi), "Channel provided to useClientTrigger wasn't private or presence channel. Client events only work on these types of channels."); | ||
// memoize trigger so it's not being created every render | ||
var trigger = useCallback(function (eventName, data) { | ||
invariant_1(eventName, 'Must pass event name to trigger a client event.'); | ||
channel && channel.trigger(eventName, data); | ||
}, [channel]); | ||
return trigger; | ||
} | ||
/** | ||
* Hook to provide a trigger function that calls the server defined in `PusherProviderProps.triggerEndpoint` using `fetch`. | ||
* Any `auth?.headers` in the config object will be passed with the `fetch` call. | ||
* | ||
* @param channelName name of channel to call trigger on | ||
* @typeparam TData shape of the data you're sending with the event | ||
* | ||
* @example | ||
* ```typescript | ||
* const trigger = useTrigger<{message: string}>('my-channel'); | ||
* trigger('my-event', {message: 'hello'}); | ||
* ``` | ||
*/ | ||
function useTrigger(channelName) { | ||
var _a = usePusher(), client = _a.client, triggerEndpoint = _a.triggerEndpoint; | ||
// you can't use this if you haven't supplied a triggerEndpoint. | ||
invariant_1(triggerEndpoint, 'No trigger endpoint specified to <PusherProvider />. Cannot trigger an event.'); | ||
// subscribe to the channel we'll be triggering to. | ||
useChannel(channelName); | ||
invariant_1(channelName, "No channel specified to trigger to."); | ||
invariant_1(triggerEndpoint, "No trigger endpoint specified to <PusherProvider />. Cannot trigger an event."); | ||
/** | ||
* Memoized trigger function | ||
*/ | ||
var trigger = React.useCallback(function (eventName, data) { | ||
// memoized trigger function to return | ||
var trigger = useCallback(function (eventName, data) { | ||
var fetchOptions = { | ||
method: "POST", | ||
body: JSON.stringify({ channelName: channelName, eventName: eventName, data: data }) | ||
method: 'POST', | ||
body: JSON.stringify({ channelName: channelName, eventName: eventName, data: data }), | ||
}; | ||
if (client.current && client.current.config.auth) { | ||
if (client && client.current && client.current.config.auth) { | ||
fetchOptions.headers = client.current.config.auth.headers; | ||
} | ||
else { | ||
console.warn("No auth parameters supplied to <PusherProvider />. Your events will be unauthenticated."); | ||
console.warn('No auth parameters supplied to <PusherProvider />. Your events will be unauthenticated.'); | ||
} | ||
// forcing triggerEndpoint to exist for TS here | ||
// because invariant will throw during dev | ||
return fetch(triggerEndpoint, fetchOptions); | ||
@@ -410,14 +412,2 @@ }, [client, triggerEndpoint, channelName]); | ||
function useClientTrigger(channel) { | ||
channel && | ||
invariant_1(channel.name.match(/(private-|presence-)/gi), "Channel provided to useClientTrigger wasn't private or presence channel. Client events only work on these types of channels."); | ||
// memoize trigger so it's not being created every render | ||
var trigger = React.useCallback(function (eventName, data) { | ||
if (data === void 0) { data = {}; } | ||
invariant_1(eventName, 'Must pass event name to trigger a client event.'); | ||
channel && channel.trigger(eventName, data); | ||
}, [channel]); | ||
return trigger; | ||
} | ||
var PusherChannelMock = /** @class */ (function () { | ||
@@ -510,14 +500,3 @@ function PusherChannelMock(name) { | ||
exports.NOT_IN_CONTEXT_WARNING = NOT_IN_CONTEXT_WARNING; | ||
exports.PusherChannelMock = PusherChannelMock; | ||
exports.PusherMock = PusherMock; | ||
exports.PusherPresenceChannelMock = PusherPresenceChannelMock; | ||
exports.PusherProvider = PusherProvider; | ||
exports.__PusherContext = __PusherContext; | ||
exports.useChannel = useChannel; | ||
exports.useClientTrigger = useClientTrigger; | ||
exports.useEvent = useEvent; | ||
exports.usePresenceChannel = usePresenceChannel; | ||
exports.usePusher = usePusher; | ||
exports.useTrigger = useTrigger; | ||
export { NOT_IN_CONTEXT_WARNING, PusherChannelMock, PusherMock, PusherPresenceChannelMock, PusherProvider, __PusherContext, useChannel, useClientTrigger, useEvent, usePresenceChannel, usePusher, useTrigger }; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@harelpls/use-pusher", | ||
"version": "3.1.3", | ||
"version": "3.2.0", | ||
"description": "A wrapper around pusher-js for easy-as hooks in React.", | ||
@@ -24,3 +24,3 @@ "author": "@mayteio", | ||
"jsnext:main": "dist/index.es.js", | ||
"typings": "dist/index.d.ts", | ||
"types": "dist/index.d.ts", | ||
"engines": { | ||
@@ -33,7 +33,7 @@ "node": ">=8", | ||
"test:watch": "react-scripts test --env=jsdom", | ||
"build": "rollup -c", | ||
"build": "rimraf dist && rollup -c", | ||
"start": "rollup -c -w", | ||
"types": "dts-bundle-generator -o ./dist/index.d.ts ./src/index.ts --external-imports pusher-js", | ||
"docs": "typedoc --options ./typedoc.js ./src", | ||
"release": "yarn test && yarn build && yarn types && yarn publish" | ||
"release": "yarn test && yarn build && yarn types && yarn publish && ntl deploy" | ||
}, | ||
@@ -69,2 +69,3 @@ "dependencies": { | ||
"react-test-renderer": "^16.9.0", | ||
"rimraf": "^3.0.2", | ||
"rollup": "^1.20.0", | ||
@@ -71,0 +72,0 @@ "rollup-plugin-babel": "^4.3.3", |
@@ -21,3 +21,2 @@ # use-pusher | ||
- [`useTrigger`](#usetrigger) | ||
- [`useClientTrigger`](#useclienttrigger) | ||
- [`usePusher`](#usepusher) | ||
@@ -162,4 +161,2 @@ | ||
## `useClientTrigger` | ||
> _I don't want a server though_ | ||
@@ -191,3 +188,3 @@ | ||
Testing emitted events with jest can be achieved using `jest.mock` and `@testing-library/react` (or `enzyme`, though your tests should reflect what the user should see **NOT** how the component handles events internally): | ||
Testing emitted events with jest can be achieved using `jest.mock` and `react-testing-library` (or `enzyme`, though your tests should reflect what the user should see **NOT** how the component handles events internally): | ||
@@ -194,0 +191,0 @@ ```typescript |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1078
51983
31
247