-
Notifications
You must be signed in to change notification settings - Fork 15
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: ADR-006 implementation #1652
Conversation
🦋 Changeset detectedLatest commit: c681365 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
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 were some steps backwards here. review is based on reading the changeset
docs/adrs/006-web-apis.md
Outdated
/** | ||
* Tries to reconnect to the injected provider (the first one with `connected` state) | ||
* without asking for user approval | ||
*/ | ||
readonly reconnect: (providerUrl?: string) => Promise<string>; |
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 don't think this is appropriate.
- any provider may identify itself as connected
- multiple providers may identify themself as connected
- a user likely wishes to use a specific provider
implementing any automatic selection behavior in this client api is likely to guide developers to create a negative user experience for a user that wishes to select a provider. so the api should avoid any automatic selection behavior.
requiring the developer to deliberately select a frontend will force developers to anticipate this ambiguity. at that point they can either
- prompt users to select a specific provider
- implement some technique for their dapp to remember
- encode their own priority
currently, minifront will only connect to prax. but by implementing this reconnect
api and then using it in minifront, minifront may connect to any provider that happens to appear in the record, and it's not clear if the selection is even deterministic.
you've removed the PenumbraClient.providers
method, but with that method a developer could easily implement a similar behavior by filtering the returned record by testing isConnected
on each provider.
edit: i see there is a similar standalone method for getting all providers
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.
Fair enough. Somehow I thought checking for manifest validity would be enough but I see know it isn't. Especially at the 'multiple providers may identify themself as connected' point.
Probably will delete it for now
docs/adrs/006-web-apis.md
Outdated
export type PenumbraManifest = Partial<chrome.runtime.ManifestV3> & | ||
Required<Pick<chrome.runtime.ManifestV3, 'name' | 'version' | 'description' | 'icons'>>; | ||
|
||
export type getInjectedProvider = (penumbraOrigin: string) => Promise<PenumbraProvider>; | ||
|
||
export type getAllInjectedProviders = () => string[]; | ||
|
||
export type getPenumbraManifest = ( | ||
penumbraOrigin: string, | ||
signal?: AbortSignal, | ||
) => Promise<PenumbraManifest>; | ||
|
||
export type getAllPenumbraManifests = () => Record< | ||
keyof (typeof window)[typeof PenumbraSymbol], | ||
Promise<PenumbraManifest> | ||
>; |
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 seemed to be required by previous discussion that a PenumbraClient
object should collect methods a developer would be interested in for selecting and then initiating a provider connection
is there a reason these are broken out again?
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.
moved useful utility methods into the client
with get
prefixes
docs/adrs/006-web-apis.md
Outdated
export type getInjectedProvider = (penumbraOrigin: string) => Promise<PenumbraProvider>; | ||
|
||
export type getAllInjectedProviders = () => string[]; |
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'd like to avoid the term 'injected' because in the future the api may not actually require injection, given possible externally_connectable
features
at that point to avoid misleading terminology, either the api would require a breaking change to rename, or another set of methods identifying a distinct set of providers that don't actually require a practically distinct api
by avoiding the term 'injected' and referring solely to 'providers' then there's no potential terminology problem in the future.
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.
removed these functions in favor of the get.ts
from #1648
packages/client/src/client.ts
Outdated
private assertPort() { | ||
if (!this.port) { | ||
throw new PenumbraProviderNotConnectedError(this.origin); | ||
} | ||
return this.port; | ||
} | ||
|
||
private assertProvider() { | ||
if (!this.provider) { | ||
throw new PenumbraProviderNotConnectedError(this.origin); | ||
} | ||
return this.provider; | ||
} |
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.
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.
good point, removed these assertion methods in favor of non-throwing.
as for the question – i will continue pursuing the client without the necessary origin
in the constructor. It is not useless – it allows the creation of client in the setup of the users' app and the future reuse, a good practice popularized by many libraries (listed in the ADR as the source of inspiration). This approach is proven to be effective in terms of DX
docs/adrs/006-web-apis.md
Outdated
/** | ||
* Connects to the injected provider, asks for user approval if wasn't connected before. | ||
* If `providerUrl` argument is not provided, tries to connect to the first injected provider. | ||
* Returns the manifest URL of the connected provider or throws an error otherwise. | ||
*/ | ||
readonly connect: (providerUrl?: string) => Promise<string>; |
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.
returning manifest url from the connect
method seems like the least useful choice.
it seems more better to return the MessagePort
or a created Transport
, allowing the caller to handle the Transport
directly if they wish, as designed in #1648
if the manifest is really desired, just go ahead and provide a parsed manifest - the connection init process must fetch it anyway to confirm it exists.
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.
That's true – the provider origin URL is not that useful. The same can be said about MessagePort
or Transport
– they are of no value for the library users. It might be better to return Promise<void>
for now until we find out the really useful return, to not produce breaking changes in the future
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.
changed to return Promise<void>
packages/client/src/client.ts
Outdated
public onConnectionChange(callback: (detail: PenumbraStateEventDetail) => void) { | ||
this.callbacks.add(callback); | ||
} |
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 seems like there's now no way to remove a callback
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.
copied the AbortController usage here
packages/client/src/client.ts
Outdated
public async reconnect(requireOrigin?: string) { | ||
const providers = assertPenumbra(); | ||
|
||
let provider: PenumbraProvider | undefined; | ||
let origin = requireOrigin; | ||
if (requireOrigin) { | ||
provider = assertProviderRecord(requireOrigin); | ||
} else { | ||
const connectedEntry = Object.entries(providers).find(([, provider]) => | ||
provider.isConnected(), | ||
); | ||
origin = connectedEntry?.[0]; | ||
provider = connectedEntry?.[1]; | ||
} | ||
|
||
if (!origin || !provider?.isConnected()) { | ||
throw new PenumbraProviderNotConnectedError(origin); | ||
} | ||
|
||
await assertProviderManifest(origin); | ||
|
||
this.origin = origin; | ||
this.provider = provider; | ||
this.port = await provider.connect(); | ||
this.callbacks.forEach(cb => cb(new PenumbraStateEvent(origin, provider.state(), true).detail)); | ||
|
||
return origin; | ||
} |
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.
given multiple connected providers, which provider is preferred by this method?
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.
removed the reconnect
if some of these changes were intended to address state management concerns discussed in DM, i don't think they achieve that objective |
…tation # Conflicts: # packages/react/CHANGELOG.md # packages/react/package.json
closed in favor of #1648 |
Implements ADR-006. Based on previously-closed #1567 and uses newer features from #1648
This PR has its own, newer version of the ADR, that completely matches the implementation. Adds
reconnect
function and usesclient.service
to create PromiseClient.To check the implementation, do this: