Skip to content
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

Local Storage Configuration Helper #5691

Conversation

anthony-murphy
Copy link
Contributor

Proxy all our options bags to local storage, so we can easily override things at runtime

related to #5396

}
});

export function createLocalStorageConfigurationProxy<C extends Record<string, unknown>>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

having some comments about classes and functions would be nice :)

@@ -0,0 +1,78 @@
import { Lazy } from "./lazy";

const isLocalStorageAvailable = new Lazy(()=>{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we already have something like that in ODSP driver. Can we consolidate?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'd like to see the ODSP driver just use this. i updated a couple examples, but there are more

}
}

public get(target: T, p: string): any {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about set()? If I overwrite whole property/object, we should reflect that in this.configCache, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thought was config will be immutable, as it gets complex it config change underneath

.get(p);

case "undefined":
// we don't know the type of the prop, see if sub-props exist, in which case assume
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit ugly, in a sense that there are obvious paths when things will go wrong.
It assumes only narrow usage patterns, which may be not obvious for the caller.
I do not know if I have better suggestion, but maybe we say that all these configs are read-only? I.e. consumer (runtime) can only read, that would substantially reduce wrong-doing by callers

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it def needs better docs, and error handling before checkin. the big question i have is, can you safely use proxy. if so, then it's worth to do all those things

});

export function createLocalStorageConfigurationProxy<C extends Record<string, unknown>>(
namspace: string, target: C): Readonly<C> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can see here I return the object as read-only


export class LocalStorageConfigurationProxyHandler<T extends Record<string, unknown>> implements ProxyHandler<T> {
private readonly configCache = new Map<string, unknown>();
constructor(private readonly namespace: string) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think about how something like nconf can be wrap on the node side as well to allow argv/env/json config files to provide options.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i was thinking about that exact thing, and i'm not sure. it's an open question to me if we should setup the proxy, like I'm doing here, or ask partners to do it, basically they should wrap it before they give it to us. I see benefits and draw backs to both, so not sure which direction to go

// the target property is an object, so construct a new proxy for it
return this.configCache.set(
p,
new Proxy(targetValue ?? {}, new LocalStorageConfigurationProxyHandler(localStorageKey)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the '??' for null? (...if so, probably want to set the cache to an unproxied null.)

// not a object, and not in local storage, so return the in-memory value
return this.configCache.set(p, targetValue).get(p);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just FYI - IIRC, the additional handlers (ownKeys, getOwnPropertyDescriptors, etc.) are required to avoid breaking features that use reflection, such as the spread operator, JSON stringify, etc.

@anthony-murphy
Copy link
Contributor Author

closing for #5921

@anthony-murphy anthony-murphy deleted the local-storage-config-helper branch September 10, 2024 00:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants