-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add State Provider Framework (#6640)
* 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]>
- Loading branch information
1 parent
801141f
commit e1b5b83
Showing
36 changed files
with
1,352 additions
and
68 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
103 changes: 103 additions & 0 deletions
103
apps/browser/src/platform/browser/from-chrome-event.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import { fromChromeEvent } from "./from-chrome-event"; | ||
|
||
describe("fromChromeEvent", () => { | ||
class FakeEvent implements chrome.events.Event<(arg1: string, arg2: number) => void> { | ||
listenerWasAdded: boolean; | ||
listenerWasRemoved: boolean; | ||
activeListeners: ((arg1: string, arg2: number) => void)[] = []; | ||
|
||
addListener(callback: (arg1: string, arg2: number) => void): void { | ||
this.listenerWasAdded = true; | ||
this.activeListeners.push(callback); | ||
} | ||
getRules(callback: (rules: chrome.events.Rule[]) => void): void; | ||
getRules(ruleIdentifiers: string[], callback: (rules: chrome.events.Rule[]) => void): void; | ||
getRules(ruleIdentifiers: unknown, callback?: unknown): void { | ||
throw new Error("Method not implemented."); | ||
} | ||
hasListener(callback: (arg1: string, arg2: number) => void): boolean { | ||
throw new Error("Method not implemented."); | ||
} | ||
removeRules(ruleIdentifiers?: string[], callback?: () => void): void; | ||
removeRules(callback?: () => void): void; | ||
removeRules(ruleIdentifiers?: unknown, callback?: unknown): void { | ||
throw new Error("Method not implemented."); | ||
} | ||
addRules(rules: chrome.events.Rule[], callback?: (rules: chrome.events.Rule[]) => void): void { | ||
throw new Error("Method not implemented."); | ||
} | ||
removeListener(callback: (arg1: string, arg2: number) => void): void { | ||
const index = this.activeListeners.findIndex((c) => c == callback); | ||
if (index === -1) { | ||
throw new Error("No registered callback."); | ||
} | ||
|
||
this.listenerWasRemoved = true; | ||
this.activeListeners.splice(index, 1); | ||
} | ||
hasListeners(): boolean { | ||
throw new Error("Method not implemented."); | ||
} | ||
|
||
fireEvent(arg1: string, arg2: number) { | ||
this.activeListeners.forEach((listener) => { | ||
listener(arg1, arg2); | ||
}); | ||
} | ||
} | ||
|
||
let event: FakeEvent; | ||
|
||
beforeEach(() => { | ||
event = new FakeEvent(); | ||
}); | ||
|
||
it("should never call addListener when never subscribed to", () => { | ||
fromChromeEvent(event); | ||
expect(event.listenerWasAdded).toBeFalsy(); | ||
}); | ||
|
||
it("should add a listener when subscribed to.", () => { | ||
const eventObservable = fromChromeEvent(event); | ||
eventObservable.subscribe(); | ||
expect(event.listenerWasAdded).toBeTruthy(); | ||
expect(event.activeListeners).toHaveLength(1); | ||
}); | ||
|
||
it("should call remove listener when the created subscription is unsubscribed", () => { | ||
const eventObservable = fromChromeEvent(event); | ||
const subscription = eventObservable.subscribe(); | ||
subscription.unsubscribe(); | ||
expect(event.listenerWasAdded).toBeTruthy(); | ||
expect(event.listenerWasRemoved).toBeTruthy(); | ||
expect(event.activeListeners).toHaveLength(0); | ||
}); | ||
|
||
it("should fire each callback given to subscribe", () => { | ||
const eventObservable = fromChromeEvent(event); | ||
|
||
let subscription1Called = false; | ||
let subscription2Called = false; | ||
|
||
const subscription1 = eventObservable.subscribe(([arg1, arg2]) => { | ||
expect(arg1).toBe("Hi!"); | ||
expect(arg2).toBe(2); | ||
subscription1Called = true; | ||
}); | ||
|
||
const subscription2 = eventObservable.subscribe(([arg1, arg2]) => { | ||
expect(arg1).toBe("Hi!"); | ||
expect(arg2).toBe(2); | ||
subscription2Called = true; | ||
}); | ||
|
||
event.fireEvent("Hi!", 2); | ||
|
||
subscription1.unsubscribe(); | ||
subscription2.unsubscribe(); | ||
|
||
expect(event.activeListeners).toHaveLength(0); | ||
expect(subscription1Called).toBeTruthy(); | ||
expect(subscription2Called).toBeTruthy(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { Observable } from "rxjs"; | ||
|
||
import { BrowserApi } from "./browser-api"; | ||
|
||
/** | ||
* Converts a Chrome event to an Observable stream. | ||
* | ||
* @typeParam T - The type of the event arguments. | ||
* @param event - The Chrome event to convert. | ||
* @returns An Observable stream of the event arguments. | ||
* | ||
* @remarks | ||
* This function creates an Observable stream that listens to a Chrome event and emits its arguments | ||
* whenever the event is triggered. If the event throws an error, the Observable will emit an error | ||
* notification with the error message. | ||
* | ||
* @example | ||
* ```typescript | ||
* const onMessage = fromChromeEvent(chrome.runtime.onMessage); | ||
* onMessage.subscribe((message) => console.log('Received message:', message)); | ||
* ``` | ||
*/ | ||
export function fromChromeEvent<T extends unknown[]>( | ||
event: chrome.events.Event<(...args: T) => void> | ||
): Observable<T> { | ||
return new Observable<T>((subscriber) => { | ||
const handler = (...args: T) => { | ||
if (chrome.runtime.lastError) { | ||
subscriber.error(chrome.runtime.lastError); | ||
return; | ||
} | ||
|
||
subscriber.next(args); | ||
}; | ||
|
||
BrowserApi.addListener(event, handler); | ||
return () => BrowserApi.removeListener(event, handler); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 3 additions & 1 deletion
4
apps/browser/src/platform/services/browser-local-storage.service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
import AbstractChromeStorageService from "./abstractions/abstract-chrome-storage-api.service"; | ||
|
||
export default class BrowserLocalStorageService extends AbstractChromeStorageService { | ||
protected chromeStorageApi = chrome.storage.local; | ||
constructor() { | ||
super(chrome.storage.local); | ||
} | ||
} |
4 changes: 3 additions & 1 deletion
4
apps/browser/src/platform/services/browser-memory-storage.service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
import AbstractChromeStorageService from "./abstractions/abstract-chrome-storage-api.service"; | ||
|
||
export default class BrowserMemoryStorageService extends AbstractChromeStorageService { | ||
protected chromeStorageApi = chrome.storage.session; | ||
constructor() { | ||
super(chrome.storage.session); | ||
} | ||
} |
Oops, something went wrong.