@dpgradio/creative 8.0.0 → 8.1.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dpgradio/creative",
3
- "version": "8.0.0",
3
+ "version": "8.1.1",
4
4
  "description": "Support package for standalone Javascript applications",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -1,5 +1,8 @@
1
1
  import tap from '../utils/tap.js'
2
+ import authentication from '../app/authentication.js'
2
3
 
4
+ let authenticationRetries = 0
5
+ let tokenRefreshPromise = null
3
6
  export default class Request {
4
7
  constructor(baseUrl, version, errorHandlers = []) {
5
8
  this.baseUrl = baseUrl
@@ -76,6 +79,21 @@ export default class Request {
76
79
  })
77
80
 
78
81
  if (!response.ok) {
82
+ if (response.status === 401 && authenticationRetries < 2) {
83
+ if (!tokenRefreshPromise) {
84
+ tokenRefreshPromise = authentication.refreshToken()
85
+ }
86
+
87
+ try {
88
+ const newToken = await tokenRefreshPromise
89
+ authenticationRetries++
90
+ this.withHeader('Authorization', `Bearer ${newToken}`)
91
+ return await this.fetchJson(endpoint, method)
92
+ } finally {
93
+ tokenRefreshPromise = null
94
+ }
95
+ }
96
+
79
97
  this.errorHandlers.forEach((handler) => handler({ response }))
80
98
 
81
99
  throw new Error(
@@ -84,6 +102,9 @@ export default class Request {
84
102
  )
85
103
  }
86
104
 
105
+ // reset authentication retries
106
+ authenticationRetries = 0
107
+
87
108
  try {
88
109
  return await response.json()
89
110
  } catch (error) {
@@ -22,11 +22,14 @@ class Authentication {
22
22
  }
23
23
 
24
24
  initialize() {
25
- hybrid.appLoaded().then((radioToken) => {
26
- if (radioToken) {
27
- this.setToken(radioToken)
28
- }
29
- })
25
+ hybrid
26
+ .appLoaded()
27
+ .then((radioToken) => {
28
+ if (radioToken) {
29
+ this.setToken(radioToken)
30
+ }
31
+ })
32
+ .catch(() => {}) // We don't have to do anything if there is no radio token at app load
30
33
  hybrid.on('authenticated', ({ radioToken }) => {
31
34
  this.setToken(radioToken)
32
35
  })
@@ -110,6 +113,38 @@ class Authentication {
110
113
  }
111
114
  })
112
115
  }
116
+
117
+ async refreshToken() {
118
+ if (hybrid.isNativeApp()) {
119
+ const updatedToken = Promise.race([
120
+ new Promise((resolve) => {
121
+ hybrid.on('authenticated', (token) => resolve(token))
122
+ }),
123
+ new Promise((_, reject) => {
124
+ setTimeout(() => reject(new Error('Timeout: no token received')), 2000)
125
+ }),
126
+ ])
127
+
128
+ hybrid.call('refreshExpiredToken')
129
+
130
+ return (await updatedToken).radioToken
131
+ } else {
132
+ try {
133
+ const response = await fetch('/login/refresh', {
134
+ method: 'POST',
135
+ headers: {
136
+ 'Content-Type': 'application/json',
137
+ },
138
+ })
139
+ const token = (await response.json()).radioToken
140
+ localStorage.setItem(RADIO_TOKEN_LOCAL_STORAGE_KEY, token)
141
+ return token
142
+ } catch (e) {
143
+ localStorage.removeItem(RADIO_TOKEN_LOCAL_STORAGE_KEY)
144
+ throw e
145
+ }
146
+ }
147
+ }
113
148
  }
114
149
 
115
150
  export default new Authentication()