miolo-react 3.0.0-beta.221 → 3.0.0-beta.224

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "miolo-react",
3
- "version": "3.0.0-beta.221",
3
+ "version": "3.0.0-beta.224",
4
4
  "description": "React utils for miolo",
5
5
  "author": "Donato Lorenzo <donato@afialapis.com>",
6
6
  "contributors": [
@@ -30,7 +30,7 @@
30
30
  "prepublishOnly": "npm run lint"
31
31
  },
32
32
  "dependencies": {
33
- "idb-keyval": "^6.2.6",
33
+ "idb-keyval": "^6.3.0",
34
34
  "miolo-cli": "../miolo-cli"
35
35
  },
36
36
  "peerDependencies": {
@@ -3,6 +3,26 @@ import { useCallback, /*useEffect,*/ useState } from "react"
3
3
  import { useSsrDataOrReload } from "../ssr/useSsrDataOrReload.mjs"
4
4
  import Context from "./MioloContext.mjs"
5
5
 
6
+ /**
7
+ * @typedef {import('../ssr/useSsrDataOrReload.mjs').MioloSSRData} MioloSSRData
8
+ * @typedef {import('../ssr/useSsrDataOrReload.mjs').MioloSSRDataOptions} MioloSSRDataOptions
9
+ *
10
+ * @typedef {Object} MioloContextData
11
+ * @property {Object} user - session's data as in app.ctx
12
+ * @property {boolean} authenticated - authenticated flag as in app.ctx
13
+ * @property {Function} updateUser - function to update user
14
+ * @property {Function} googleLogin - function to login with google
15
+ * @property {Function} localLogin - function to login with local
16
+ * @property {Function} logout - function to logout
17
+ * @property {(name: string, options: MioloSSRDataOptions) => MioloSSRData} useSsrData - function to handle some ssr data
18
+ * @property {string} authMethod - authentication method
19
+ */
20
+
21
+ /**
22
+ * @param {Object} context - Miolo's app.ctx object
23
+ * @param {React.ReactNode} children - React children
24
+ * @returns {React.ReactNode}
25
+ */
6
26
  const MioloContextProvider = ({ context, children }) => {
7
27
  const [innerContext, setInnerContext] = useState(context)
8
28
  const [mioloObj, _setMioloObj] = useState(miolo_client(context))
@@ -0,0 +1,25 @@
1
+ let _historyPatched = false
2
+
3
+ export default function patchHistory() {
4
+ if (typeof window === "undefined" || _historyPatched) return
5
+
6
+ const originalPushState = window.history.pushState
7
+ window.history.pushState = function (...args) {
8
+ const ret = originalPushState.apply(this, args)
9
+ window.dispatchEvent(new Event("miolo-navigation"))
10
+ return ret
11
+ }
12
+
13
+ const originalReplaceState = window.history.replaceState
14
+ window.history.replaceState = function (...args) {
15
+ const ret = originalReplaceState.apply(this, args)
16
+ window.dispatchEvent(new Event("miolo-navigation"))
17
+ return ret
18
+ }
19
+
20
+ window.addEventListener("popstate", () => {
21
+ window.dispatchEvent(new Event("miolo-navigation"))
22
+ })
23
+
24
+ _historyPatched = true
25
+ }
@@ -0,0 +1,58 @@
1
+ import { useCallback } from "react"
2
+
3
+ const _makeSerializable = (obj) => {
4
+ try {
5
+ return JSON.parse(JSON.stringify(obj))
6
+ } catch (_) {
7
+ return obj
8
+ }
9
+ }
10
+
11
+ export default function useIndexedDb(name, logger, cache, ttl) {
12
+ const cacheInvalidate = useCallback(async () => {
13
+ if (typeof window !== "undefined") {
14
+ const { del } = await import("idb-keyval")
15
+ await del(`ssr-cache-${name}`)
16
+ }
17
+ }, [name])
18
+
19
+ const cacheSet = useCallback(
20
+ async (data) => {
21
+ if (cache === true) {
22
+ if (typeof window !== "undefined") {
23
+ try {
24
+ const { set } = await import("idb-keyval")
25
+ await set(`ssr-cache-${name}`, { data: _makeSerializable(data), ts: Date.now() })
26
+ } catch (err) {
27
+ logger.error(`[miolo-react][ssr][${name}] error setting cache for ${name}: ${err}`)
28
+ }
29
+ }
30
+ }
31
+ },
32
+ [logger, cache, name]
33
+ )
34
+
35
+ const cacheGet = useCallback(async () => {
36
+ if (cache === true) {
37
+ if (typeof window !== "undefined") {
38
+ try {
39
+ const { get } = await import("idb-keyval")
40
+ const cached = await get(`ssr-cache-${name}`)
41
+ if (cached && cached.data !== undefined) {
42
+ const expired = ttl !== undefined && Date.now() - cached.ts > ttl * 1000
43
+ return [cached.data, expired, cached.ts]
44
+ }
45
+ } catch (err) {
46
+ logger.error(`[miolo-react][ssr][${name}] error getting cache for ${name}: ${err}`)
47
+ }
48
+ }
49
+ }
50
+ return [null, false]
51
+ }, [logger, cache, name, ttl])
52
+
53
+ return {
54
+ cacheInvalidate,
55
+ cacheSet,
56
+ cacheGet
57
+ }
58
+ }
@@ -1,40 +1,39 @@
1
1
  import { useCallback, useEffect, useMemo, useRef, useState } from "react"
2
2
  import getSsrDataFromContext from "./getSsrDataFromContext.mjs"
3
+ import patchHistory from "./patchHistory.mjs"
4
+ import useIndexedDb from "./useIndexedDb.mjs"
3
5
  import useOnWindowFocus from "./useOnWindowFocus.mjs"
4
6
  import usePropsCheck from "./usePropsCheck.mjs"
5
7
 
6
- const _makeSerializable = (obj) => {
7
- try {
8
- return JSON.parse(JSON.stringify(obj))
9
- } catch (_) {
10
- return obj
11
- }
12
- }
13
-
14
- let _historyPatched = false
15
- const patchHistory = () => {
16
- if (typeof window === "undefined" || _historyPatched) return
17
-
18
- const originalPushState = window.history.pushState
19
- window.history.pushState = function (...args) {
20
- const ret = originalPushState.apply(this, args)
21
- window.dispatchEvent(new Event("miolo-navigation"))
22
- return ret
23
- }
24
-
25
- const originalReplaceState = window.history.replaceState
26
- window.history.replaceState = function (...args) {
27
- const ret = originalReplaceState.apply(this, args)
28
- window.dispatchEvent(new Event("miolo-navigation"))
29
- return ret
30
- }
31
-
32
- window.addEventListener("popstate", () => {
33
- window.dispatchEvent(new Event("miolo-navigation"))
34
- })
35
-
36
- _historyPatched = true
37
- }
8
+ /**
9
+ * @typedef {import('miolo-model').MioloModel} MioloModel
10
+ * @typedef {import('miolo-model').MioloArray} MioloArray
11
+ *
12
+ *
13
+ *
14
+ * @typedef {Object} MioloSSRDataOptions
15
+ * @property {any} [defval=[]] - The default value for the data.
16
+ * @property {Function} [loader] - A function that loads the data remotely. You need either @loader or @url.
17
+ * @property {string} [url] - The URL to load the data from. You need either @loader or @url.
18
+ * @property {Object} [params] - The parameters to pass to the @loader.
19
+ * @property {MioloModel} [model] - A MioloModel class for the data.
20
+ * @property {Function} [modifier] - A function that modifies the data (after ssr'ed or loaded, and after instantiated @model if any).
21
+ * @property {Function} [effect] - A function that is called when the data is loaded. The @effect function should return true if the data needs to be reloaded.
22
+ * @property {boolean} [cache=false] - Whether to cache the data.
23
+ * @property {number} [ttl] - The time to live for the cached data in seconds.
24
+ * @property {boolean} [autoRefresh=true] - Whether to automatically refresh the data on cache expiration.
25
+ *
26
+ *
27
+ * @typedef {Object} MioloSSRData
28
+ * @property {MioloModel | MioloArray | any} data - The data state. Generaly defined by @model and/or @modifier options.
29
+ * @property {Function} setData - Set the data state directly.
30
+ * @property {Function} refresh - If needed, remotely reload data (by calling @loader or @url).
31
+ * @property {Function} invalidate - Invalidate the data cache (requires @cache to be true).
32
+ * @property {string|undefined} error - The error message if any.
33
+ *
34
+ * @property {boolean} ok - Status of SSR data, true if everything was ssr'ed or remotely loaded ok.
35
+ * @property {boolean} ready - true when @data is loaded (either ssr'ed or remotely).
36
+ */
38
37
 
39
38
  const globalSocketState = {
40
39
  rooms: new Map(),
@@ -43,6 +42,18 @@ const globalSocketState = {
43
42
  versionsRequestedAt: 0
44
43
  }
45
44
 
45
+ /**
46
+ * Hook to get some ssr data or reload it if needed.
47
+ *
48
+ * @param {Object} context - The miolo context's state object.
49
+ * @param {Object} miolo - The miolo client object, that is:
50
+ * - @prop {Object} fetcher - The fetcher object.
51
+ * - @prop {Object} socket - The socket object.
52
+ * - @prop {Object} logger - The logger object.
53
+ * @param {string} name - The name of the data.
54
+ * @param {MioloSSRDataOptions} options - The options object:
55
+ * @returns {MioloSSRData}
56
+ */
46
57
  const useSsrDataOrReload = (context, miolo, name, options) => {
47
58
  const { fetcher, socket, logger } = miolo
48
59
  const {
@@ -85,46 +96,7 @@ const useSsrDataOrReload = (context, miolo, name, options) => {
85
96
  const [error, setError] = useState(undefined)
86
97
  const pendingLazyRefreshRef = useRef(false)
87
98
 
88
- const cacheInvalidate = useCallback(async () => {
89
- if (typeof window !== "undefined") {
90
- const { del } = await import("idb-keyval")
91
- await del(`ssr-cache-${name}`)
92
- }
93
- }, [name])
94
-
95
- const cacheSet = useCallback(
96
- async (data) => {
97
- if (cache === true) {
98
- if (typeof window !== "undefined") {
99
- try {
100
- const { set } = await import("idb-keyval")
101
- await set(`ssr-cache-${name}`, { data: _makeSerializable(data), ts: Date.now() })
102
- } catch (err) {
103
- logger.error(`[miolo-react][ssr][${name}] error setting cache for ${name}: ${err}`)
104
- }
105
- }
106
- }
107
- },
108
- [logger, cache, name]
109
- )
110
-
111
- const cacheGet = useCallback(async () => {
112
- if (cache === true) {
113
- if (typeof window !== "undefined") {
114
- try {
115
- const { get } = await import("idb-keyval")
116
- const cached = await get(`ssr-cache-${name}`)
117
- if (cached && cached.data !== undefined) {
118
- const expired = ttl !== undefined && Date.now() - cached.ts > ttl * 1000
119
- return [cached.data, expired, cached.ts]
120
- }
121
- } catch (err) {
122
- logger.error(`[miolo-react][ssr][${name}] error getting cache for ${name}: ${err}`)
123
- }
124
- }
125
- }
126
- return [null, false]
127
- }, [logger, cache, name, ttl])
99
+ const { cacheInvalidate, cacheSet, cacheGet } = useIndexedDb(name, logger, cache, ttl)
128
100
 
129
101
  const updateSsrData = useCallback(
130
102
  (data) => {
@@ -195,7 +167,7 @@ const useSsrDataOrReload = (context, miolo, name, options) => {
195
167
  )
196
168
  await cacheInvalidate()
197
169
  if (autoRefresh === true) {
198
- refreshSsrData()
170
+ await refreshSsrData()
199
171
  }
200
172
  } else {
201
173
  logger.verbose(`[miolo-react][ssr][${name}] ssr-versions match for ${name}`)
@@ -232,13 +204,13 @@ const useSsrDataOrReload = (context, miolo, name, options) => {
232
204
 
233
205
  if (expired) {
234
206
  logger.verbose(`[miolo-react][ssr][${name}] expired cache for ${name}, refreshing`)
235
- refreshSsrData()
207
+ await refreshSsrData()
236
208
  } else {
237
209
  setStatus("loaded")
238
210
  }
239
211
  } else {
240
212
  logger.verbose(`[miolo-react][ssr][${name}] no cached data for ${name}, refreshing`)
241
- refreshSsrData()
213
+ await refreshSsrData()
242
214
  }
243
215
  }
244
216
  }
@@ -347,7 +319,7 @@ const useSsrDataOrReload = (context, miolo, name, options) => {
347
319
  await handlersRef.current.cacheInvalidate()
348
320
 
349
321
  if (!data.lazy) {
350
- handlersRef.current.refreshSsrData()
322
+ await handlersRef.current.refreshSsrData()
351
323
  } else {
352
324
  if (handlersRef.current.refreshSsrDataLazy) {
353
325
  handlersRef.current.refreshSsrDataLazy()