jason-rails 0.3.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -1
  3. data/.ruby-version +1 -0
  4. data/Gemfile.lock +184 -0
  5. data/README.md +118 -10
  6. data/app/controllers/jason/api/pusher_controller.rb +15 -0
  7. data/app/controllers/jason/api_controller.rb +78 -0
  8. data/client/babel.config.js +13 -0
  9. data/client/lib/JasonContext.d.ts +6 -1
  10. data/client/lib/JasonProvider.d.ts +6 -5
  11. data/client/lib/JasonProvider.js +5 -97
  12. data/client/lib/actionFactory.js +1 -1
  13. data/client/lib/createActions.d.ts +1 -1
  14. data/client/lib/createActions.js +2 -27
  15. data/client/lib/createJasonReducers.js +49 -3
  16. data/client/lib/createOptDis.d.ts +1 -0
  17. data/client/lib/createOptDis.js +43 -0
  18. data/client/lib/createPayloadHandler.d.ts +9 -1
  19. data/client/lib/createPayloadHandler.js +52 -43
  20. data/client/lib/createServerActionQueue.d.ts +10 -0
  21. data/client/lib/createServerActionQueue.js +48 -0
  22. data/client/lib/createServerActionQueue.test.d.ts +1 -0
  23. data/client/lib/createServerActionQueue.test.js +37 -0
  24. data/client/lib/createTransportAdapter.d.ts +5 -0
  25. data/client/lib/createTransportAdapter.js +20 -0
  26. data/client/lib/deepCamelizeKeys.d.ts +1 -0
  27. data/client/lib/deepCamelizeKeys.js +23 -0
  28. data/client/lib/deepCamelizeKeys.test.d.ts +1 -0
  29. data/client/lib/deepCamelizeKeys.test.js +106 -0
  30. data/client/lib/index.d.ts +6 -5
  31. data/client/lib/pruneIdsMiddleware.d.ts +2 -0
  32. data/client/lib/pruneIdsMiddleware.js +24 -0
  33. data/client/lib/restClient.d.ts +2 -0
  34. data/client/lib/restClient.js +17 -0
  35. data/client/lib/transportAdapters/actionCableAdapter.d.ts +5 -0
  36. data/client/lib/transportAdapters/actionCableAdapter.js +35 -0
  37. data/client/lib/transportAdapters/pusherAdapter.d.ts +5 -0
  38. data/client/lib/transportAdapters/pusherAdapter.js +68 -0
  39. data/client/lib/useJason.d.ts +5 -0
  40. data/client/lib/useJason.js +94 -0
  41. data/client/lib/useJason.test.d.ts +1 -0
  42. data/client/lib/useJason.test.js +85 -0
  43. data/client/lib/useSub.d.ts +1 -1
  44. data/client/lib/useSub.js +6 -3
  45. data/client/package.json +19 -4
  46. data/client/src/JasonProvider.tsx +6 -96
  47. data/client/src/actionFactory.ts +1 -1
  48. data/client/src/createActions.ts +2 -33
  49. data/client/src/createJasonReducers.ts +57 -3
  50. data/client/src/createOptDis.ts +45 -0
  51. data/client/src/createPayloadHandler.ts +58 -47
  52. data/client/src/createServerActionQueue.test.ts +42 -0
  53. data/client/src/createServerActionQueue.ts +47 -0
  54. data/client/src/createTransportAdapter.ts +13 -0
  55. data/client/src/deepCamelizeKeys.test.ts +113 -0
  56. data/client/src/deepCamelizeKeys.ts +17 -0
  57. data/client/src/pruneIdsMiddleware.ts +24 -0
  58. data/client/src/restClient.ts +14 -0
  59. data/client/src/transportAdapters/actionCableAdapter.ts +38 -0
  60. data/client/src/transportAdapters/pusherAdapter.ts +72 -0
  61. data/client/src/useJason.test.ts +87 -0
  62. data/client/src/useJason.ts +110 -0
  63. data/client/src/useSub.ts +6 -3
  64. data/client/yarn.lock +4607 -81
  65. data/config/routes.rb +8 -0
  66. data/jason-rails.gemspec +9 -0
  67. data/lib/jason.rb +40 -1
  68. data/lib/jason/api_model.rb +15 -9
  69. data/lib/jason/broadcaster.rb +19 -0
  70. data/lib/jason/channel.rb +50 -21
  71. data/lib/jason/engine.rb +5 -0
  72. data/lib/jason/graph_helper.rb +165 -0
  73. data/lib/jason/includes_helper.rb +108 -0
  74. data/lib/jason/lua_generator.rb +71 -0
  75. data/lib/jason/publisher.rb +103 -30
  76. data/lib/jason/publisher_old.rb +112 -0
  77. data/lib/jason/subscription.rb +352 -101
  78. data/lib/jason/subscription_old.rb +171 -0
  79. data/lib/jason/version.rb +1 -1
  80. metadata +151 -4
@@ -0,0 +1,10 @@
1
+ export default function createServerActionQueue(): {
2
+ addItem: (item: any) => void;
3
+ getItem: () => any;
4
+ itemProcessed: () => boolean;
5
+ fullySynced: () => boolean;
6
+ getData: () => {
7
+ queue: any[];
8
+ inFlight: boolean;
9
+ };
10
+ };
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ // A FIFO queue with deduping of actions whose effect will be cancelled by later actions
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const lodash_1 = __importDefault(require("lodash"));
8
+ function createServerActionQueue() {
9
+ const queue = [];
10
+ let inFlight = false;
11
+ function addItem(item) {
12
+ // Check if there are any items ahead in the queue that this item would effectively overwrite.
13
+ // In that case we can remove them
14
+ // If this is an upsert && item ID is the same && current item attributes are a superset of the earlier item attributes
15
+ const { type, payload } = item;
16
+ if (type.split('/')[1] !== 'upsert') {
17
+ queue.push(item);
18
+ return;
19
+ }
20
+ lodash_1.default.remove(queue, item => {
21
+ const { type: itemType, payload: itemPayload } = item;
22
+ if (type !== itemType)
23
+ return false;
24
+ if (itemPayload.id !== payload.id)
25
+ return false;
26
+ // Check that all keys of itemPayload are in payload.
27
+ return lodash_1.default.difference(lodash_1.default.keys(itemPayload), lodash_1.default.keys(payload)).length === 0;
28
+ });
29
+ queue.push(item);
30
+ }
31
+ return {
32
+ addItem,
33
+ getItem: () => {
34
+ if (inFlight)
35
+ return false;
36
+ const item = queue.shift();
37
+ if (item) {
38
+ inFlight = true;
39
+ return item;
40
+ }
41
+ return false;
42
+ },
43
+ itemProcessed: () => inFlight = false,
44
+ fullySynced: () => queue.length === 0 && !inFlight,
45
+ getData: () => ({ queue, inFlight })
46
+ };
47
+ }
48
+ exports.default = createServerActionQueue;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const createServerActionQueue_1 = __importDefault(require("./createServerActionQueue"));
7
+ test('Adding items', () => {
8
+ const serverActionQueue = createServerActionQueue_1.default();
9
+ serverActionQueue.addItem({ type: 'entity/add', payload: { id: 'abc', attribute: 1 } });
10
+ const item = serverActionQueue.getItem();
11
+ expect(item).toStrictEqual({ type: 'entity/add', payload: { id: 'abc', attribute: 1 } });
12
+ });
13
+ test('Deduping of items that will overwrite each other', () => {
14
+ const serverActionQueue = createServerActionQueue_1.default();
15
+ serverActionQueue.addItem({ type: 'entity/upsert', payload: { id: 'abc', attribute: 1 } });
16
+ serverActionQueue.addItem({ type: 'entity/upsert', payload: { id: 'abc', attribute: 2 } });
17
+ serverActionQueue.addItem({ type: 'entity/upsert', payload: { id: 'abc', attribute: 3 } });
18
+ const item = serverActionQueue.getItem();
19
+ expect(item).toStrictEqual({ type: 'entity/upsert', payload: { id: 'abc', attribute: 3 } });
20
+ });
21
+ test('Deduping of items with a superset', () => {
22
+ const serverActionQueue = createServerActionQueue_1.default();
23
+ serverActionQueue.addItem({ type: 'entity/upsert', payload: { id: 'abc', attribute: 1 } });
24
+ serverActionQueue.addItem({ type: 'entity/upsert', payload: { id: 'abc', attribute: 2, attribute2: 'test' } });
25
+ const item = serverActionQueue.getItem();
26
+ expect(item).toStrictEqual({ type: 'entity/upsert', payload: { id: 'abc', attribute: 2, attribute2: 'test' } });
27
+ });
28
+ test("doesn't dedupe items with some attributes missing", () => {
29
+ const serverActionQueue = createServerActionQueue_1.default();
30
+ serverActionQueue.addItem({ type: 'entity/upsert', payload: { id: 'abc', attribute: 1 } });
31
+ serverActionQueue.addItem({ type: 'entity/upsert', payload: { id: 'abc', attribute2: 'test' } });
32
+ const item = serverActionQueue.getItem();
33
+ serverActionQueue.itemProcessed();
34
+ const item2 = serverActionQueue.getItem();
35
+ expect(item).toStrictEqual({ type: 'entity/upsert', payload: { id: 'abc', attribute: 1 } });
36
+ expect(item2).toStrictEqual({ type: 'entity/upsert', payload: { id: 'abc', attribute2: 'test' } });
37
+ });
@@ -0,0 +1,5 @@
1
+ export default function createTransportAdapter(jasonConfig: any, handlePayload: any, dispatch: any, onConnect: any): {
2
+ getPayload: (config: any, options: any) => void;
3
+ createSubscription: (config: any) => void;
4
+ removeSubscription: (config: any) => void;
5
+ };
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const actionCableAdapter_1 = __importDefault(require("./transportAdapters/actionCableAdapter"));
7
+ const pusherAdapter_1 = __importDefault(require("./transportAdapters/pusherAdapter"));
8
+ function createTransportAdapter(jasonConfig, handlePayload, dispatch, onConnect) {
9
+ const { transportService } = jasonConfig;
10
+ if (transportService === 'action_cable') {
11
+ return actionCableAdapter_1.default(jasonConfig, handlePayload, dispatch, onConnect);
12
+ }
13
+ else if (transportService === 'pusher') {
14
+ return pusherAdapter_1.default(jasonConfig, handlePayload, dispatch);
15
+ }
16
+ else {
17
+ throw (`Transport adapter does not exist for ${transportService}`);
18
+ }
19
+ }
20
+ exports.default = createTransportAdapter;
@@ -0,0 +1 @@
1
+ export default function deepCamelizeKeys(item: any, excludeIf?: (k: any) => boolean): any;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const lodash_1 = __importDefault(require("lodash"));
7
+ function deepCamelizeKeys(item, excludeIf = k => false) {
8
+ function camelizeKey(key) {
9
+ if (excludeIf(key))
10
+ return key;
11
+ return lodash_1.default.camelCase(key);
12
+ }
13
+ if (lodash_1.default.isArray(item)) {
14
+ return lodash_1.default.map(item, item => deepCamelizeKeys(item, excludeIf));
15
+ }
16
+ else if (lodash_1.default.isObject(item)) {
17
+ return lodash_1.default.mapValues(lodash_1.default.mapKeys(item, (v, k) => camelizeKey(k)), (v, k) => deepCamelizeKeys(v, excludeIf));
18
+ }
19
+ else {
20
+ return item;
21
+ }
22
+ }
23
+ exports.default = deepCamelizeKeys;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const deepCamelizeKeys_1 = __importDefault(require("./deepCamelizeKeys"));
7
+ test('scalar number', () => {
8
+ expect(deepCamelizeKeys_1.default(1)).toBe(1);
9
+ });
10
+ test('scalar number float', () => {
11
+ expect(deepCamelizeKeys_1.default(1.123)).toBe(1.123);
12
+ });
13
+ test('scalar string', () => {
14
+ expect(deepCamelizeKeys_1.default('test')).toBe('test');
15
+ });
16
+ test('scalar null', () => {
17
+ expect(deepCamelizeKeys_1.default(null)).toBe(null);
18
+ });
19
+ test('scalar boolean', () => {
20
+ expect(deepCamelizeKeys_1.default(true)).toBe(true);
21
+ });
22
+ test('object with existing camelized keys', () => {
23
+ expect(deepCamelizeKeys_1.default({ testMe: 'test' })).toStrictEqual({ testMe: 'test' });
24
+ });
25
+ test('array with existing camelized keys', () => {
26
+ expect(deepCamelizeKeys_1.default([{ testMe: 'test' }, { testMe2: 'test' }])).toStrictEqual([{ testMe: 'test' }, { testMe2: 'test' }]);
27
+ });
28
+ test('object with mixed keys', () => {
29
+ expect(deepCamelizeKeys_1.default({ testMe: 'test', test_2: 'dog', test_me2: true })).toStrictEqual({ testMe: 'test', test2: 'dog', testMe2: true });
30
+ });
31
+ test('array with mixed keys', () => {
32
+ expect(deepCamelizeKeys_1.default([
33
+ { testMe: 'test', test_2: 'dog', test_me2: true },
34
+ { testMe3: 'test', test_3: 'dog', test_me4: true }
35
+ ])).toStrictEqual([
36
+ { testMe: 'test', test2: 'dog', testMe2: true },
37
+ { testMe3: 'test', test3: 'dog', testMe4: true }
38
+ ]);
39
+ });
40
+ test('nested with object at top level', () => {
41
+ expect(deepCamelizeKeys_1.default({
42
+ test_me: {
43
+ test_me2: {
44
+ test_me3: [
45
+ { test_it_out: '49' },
46
+ { test_fun: 'what' }
47
+ ]
48
+ }
49
+ }
50
+ })).toStrictEqual({
51
+ testMe: {
52
+ testMe2: {
53
+ testMe3: [
54
+ { testItOut: '49' },
55
+ { testFun: 'what' }
56
+ ]
57
+ }
58
+ }
59
+ });
60
+ });
61
+ test('nested with object at top level', () => {
62
+ expect(deepCamelizeKeys_1.default([{
63
+ test_me: {
64
+ test_me2: {
65
+ test_me3: [
66
+ { test_it_out: '49' },
67
+ { test_fun: 'what' }
68
+ ]
69
+ }
70
+ }
71
+ }, {
72
+ test_it52: 'what?'
73
+ }])).toStrictEqual([{
74
+ testMe: {
75
+ testMe2: {
76
+ testMe3: [
77
+ { testItOut: '49' },
78
+ { testFun: 'what' }
79
+ ]
80
+ }
81
+ }
82
+ }, {
83
+ testIt52: 'what?'
84
+ }]);
85
+ });
86
+ test('excludes keys by function', () => {
87
+ expect(deepCamelizeKeys_1.default({
88
+ test_me: {
89
+ test_me2: {
90
+ test_me3: [
91
+ { test_it_out: '49' },
92
+ { test_fun: 'what' }
93
+ ]
94
+ }
95
+ }
96
+ }, k => (k === 'test_me2'))).toStrictEqual({
97
+ testMe: {
98
+ test_me2: {
99
+ testMe3: [
100
+ { testItOut: '49' },
101
+ { testFun: 'what' }
102
+ ]
103
+ }
104
+ }
105
+ });
106
+ });
@@ -1,10 +1,11 @@
1
+ /// <reference types="react" />
1
2
  import _useAct from './useAct';
2
3
  import _useSub from './useSub';
3
4
  export declare const JasonProvider: ({ reducers, middleware, extraActions, children }: {
4
- reducers: any;
5
- middleware: any;
6
- extraActions: any;
7
- children: any;
8
- }) => any;
5
+ reducers?: any;
6
+ middleware?: any;
7
+ extraActions?: any;
8
+ children?: import("react").FC<{}> | undefined;
9
+ }) => JSX.Element;
9
10
  export declare const useAct: typeof _useAct;
10
11
  export declare const useSub: typeof _useSub;
@@ -0,0 +1,2 @@
1
+ declare const pruneIdsMiddleware: (schema: any) => (store: any) => (next: any) => (action: any) => any;
2
+ export default pruneIdsMiddleware;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const lodash_1 = __importDefault(require("lodash"));
7
+ const pluralize_1 = __importDefault(require("pluralize"));
8
+ const pruneIdsMiddleware = schema => store => next => action => {
9
+ const { type, payload } = action;
10
+ const result = next(action);
11
+ const state = store.getState();
12
+ if (type === 'jasonModels/setSubscriptionIds' || type === 'jasonModels/removeSubscriptionIds') {
13
+ const { model, ids } = payload;
14
+ let idsInSubs = [];
15
+ lodash_1.default.map(state.jasonModels[model], (subscribedIds, k) => {
16
+ idsInSubs = lodash_1.default.union(idsInSubs, subscribedIds);
17
+ });
18
+ // Find IDs currently in Redux that aren't in any subscription
19
+ const idsToRemove = lodash_1.default.difference(state[pluralize_1.default(model)].ids, idsInSubs);
20
+ store.dispatch({ type: `${pluralize_1.default(model)}/removeMany`, payload: idsToRemove });
21
+ }
22
+ return result;
23
+ };
24
+ exports.default = pruneIdsMiddleware;
@@ -0,0 +1,2 @@
1
+ declare const restClient: any;
2
+ export default restClient;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ var _a;
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const axios_case_converter_1 = __importDefault(require("axios-case-converter"));
9
+ const uuid_1 = require("uuid");
10
+ const csrfToken = (_a = document === null || document === void 0 ? void 0 : document.querySelector("meta[name=csrf-token]")) === null || _a === void 0 ? void 0 : _a.content;
11
+ axios_1.default.defaults.headers.common['X-CSRF-Token'] = csrfToken;
12
+ const restClient = axios_case_converter_1.default(axios_1.default.create(), {
13
+ preservedKeys: (key) => {
14
+ return uuid_1.validate(key);
15
+ }
16
+ });
17
+ exports.default = restClient;
@@ -0,0 +1,5 @@
1
+ export default function actionCableAdapter(jasonConfig: any, handlePayload: any, dispatch: any, onConnected: any): {
2
+ getPayload: (config: any, options: any) => void;
3
+ createSubscription: (config: any) => void;
4
+ removeSubscription: (config: any) => void;
5
+ };
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const actioncable_1 = require("@rails/actioncable");
4
+ function actionCableAdapter(jasonConfig, handlePayload, dispatch, onConnected) {
5
+ const consumer = actioncable_1.createConsumer();
6
+ const subscription = (consumer.subscriptions.create({
7
+ channel: 'Jason::Channel'
8
+ }, {
9
+ connected: () => {
10
+ dispatch({ type: 'jason/upsert', payload: { connected: true } });
11
+ console.debug('Connected to ActionCable');
12
+ // When AC loses connection - all state is lost, so we need to re-initialize all subscriptions
13
+ onConnected();
14
+ },
15
+ received: payload => {
16
+ handlePayload(payload);
17
+ console.debug("ActionCable Payload received: ", payload);
18
+ },
19
+ disconnected: () => {
20
+ dispatch({ type: 'jason/upsert', payload: { connected: false } });
21
+ console.warn('Disconnected from ActionCable');
22
+ }
23
+ }));
24
+ function getPayload(config, options) {
25
+ subscription.send(Object.assign({ getPayload: config }, options));
26
+ }
27
+ function createSubscription(config) {
28
+ subscription.send({ createSubscription: config });
29
+ }
30
+ function removeSubscription(config) {
31
+ subscription.send({ removeSubscription: config });
32
+ }
33
+ return { getPayload, createSubscription, removeSubscription };
34
+ }
35
+ exports.default = actionCableAdapter;
@@ -0,0 +1,5 @@
1
+ export default function pusherAdapter(jasonConfig: any, handlePayload: any, dispatch: any): {
2
+ getPayload: (config: any, options: any) => void;
3
+ createSubscription: (config: any) => void;
4
+ removeSubscription: (config: any) => void;
5
+ };
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const pusher_js_1 = __importDefault(require("pusher-js"));
7
+ const restClient_1 = __importDefault(require("../restClient"));
8
+ const uuid_1 = require("uuid");
9
+ const lodash_1 = __importDefault(require("lodash"));
10
+ function pusherAdapter(jasonConfig, handlePayload, dispatch) {
11
+ let consumerId = uuid_1.v4();
12
+ const { pusherKey, pusherRegion, pusherChannelPrefix } = jasonConfig;
13
+ const pusher = new pusher_js_1.default(pusherKey, {
14
+ cluster: 'eu',
15
+ forceTLS: true,
16
+ authEndpoint: '/jason/api/pusher/auth'
17
+ });
18
+ pusher.connection.bind('state_change', ({ current }) => {
19
+ if (current === 'connected') {
20
+ dispatch({ type: 'jason/upsert', payload: { connected: true } });
21
+ }
22
+ else {
23
+ dispatch({ type: 'jason/upsert', payload: { connected: false } });
24
+ }
25
+ });
26
+ pusher.connection.bind('error', error => {
27
+ dispatch({ type: 'jason/upsert', payload: { connected: false } });
28
+ });
29
+ const configToChannel = {};
30
+ function createSubscription(config) {
31
+ restClient_1.default.post('/jason/api/create_subscription', { config, consumerId })
32
+ .then(({ data: { channelName } }) => {
33
+ configToChannel[JSON.stringify(config)] = channelName;
34
+ subscribeToChannel(channelName);
35
+ })
36
+ .catch(e => console.error(e));
37
+ }
38
+ function removeSubscription(config) {
39
+ const channelName = configToChannel[JSON.stringify(config)];
40
+ unsubscribeFromChannel(fullChannelName(channelName));
41
+ restClient_1.default.post('/jason/api/remove_subscription', { config, consumerId })
42
+ .catch(e => console.error(e));
43
+ }
44
+ function getPayload(config, options) {
45
+ restClient_1.default.post('/jason/api/get_payload', {
46
+ config,
47
+ options
48
+ })
49
+ .then(({ data }) => {
50
+ lodash_1.default.map(data, (payload, modelName) => {
51
+ handlePayload(payload);
52
+ });
53
+ })
54
+ .catch(e => console.error(e));
55
+ }
56
+ function subscribeToChannel(channelName) {
57
+ const channel = pusher.subscribe(fullChannelName(channelName));
58
+ channel.bind('changed', message => handlePayload(message));
59
+ }
60
+ function unsubscribeFromChannel(channelName) {
61
+ const channel = pusher.unsubscribe(fullChannelName(channelName));
62
+ }
63
+ function fullChannelName(channelName) {
64
+ return `private-${pusherChannelPrefix}-${channelName}`;
65
+ }
66
+ return { getPayload, createSubscription, removeSubscription };
67
+ }
68
+ exports.default = pusherAdapter;