@fullstackunicorn/create-root 1.0.28 → 1.0.29

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.
@@ -51,10 +51,16 @@ uri.errors.error = `:lang/errors/:message`
51
51
  uri.auth = {}
52
52
  const { env } = constants
53
53
 
54
- uri.auth.client = {}
55
- uri.auth.client.login = `${env.SERVER_URL_AUTH}/auth/login`
56
- uri.auth.client.logout = `${env.SERVER_URL_AUTH}/auth/logout`
57
- uri.auth.client.refresh = `${env.SERVER_URL_AUTH}/auth/refresh`
54
+ uri.auth.gateway = {}
55
+ uri.auth.gateway.login = `${env.SERVER_URL_AUTH}/auth/login`
56
+ uri.auth.gateway.logout = `${env.SERVER_URL_AUTH}/auth/logout`
57
+ uri.auth.gateway.refresh = `${env.SERVER_URL_AUTH}/auth/refresh`
58
+
59
+ uri.auth.bff = {}
60
+ uri.auth.bff.login = `${env.SERVER_URL_BFF}/auth/login`
61
+ uri.auth.bff.logout = `${env.SERVER_URL_BFF}/auth/logout`
62
+ uri.auth.bff.sessionMe = `${env.SERVER_URL_BFF}/session/me`
63
+ uri.auth.bff.bootstrap = `${env.SERVER_URL_BFF}/bootstrap`
58
64
 
59
65
  uri.auth.user = {}
60
66
  uri.auth.user.login = `${env.CLIENT_URL_AUTH}/auth?:type&:token`
@@ -1,6 +1,6 @@
1
- import { atom, useAtom, useSetAtom, useGetAtom, makeId } from '#@/imports/npm.js'
2
- import { useNavigateUrl } from '#@/imports/router.js'
3
- import { storage } from '#@/imports/storage.js'
1
+ import { atom, useAtom, useSetAtom, useGetAtom } from '#@/imports/npm.js'
2
+ import { getCurrentHref, useNavigate, useNavigateUrl } from '#@/imports/router.js'
3
+ import { useSetAlerts } from '#@/base/alerts/@use.js'
4
4
  import { uri } from '#@/App.uri.js'
5
5
  import { abs } from '#@/abstracts/abs.js'
6
6
  import { api } from '#@/client/@api.js'
@@ -14,7 +14,7 @@ export const initializeUser = atom(
14
14
  (get) => get(isUserInitialized),
15
15
  async (get, set, value) => {
16
16
 
17
- const userInit = await api.auth.init()
17
+ const userInit = await api.auth.bootstrap()
18
18
  const userInitialized = userInit?.id ? userInit : {}
19
19
 
20
20
  set(user, userInitialized)
@@ -38,16 +38,8 @@ export const useAuthLogin = () => {
38
38
 
39
39
  if (!types.includes(type)) return
40
40
 
41
- const tokenRaw = {}
42
- tokenRaw.nonce = makeId()
43
- tokenRaw.request_type = type
44
- tokenRaw.client_id = env.CLIENT_ID
45
- tokenRaw.protocol = env.PROTOCOL_AUTH
46
-
47
- storage.set(type, tokenRaw.nonce)
48
-
49
- const token = abs.jwt.encode(tokenRaw)
50
- const authLink = F3.fabUrl(uri.auth.user.login, { type, token })
41
+ const returnUrl = encodeURIComponent(getCurrentHref())
42
+ const authLink = `${uri.auth.bff.login}?type=${type}&client_id=${env.CLIENT_ID}&return_url=${returnUrl}`
51
43
 
52
44
  navigateUrl(authLink)
53
45
  }
@@ -58,6 +50,8 @@ export const useAuthLogout = () => {
58
50
 
59
51
  const { lang } = useUrl()
60
52
  const setUser = useSetUser()
53
+ const setAlerts = useSetAlerts()
54
+ const navigate = useNavigate()
61
55
 
62
56
  const authLogout = async () => {
63
57
 
@@ -69,8 +63,7 @@ export const useAuthLogout = () => {
69
63
  navigate(F3.fabUrl(uri.errors, { message, lang }))
70
64
  }
71
65
  else {
72
- storage.remove('accessToken')
73
- storage.remove('refreshToken')
66
+ api.auth.cleanUp()
74
67
  setUser({})
75
68
  }
76
69
  }
@@ -1,4 +1,5 @@
1
1
  import { constants } from '#@/root/constants.js'
2
+ import { getSubmitMetadata } from '#@/imports/device.js'
2
3
 
3
4
  class Tools {
4
5
 
@@ -15,52 +16,7 @@ class Tools {
15
16
  getSubmit = async (device_id) => {
16
17
  const { env } = constants
17
18
 
18
- const battery = navigator.getBattery ? await navigator.getBattery() : {}
19
- const metadataObj = {
20
- timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
21
- language: window.navigator.language,
22
- pageTitle: document.title,
23
- referrer: document.referrer,
24
- pageURL: window.location.href,
25
- platform: window.navigator.platform,
26
- deviceMemory: navigator.deviceMemory,
27
- screenWidth: window.screen.width,
28
- screenHeight: window.screen.height,
29
- colorDepth: window.screen.colorDepth,
30
- maxScreenWidth: window.screen.width * window.devicePixelRatio,
31
- maxScreenHeight: window.screen.height * window.devicePixelRatio,
32
- pixelRatio: window.devicePixelRatio,
33
- screenOrientation: screen?.orientation?.type,
34
- hardwareConcurrency: navigator.hardwareConcurrency,
35
- touchSupport: 'ontouchstart' in window || navigator.maxTouchPoints > 0,
36
- colorGamut: window.matchMedia("(color-gamut: srgb)").matches
37
- ? "srgb"
38
- : window.matchMedia("(color-gamut: p3)").matches
39
- ? "p3"
40
- : window.matchMedia("(color-gamut: rec2020)").matches
41
- ? "rec2020"
42
- : "unknown",
43
- rtt: navigator?.connection?.rtt,
44
- hasGamepad: navigator.getGamepads ? navigator.getGamepads().length > 0 : false,
45
- keyboardEnabled: "onkeydown" in document,
46
- cookieEnabled: navigator.cookieEnabled,
47
- javaEnabled: navigator.javaEnabled ? navigator.javaEnabled() : false,
48
- doNotTrack: navigator.doNotTrack,
49
- networkType: navigator?.connection?.effectiveType,
50
- downlinkSpeed: navigator?.connection?.downlink,
51
- batteryLevel: battery?.level * 100,
52
- batteryCharging: battery?.charging
53
- }
54
-
55
- const metadata = {
56
- submit_timestamp: new Date().toISOString(),
57
- submit_device_id: device_id,
58
- submit_client_id: env.CLIENT_ID,
59
- submit_user_agent: window.navigator.userAgent,
60
- submit_metadata: Object.entries(metadataObj).map(([key, value]) => `${key}:${value ? value : 'unknown'}`).join(" | ")
61
- }
62
-
63
- return metadata
19
+ return await getSubmitMetadata({ clientId: env.CLIENT_ID, deviceId: device_id })
64
20
  }
65
21
  }
66
22
 
@@ -11,6 +11,7 @@ class Tools {
11
11
  if (user.isOffline) setAlerts({ id: 'offline', onClose: () => setIsAuthRun(true) })
12
12
  else if (user.isError) navigate(`/errors/${user.error || 'login-failed'}`)
13
13
  else {
14
+ api.auth.cleanUp()
14
15
  setUser(user)
15
16
  navigate('/user')
16
17
  }
@@ -108,4 +109,4 @@ class Tools {
108
109
  }
109
110
  }
110
111
 
111
- export const tools = new Tools()
112
+ export const tools = new Tools()
@@ -8,9 +8,23 @@ import { storage } from '#@/imports/storage'
8
8
  class Auth {
9
9
 
10
10
  config = { headers: { 'Content-Type': 'application/json' } }
11
+ sessionConfig = { headers: { 'Content-Type': 'application/json' }, withCredentials: true }
11
12
  env = constants.env
12
13
 
13
14
  getUser = (token = {}) => ({ id: token.sub, logo: token.logo })
15
+ getSessionUser = (payload = {}) => ({ id: payload?.user?.id, logo: payload?.user?.logo })
16
+ getBootstrapUser = (payload = {}) => {
17
+ const user = this.getSessionUser(payload)
18
+ return {
19
+ ...user,
20
+ bootstrap: payload?.bootstrap || {},
21
+ permissions: payload?.permissions || [],
22
+ groups: payload?.groups || [],
23
+ entities: payload?.entities || {},
24
+ client: payload?.client || null,
25
+ features: payload?.features || {}
26
+ }
27
+ }
14
28
 
15
29
  loginOps = ['login', 'signup']
16
30
 
@@ -25,17 +39,9 @@ class Auth {
25
39
 
26
40
  const nonce = storage.get(type)
27
41
 
28
- // const isValid = nonce === token.nonce
29
- // if (!isValid) throw new Error('abort')
30
-
31
- // const rawToken = {}
32
- // rawToken.authcode = token.authcode
33
- // // rawToken.nonce = nonce
34
- // rawToken.client_id = env.CLIENT_ID
35
-
36
42
  const config = this.config
37
43
  const data = { token: token_encoded, nonce }
38
- const endpoint = uri.auth.client.login
44
+ const endpoint = uri.auth.gateway.login
39
45
 
40
46
  const response = await client.post(endpoint, data, config)
41
47
 
@@ -50,38 +56,45 @@ class Auth {
50
56
 
51
57
  return this.getUser(response.access_token)
52
58
 
53
- } catch (error) {
59
+ } catch (error) {
54
60
  console.log("error", error)
55
- return err.cleanup(() => storage.remove(type), { isError: true }) }
61
+ return err.cleanup(() => storage.remove(type), { isError: true })
62
+ }
56
63
  }
57
64
 
58
65
  refresh = async (refresh_token) => {
59
66
 
60
67
  const config = this.config
61
68
  const data = { refresh_token, client_id: this.env.CLIENT_ID }
62
- const endpoint = uri.auth.client.refresh
69
+ const endpoint = uri.auth.gateway.refresh
63
70
 
64
71
  return await client.post(endpoint, data, config)
65
72
 
66
73
  }
67
74
 
68
75
  logout = async () => {
76
+ const endpoint = uri.auth.bff.logout
77
+ const response = await client.post(endpoint, {}, this.sessionConfig)
78
+ return response?.isLogout ? response : { isLogout: true }
69
79
 
70
- const refresh_token = storage.get('refreshToken') || ''
71
- const access_token = storage.get('accessToken') || ''
72
-
73
- if (!refresh_token && !access_token) return { isLogout: true }
74
-
75
- const config = this.config
76
- const data = { access_token, refresh_token, client_id: this.env.CLIENT_ID }
77
- const endpoint = uri.auth.client.logout
78
-
79
- const response = await client.post(endpoint, data, config)
80
+ }
80
81
 
81
- const isLogout = response.access_token && response.refresh_token
82
+ bootstrap = async () => {
83
+ try {
84
+ const response = await client.data({
85
+ key: uri.auth.bff.bootstrap,
86
+ method: 'get',
87
+ endpoint: uri.auth.bff.bootstrap,
88
+ config: this.sessionConfig
89
+ }, true)
82
90
 
83
- return isLogout || response
91
+ if (response.isOffline) return { isOffline: true }
92
+ if (response.isError) throw new Error('is-logout')
93
+ if (!response?.user?.id) throw new Error('is-logout')
84
94
 
95
+ this.cleanUp()
96
+ return this.getBootstrapUser(response)
97
+ } catch (error) { return { isLogout: true } }
85
98
  }
86
99
 
87
100
  handleAccessToken = (accessToken) => {
@@ -156,57 +169,30 @@ class Auth {
156
169
  init = async () => {
157
170
 
158
171
  try {
172
+ const bootstrapped = await this.bootstrap()
173
+ if (bootstrapped?.id || bootstrapped?.isOffline) return bootstrapped
159
174
 
160
- const accessToken = storage.get('accessToken')
161
- if (!accessToken) throw new Error('is-logout')
162
-
163
- const refreshToken = storage.get('refreshToken')
164
- if (!refreshToken) throw new Error('is-logout')
175
+ const response = await client.data({
176
+ key: uri.auth.bff.sessionMe,
177
+ method: 'get',
178
+ endpoint: uri.auth.bff.sessionMe,
179
+ config: this.sessionConfig
180
+ }, true)
165
181
 
166
- let access
167
-
168
- access = this.handleAccessToken(accessToken)
169
- if (access.decoded?.sub) return this.getUser(access.decoded)
170
-
171
- access = await this.handleRefreshToken(refreshToken)
172
- if (access.decoded?.sub) return this.getUser(access.decoded)
173
-
174
- if (access.isOffline) {
175
- const user = this.getUserOffline(accessToken)
176
- if (user.id) return user
177
- new Error('is-logout')
178
- }
182
+ if (response.isOffline) return { isOffline: true }
183
+ if (response.isError) throw new Error('is-logout')
184
+ if (!response?.user?.id) throw new Error('is-logout')
179
185
 
180
- throw new Error('is-logout')
186
+ this.cleanUp()
187
+ return this.getSessionUser(response)
181
188
 
182
- } catch (error) {
189
+ } catch (error) {
183
190
  return { isLogout: true }
184
- // return err.cleanup(this.cleanUp, { isLogout: true })
185
191
  }
186
192
  }
187
193
 
188
194
  getAccessToken = async () => {
189
-
190
- try {
191
-
192
- const accessToken = storage.get('accessToken')
193
- if (!accessToken) throw new Error('is-logout')
194
-
195
- const refreshToken = storage.get('refreshToken')
196
- if (!refreshToken) throw new Error('is-logout')
197
-
198
- let access
199
-
200
- access = this.handleAccessToken(accessToken)
201
- if (access.token) return { accessToken: access.token }
202
-
203
- access = await this.handleRefreshToken(refreshToken)
204
- if (access.token) return { accessToken: access.token }
205
-
206
- if (access.isOffline) return { isOffline: true }
207
- throw new Error('is-logout')
208
-
209
- } catch (error) { return err.cleanup(this.cleanUp, { isLogout: true }) }
195
+ return { isLogout: true }
210
196
  }
211
197
  }
212
198
 
@@ -4,5 +4,6 @@
4
4
  "CLIENT_ID": "clientxx-xxxx-4xxx-8xxx-xxxxxxxxxxxx",
5
5
  "CLIENT_URL_AUTH": "https://auth.minderable.com",
6
6
  "CLIENT_URL_ACCOUNT": "https://account.minderable.com",
7
+ "SERVER_URL_BFF": "http://localhost:4820",
7
8
  "SERVER_URL_AUTH": "https://api.auth.minderable.com"
8
9
  }
@@ -4,5 +4,6 @@
4
4
  "CLIENT_ID": "clientxx-xxxx-4xxx-8xxx-xxxxxxxxxxxx",
5
5
  "CLIENT_URL_AUTH": "https://auth.minderable.com",
6
6
  "CLIENT_URL_ACCOUNT": "https://account.minderable.com",
7
+ "SERVER_URL_BFF": "https://bff.minderable.com",
7
8
  "SERVER_URL_AUTH": "https://api.auth.minderable.com"
8
9
  }
@@ -0,0 +1,46 @@
1
+ export const getSubmitMetadata = async ({ clientId, deviceId }) => {
2
+ const battery = navigator.getBattery ? await navigator.getBattery() : {}
3
+ const metadataObj = {
4
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
5
+ language: window.navigator.language,
6
+ pageTitle: document.title,
7
+ referrer: document.referrer,
8
+ pageURL: window.location.href,
9
+ platform: window.navigator.platform,
10
+ deviceMemory: navigator.deviceMemory,
11
+ screenWidth: window.screen.width,
12
+ screenHeight: window.screen.height,
13
+ colorDepth: window.screen.colorDepth,
14
+ maxScreenWidth: window.screen.width * window.devicePixelRatio,
15
+ maxScreenHeight: window.screen.height * window.devicePixelRatio,
16
+ pixelRatio: window.devicePixelRatio,
17
+ screenOrientation: screen?.orientation?.type,
18
+ hardwareConcurrency: navigator.hardwareConcurrency,
19
+ touchSupport: 'ontouchstart' in window || navigator.maxTouchPoints > 0,
20
+ colorGamut: window.matchMedia("(color-gamut: srgb)").matches
21
+ ? "srgb"
22
+ : window.matchMedia("(color-gamut: p3)").matches
23
+ ? "p3"
24
+ : window.matchMedia("(color-gamut: rec2020)").matches
25
+ ? "rec2020"
26
+ : "unknown",
27
+ rtt: navigator?.connection?.rtt,
28
+ hasGamepad: navigator.getGamepads ? navigator.getGamepads().length > 0 : false,
29
+ keyboardEnabled: "onkeydown" in document,
30
+ cookieEnabled: navigator.cookieEnabled,
31
+ javaEnabled: navigator.javaEnabled ? navigator.javaEnabled() : false,
32
+ doNotTrack: navigator.doNotTrack,
33
+ networkType: navigator?.connection?.effectiveType,
34
+ downlinkSpeed: navigator?.connection?.downlink,
35
+ batteryLevel: battery?.level * 100,
36
+ batteryCharging: battery?.charging
37
+ }
38
+
39
+ return {
40
+ submit_timestamp: new Date().toISOString(),
41
+ submit_device_id: deviceId,
42
+ submit_client_id: clientId,
43
+ submit_user_agent: window.navigator.userAgent,
44
+ submit_metadata: Object.entries(metadataObj).map(([key, value]) => `${key}:${value ? value : 'unknown'}`).join(" | ")
45
+ }
46
+ }
@@ -7,6 +7,8 @@ export {
7
7
 
8
8
  export const useNavigateUrl = () => url => window.location.href = url
9
9
 
10
+ export const getCurrentHref = () => window.location.href
11
+
10
12
  import { useLocation } from 'react-router-dom'
11
13
 
12
14
  export const useGetUrl = () => {
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.0.28",
2
+ "version": "1.0.29",
3
3
  "name": "@fullstackunicorn/create-root",
4
4
  "author": "lucanigido (https://fullstackunicorn.dev/author/lucanigido)",
5
5
  "description": "create-root: bootstrapper that writes config assets and installs @fullstackunicorn/root",