packages/core: naming and docs updates for OAuthRequest API

This commit is contained in:
Patrik Oldsberg
2020-05-14 11:02:35 +02:00
parent 1c50ded618
commit eec599738d
6 changed files with 53 additions and 41 deletions
@@ -63,10 +63,10 @@ export type LoginPopupOptions = {
/**
* Information about the auth provider that we're requesting a login towards.
*
* This should be show to the user so that they can be informed about what login is being requested
* This should be shown to the user so that they can be informed about what login is being requested
* before a popup is shown.
*/
export type AuthProviderInfo = {
export type AuthProvider = {
/**
* Title for the auth provider, for example "GitHub"
*/
@@ -82,39 +82,45 @@ export type AuthProviderInfo = {
* Describes how to handle auth requests. Both how to show them to the user, and what to do when
* the user accesses the auth request.
*/
export type AuthRequesterOptions<T> = {
export type AuthRequesterOptions<AuthResponse> = {
/**
* Information about the auth provider, which will be forwarded to auth requests.
*/
info: AuthProviderInfo;
provider: AuthProvider;
/**
* Implementation of the auth flow, which will be called synchronously when
* triggerAuth() is called on an auth requests.
* trigger() is called on an auth requests.
*/
authHandler(scope: OAuthScopes): Promise<T>;
onAuthRequest(scope: OAuthScopes): Promise<AuthResponse>;
};
/**
* Function used to trigger new auth requests for a set of scopes.
*
* The returned promise will resolve to the same value returned by the authHandler in the
* The returned promise will resolve to the same value returned by the onAuthRequest in the
* AuthRequesterOptions. Or rejected, if the request is rejected.
*
* This function can be called multiple times before the promise resolves. All calls
* will be merged into one request, and the scopes forwarded to the authHandler will be the
* will be merged into one request, and the scopes forwarded to the onAuthRequest will be the
* union of all requested scopes.
*/
export type AuthRequester<T> = (scope: OAuthScopes) => Promise<T>;
export type AuthRequester<AuthResponse> = (
scope: OAuthScopes,
) => Promise<AuthResponse>;
/**
* An auth request for a single auth provider.
* An pending auth request for a single auth provider. The request will remain in this pending
* state until either reject() or trigger() is called.
*
* Any new requests for the same provider are merged into the existing pending request, meaning
* there will only ever be a single pending request for a given provider.
*/
export type AuthRequest = {
export type PendingAuthRequest = {
/**
* Information about the auth provider, as given in the AuthRequesterOptions
*/
info: AuthProviderInfo;
provider: AuthProvider;
/**
* Rejects the request, causing all pending AuthRequester calls to fail with "RejectedError".
@@ -122,9 +128,11 @@ export type AuthRequest = {
reject: () => void;
/**
* Synchronously calls the auth handler with all scope currently in the request.
* Trigger the auth request to continue the auth flow, by for example showing a popup.
*
* Synchronously calls onAuthRequest with all scope currently in the request.
*/
triggerAuth(): Promise<void>;
trigger(): Promise<void>;
};
/**
@@ -136,6 +144,8 @@ export type OAuthRequestApi = {
*
* The redirect handler of the flow should use postMessage to communicate back
* to the app window.
*
* The returned promise resolves to the contents of the message that was posted from the auth popup.
*/
showLoginPopup(options: LoginPopupOptions): Promise<any>;
@@ -143,7 +153,7 @@ export type OAuthRequestApi = {
* A utility for showing login popups or similar things, and merging together multiple requests for
* different scopes into one request that inclues all scopes.
*
* The passed in options provide information about the login provider, and how handle auth requests.
* The passed in options provide information about the login provider, and how to handle auth requests.
*
* The returned AuthRequester function is used to request login with new scopes. These requests
* are merged together and forwarded to the auth handler, as soon as a consumer of auth requests
@@ -151,10 +161,12 @@ export type OAuthRequestApi = {
*
* See AuthRequesterOptions, AuthRequester, and handleAuthRequests for more info.
*/
createAuthRequester<T>(options: AuthRequesterOptions<T>): AuthRequester<T>;
createAuthRequester<AuthResponse>(
options: AuthRequesterOptions<AuthResponse>,
): AuthRequester<AuthResponse>;
/**
* Subscribes as a handler of auth requests. The returned observable will emit all
* Observers panding auth requests. The returned observable will emit all
* current active auth request, at most one for each created auth requester.
*
* Each request has its own info about the login provider, forwarded from the auth requester options.
@@ -162,9 +174,9 @@ export type OAuthRequestApi = {
* Depending on user interaction, the request should either be rejected, or used to trigger the auth handler.
* If the request is rejected, all pending AuthRequester calls will fail with a "RejectedError".
* If a auth is triggered, and the auth handler resolves successfully, then all currently pending
* AuthRequester calls will resolve to the value returned by the authHandler call.
* AuthRequester calls will resolve to the value returned by the onAuthRequest call.
*/
handleAuthRequests(): Observable<AuthRequest[]>;
authRequest$(): Observable<PendingAuthRequest[]>;
};
export const oauthRequestApiRef = new ApiRef<OAuthRequestApi>({
@@ -38,8 +38,8 @@ export type OAuthPendingRequestsApi<ResultType> = {
/**
* The OAuthPendingRequests class is a utility for managing and observing
* a stream of requests for oauth scopes, and resolving them correctly once
* requests are fulfilled.
* a stream of requests for oauth scopes for a single provider, and resolving
* them correctly once requests are fulfilled.
*/
export class OAuthPendingRequests<ResultType>
implements OAuthPendingRequestsApi<ResultType> {
@@ -17,7 +17,7 @@
import {
OAuthRequestApi,
LoginPopupOptions,
AuthRequest,
PendingAuthRequest,
AuthRequester,
AuthRequesterOptions,
} from '../../definitions/oauthrequest';
@@ -29,18 +29,18 @@ import { OAuthPendingRequests, PendingRequest } from './OAuthPendingRequests';
*
* The purpose of this class and the API is to read a stream of incoming requests
* of OAuth access tokens from different providers with varying scope, and funnel
* them all together into a single requests for each OAuth provider.
* them all together into a single request for each OAuth provider.
*/
export class OAuthRequestManager implements OAuthRequestApi {
private readonly requests$: Observable<AuthRequest[]>;
private readonly request$: Observable<PendingAuthRequest[]>;
private readonly observers = new Set<
ZenObservable.SubscriptionObserver<AuthRequest[]>
ZenObservable.SubscriptionObserver<PendingAuthRequest[]>
>();
private currentRequests: AuthRequest[] = [];
private currentRequests: PendingAuthRequest[] = [];
private handlerCount = 0;
constructor() {
this.requests$ = new Observable<AuthRequest[]>((observer) => {
this.request$ = new Observable<PendingAuthRequest[]>((observer) => {
observer.next(this.currentRequests);
this.observers.add(observer);
@@ -79,16 +79,16 @@ export class OAuthRequestManager implements OAuthRequestApi {
private makeAuthRequest(
request: PendingRequest<any>,
options: AuthRequesterOptions<any>,
): AuthRequest | undefined {
): PendingAuthRequest | undefined {
const { scopes } = request;
if (!scopes) {
return undefined;
}
return {
info: options.info,
triggerAuth: async () => {
const result = await options.authHandler(scopes);
provider: options.provider,
trigger: async () => {
const result = await options.onAuthRequest(scopes);
request.resolve(result);
},
reject: () => {
@@ -99,8 +99,8 @@ export class OAuthRequestManager implements OAuthRequestApi {
};
}
handleAuthRequests(): Observable<AuthRequest[]> {
return this.requests$;
authRequest$(): Observable<PendingAuthRequest[]> {
return this.request$;
}
async showLoginPopup(options: LoginPopupOptions): Promise<any> {
+1 -1
View File
@@ -32,7 +32,7 @@ export type Observer<T> = {
*/
export type Subscription = {
/**
* CAncels the subscription
* Cancels the subscription
*/
unsubscribe(): void;
@@ -23,7 +23,7 @@ import {
Theme,
} from '@material-ui/core';
import React, { FC, useState } from 'react';
import { AuthRequest } from '../../api';
import { PendingAuthRequest } from '../../api';
const useItemStyles = makeStyles<Theme>((theme) => ({
root: {
@@ -32,7 +32,7 @@ const useItemStyles = makeStyles<Theme>((theme) => ({
}));
type RowProps = {
request: AuthRequest;
request: PendingAuthRequest;
busy: boolean;
setBusy: (busy: boolean) => void;
};
@@ -44,7 +44,7 @@ const LoginRequestListItem: FC<RowProps> = ({ request, busy, setBusy }) => {
const handleContinue = async () => {
setBusy(true);
try {
await request.triggerAuth();
await request.trigger();
} catch (e) {
setError(e);
} finally {
@@ -52,7 +52,7 @@ const LoginRequestListItem: FC<RowProps> = ({ request, busy, setBusy }) => {
}
};
const IconComponent = request.info.icon;
const IconComponent = request.provider.icon;
return (
<ListItem
@@ -65,7 +65,7 @@ const LoginRequestListItem: FC<RowProps> = ({ request, busy, setBusy }) => {
<IconComponent fontSize="large" />
</ListItemAvatar>
<ListItemText
primary={request.info.title}
primary={request.provider.title}
secondary={
error && (
<Typography color="error">
@@ -48,7 +48,7 @@ export const OAuthRequestDialog: FC<OAuthRequestDialogProps> = () => {
const [busy, setBusy] = useState(false);
const oauthRequestApi = useApi(oauthRequestApiRef);
const requests = useObservable(
useMemo(() => oauthRequestApi.handleAuthRequests(), [oauthRequestApi]),
useMemo(() => oauthRequestApi.authRequest$(), [oauthRequestApi]),
[],
);
@@ -71,7 +71,7 @@ export const OAuthRequestDialog: FC<OAuthRequestDialogProps> = () => {
<List>
{requests.map((request) => (
<LoginRequestListItem
key={request.info.title}
key={request.provider.title}
request={request}
busy={busy}
setBusy={setBusy}