@rpcbase/client 0.51.0 → 0.53.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.
@@ -0,0 +1,4 @@
1
+ /* @flow */
2
+ import {DEBUG} from "env"
3
+
4
+ localStorage.debug = DEBUG
@@ -0,0 +1,35 @@
1
+ /* @flow */
2
+ import "./debug"
3
+
4
+ import {PostHogProvider} from "posthog-js/react"
5
+
6
+ import {HashStateProvider} from "../hashState"
7
+
8
+ // TODO: flags here should be optional
9
+ import {flagValues} from "config/flags"
10
+
11
+ import {POSTHOG_KEY} from "env"
12
+
13
+ const AppProvider = ({children, ...props}) => {
14
+
15
+
16
+ return (
17
+ <PostHogProvider
18
+ apiKey={POSTHOG_KEY}
19
+ options={{
20
+ api_host: "https://eu.posthog.com",
21
+ // TODO: this doesn't work
22
+ bootstrap: {
23
+ featureFlags: flagValues,
24
+ },
25
+ }}
26
+ >
27
+ <HashStateProvider>
28
+ {children}
29
+ </HashStateProvider>
30
+ </PostHogProvider>
31
+ )
32
+
33
+ }
34
+
35
+ export default AppProvider
package/hashState.js ADDED
@@ -0,0 +1,141 @@
1
+ /* @flow */
2
+ import {useState, useEffect, createContext, useContext, useCallback} from "react"
3
+ import LZString from "lz-string"
4
+ import _isNil from "lodash/isNil"
5
+ import _omitBy from "lodash/omitBy"
6
+ import isEqual from "fast-deep-equal"
7
+
8
+ import {PAGE_NAVIGATION} from "config/events"
9
+
10
+
11
+ const EMPTY_STATE_TOKEN = "N4XyA" // lz-string encoded empty state ''
12
+
13
+ // WARNING: this assumes hash_str starts with "#"
14
+ const parse_hash_str = (hash_str = window.location.hash) => {
15
+ if (hash_str.length < 1) {
16
+ return {}
17
+ }
18
+ const current_state_str = hash_str.slice(1)
19
+ let parsed
20
+ try {
21
+ const decoded = LZString.decompressFromEncodedURIComponent(current_state_str)
22
+ parsed = JSON.parse(decoded)
23
+ } catch (e) {
24
+ console.error(e)
25
+ }
26
+
27
+ return parsed || {}
28
+ }
29
+
30
+ // On first load, retrieve hashState from URL
31
+ const __initial_state = _omitBy(parse_hash_str(), _isNil)
32
+
33
+ export const encode_payload = (payload) =>
34
+ LZString.compressToEncodedURIComponent(JSON.stringify(payload))
35
+
36
+ // add payload to window hash
37
+ const apply_hash_state = (payload) => {
38
+ const str = encode_payload(payload)
39
+
40
+ if (str === EMPTY_STATE_TOKEN) {
41
+ history.replaceState(null, null, window.location.pathname)
42
+ } else {
43
+ history.replaceState(null, null, `${window.location.pathname}#${encode_payload(payload)}`)
44
+ }
45
+ }
46
+
47
+ export const HashContext = createContext({
48
+ hashState: {},
49
+ serializeHashState: () => null,
50
+ encodeHashLink: () => null,
51
+ })
52
+
53
+ export const useHashState = () => {
54
+ return useContext(HashContext)
55
+ }
56
+
57
+ export const withHashState = (Component) => {
58
+ const WrappedComp = ({children, ...props}) => {
59
+ const hashCtx = useContext(HashContext)
60
+
61
+ return (
62
+ <Component
63
+ {...props}
64
+ hashState={hashCtx.hashState}
65
+ serializeHashState={hashCtx.serializeHashState}
66
+ encodeHashLink={hashCtx.encodeHashLink}
67
+ />
68
+ )
69
+ }
70
+
71
+ WrappedComp.displayName = `withHashState(${Component.displayName})`
72
+
73
+ return WrappedComp
74
+ }
75
+
76
+ export const HashStateProvider = ({children}) => {
77
+ const [hashState, setHashState] = useState(__initial_state)
78
+
79
+ useEffect(() => {
80
+ const onChange = (ev) => {
81
+ const newHashStr = ev.detail.context?.hash
82
+ if (!newHashStr) return
83
+ // WARNING: page.js strips the "#" we add it back
84
+ const parsed = _omitBy(parse_hash_str(`#${newHashStr}`), _isNil)
85
+ const newState = {
86
+ ...hashState,
87
+ ...parsed,
88
+ }
89
+ // apply only if changed
90
+ if (!isEqual(hashState, newState)) {
91
+ setHashState(newState)
92
+ }
93
+ }
94
+ document.body.addEventListener(PAGE_NAVIGATION, onChange)
95
+
96
+ return () => document.body.removeEventListener(PAGE_NAVIGATION, onChange)
97
+ }, [hashState, setHashState])
98
+
99
+ useEffect(() => {
100
+ apply_hash_state(hashState)
101
+ window.__PRIVATE_HASH_STATE_DO_NOT_USE = hashState
102
+ }, [hashState])
103
+
104
+ const serializeHashState = useCallback((payload) => {
105
+ setHashState((current) => {
106
+ // clone and remove nil values
107
+ const newState = _omitBy(
108
+ {
109
+ ...current,
110
+ ...payload,
111
+ },
112
+ _isNil,
113
+ )
114
+ return newState
115
+ })
116
+ }, [])
117
+
118
+ const encodeHashLink = useCallback((payload) => {
119
+ const newState = _omitBy(
120
+ {
121
+ ...hashState,
122
+ ...payload,
123
+ },
124
+ _isNil,
125
+ )
126
+
127
+ return encode_payload(newState)
128
+ }, [])
129
+
130
+ return (
131
+ <HashContext.Provider
132
+ value={{
133
+ hashState,
134
+ serializeHashState,
135
+ encodeHashLink,
136
+ }}
137
+ >
138
+ {children}
139
+ </HashContext.Provider>
140
+ )
141
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpcbase/client",
3
- "version": "0.51.0",
3
+ "version": "0.53.0",
4
4
  "scripts": {
5
5
  "test": "echo \"Error: no test specified\" && exit 0"
6
6
  },
@@ -13,6 +13,7 @@
13
13
  "pouchdb-adapter-indexeddb": "8.0.1",
14
14
  "pouchdb-core": "8.0.1",
15
15
  "pouchdb-find": "8.0.1",
16
+ "posthog-js": "1.70.0",
16
17
  "react-i18next": "13.0.1",
17
18
  "socket.io-client": "4.7.1"
18
19
  }
@@ -1,8 +0,0 @@
1
- /* @flow */
2
-
3
-
4
- const AppProvider = () => {
5
-
6
- }
7
-
8
- export default AppProvider