@rpcbase/client 0.124.0 → 0.127.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,36 @@
1
+ /* @flow */
2
+
3
+ const createBatcher = (func, delay) => {
4
+ let queue = []
5
+ let timeout = null
6
+
7
+ function processBatch() {
8
+ const batch = [...queue]
9
+ queue = []
10
+ timeout = null
11
+
12
+ func(batch.map((item) => item.args))
13
+ .then((results) => {
14
+ for (let i = 0; i < batch.length; i++) {
15
+ batch[i].resolve(results[i])
16
+ }
17
+ })
18
+ .catch((err) => {
19
+ for (let item of batch) {
20
+ item.reject(err)
21
+ }
22
+ })
23
+ }
24
+
25
+ return (...args) => {
26
+ return new Promise((resolve, reject) => {
27
+ queue.push({args, resolve, reject})
28
+
29
+ if (!timeout) {
30
+ timeout = setTimeout(processBatch, delay)
31
+ }
32
+ })
33
+ }
34
+ }
35
+
36
+ export default createBatcher
@@ -0,0 +1,30 @@
1
+ /* @flow */
2
+ import assert from "assert"
3
+ import debug from "debug"
4
+
5
+ import post from "../post"
6
+ import createBatcher from "../createBatcher"
7
+
8
+ const log = debug("useStoredValue:get")
9
+
10
+ // we keep it just above the react rendering time, but it could even be a request animation frame
11
+ const BATCH_TIMEOUT_MS = 4
12
+
13
+ const batchedGetStoredValues = async(args) => {
14
+ log("batched call to args", args)
15
+
16
+ const keys = args.map((arg) => arg[0])
17
+
18
+ const res = await post("/api/v1/stored-values/get", keys)
19
+ assert(res.status === "ok")
20
+
21
+ if (debug.enabled) {
22
+ for (let i = 0; i < args.length; i++) {
23
+ log(args[i][0], res.values[i])
24
+ }
25
+ }
26
+
27
+ return res.values
28
+ }
29
+
30
+ export default createBatcher(batchedGetStoredValues, BATCH_TIMEOUT_MS)
@@ -0,0 +1,107 @@
1
+ /* @flow */
2
+ import {useEffect, useState, useRef, useCallback} from "react"
3
+ import _throttle from "lodash/throttle"
4
+ import isEqual from "fast-deep-equal/react"
5
+
6
+ import {getUid} from "../../auth"
7
+ import storage from "../../storage"
8
+
9
+ import batchedGetStoredValues from "./batchedGetStoredValues"
10
+ import setStoredValues from "./setStoredValues"
11
+
12
+
13
+ const DEFAULT_REMOTE = true
14
+ const UPDATE_THROTTLE_DELAY = 300
15
+
16
+ const useStoredValue = (_key, defaultValueOrFn = null, options = {}) => {
17
+ const uid = getUid()
18
+ const key = `${uid}.${_key}`
19
+
20
+ const hasRemote = typeof options.remote === "boolean" ? options.remote : DEFAULT_REMOTE
21
+
22
+ const previousKey = useRef()
23
+
24
+ const getInitialState = () => {
25
+ const defaultValue =
26
+ typeof defaultValueOrFn === "function" ? defaultValueOrFn() : defaultValueOrFn
27
+
28
+ if (!_key) return defaultValue
29
+
30
+ const val = storage.getItem(key)
31
+
32
+ return typeof val !== "undefined" && val !== null ? val : defaultValue
33
+ }
34
+
35
+ const [value, setValue] = useState(getInitialState())
36
+
37
+ // reload initial state when key changes
38
+ useEffect(() => {
39
+ const initialStateForKey = getInitialState()
40
+ if (!isEqual(initialStateForKey, value)) {
41
+ setValue(initialStateForKey)
42
+ }
43
+ }, [key])
44
+
45
+
46
+ const refresh = useCallback(async() => {
47
+ const nextVal = await batchedGetStoredValues(key)
48
+
49
+ // TODO: we check against null here because localStorage of a non existing key returns null, but this is wrong, it should be returning undefined, in case we want to be able to store a null value
50
+ if (typeof nextVal !== "undefined" && nextVal !== null && !isEqual(nextVal, value)) {
51
+ setValue(nextVal)
52
+ // add the value to local storage in case it wasn't present
53
+ storage.setItem(key, nextVal)
54
+ }
55
+ }, [key])
56
+
57
+
58
+ useEffect(() => {
59
+ if (!hasRemote) return
60
+ if (!key) return
61
+ // skip when value is still undefined -> it hasnt loaded from cache / default value
62
+ if (typeof value === "undefined") return
63
+
64
+ if (previousKey.current !== key) {
65
+ refresh()
66
+ previousKey.current = key
67
+ }
68
+ }, [hasRemote, key, value, setValue])
69
+
70
+ // TODO: are there several instances of this function that run for differents keys ?
71
+ const throttledUpdateRemote = useCallback(
72
+ _throttle(
73
+ async(newVal) => {
74
+ await setStoredValues({
75
+ values: [
76
+ {
77
+ key,
78
+ value: newVal,
79
+ },
80
+ ],
81
+ })
82
+ },
83
+ UPDATE_THROTTLE_DELAY,
84
+ {leading: false, trailing: true},
85
+ ),
86
+ [key],
87
+ )
88
+
89
+ const updateValue = async(newValOrFn) => {
90
+ const newVal = typeof newValOrFn === "function" ? newValOrFn(value) : newValOrFn
91
+
92
+ if (newVal !== value) {
93
+ setValue(newVal)
94
+ }
95
+ if (!_key) return
96
+
97
+ storage.setItem(key, newVal)
98
+
99
+ if (hasRemote) {
100
+ throttledUpdateRemote(newVal)
101
+ }
102
+ }
103
+
104
+ return [value, updateValue]
105
+ }
106
+
107
+ export default useStoredValue
@@ -0,0 +1,14 @@
1
+ /* @flow */
2
+ import assert from "assert"
3
+
4
+ import post from "../post"
5
+
6
+
7
+ const setStoredValue = async(payload) => {
8
+ const res = await post("/api/v1/stored-values/set", payload)
9
+
10
+ assert(res.status === "ok")
11
+ return res
12
+ }
13
+
14
+ export default setStoredValue
package/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  /* @flow */
2
2
  import useRPC from "./helpers/useRPC"
3
+ import useStoredValue from "./helpers/useStoredValue"
3
4
 
4
- export {useRPC}
5
+ export {useRPC, useStoredValue}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpcbase/client",
3
- "version": "0.124.0",
3
+ "version": "0.127.0",
4
4
  "scripts": {
5
5
  "build-firebase": "webpack -c firebase/webpack.config.js",
6
6
  "build": "yarn build-firebase",
@@ -4,13 +4,13 @@ import PouchDB from "pouchdb-core"
4
4
  import IndexedDBAdapter from "pouchdb-adapter-indexeddb"
5
5
  import FindPlugin from "pouchdb-find"
6
6
 
7
- import {TENANT_PREFIX, DATABASE_NAME} from "env"
7
+ import {TENANT_PREFIX, RB_APP_NAME} from "env"
8
8
 
9
9
  const log = debug("rb:rts:store")
10
10
 
11
11
  let prefix = `rb/${TENANT_PREFIX}/`
12
12
 
13
- if (DATABASE_NAME) prefix += `${DATABASE_NAME}/`
13
+ if (RB_APP_NAME) prefix += `${RB_APP_NAME}/`
14
14
 
15
15
  PouchDB.prefix = prefix
16
16