-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
feat(clients): use custom cognito-identity and pinpoint clients #11427
Conversation
…eware (#11188) * feat(clients): middleware interface and retry middleware * test(clients): retry middleare unit test * fix(clients): middleware type to include options * feat(clients): add retry middleware unit test and update interface * chore(clients): update bundle size limit for fetch and retry * chore(clients): add retry docs; fix format * fix(clients): address feedbacks
* fix(retry): add metadata to returns from retry middldeware; fix minor bugs * feat(clients): address retry middleware feedbacks Co-authored-by: Chris F <5827964+cshfang@users.noreply.github.com>
* feat(clients): implement service API composer * chore(clients): rename middleware interface * feat(clients): middleware handler interface can be non request/response interface * chore(clients): move fetch handler to handlers folder * feat(clients): implement user agent middleware * feat(clients): implement unauth aws transfer handler * feat(clients): implement api handler composer * feat(clients): implement cognito-identity client * chore(clients): update bundle size limit * feat(clients): add serde utils; remove retry in api handler composer * feat(clients): integrate cognito-identity client to Credentials class * fix(clients): make retryDecider interface async * chore: move cognito client to dev dep * chore(clients): use Pascale path name * fix(clients): handle fetch response.body undefined in RN * chore: publish under v5-custom-clients dist-tag * fix(clients): read body once for errors
* test(clients): add cognito-identity functional test * chore(clients): prefer destructuring parameters at top
* feat(clients): Add custom signature v4 signer * Updated docstrings * Extracted common code * Use == null instead of isNil * Add unit tests * Add missing licensing headers * Use test case options in presign tests * Fixed comment * Add test for data hashing with SourceData keys * Remove buffer dependency * Remove internal sdk dependency
* feat(clients): Add signing middleware * Use closure for clock offset * Add bundle size test entry * Address comments
…1311) * feat(clients): support CN partition by adding DNS suffix resolver * chore(clients): update bundle size test limit * fix(clients): address feedbacks * chore: update bundle size limit
* feat(clients) Add updateEndpoint API * Rename handler
* feat(clients) Add putEvents API * Add additional verification for expected date format * Mark API as internal
* feat(clients) Add getInAppMessages API * Update unit test
Co-authored-by: Allan Zheng <zheallan@amazon.com>
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'm only half way through, submitting comments now and will return to this in a couple hours.
packages/core/src/AwsClients/CognitoIdentity/getCredentialsForIdentity.ts
Show resolved
Hide resolved
packages/notifications/src/InAppMessaging/Providers/AWSPinpointProvider/utils.ts
Show resolved
Hide resolved
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.
LGTM
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.
Lots of comments for you! Feel free to take most as signaling my preferences for future PR's. And on that note, let's try strategize future PR's to be more focused, please.
Four things I'd want touched on in this PR before approving:
- The potential race in the response stream/body reader/cache promise.
- Confirmation that error cases are tested to the extent they need to be.
- A link to the encodeURIComponent RFC gapfill.
- I had a comment somewhere in here about something that sounds like a latent bomb. Can't remember where. But, something there to settle my nerves, please!
In general, a few things were initially hard to follow. But, nothing that should block the PR. And, it seems like some of the harder-to-follow bits are in support of some pretty easy-to-read client/"service api" generation. So, net good, IMO. Good work!
I think most of my comments are about half-baked docstrings. If you have time, I'd love to see followup PR (at least eventually) with meaningful docstrings. It looks like you started in some areas and produced some really helpful docs and maybe just lost steam.
And my disclosure: I'm not an expert on the auth exchanges, and I didn't look to closely at the pinpoint stuff. I assume others are reviewing these in depth.
let cached: T; | ||
return async () => { | ||
if (!cached) { | ||
cached = await payloadAccessor(); | ||
} | ||
return cached; | ||
}; |
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.
This formulation contains an inherent race. If this is invoked repeatedly in rapid succession, multiple calls to payloadAccessor()
can be spawned concurrently. The race can be eliminated by storing and branching on the source promise directly instead of branching on the awaited result.
let cached: T; | |
return async () => { | |
if (!cached) { | |
cached = await payloadAccessor(); | |
} | |
return cached; | |
}; | |
let cached: Promise<T>; | |
return async () => { | |
if (!cached) { | |
// Explicitly not awaiting. Intermediate await would add overhead and | |
// introduce a possible race in the event that this wrapper is called | |
// again before the first `payloadAccessor` call resolves. | |
cached = payloadAccessor(); | |
} | |
return cached; | |
}; |
I've tried to demo what I mean in this playground.
The inherent race might be mitigated due to calls being internal and fairly well-controlled. But, I don't have my head around this all yet to be confident. So, at the moment, I'd be more comfortable if we could eliminate the possibility.
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.
This race will only happen if the withPayloadCaching
is called concurrently. However payload accessor is only called once per http response
const responseHeaders = {}; | ||
resp.headers?.forEach((value, key) => { | ||
responseHeaders[key.toLowerCase()] = value; | ||
}); |
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 didn't expect to see this here. That doesn't mean it's wrong, but perhaps it warrants a comment. Why is lower-casing header keys a responsibility of this handler?
packages/core/__tests__/AwsClients/CognitoIdentity/getCredentialsForIdentity-test.ts
Show resolved
Hide resolved
export const jitteredBackoff: RetryOptions['computeDelay'] = attempt => { | ||
const delayFunction = jitteredBackoffUtil(); | ||
const delay = delayFunction(attempt); | ||
return delay === false ? MAX_DELAY_MS : delay; |
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.
Is delay
ever > MAX_DELAY_MS
?
maxAttempts = DEFAULT_RETRY_ATTEMPTS, | ||
retryDecider, | ||
computeDelay, | ||
abortSignal, |
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.
Interesting ... I must have read right past this before or it didn't "click" for me. But, having this here means that we build the middleware for each request, correct?
Not a blocker. But, that seems odd to me.
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.
Yes, the composing of pure functional middleware happens for each request. It's the same for AWS SDK too.
serializer: (input: Input, endpoint: Endpoint) => HttpRequest, | ||
deserializer: (output: HttpResponse) => Promise<Output>, |
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.
FWIW: Here and throughout, I find it a little odd that these functions are nouns instead of verbs.
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.
This is awesome!!
Thanks for the hard work and putting this out.
I have some nit comments, but feel free to update later.
packages/core/src/Credentials.ts
Outdated
let credentials = undefined; | ||
if (identity_id) { | ||
const cognitoIdentityParams: FromCognitoIdentityParameters = { | ||
const credentialsProvider = async () => { |
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.
nit: the name could be authenticatedCredentialsProvider
packages/core/src/Credentials.ts
Outdated
IdentityPoolId: identityPoolId, | ||
}) | ||
); | ||
const credentialsProvider = async () => { |
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.
nit: I would name it guestCredentialsProvider
semi-nit: This code is very similar to a code below
* The endpoint resolver function that returns the endpoint URL for a given region. | ||
*/ | ||
const endpointResolver = ({ region }: EndpointResolverOptions) => ({ | ||
url: new URL(`https://cognito-identity.${region}.${getDnsSuffix(region)}`), |
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.
nit: reuse SERVICE_NAME
to save a couple of bytes
9beb16b
9beb16b
to
c67f268
Compare
c67f268
to
2d6eecf
Compare
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.
Great work
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.
Approving for the devops portion (which got removed anyway 😛)
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.
Thanks for the rev!
const MAX_DELAY_MS = 5 * 60 * 1000; | ||
const DEFAULT_MAX_DELAY_MS = 5 * 60 * 1000; | ||
|
||
export const jitteredBackoff: RetryOptions['computeDelay'] = attempt => { | ||
const delayFunction = jitteredBackoffUtil(); | ||
const delayFunction = jitteredBackoffUtil(DEFAULT_MAX_DELAY_MS); | ||
const delay = delayFunction(attempt); | ||
return delay === false ? MAX_DELAY_MS : delay; | ||
// The delayFunction returns false when the delay is greater than the max delay(5 mins). | ||
// In this case, the retry middleware will delay 5 mins instead, as a ceiling of the delay. | ||
return delay === false ? DEFAULT_MAX_DELAY_MS : delay; | ||
}; |
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.
It's a bit odd having both the delay function and this function doing conditional things around the DEFAULT_MAX_DELAY_MS
. But, I think I can see how it makes sense. And, the change addresses the larger concern I had, so I appreciate it. Thanks!
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
/** | ||
* Wraps encodeURIComponent to encode additional characters to fully adhere to RFC 3986. |
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.
Not the kind of reference I was hoping for. But, it does demonstrates that this copies another established library that does AWS stuff. So, I'll take it! Thanks!
@@ -3,16 +3,16 @@ | |||
|
|||
import { getSkewCorrectedDate } from './getSkewCorrectedDate'; | |||
|
|||
const SKEW_WINDOW = 5 * 60 * 1000; // 5 minutes | |||
// 5 mins in milliseconds. Ref: https://github.com/aws/aws-sdk-js-v3/blob/6c0f44fab30a1bb2134af47362a31332abc3666b/packages/middleware-signing/src/utils/isClockSkewed.ts#L10 |
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.
Not quite the explanation I thought we'd have, but it works for me!
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.
Thanks for the rev!
Description of changes
Custom clients for Cognito Identity and Pinpoint to reduce the library bundle size. No interface change or compatibility change.
Bundle size reduction from custom clients:
Description of how you validated changes
Unit test; Integrations test; Amplify UI canary; Amplify Studio build
Checklist
yarn test
passesBy submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.