-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a55d34b
commit b607f24
Showing
7 changed files
with
201 additions
and
14 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,4 +2,4 @@ | |
'@penumbra-zone/client': major | ||
--- | ||
|
||
add disconnect method | ||
add disconnect method, add `create` module |
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
10 changes: 0 additions & 10 deletions
10
apps/extension/src/content-scripts/injected-disconnect-listener.ts
This file was deleted.
Oops, something went wrong.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import { createPromiseClient, type Transport } from '@connectrpc/connect'; | ||
import type { PenumbraService } from '@penumbra-zone/protobuf'; | ||
import { jsonOptions } from '@penumbra-zone/protobuf'; | ||
import { | ||
createChannelTransport, | ||
type ChannelTransportOptions, | ||
} from '@penumbra-zone/transport-dom/create'; | ||
import { PenumbraSymbol, type PenumbraInjection } from '.'; | ||
|
||
// Naively return the first available provider origin, or `undefined`. | ||
const availableOrigin = () => Object.keys(window[PenumbraSymbol] ?? {})[0]; | ||
|
||
/** | ||
* Given a specific origin, identify the relevant injection or throw. An | ||
* `undefined` origin is accepted but will throw. | ||
*/ | ||
const assertProvider = (providerOrigin?: string): PenumbraInjection => { | ||
const provider = providerOrigin && window[PenumbraSymbol]?.[providerOrigin]; | ||
if (!provider) throw new Error(`Provider ${providerOrigin} not available`); | ||
return provider; | ||
}; | ||
|
||
/** | ||
* Given a specific origin, identify the relevant injection, and confirm its | ||
* manifest is actually present or throw. An `undefined` origin is accepted but | ||
* will throw. | ||
*/ | ||
const assertProviderManifest = async (providerOrigin?: string): Promise<PenumbraInjection> => { | ||
// confirm the provider injection is present | ||
const provider = assertProvider(providerOrigin); | ||
|
||
// confirm the provider manifest is located at the expected origin | ||
if (new URL(provider.manifest).origin !== providerOrigin) | ||
throw new Error('Provider manifest origin mismatch'); | ||
|
||
// confirm the provider manifest exists, can be fetched, and is json | ||
try { | ||
const req = await fetch(provider.manifest); | ||
const manifest: unknown = await req.json(); | ||
if (!manifest) throw new Error('Provider manifest not present'); | ||
} catch { | ||
throw new Error('Provider manifest not present'); | ||
} | ||
|
||
return provider; | ||
}; | ||
|
||
/** | ||
* Asynchronously get a connection to the specified provider, or the first | ||
* available provider if unspecified. | ||
* | ||
* Confirms presence of the provider's manifest. Will attempt to request | ||
* approval if connection is not already active. | ||
* | ||
* @param requireProvider optional string identifying a provider origin | ||
*/ | ||
export const getPenumbraPort = async (requireProvider?: string) => { | ||
const provider = await assertProviderManifest(requireProvider ?? availableOrigin()); | ||
if (provider.isConnected() === undefined) await provider.request(); | ||
return provider.connect(); | ||
}; | ||
|
||
/** | ||
* Synchronously create a channel transport for the specified provider, or the | ||
* first available provider if unspecified. | ||
* | ||
* Will always succeed, but the transport may fail if the provider is not | ||
* present, or if the provider rejects the connection. | ||
* | ||
* Confirms presence of the provider's manifest. Will attempt to request | ||
* approval if connection is not already active. | ||
* | ||
* @param requireProvider optional string identifying a provider origin | ||
* @param transportOptions optional `ChannelTransportOptions` without `getPort` | ||
*/ | ||
export const syncCreatePenumbraChannelTransport = ( | ||
requireProvider?: string, | ||
transportOptions: Omit<ChannelTransportOptions, 'getPort'> = { jsonOptions }, | ||
): Transport => | ||
createChannelTransport({ | ||
...transportOptions, | ||
getPort: () => getPenumbraPort(requireProvider), | ||
}); | ||
|
||
/** | ||
* Asynchronously create a channel transport for the specified provider, or the | ||
* first available provider if unspecified. | ||
* | ||
* Like `syncCreatePenumbraChannelTransport`, but awaits connection init. | ||
*/ | ||
export const createPenumbraChannelTransport = async ( | ||
requireProvider?: string, | ||
transportOptions: Omit<ChannelTransportOptions, 'getPort'> = { jsonOptions }, | ||
): Promise<Transport> => { | ||
const port = await getPenumbraPort(requireProvider); | ||
return createChannelTransport({ | ||
...transportOptions, | ||
getPort: () => Promise.resolve(port), | ||
}); | ||
}; | ||
|
||
/** | ||
* Synchronously create a client for `service` from the specified provider, or the | ||
* first available provider if unspecified. | ||
* | ||
* If the provider is unavailable, the client will fail to make requests. | ||
*/ | ||
export const syncCreatePenumbraClient = <P extends PenumbraService>( | ||
service: P, | ||
requireProvider?: string, | ||
) => createPromiseClient(service, syncCreatePenumbraChannelTransport(requireProvider)); | ||
|
||
/** | ||
* Asynchronously create a client for `service` from the specified provider, or | ||
* the first available provider if unspecified. | ||
* | ||
* Like `syncCreatePenumbraClient`, but awaits connection init. | ||
*/ | ||
export const createPenumbraClient = async <P extends PenumbraService>( | ||
service: P, | ||
requireProvider?: string, | ||
transportOptions?: Omit<ChannelTransportOptions, 'getPort'>, | ||
) => | ||
createPromiseClient( | ||
service, | ||
await createPenumbraChannelTransport(requireProvider, transportOptions), | ||
); |
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
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.