jason-rails 0.4.1 → 0.5.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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -0
  3. data/Gemfile.lock +152 -2
  4. data/app/controllers/jason/api_controller.rb +1 -1
  5. data/client/lib/JasonContext.d.ts +6 -1
  6. data/client/lib/JasonProvider.d.ts +2 -2
  7. data/client/lib/JasonProvider.js +5 -124
  8. data/client/lib/createJasonReducers.js +41 -3
  9. data/client/lib/createOptDis.js +0 -2
  10. data/client/lib/createPayloadHandler.d.ts +6 -1
  11. data/client/lib/createPayloadHandler.js +42 -54
  12. data/client/lib/createServerActionQueue.d.ts +10 -0
  13. data/client/lib/createServerActionQueue.js +48 -0
  14. data/client/lib/createServerActionQueue.test.d.ts +1 -0
  15. data/client/lib/createServerActionQueue.test.js +37 -0
  16. data/client/lib/index.d.ts +3 -2
  17. data/client/lib/pruneIdsMiddleware.d.ts +2 -0
  18. data/client/lib/pruneIdsMiddleware.js +26 -0
  19. data/client/lib/restClient.d.ts +2 -0
  20. data/client/lib/restClient.js +17 -0
  21. data/client/lib/useJason.d.ts +5 -0
  22. data/client/lib/useJason.js +99 -0
  23. data/client/lib/useJason.test.d.ts +1 -0
  24. data/client/lib/useJason.test.js +79 -0
  25. data/client/lib/useSub.js +1 -0
  26. data/client/package.json +4 -3
  27. data/client/src/JasonProvider.tsx +5 -123
  28. data/client/src/createJasonReducers.ts +49 -3
  29. data/client/src/createOptDis.ts +0 -2
  30. data/client/src/createPayloadHandler.ts +47 -63
  31. data/client/src/createServerActionQueue.test.ts +42 -0
  32. data/client/src/createServerActionQueue.ts +47 -0
  33. data/client/src/pruneIdsMiddleware.ts +24 -0
  34. data/client/src/restClient.ts +13 -0
  35. data/client/src/useJason.test.ts +81 -0
  36. data/client/src/useJason.ts +115 -0
  37. data/client/src/useSub.ts +1 -0
  38. data/client/yarn.lock +59 -3
  39. data/jason-rails.gemspec +4 -0
  40. data/lib/jason.rb +12 -0
  41. data/lib/jason/api_model.rb +2 -12
  42. data/lib/jason/channel.rb +43 -21
  43. data/lib/jason/lua_generator.rb +49 -0
  44. data/lib/jason/publisher.rb +76 -35
  45. data/lib/jason/publisher_old.rb +112 -0
  46. data/lib/jason/subscription.rb +322 -99
  47. data/lib/jason/subscription_old.rb +171 -0
  48. data/lib/jason/version.rb +1 -1
  49. metadata +67 -3
@@ -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,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
+ });
@@ -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
5
  reducers?: any;
5
6
  middleware?: any;
6
7
  extraActions?: any;
7
- children?: any;
8
- }) => 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,26 @@
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 } = action;
10
+ const result = next(action);
11
+ const state = store.getState();
12
+ if (type === 'jasonModels/setSubscriptionIds') {
13
+ // Check every model
14
+ lodash_1.default.map(lodash_1.default.keys(schema), model => {
15
+ let ids = [];
16
+ lodash_1.default.map(state.jasonModels[model], (subscribedIds, k) => {
17
+ ids = lodash_1.default.union(ids, subscribedIds);
18
+ });
19
+ // Find IDs currently in Redux that aren't in any subscription
20
+ const idsToRemove = lodash_1.default.difference(state[pluralize_1.default(model)].ids, ids);
21
+ store.dispatch({ type: `${pluralize_1.default(model)}/removeMany`, payload: idsToRemove });
22
+ });
23
+ }
24
+ return result;
25
+ };
26
+ exports.default = pruneIdsMiddleware;
@@ -0,0 +1,2 @@
1
+ declare const restClient: import("axios").AxiosInstance;
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 useJason({ reducers, middleware, extraActions }: {
2
+ reducers?: any;
3
+ middleware?: any[];
4
+ extraActions?: any;
5
+ }): any[];
@@ -0,0 +1,99 @@
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 createActions_1 = __importDefault(require("./createActions"));
7
+ const createJasonReducers_1 = __importDefault(require("./createJasonReducers"));
8
+ const createPayloadHandler_1 = __importDefault(require("./createPayloadHandler"));
9
+ const createOptDis_1 = __importDefault(require("./createOptDis"));
10
+ const createServerActionQueue_1 = __importDefault(require("./createServerActionQueue"));
11
+ const restClient_1 = __importDefault(require("./restClient"));
12
+ const pruneIdsMiddleware_1 = __importDefault(require("./pruneIdsMiddleware"));
13
+ const actioncable_1 = require("@rails/actioncable");
14
+ const toolkit_1 = require("@reduxjs/toolkit");
15
+ const makeEager_1 = __importDefault(require("./makeEager"));
16
+ const humps_1 = require("humps");
17
+ const blueimp_md5_1 = __importDefault(require("blueimp-md5"));
18
+ const lodash_1 = __importDefault(require("lodash"));
19
+ const react_1 = require("react");
20
+ function useJason({ reducers, middleware = [], extraActions }) {
21
+ const [store, setStore] = react_1.useState(null);
22
+ const [value, setValue] = react_1.useState(null);
23
+ const [connected, setConnected] = react_1.useState(false);
24
+ react_1.useEffect(() => {
25
+ restClient_1.default.get('/jason/api/schema')
26
+ .then(({ data: snakey_schema }) => {
27
+ const schema = humps_1.camelizeKeys(snakey_schema);
28
+ console.debug({ schema });
29
+ const serverActionQueue = createServerActionQueue_1.default();
30
+ const consumer = actioncable_1.createConsumer();
31
+ const allReducers = Object.assign(Object.assign({}, reducers), createJasonReducers_1.default(schema));
32
+ console.debug({ allReducers });
33
+ const store = toolkit_1.configureStore({ reducer: allReducers, middleware: [...middleware, pruneIdsMiddleware_1.default(schema)] });
34
+ const dispatch = store.dispatch;
35
+ const optDis = createOptDis_1.default(schema, dispatch, restClient_1.default, serverActionQueue);
36
+ const actions = createActions_1.default(schema, store, restClient_1.default, optDis, extraActions);
37
+ const eager = makeEager_1.default(schema);
38
+ let payloadHandlers = {};
39
+ let configs = {};
40
+ function handlePayload(payload) {
41
+ const { md5Hash } = payload;
42
+ const handler = payloadHandlers[md5Hash];
43
+ if (handler) {
44
+ handler(payload);
45
+ }
46
+ else {
47
+ console.warn("Payload arrived with no handler", payload, payloadHandlers);
48
+ }
49
+ }
50
+ const subscription = (consumer.subscriptions.create({
51
+ channel: 'Jason::Channel'
52
+ }, {
53
+ connected: () => {
54
+ setConnected(true);
55
+ dispatch({ type: 'jason/upsert', payload: { connected: true } });
56
+ console.debug('Connected to ActionCable');
57
+ // When AC loses connection - all state is lost, so we need to re-initialize all subscriptions
58
+ lodash_1.default.values(configs).forEach(config => createSubscription(config));
59
+ },
60
+ received: payload => {
61
+ handlePayload(payload);
62
+ console.debug("ActionCable Payload received: ", payload);
63
+ },
64
+ disconnected: () => {
65
+ setConnected(false);
66
+ dispatch({ type: 'jason/upsert', payload: { connected: false } });
67
+ console.warn('Disconnected from ActionCable');
68
+ }
69
+ }));
70
+ function createSubscription(config) {
71
+ // We need the hash to be consistent in Ruby / Javascript
72
+ const hashableConfig = lodash_1.default(Object.assign({ conditions: {}, includes: {} }, config)).toPairs().sortBy(0).fromPairs().value();
73
+ const md5Hash = blueimp_md5_1.default(JSON.stringify(hashableConfig));
74
+ payloadHandlers[md5Hash] = createPayloadHandler_1.default({ dispatch, serverActionQueue, subscription, config });
75
+ configs[md5Hash] = hashableConfig;
76
+ setTimeout(() => subscription.send({ createSubscription: hashableConfig }), 500);
77
+ return {
78
+ remove: () => removeSubscription(hashableConfig),
79
+ md5Hash
80
+ };
81
+ }
82
+ function removeSubscription(config) {
83
+ subscription.send({ removeSubscription: config });
84
+ const md5Hash = blueimp_md5_1.default(JSON.stringify(config));
85
+ delete payloadHandlers[md5Hash];
86
+ delete configs[md5Hash];
87
+ }
88
+ setValue({
89
+ actions: actions,
90
+ subscribe: config => createSubscription(config),
91
+ eager,
92
+ handlePayload
93
+ });
94
+ setStore(store);
95
+ });
96
+ }, []);
97
+ return [store, value, connected];
98
+ }
99
+ exports.default = useJason;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const react_hooks_1 = require("@testing-library/react-hooks");
16
+ const useJason_1 = __importDefault(require("./useJason"));
17
+ const restClient_1 = __importDefault(require("./restClient"));
18
+ jest.mock('./restClient');
19
+ test('it works', () => __awaiter(void 0, void 0, void 0, function* () {
20
+ const resp = { data: { post: {} } };
21
+ // @ts-ignore
22
+ restClient_1.default.get.mockResolvedValue(resp);
23
+ const { result, waitForNextUpdate } = react_hooks_1.renderHook(() => useJason_1.default({ reducers: {
24
+ test: (s, a) => s || {}
25
+ } }));
26
+ yield waitForNextUpdate();
27
+ const [store, value, connected] = result.current;
28
+ const { handlePayload, subscribe } = value;
29
+ const subscription = subscribe({ post: {} });
30
+ handlePayload({
31
+ type: 'payload',
32
+ model: 'post',
33
+ payload: [{ id: 4, name: 'test' }],
34
+ md5Hash: subscription.md5Hash,
35
+ idx: 1
36
+ });
37
+ handlePayload({
38
+ id: 4,
39
+ model: 'post',
40
+ destroy: true,
41
+ md5Hash: subscription.md5Hash,
42
+ idx: 2
43
+ });
44
+ handlePayload({
45
+ id: 5,
46
+ model: 'post',
47
+ payload: { id: 5, name: 'test2' },
48
+ md5Hash: subscription.md5Hash,
49
+ idx: 3
50
+ });
51
+ }));
52
+ test('pruning IDs', () => __awaiter(void 0, void 0, void 0, function* () {
53
+ const resp = { data: { post: {} } };
54
+ // @ts-ignore
55
+ restClient_1.default.get.mockResolvedValue(resp);
56
+ const { result, waitForNextUpdate } = react_hooks_1.renderHook(() => useJason_1.default({ reducers: {
57
+ test: (s, a) => s || {}
58
+ } }));
59
+ yield waitForNextUpdate();
60
+ const [store, value, connected] = result.current;
61
+ const { handlePayload, subscribe } = value;
62
+ const subscription = subscribe({ post: {} });
63
+ handlePayload({
64
+ type: 'payload',
65
+ model: 'post',
66
+ payload: [{ id: 4, name: 'test' }],
67
+ md5Hash: subscription.md5Hash,
68
+ idx: 1
69
+ });
70
+ handlePayload({
71
+ type: 'payload',
72
+ model: 'post',
73
+ payload: [{ id: 5, name: 'test it out' }],
74
+ md5Hash: subscription.md5Hash,
75
+ idx: 2
76
+ });
77
+ // The ID 4 should have been pruned
78
+ expect(store.getState().posts.ids).toStrictEqual([5]);
79
+ }));
@@ -8,6 +8,7 @@ const react_1 = require("react");
8
8
  function useSub(config) {
9
9
  const subscribe = react_1.useContext(JasonContext_1.default).subscribe;
10
10
  react_1.useEffect(() => {
11
+ // @ts-ignore
11
12
  return subscribe(config);
12
13
  }, []);
13
14
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jamesr2323/jason",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "module": "./lib/index.js",
5
5
  "types": "./lib/index.d.ts",
6
6
  "scripts": {
@@ -23,11 +23,12 @@
23
23
  "@babel/preset-env": "^7.12.11",
24
24
  "@babel/preset-typescript": "^7.12.7",
25
25
  "@reduxjs/toolkit": "^1.5.0",
26
+ "@testing-library/react-hooks": "^5.0.3",
26
27
  "@types/jest": "^26.0.19",
27
28
  "babel-jest": "^26.6.3",
28
29
  "jest": "^26.6.3",
29
- "react": "^16.8.3",
30
- "react-dom": "^16.8.3",
30
+ "react": "^16.9.x",
31
+ "react-dom": "^16.9.x",
31
32
  "react-redux": "^7.2.2",
32
33
  "typescript": "^4.1.2"
33
34
  },
@@ -1,130 +1,12 @@
1
- import createActions from './createActions'
2
- import { createConsumer } from "@rails/actioncable"
3
- import JasonContext from './JasonContext'
4
- import axios from 'axios'
5
- import applyCaseMiddleware from 'axios-case-converter'
1
+ import React from 'react'
2
+ import useJason from './useJason'
6
3
  import { Provider } from 'react-redux'
7
- import { createEntityAdapter, createSlice, createReducer, configureStore } from '@reduxjs/toolkit'
8
- import createJasonReducers from './createJasonReducers'
9
- import createPayloadHandler from './createPayloadHandler'
10
- import createOptDis from './createOptDis'
11
- import makeEager from './makeEager'
12
- import { camelizeKeys } from 'humps'
13
- import md5 from 'blueimp-md5'
14
- import _ from 'lodash'
15
- import React, { useState, useEffect } from 'react'
16
- import { validate as isUuid } from 'uuid'
4
+ import JasonContext from './JasonContext'
17
5
 
18
6
  const JasonProvider = ({ reducers, middleware, extraActions, children }: { reducers?: any, middleware?: any, extraActions?: any, children?: React.FC }) => {
19
- const [store, setStore] = useState(null)
20
- const [value, setValue] = useState(null)
21
- const [connected, setConnected] = useState(false)
22
-
23
- const csrfToken = (document.querySelector("meta[name=csrf-token]") as any).content
24
- axios.defaults.headers.common['X-CSRF-Token'] = csrfToken
25
- const restClient = applyCaseMiddleware(axios.create(), {
26
- preservedKeys: (key) => {
27
- return isUuid(key)
28
- }
29
- })
30
-
31
- useEffect(() => {
32
- restClient.get('/jason/api/schema')
33
- .then(({ data: snakey_schema }) => {
34
- const schema = camelizeKeys(snakey_schema)
35
-
36
- const serverActionQueue = function() {
37
- const queue: any[] = []
38
- let inFlight = false
39
-
40
- return {
41
- addItem: (item) => queue.push(item),
42
- getItem: () => {
43
- if (inFlight) return false
44
-
45
- const item = queue.shift()
46
- if (item) {
47
- inFlight = true
48
- return item
49
- }
50
- return false
51
- },
52
- itemProcessed: () => inFlight = false,
53
- fullySynced: () => queue.length === 0 && !inFlight,
54
- getData: () => ({ queue, inFlight })
55
- }
56
- }()
57
-
58
- const consumer = createConsumer()
59
- const allReducers = {
60
- ...reducers,
61
- ...createJasonReducers(schema)
62
- }
63
-
64
- console.log({ schema, allReducers })
65
- const store = configureStore({ reducer: allReducers, middleware })
66
-
67
- let payloadHandlers = {}
68
- function handlePayload(payload) {
69
- const { model, md5Hash } = payload
70
- console.log({ md5Hash, fn: `${model}:${md5Hash}`, payloadHandlers, model: _.camelCase(model), payload })
71
- const handler = payloadHandlers[`${_.camelCase(model)}:${md5Hash}`]
72
- if (handler) {
73
- handler({ ...payload, model: _.camelCase(model) })
74
- }
75
- }
76
-
77
- const subscription = (consumer.subscriptions.create({
78
- channel: 'Jason::Channel'
79
- }, {
80
- connected: () => {
81
- setConnected(true)
82
- },
83
- received: payload => {
84
- console.log("Payload received", payload)
85
- handlePayload(payload)
86
- },
87
- disconnected: () => console.warn('Disconnected from ActionCable')
88
- }));
89
-
90
- console.log('sending message')
91
- subscription.send({ message: 'test' })
92
-
93
- function createSubscription(config) {
94
- const md5Hash = md5(JSON.stringify(config))
95
- console.log('Subscribe with', config, md5Hash)
96
-
97
- _.map(config, (v, model) => {
98
- payloadHandlers[`${model}:${md5Hash}`] = createPayloadHandler(store.dispatch, serverActionQueue, subscription, model, schema[model])
99
- })
100
- subscription.send({ createSubscription: config })
101
-
102
- return () => removeSubscription(config)
103
- }
104
-
105
- function removeSubscription(config) {
106
- subscription.send({ removeSubscription: config })
107
- const md5Hash = md5(JSON.stringify(config))
108
- _.map(config, (v, model) => {
109
- delete payloadHandlers[`${model}:${md5Hash}`]
110
- })
111
- }
112
- const optDis = createOptDis(schema, store.dispatch, restClient, serverActionQueue)
113
- const actions = createActions(schema, store, restClient, optDis, extraActions)
114
- const eager = makeEager(schema)
115
-
116
- console.log({ actions })
117
-
118
- setValue({
119
- actions: actions,
120
- subscribe: (config) => createSubscription(config),
121
- eager
122
- })
123
- setStore(store)
124
- })
125
- }, [])
7
+ const [store, value, connected] = useJason({ reducers, middleware, extraActions })
126
8
 
127
- if(!(store && value && connected)) return <div /> // Wait for async fetch of schema to complete
9
+ if(!(store && value)) return <div /> // Wait for async fetch of schema to complete
128
10
 
129
11
  return <Provider store={store}>
130
12
  <JasonContext.Provider value={value}>{ children }</JasonContext.Provider>