jason-rails 0.4.0 → 0.6.1

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 (74) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -1
  3. data/.ruby-version +1 -0
  4. data/Gemfile.lock +152 -2
  5. data/README.md +117 -5
  6. data/app/controllers/jason/api/pusher_controller.rb +15 -0
  7. data/app/controllers/jason/api_controller.rb +44 -2
  8. data/client/lib/JasonContext.d.ts +6 -1
  9. data/client/lib/JasonProvider.d.ts +2 -2
  10. data/client/lib/JasonProvider.js +5 -124
  11. data/client/lib/createJasonReducers.js +48 -3
  12. data/client/lib/createOptDis.js +0 -2
  13. data/client/lib/createPayloadHandler.d.ts +9 -1
  14. data/client/lib/createPayloadHandler.js +47 -55
  15. data/client/lib/createServerActionQueue.d.ts +10 -0
  16. data/client/lib/createServerActionQueue.js +48 -0
  17. data/client/lib/createServerActionQueue.test.d.ts +1 -0
  18. data/client/lib/createServerActionQueue.test.js +37 -0
  19. data/client/lib/createTransportAdapter.d.ts +5 -0
  20. data/client/lib/createTransportAdapter.js +20 -0
  21. data/client/lib/index.d.ts +3 -2
  22. data/client/lib/pruneIdsMiddleware.d.ts +2 -0
  23. data/client/lib/pruneIdsMiddleware.js +24 -0
  24. data/client/lib/restClient.d.ts +2 -0
  25. data/client/lib/restClient.js +17 -0
  26. data/client/lib/transportAdapters/actionCableAdapter.d.ts +5 -0
  27. data/client/lib/transportAdapters/actionCableAdapter.js +35 -0
  28. data/client/lib/transportAdapters/pusherAdapter.d.ts +5 -0
  29. data/client/lib/transportAdapters/pusherAdapter.js +68 -0
  30. data/client/lib/useJason.d.ts +5 -0
  31. data/client/lib/useJason.js +94 -0
  32. data/client/lib/useJason.test.d.ts +1 -0
  33. data/client/lib/useJason.test.js +85 -0
  34. data/client/lib/useSub.d.ts +1 -1
  35. data/client/lib/useSub.js +6 -3
  36. data/client/package.json +5 -3
  37. data/client/src/JasonProvider.tsx +5 -123
  38. data/client/src/createJasonReducers.ts +56 -3
  39. data/client/src/createOptDis.ts +0 -2
  40. data/client/src/createPayloadHandler.ts +53 -64
  41. data/client/src/createServerActionQueue.test.ts +42 -0
  42. data/client/src/createServerActionQueue.ts +47 -0
  43. data/client/src/createTransportAdapter.ts +13 -0
  44. data/client/src/pruneIdsMiddleware.ts +24 -0
  45. data/client/src/restClient.ts +14 -0
  46. data/client/src/transportAdapters/actionCableAdapter.ts +38 -0
  47. data/client/src/transportAdapters/pusherAdapter.ts +72 -0
  48. data/client/src/useJason.test.ts +87 -0
  49. data/client/src/useJason.ts +110 -0
  50. data/client/src/useSub.ts +6 -3
  51. data/client/yarn.lock +71 -3
  52. data/config/routes.rb +5 -1
  53. data/jason-rails.gemspec +4 -0
  54. data/lib/jason.rb +61 -1
  55. data/lib/jason/api_model.rb +2 -12
  56. data/lib/jason/broadcaster.rb +19 -0
  57. data/lib/jason/channel.rb +50 -21
  58. data/lib/jason/graph_helper.rb +165 -0
  59. data/lib/jason/includes_helper.rb +108 -0
  60. data/lib/jason/lua_generator.rb +71 -0
  61. data/lib/jason/publisher.rb +82 -37
  62. data/lib/jason/publisher_old.rb +112 -0
  63. data/lib/jason/subscription.rb +349 -97
  64. data/lib/jason/subscription_old.rb +171 -0
  65. data/lib/jason/version.rb +1 -1
  66. metadata +80 -11
  67. data/app/assets/config/jason_engine_manifest.js +0 -1
  68. data/app/assets/images/jason/engine/.keep +0 -0
  69. data/app/assets/stylesheets/jason/engine/application.css +0 -15
  70. data/app/helpers/jason/engine/application_helper.rb +0 -6
  71. data/app/jobs/jason/engine/application_job.rb +0 -6
  72. data/app/mailers/jason/engine/application_mailer.rb +0 -8
  73. data/app/models/jason/engine/application_record.rb +0 -7
  74. data/app/views/layouts/jason/engine/application.html.erb +0 -15
@@ -0,0 +1,13 @@
1
+ import actionCableAdapter from './transportAdapters/actionCableAdapter'
2
+ import pusherAdapter from './transportAdapters/pusherAdapter'
3
+
4
+ export default function createTransportAdapter(jasonConfig, handlePayload, dispatch, onConnect) {
5
+ const { transportService } = jasonConfig
6
+ if (transportService === 'action_cable') {
7
+ return actionCableAdapter(jasonConfig, handlePayload, dispatch, onConnect)
8
+ } else if (transportService === 'pusher') {
9
+ return pusherAdapter(jasonConfig, handlePayload, dispatch)
10
+ } else {
11
+ throw(`Transport adapter does not exist for ${transportService}`)
12
+ }
13
+ }
@@ -0,0 +1,24 @@
1
+ import _ from 'lodash'
2
+ import pluralize from 'pluralize'
3
+
4
+ const pruneIdsMiddleware = schema => store => next => action => {
5
+ const { type, payload } = action
6
+ const result = next(action)
7
+
8
+ const state = store.getState()
9
+ if (type === 'jasonModels/setSubscriptionIds' || type === 'jasonModels/removeSubscriptionIds') {
10
+ const { model, ids } = payload
11
+
12
+ let idsInSubs = []
13
+ _.map(state.jasonModels[model], (subscribedIds, k) => {
14
+ idsInSubs = _.union(idsInSubs, subscribedIds)
15
+ })
16
+ // Find IDs currently in Redux that aren't in any subscription
17
+ const idsToRemove = _.difference(state[pluralize(model)].ids, idsInSubs)
18
+ store.dispatch({ type: `${pluralize(model)}/removeMany`, payload: idsToRemove })
19
+ }
20
+
21
+ return result
22
+ }
23
+
24
+ export default pruneIdsMiddleware
@@ -0,0 +1,14 @@
1
+ import axios from 'axios'
2
+ import applyCaseMiddleware from 'axios-case-converter'
3
+ import { validate as isUuid } from 'uuid'
4
+
5
+ const csrfToken = (document?.querySelector("meta[name=csrf-token]") as any)?.content
6
+ axios.defaults.headers.common['X-CSRF-Token'] = csrfToken
7
+
8
+ const restClient = applyCaseMiddleware(axios.create() as any, {
9
+ preservedKeys: (key) => {
10
+ return isUuid(key)
11
+ }
12
+ }) as any
13
+
14
+ export default restClient
@@ -0,0 +1,38 @@
1
+ import { createConsumer } from "@rails/actioncable"
2
+
3
+ export default function actionCableAdapter(jasonConfig, handlePayload, dispatch, onConnected) {
4
+ const consumer = createConsumer()
5
+ const subscription = (consumer.subscriptions.create({
6
+ channel: 'Jason::Channel'
7
+ }, {
8
+ connected: () => {
9
+ dispatch({ type: 'jason/upsert', payload: { connected: true } })
10
+ console.debug('Connected to ActionCable')
11
+
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
+
25
+ function getPayload(config, options) {
26
+ subscription.send({ getPayload: config, ...options })
27
+ }
28
+
29
+ function createSubscription(config) {
30
+ subscription.send({ createSubscription: config })
31
+ }
32
+
33
+ function removeSubscription(config) {
34
+ subscription.send({ removeSubscription: config })
35
+ }
36
+
37
+ return { getPayload, createSubscription, removeSubscription }
38
+ }
@@ -0,0 +1,72 @@
1
+ import Pusher from 'pusher-js'
2
+ import { createConsumer } from "@rails/actioncable"
3
+ import restClient from '../restClient'
4
+ import { v4 as uuidv4 } from 'uuid'
5
+ import _ from 'lodash'
6
+
7
+ export default function pusherAdapter(jasonConfig, handlePayload, dispatch) {
8
+ let consumerId = uuidv4()
9
+
10
+ const { pusherKey, pusherRegion, pusherChannelPrefix } = jasonConfig
11
+ const pusher = new Pusher(pusherKey, {
12
+ cluster: 'eu',
13
+ forceTLS: true,
14
+ authEndpoint: '/jason/api/pusher/auth'
15
+ })
16
+ pusher.connection.bind('state_change', ({ current }) => {
17
+ if (current === 'connected') {
18
+ dispatch({ type: 'jason/upsert', payload: { connected: true } })
19
+ } else {
20
+ dispatch({ type: 'jason/upsert', payload: { connected: false } })
21
+ }
22
+ })
23
+ pusher.connection.bind( 'error', error => {
24
+ dispatch({ type: 'jason/upsert', payload: { connected: false } })
25
+ });
26
+
27
+ const configToChannel = {}
28
+
29
+ function createSubscription(config) {
30
+ restClient.post('/jason/api/create_subscription', { config, consumerId })
31
+ .then(({ data: { channelName } }) => {
32
+ configToChannel[JSON.stringify(config)] = channelName
33
+ subscribeToChannel(channelName)
34
+ })
35
+ .catch(e => console.error(e))
36
+ }
37
+
38
+ function removeSubscription(config) {
39
+ const channelName = configToChannel[JSON.stringify(config)]
40
+ unsubscribeFromChannel(fullChannelName(channelName))
41
+ restClient.post('/jason/api/remove_subscription', { config, consumerId })
42
+ .catch(e => console.error(e))
43
+ }
44
+
45
+ function getPayload(config, options) {
46
+ restClient.post('/jason/api/get_payload', {
47
+ config,
48
+ options
49
+ })
50
+ .then(({ data }) => {
51
+ _.map(data, (payload, modelName) => {
52
+ handlePayload(payload)
53
+ })
54
+ })
55
+ .catch(e => console.error(e))
56
+ }
57
+
58
+ function subscribeToChannel(channelName) {
59
+ const channel = pusher.subscribe(fullChannelName(channelName))
60
+ channel.bind('changed', message => handlePayload(message))
61
+ }
62
+
63
+ function unsubscribeFromChannel(channelName) {
64
+ const channel = pusher.unsubscribe(fullChannelName(channelName))
65
+ }
66
+
67
+ function fullChannelName(channelName) {
68
+ return `private-${pusherChannelPrefix}-${channelName}`
69
+ }
70
+
71
+ return { getPayload, createSubscription, removeSubscription }
72
+ }
@@ -0,0 +1,87 @@
1
+ import { renderHook, act } from '@testing-library/react-hooks'
2
+ import useJason from './useJason'
3
+ import restClient from './restClient'
4
+
5
+ jest.mock('./restClient')
6
+
7
+ test('it works', async () => {
8
+ const resp = { data: {
9
+ schema: { post: {} },
10
+ transportService: 'action_cable'
11
+ } };
12
+ // @ts-ignore
13
+ restClient.get.mockResolvedValue(resp);
14
+
15
+ const { result, waitForNextUpdate } = renderHook(() => useJason({ reducers: {
16
+ test: (s,a) => s || {}
17
+ }}));
18
+
19
+ await waitForNextUpdate()
20
+ const [store, value, connected] = result.current
21
+ const { handlePayload, subscribe } = value
22
+
23
+ const subscription = subscribe({ post: {} })
24
+
25
+ handlePayload({
26
+ type: 'payload',
27
+ model: 'post',
28
+ payload: [{ id: 4, name: 'test' }],
29
+ md5Hash: subscription.md5Hash,
30
+ idx: 1
31
+ })
32
+
33
+ handlePayload({
34
+ id: 4,
35
+ model: 'post',
36
+ destroy: true,
37
+ md5Hash: subscription.md5Hash,
38
+ idx: 2
39
+ })
40
+
41
+ handlePayload({
42
+ id: 5,
43
+ model: 'post',
44
+ payload: { id: 5, name: 'test2' },
45
+ md5Hash: subscription.md5Hash,
46
+ idx: 3
47
+ })
48
+ })
49
+
50
+ test('pruning IDs', async () => {
51
+ const resp = { data: {
52
+ schema: { post: {} },
53
+ transportService: 'action_cable'
54
+ } };
55
+
56
+ // @ts-ignore
57
+ restClient.get.mockResolvedValue(resp);
58
+
59
+ const { result, waitForNextUpdate } = renderHook(() => useJason({ reducers: {
60
+ test: (s,a) => s || {}
61
+ }}));
62
+
63
+ await waitForNextUpdate()
64
+ const [store, value, connected] = result.current
65
+ const { handlePayload, subscribe } = value
66
+
67
+ const subscription = subscribe({ post: {} })
68
+
69
+ handlePayload({
70
+ type: 'payload',
71
+ model: 'post',
72
+ payload: [{ id: 4, name: 'test' }],
73
+ md5Hash: subscription.md5Hash,
74
+ idx: 1
75
+ })
76
+
77
+ handlePayload({
78
+ type: 'payload',
79
+ model: 'post',
80
+ payload: [{ id: 5, name: 'test it out' }],
81
+ md5Hash: subscription.md5Hash,
82
+ idx: 2
83
+ })
84
+
85
+ // The ID 4 should have been pruned
86
+ expect(store.getState().posts.ids).toStrictEqual([5])
87
+ })
@@ -0,0 +1,110 @@
1
+ import createActions from './createActions'
2
+ import createJasonReducers from './createJasonReducers'
3
+ import createPayloadHandler from './createPayloadHandler'
4
+ import createOptDis from './createOptDis'
5
+ import createServerActionQueue from './createServerActionQueue'
6
+ import restClient from './restClient'
7
+ import pruneIdsMiddleware from './pruneIdsMiddleware'
8
+ import createTransportAdapater from './createTransportAdapter'
9
+
10
+ import { createEntityAdapter, createSlice, createReducer, configureStore } from '@reduxjs/toolkit'
11
+
12
+ import makeEager from './makeEager'
13
+ import { camelizeKeys } from 'humps'
14
+ import md5 from 'blueimp-md5'
15
+ import _ from 'lodash'
16
+ import React, { useState, useEffect } from 'react'
17
+
18
+ export default function useJason({ reducers, middleware = [], extraActions }: { reducers?: any, middleware?: any[], extraActions?: any }) {
19
+ const [store, setStore] = useState(null as any)
20
+ const [value, setValue] = useState(null as any)
21
+
22
+ useEffect(() => {
23
+ restClient.get('/jason/api/config')
24
+ .then(({ data: jasonConfig }) => {
25
+ const { schema: snakey_schema } = jasonConfig
26
+ const schema = camelizeKeys(snakey_schema)
27
+ console.debug({ schema })
28
+
29
+ const serverActionQueue = createServerActionQueue()
30
+
31
+
32
+ const allReducers = {
33
+ ...reducers,
34
+ ...createJasonReducers(schema)
35
+ }
36
+
37
+ console.debug({ allReducers })
38
+
39
+ const store = configureStore({ reducer: allReducers, middleware: [...middleware, pruneIdsMiddleware(schema)] })
40
+ const dispatch = store.dispatch
41
+
42
+ const optDis = createOptDis(schema, dispatch, restClient, serverActionQueue)
43
+ const actions = createActions(schema, store, restClient, optDis, extraActions)
44
+ const eager = makeEager(schema)
45
+
46
+ let payloadHandlers = {}
47
+ let configs = {}
48
+ let subOptions = {}
49
+
50
+ function handlePayload(payload) {
51
+ const { md5Hash } = payload
52
+
53
+ const { handlePayload } = payloadHandlers[md5Hash]
54
+ if (handlePayload) {
55
+ handlePayload(payload)
56
+ } else {
57
+ console.warn("Payload arrived with no handler", payload, payloadHandlers)
58
+ }
59
+ }
60
+
61
+ const transportAdapter = createTransportAdapater(jasonConfig, handlePayload, dispatch, () => _.keys(configs).forEach(md5Hash => createSubscription(configs[md5Hash], subOptions[md5Hash])))
62
+
63
+ function createSubscription(config, options = {}) {
64
+ // We need the hash to be consistent in Ruby / Javascript
65
+ const hashableConfig = _({ conditions: {}, includes: {}, ...config }).toPairs().sortBy(0).fromPairs().value()
66
+ const md5Hash = md5(JSON.stringify(hashableConfig))
67
+ payloadHandlers[md5Hash] = createPayloadHandler({ dispatch, serverActionQueue, transportAdapter, config })
68
+ configs[md5Hash] = hashableConfig
69
+ subOptions[md5Hash] = options
70
+
71
+ setTimeout(() => transportAdapter.createSubscription(hashableConfig), 500)
72
+ let pollInterval = null as any;
73
+
74
+ // This is only for debugging / dev - not prod!
75
+ // @ts-ignore
76
+ if (options.pollInterval) {
77
+ // @ts-ignore
78
+ pollInterval = setInterval(() => transportAdapter.getPayload(hashableConfig, { forceRefresh: true }), options.pollInterval)
79
+ }
80
+
81
+ return {
82
+ remove() {
83
+ removeSubscription(hashableConfig)
84
+ if (pollInterval) clearInterval(pollInterval)
85
+ },
86
+ md5Hash
87
+ }
88
+ }
89
+
90
+ function removeSubscription(config) {
91
+ transportAdapter.removeSubscription(config)
92
+ const md5Hash = md5(JSON.stringify(config))
93
+ payloadHandlers[md5Hash].tearDown()
94
+ delete payloadHandlers[md5Hash]
95
+ delete configs[md5Hash]
96
+ delete subOptions[md5Hash]
97
+ }
98
+
99
+ setValue({
100
+ actions: actions,
101
+ subscribe: createSubscription,
102
+ eager,
103
+ handlePayload
104
+ })
105
+ setStore(store)
106
+ })
107
+ }, [])
108
+
109
+ return [store, value]
110
+ }
data/client/src/useSub.ts CHANGED
@@ -1,10 +1,13 @@
1
1
  import JasonContext from './JasonContext'
2
2
  import { useContext, useEffect } from 'react'
3
3
 
4
- export default function useSub(config) {
4
+ export default function useSub(config, options = {}) {
5
+ // useEffect uses strict equality
6
+ const configJson = JSON.stringify(config)
5
7
  const subscribe = useContext(JasonContext).subscribe
6
8
 
7
9
  useEffect(() => {
8
- return subscribe(config)
9
- }, [])
10
+ // @ts-ignore
11
+ return subscribe(config, options).remove
12
+ }, [configJson])
10
13
  }
data/client/yarn.lock CHANGED
@@ -813,7 +813,7 @@
813
813
  "@babel/helper-validator-option" "^7.12.1"
814
814
  "@babel/plugin-transform-typescript" "^7.12.1"
815
815
 
816
- "@babel/runtime@^7.12.1", "@babel/runtime@^7.8.4":
816
+ "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.8.4":
817
817
  version "7.12.5"
818
818
  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e"
819
819
  integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==
@@ -1082,6 +1082,18 @@
1082
1082
  dependencies:
1083
1083
  "@sinonjs/commons" "^1.7.0"
1084
1084
 
1085
+ "@testing-library/react-hooks@^5.0.3":
1086
+ version "5.0.3"
1087
+ resolved "https://registry.yarnpkg.com/@testing-library/react-hooks/-/react-hooks-5.0.3.tgz#dd0d2048817b013b266d35ca45e3ea48a19fd87e"
1088
+ integrity sha512-UrnnRc5II7LMH14xsYNm/WRch/67cBafmrSQcyFh0v+UUmSf1uzfB7zn5jQXSettGwOSxJwdQUN7PgkT0w22Lg==
1089
+ dependencies:
1090
+ "@babel/runtime" "^7.12.5"
1091
+ "@types/react" ">=16.9.0"
1092
+ "@types/react-dom" ">=16.9.0"
1093
+ "@types/react-test-renderer" ">=16.9.0"
1094
+ filter-console "^0.1.1"
1095
+ react-error-boundary "^3.1.0"
1096
+
1085
1097
  "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7":
1086
1098
  version "7.1.12"
1087
1099
  resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.12.tgz#4d8e9e51eb265552a7e4f1ff2219ab6133bdfb2d"
@@ -1164,6 +1176,33 @@
1164
1176
  resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.1.5.tgz#b6ab3bba29e16b821d84e09ecfaded462b816b00"
1165
1177
  integrity sha512-UEyp8LwZ4Dg30kVU2Q3amHHyTn1jEdhCIE59ANed76GaT1Vp76DD3ZWSAxgCrw6wJ0TqeoBpqmfUHiUDPs//HQ==
1166
1178
 
1179
+ "@types/prop-types@*":
1180
+ version "15.7.3"
1181
+ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
1182
+ integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
1183
+
1184
+ "@types/react-dom@>=16.9.0":
1185
+ version "17.0.0"
1186
+ resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.0.tgz#b3b691eb956c4b3401777ee67b900cb28415d95a"
1187
+ integrity sha512-lUqY7OlkF/RbNtD5nIq7ot8NquXrdFrjSOR6+w9a9RFQevGi1oZO1dcJbXMeONAPKtZ2UrZOEJ5UOCVsxbLk/g==
1188
+ dependencies:
1189
+ "@types/react" "*"
1190
+
1191
+ "@types/react-test-renderer@>=16.9.0":
1192
+ version "17.0.0"
1193
+ resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-17.0.0.tgz#9be47b375eeb906fced37049e67284a438d56620"
1194
+ integrity sha512-nvw+F81OmyzpyIE1S0xWpLonLUZCMewslPuA8BtjSKc5XEbn8zEQBXS7KuOLHTNnSOEM2Pum50gHOoZ62tqTRg==
1195
+ dependencies:
1196
+ "@types/react" "*"
1197
+
1198
+ "@types/react@*", "@types/react@>=16.9.0":
1199
+ version "17.0.0"
1200
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.0.tgz#5af3eb7fad2807092f0046a1302b7823e27919b8"
1201
+ integrity sha512-aj/L7RIMsRlWML3YB6KZiXB3fV2t41+5RBGYF8z+tAKU43Px8C3cYUZsDvf1/+Bm4FK21QWBrDutu8ZJ/70qOw==
1202
+ dependencies:
1203
+ "@types/prop-types" "*"
1204
+ csstype "^3.0.2"
1205
+
1167
1206
  "@types/stack-utils@^2.0.0":
1168
1207
  version "2.0.0"
1169
1208
  resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff"
@@ -1742,6 +1781,11 @@ cssstyle@^2.2.0:
1742
1781
  dependencies:
1743
1782
  cssom "~0.3.6"
1744
1783
 
1784
+ csstype@^3.0.2:
1785
+ version "3.0.6"
1786
+ resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.6.tgz#865d0b5833d7d8d40f4e5b8a6d76aea3de4725ef"
1787
+ integrity sha512-+ZAmfyWMT7TiIlzdqJgjMb7S4f1beorDbWbsocyK4RaiqA5RTX3K14bnBWmmA9QEM0gRdsjyyrEmcyga8Zsxmw==
1788
+
1745
1789
  dashdash@^1.12.0:
1746
1790
  version "1.14.1"
1747
1791
  resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
@@ -2081,6 +2125,11 @@ fill-range@^7.0.1:
2081
2125
  dependencies:
2082
2126
  to-regex-range "^5.0.1"
2083
2127
 
2128
+ filter-console@^0.1.1:
2129
+ version "0.1.1"
2130
+ resolved "https://registry.yarnpkg.com/filter-console/-/filter-console-0.1.1.tgz#6242be28982bba7415bcc6db74a79f4a294fa67c"
2131
+ integrity sha512-zrXoV1Uaz52DqPs+qEwNJWJFAWZpYJ47UNmpN9q4j+/EYsz85uV0DC9k8tRND5kYmoVzL0W+Y75q4Rg8sRJCdg==
2132
+
2084
2133
  find-up@^4.0.0, find-up@^4.1.0:
2085
2134
  version "4.1.0"
2086
2135
  resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
@@ -3596,12 +3645,19 @@ punycode@^2.1.0, punycode@^2.1.1:
3596
3645
  resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
3597
3646
  integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
3598
3647
 
3648
+ pusher-js@^7.0.3:
3649
+ version "7.0.3"
3650
+ resolved "https://registry.yarnpkg.com/pusher-js/-/pusher-js-7.0.3.tgz#f81c78cdf2ad32f546caa7532ec7f9081ef00b8d"
3651
+ integrity sha512-HIfCvt00CAqgO4W0BrdpPsDcAwy51rB6DN0VMC+JeVRRbo8mn3XTeUeIFjmmlRLZLX8rPhUtLRo7vPag6b8GCw==
3652
+ dependencies:
3653
+ tweetnacl "^1.0.3"
3654
+
3599
3655
  qs@~6.5.2:
3600
3656
  version "6.5.2"
3601
3657
  resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
3602
3658
  integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
3603
3659
 
3604
- react-dom@^16.8.3:
3660
+ react-dom@^16.9.x:
3605
3661
  version "16.14.0"
3606
3662
  resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.14.0.tgz#7ad838ec29a777fb3c75c3a190f661cf92ab8b89"
3607
3663
  integrity sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==
@@ -3611,6 +3667,13 @@ react-dom@^16.8.3:
3611
3667
  prop-types "^15.6.2"
3612
3668
  scheduler "^0.19.1"
3613
3669
 
3670
+ react-error-boundary@^3.1.0:
3671
+ version "3.1.0"
3672
+ resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-3.1.0.tgz#9487443df2f9ba1db90d8ab52351814907ea4af3"
3673
+ integrity sha512-lmPrdi5SLRJR+AeJkqdkGlW/CRkAUvZnETahK58J4xb5wpbfDngasEGu+w0T1iXEhVrYBJZeW+c4V1hILCnMWQ==
3674
+ dependencies:
3675
+ "@babel/runtime" "^7.12.5"
3676
+
3614
3677
  react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.1:
3615
3678
  version "16.13.1"
3616
3679
  resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
@@ -3632,7 +3695,7 @@ react-redux@^7.2.2:
3632
3695
  prop-types "^15.7.2"
3633
3696
  react-is "^16.13.1"
3634
3697
 
3635
- react@^16.8.3:
3698
+ react@^16.9.x:
3636
3699
  version "16.14.0"
3637
3700
  resolved "https://registry.yarnpkg.com/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d"
3638
3701
  integrity sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==
@@ -4302,6 +4365,11 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0:
4302
4365
  resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
4303
4366
  integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
4304
4367
 
4368
+ tweetnacl@^1.0.3:
4369
+ version "1.0.3"
4370
+ resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596"
4371
+ integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==
4372
+
4305
4373
  type-check@~0.3.2:
4306
4374
  version "0.3.2"
4307
4375
  resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"