-
Notifications
You must be signed in to change notification settings - Fork 363
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SDK-1279] getTokenSilently retry logic #336
Changes from 8 commits
2bca127
3e31e26
e196a80
7f3b67d
6cc0f57
021445f
422e0bf
178850b
df1ba30
6cc044e
977574d
db1ff54
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,21 @@ | ||
import fetch from 'unfetch'; | ||
|
||
import { DEFAULT_AUTHORIZE_TIMEOUT_IN_SECONDS } from './constants'; | ||
import { | ||
AuthenticationResult, | ||
PopupConfigOptions, | ||
TokenEndpointOptions | ||
} from './global'; | ||
|
||
import { | ||
DEFAULT_AUTHORIZE_TIMEOUT_IN_SECONDS, | ||
DEFAULT_SILENT_TOKEN_RETRY_COUNT, | ||
DEFAULT_FETCH_TIMEOUT_MS | ||
} from './constants'; | ||
|
||
const dedupe = arr => arr.filter((x, i) => arr.indexOf(x) === i); | ||
|
||
const TIMEOUT_ERROR = { error: 'timeout', error_description: 'Timeout' }; | ||
|
||
export const getUniqueScopes = (...scopes: string[]) => { | ||
const scopeString = scopes.filter(Boolean).join(); | ||
return dedupe(scopeString.replace(/\s/g, ',').split(',')) | ||
|
@@ -182,25 +188,62 @@ export const bufferToBase64UrlEncoded = input => { | |
); | ||
}; | ||
|
||
const getJSON = async (url, options) => { | ||
const response = await fetch(url, options); | ||
const fetchWithTimeout = (url, options, timeout = DEFAULT_FETCH_TIMEOUT_MS) => { | ||
// The promise will resolve with one of these two promises (the fetch and the timeout), whichever completes first. | ||
return Promise.race([ | ||
fetch(url, options), | ||
new Promise((_, reject) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm sure this works for rejecting the promise early and eventually retrying. But to me, it feels like the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are perhaps correct. However, we don't use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then, do we get a way to cancel that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I've done some research into this and we can cancel Let me investigate how big that bump would be and come back to you. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @lbalmaceda I've implemented The polyfill bumps the distributed package size up to 16.55kb, a 12.4% increase. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That doesn't seem like a huge increment, but I'd leave that to your discretion. Polyfill Q: Is there any way of only importing it on IE or is this something that if added, must be added in a general way? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As it's all bundled, we have to add it in a generic way. |
||
setTimeout( | ||
() => reject(new Error("Timeout when executing 'fetch'")), | ||
timeout | ||
); | ||
}) | ||
]); | ||
}; | ||
|
||
const getJSON = async (url, timeout, options) => { | ||
let fetchError, response; | ||
|
||
for (let i = 0; i < DEFAULT_SILENT_TOKEN_RETRY_COUNT; i++) { | ||
lbalmaceda marked this conversation as resolved.
Show resolved
Hide resolved
|
||
try { | ||
response = await fetchWithTimeout(url, options, timeout); | ||
fetchError = null; | ||
break; | ||
} catch (e) { | ||
// Fetch only fails in the case of a network issue, so should be | ||
// retried here. Failure status (4xx, 5xx, etc) return a resolved Promise | ||
// with the failure in the body. | ||
// https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API | ||
fetchError = e; | ||
} | ||
} | ||
|
||
if (fetchError) { | ||
throw fetchError; | ||
} | ||
|
||
const { error, error_description, ...success } = await response.json(); | ||
|
||
if (!response.ok) { | ||
const errorMessage = | ||
error_description || `HTTP error. Unable to fetch ${url}`; | ||
const e = <any>new Error(errorMessage); | ||
|
||
e.error = error || 'request_error'; | ||
e.error_description = errorMessage; | ||
|
||
throw e; | ||
} | ||
|
||
return success; | ||
}; | ||
|
||
export const oauthToken = async ({ | ||
baseUrl, | ||
timeout, | ||
...options | ||
}: TokenEndpointOptions) => | ||
await getJSON(`${baseUrl}/oauth/token`, { | ||
await getJSON(`${baseUrl}/oauth/token`, timeout, { | ||
method: 'POST', | ||
body: JSON.stringify({ | ||
redirect_uri: window.location.origin, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Promise.race
... handy!There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume this ends the
fetch()
process so that's not being tried in the background while the app continues?