-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Add State Provider Framework #6640
Conversation
Add a class for encapsulation information about state this will often be for a domain but creations of this will exist outside of a specific domain, hence just the name State.
This adds a type that extends state definition into another sub-key and forces creators to define the data that will be stored and how to read the data that they expect to be stored.
Adds to function to help building keys for both keys scoped to a specific user and for keys scoped to global storage. Co-authored-by: Matt Gibson <[email protected]>
Original commit by Matt: 823d954 Co-authored-by: Matt Gibson <[email protected]>
Create a helper that creats an Observable from a chrome event and removes the listener when the subscription is completed.
Use fromChromeEvent to create an observable from chrome event and map that into our expected shape.
Co-authored-by: Matt Gibson <[email protected]>
Co-authored-by: Matt Gibson <[email protected]>
No New Or Fixed Issues Found |
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.
Early review just because I think you'll the very first comment I had 😄
Rework fromChromeEvent so we have to lie to TS less and remove unneeded generics. I did this by caring less about the function and more about the parameters only. Co-authored-by: Matt Gibson <[email protected]>
c440182
to
64026d3
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.
I think there's a bit more polish to do before this is ready
apps/browser/src/platform/services/abstractions/abstract-chrome-storage-api.service.ts
Outdated
Show resolved
Hide resolved
libs/common/src/platform/state/implementations/default-user-state.ts
Outdated
Show resolved
Hide resolved
const accountChangeSubscription = activeAccountData$.subscribe(); | ||
const storageUpdateSubscription = storageUpdates$.subscribe((data) => { |
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.
💭 Looking at this again, it seems fragile to have two separate watchers be responsible for the current value of a single observable. I might be being paranoid here, though
libs/common/src/platform/state/implementations/default-user-state.ts
Outdated
Show resolved
Hide resolved
libs/common/src/platform/state/implementations/default-user-state.ts
Outdated
Show resolved
Hide resolved
Use different key format
…warden/clients into add-state-provider-framework
libs/common/src/platform/state/implementations/default-user-state.provider.ts
Outdated
Show resolved
Hide resolved
libs/common/src/platform/state/implementations/default-user-state.provider.ts
Outdated
Show resolved
Hide resolved
Co-authored-by: Oscar Hinton <[email protected]>
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.
Looks good for Vault! Thanks for creating the ticket!
* Add StateDefinition Add a class for encapsulation information about state this will often be for a domain but creations of this will exist outside of a specific domain, hence just the name State. * Add KeyDefinition This adds a type that extends state definition into another sub-key and forces creators to define the data that will be stored and how to read the data that they expect to be stored. * Add key-builders helper functions Adds to function to help building keys for both keys scoped to a specific user and for keys scoped to global storage. Co-authored-by: Matt Gibson <[email protected]> * Add updates$ stream to existing storageServices Original commit by Matt: 823d954 Co-authored-by: Matt Gibson <[email protected]> * Add fromChromeEvent helper Create a helper that creats an Observable from a chrome event and removes the listener when the subscription is completed. * Implement `updates$` property for chrome storage Use fromChromeEvent to create an observable from chrome event and map that into our expected shape. * Add GlobalState Abstractions * Add UserState Abstractions * Add Default Implementations of User/Global state Co-authored-by: Matt Gibson <[email protected]> * Add Barrel File for state Co-authored-by: Matt Gibson <[email protected]> * Fix ChromeStorageServices * Rework fromChromeEvent Rework fromChromeEvent so we have to lie to TS less and remove unneeded generics. I did this by caring less about the function and more about the parameters only. Co-authored-by: Matt Gibson <[email protected]> * Fix UserStateProvider Test * Add Inner Mock & Assert Calls * Update Tests to use new keys Use different key format * Prefer returns over mutations in update * Update Tests * Address PR Feedback * Be stricter with userId parameter * Add Better Way To Determine if it was a remove * Fix Web & Browser Storage Services * Fix Desktop & CLI Storage Services * Fix Test Storage Service * Use createKey Helper * Prefer implement to extending * Determine storage location in providers * Export default providers publicly * Fix user state tests * Name tests * Fix CLI * Prefer Implement In Chrome Storage * Remove Secure Storage Option Also throw an exception for subscribes to the secure storage observable. * Update apps/browser/src/platform/browser/from-chrome-event.ts Co-authored-by: Oscar Hinton <[email protected]> * Enforce state module barrel file * Fix Linting Error * Allow state module import from other modules * Globally Unregister fromChromeEvent Listeners Changed fromChromeEvent to add its listeners through the BrowserApi, so that they will be unregistered when safari closes. * Test default global state * Use Proper Casing in Parameter * Address Feedback * Update libs/common/src/platform/state/key-definition.ts Co-authored-by: Oscar Hinton <[email protected]> * Add `buildCacheKey` Method * Fix lint errors * Add Comment Co-authored-by: Oscar Hinton <[email protected]> * Use Generic in callback parameter * Refactor Out DerivedStateDefinition * Persist Listener Return Type * Add Ticket Link --------- Co-authored-by: Matt Gibson <[email protected]> Co-authored-by: Matt Gibson <[email protected]> Co-authored-by: Oscar Hinton <[email protected]>
* Add StateDefinition Add a class for encapsulation information about state this will often be for a domain but creations of this will exist outside of a specific domain, hence just the name State. * Add KeyDefinition This adds a type that extends state definition into another sub-key and forces creators to define the data that will be stored and how to read the data that they expect to be stored. * Add key-builders helper functions Adds to function to help building keys for both keys scoped to a specific user and for keys scoped to global storage. Co-authored-by: Matt Gibson <[email protected]> * Add updates$ stream to existing storageServices Original commit by Matt: 823d954 Co-authored-by: Matt Gibson <[email protected]> * Add fromChromeEvent helper Create a helper that creats an Observable from a chrome event and removes the listener when the subscription is completed. * Implement `updates$` property for chrome storage Use fromChromeEvent to create an observable from chrome event and map that into our expected shape. * Add GlobalState Abstractions * Add UserState Abstractions * Add Default Implementations of User/Global state Co-authored-by: Matt Gibson <[email protected]> * Add Barrel File for state Co-authored-by: Matt Gibson <[email protected]> * Fix ChromeStorageServices * Rework fromChromeEvent Rework fromChromeEvent so we have to lie to TS less and remove unneeded generics. I did this by caring less about the function and more about the parameters only. Co-authored-by: Matt Gibson <[email protected]> * Fix UserStateProvider Test * Add Inner Mock & Assert Calls * Update Tests to use new keys Use different key format * Prefer returns over mutations in update * Update Tests * Address PR Feedback * Be stricter with userId parameter * Add Better Way To Determine if it was a remove * Fix Web & Browser Storage Services * Fix Desktop & CLI Storage Services * Fix Test Storage Service * Use createKey Helper * Prefer implement to extending * Determine storage location in providers * Export default providers publicly * Fix user state tests * Name tests * Fix CLI * Prefer Implement In Chrome Storage * Remove Secure Storage Option Also throw an exception for subscribes to the secure storage observable. * Update apps/browser/src/platform/browser/from-chrome-event.ts Co-authored-by: Oscar Hinton <[email protected]> * Enforce state module barrel file * Fix Linting Error * Allow state module import from other modules * Globally Unregister fromChromeEvent Listeners Changed fromChromeEvent to add its listeners through the BrowserApi, so that they will be unregistered when safari closes. * Test default global state * Use Proper Casing in Parameter * Address Feedback * Update libs/common/src/platform/state/key-definition.ts Co-authored-by: Oscar Hinton <[email protected]> * Add `buildCacheKey` Method * Fix lint errors * Add Comment Co-authored-by: Oscar Hinton <[email protected]> * Use Generic in callback parameter * Refactor Out DerivedStateDefinition * Persist Listener Return Type * Add Ticket Link --------- Co-authored-by: Matt Gibson <[email protected]> Co-authored-by: Matt Gibson <[email protected]> Co-authored-by: Oscar Hinton <[email protected]>
Type of change
Objective
PM-4342 PM-4343
This adds a framework for how a domain can own their own state and gain observable access to the state that you own, both globally and for a user. There is no implementation of this framework in this PR, a PR with an implementation will follow the merging of this.
Code changes
StateDefinition
This is an object that will be created in a common file that is owned by platform and all creations of this type outside of there is strictly prohibited. It encapsulates the rule of the name for your state (most commonly a domain ex.
FolderService
,CipherService
.) and where this state should be stored. The name and location combination of this state should be unique across all other uses ofStateDefinition
s yet should remain human readable (not a uuid). This is why creations of this type will be required to be in a single file owned by the platform team, and tests will be created to help ensure this.KeyDefinition
This is a type that builds upon the concept of
StateDefinition
(in fact the creation of aKeyDefinition
requires a `StateDefinition) by sub-dividing a state into smaller chunks of information that a state or domain will care about. The creation of this object is also limited to a single file that is owned by platform. The keys within a state must also remain unique. This type also ensures that you give it logic to convert the JSON form of your data into the data you expect to actually be there. This is because state is often round tripped through it's json form and it is not able to be converted back unless specific logic is provided.This type also contains several helper methods for creating your keys in popular configurations like arrays or records.
GlobalState
This class provides you with 2 API's. One is an
update
method that takes a callback for manipulating your state. The second API is astate$
observable that you may subscribe to that will provide you with emissions any time your state is updated. This may be from your own usage of theupdate
method or this may be from the usage of theupdate
method in a different context than you.GlobalStateProvider
A simple class that gets your
GlobalState
implementation for the givenKeyDefinition
.UserState
This is a similar concept to
GlobalState
but for state about scoped to users. It has a similarupdate
method for updating the state of the currently active user and an observable for subscribing to the data from the current user. It also gives you the ability to get your state directly from it's storage and the ability to update state for a specified user via their id.Screenshots
Before you submit