-
Notifications
You must be signed in to change notification settings - Fork 18
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
Updates to state provider deep dive #549
base: main
Are you sure you want to change the base?
Conversation
Deploying contributing-docs with
|
Latest commit: |
fbd3861
|
Status: | ✅ Deploy successful! |
Preview URL: | https://157b4563.contributing-docs.pages.dev |
Branch Preview URL: | https://state-provider-updates.contributing-docs.pages.dev |
Great job, no security vulnerabilities found in this Pull Request |
❓ @justindbaur Do you think that it's OK to remove the section on Migration and the details on how |
@trmartin4 Thank you for this, I had thought about adding some more docs regarding I do think having a brief blurb about state migrations is good as teams will still occasionally have to do them. We don't need to keep around the state service to state provider mappings though. Since state migrations shouldn't change after being written though it could be useful to just defer to here for any examples and we don't need one here in the docs. As for ============= A simple example using const USES_KEYCONNECTOR: UserKeyDefinition<boolean> = ...;
async setUsesKeyConnector(value: boolean, userId: UserId) {
// Only do the update if the current value saved in state
// differs in equality of the incoming value.
await this.stateProvider.getUser(userId, USES_KEYCONNECTOR).update(
currentValue => currentValue !== value
);
} Implementing a custom equality operator type Cipher = { id: string, username: string, password: string, revisionDate: Date };
const LAST_USED_CIPHER: UserKeyDefinition<Cipher> = ...;
async setLastUsedCipher(lastUsedCipher: Cipher | null, userId: UserId) {
await this.stateProvider.getUser(userId, LAST_USED_CIPHER).update(
currentValue => !this.areEqual(currentValue, lastUsedCipher)
);
}
areEqual(a: Cipher | null, b: Cipher | null) {
if (a == null) {
return b == null;
}
if (b == null) {
return false;
}
// Option one - Full equality, comparing every property for value equality
return a.id === b.id &&
a.username === b.username &&
a.password === b.password &&
a.revisionDate === b.revisionDate;
// Option two - Partial equality based on requirement that any update would
// bump the revision date.
return a.id === b.id && a.revisionDate === b.revisionDate;
} It's important that if you implement an equality function that you then negate the output of that function for use in ============= |
@justindbaur I addressed your concerns, if you don't mind taking a look. |
@justindbaur added today's feedback 👍 |
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.
Just a few comments, thank you so much!
async clear(userId: UserId): Promise<void> { | ||
await this.stateProvider.getUser(userId, FOLDERS_USER_STATE).update((state) => null); | ||
async clearStateValue(userId: UserId): Promise<void> { | ||
await this.stateProvider.getUserState$(userId, DOMAIN_USER_STATE).update((state) => null); |
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.
getUserState$
is a shorthand for returning the state$
property so you can't call update
on it.
await this.stateProvider.getUserState$(userId, DOMAIN_USER_STATE).update((state) => null); | |
await this.stateProvider.getUser(userId, DOMAIN_USER_STATE).update((state) => null); |
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.
Fixed in fbd3861
(#549). Thank you for catching that.
- [`EnvironmentService`](https://github.com/bitwarden/clients/pull/7621) | ||
- [Org Keys](https://github.com/bitwarden/clients/pull/7521) | ||
Use of `firstValueFrom()` should be avoided. If you find yourself trying to use `firstValueFrom()`, | ||
consider propagating the underlying observable instead of leaving reactivity. ::: |
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.
Missing end to the warning block?
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.
Oops! Fixed in fbd3861
(#549).
where the key will be a user's ID and the value being the legacy account object. | ||
|
||
::: | ||
:::warning `firstValueFrom()` and state updates |
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.
Somewhere in here we can also mention that update
will return the new value that was just saved back to the caller, or in the case of a custom shouldUpdate
function that returned false it will return the existing state value. So if consumers need the updated value they can always get it that way.
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.
Addressed with fbd3861
(#549). Let me know if you think the warning block is too big and should just be a new section.
🎟️ Tracking
https://bitwarden.atlassian.net/browse/PM-14197
https://bitwarden.atlassian.net/browse/PM-19220
https://bitwarden.atlassian.net/browse/PM-19218
https://bitwarden.atlassian.net/browse/PM-19219
📔 Objective
update
out of the "Advanced Usage" section, since we are going to be encouraging teams to use it to avoid unnecessary I/O for state updates (see Reduce desktop disk writes clients#13271 for an example). Before we start asking teams to pay more attention to this, I wanted to make sure it had a good place in the docs.ActiveUserState
to the bottom, since it is no longer recommended.cleanupDelayMs
option behavior when it's set to0
.firstValueFrom(state$)
directly after update.state$
does not guarantee an emission on same value updates.⏰ Reminders before review
team
🦮 Reviewer guidelines
:+1:
) or similar for great changes:memo:
) or ℹ️ (:information_source:
) for notes or general info:question:
) for questions:thinking:
) or 💭 (:thought_balloon:
) for more open inquiry that's not quite a confirmedissue and could potentially benefit from discussion
:art:
) for suggestions / improvements:x:
) or:warning:
) for more significant problems or concerns needing attention:seedling:
) or ♻️ (:recycle:
) for future improvements or indications of technical debt:pick:
) for minor or nitpick changes