You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-11-21 23:00:50 +03:00
Mainly: - better handling of GraphQL errors - better logout state - dependencies update - a way to end browser sessions in the GraphQL API
124 lines
3.1 KiB
TypeScript
124 lines
3.1 KiB
TypeScript
// Copyright 2023 The Matrix.org Foundation C.I.C.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
import { AnyVariables, CombinedError, OperationContext } from "@urql/core";
|
|
import { atom, WritableAtom } from "jotai";
|
|
import { useHydrateAtoms } from "jotai/utils";
|
|
import { AtomWithQuery, atomWithQuery, clientAtom } from "jotai-urql";
|
|
import type { ReactElement } from "react";
|
|
|
|
import { graphql } from "./gql";
|
|
import { client } from "./graphql";
|
|
import { err, ok, Result } from "./result";
|
|
|
|
export type GqlResult<T> = Result<T, CombinedError>;
|
|
export type GqlAtom<T> = WritableAtom<
|
|
Promise<GqlResult<T>>,
|
|
[context?: Partial<OperationContext>],
|
|
void
|
|
>;
|
|
|
|
/**
|
|
* Map the result of a query atom to a new value, making it a GqlResult
|
|
*
|
|
* @param queryAtom: An atom got from atomWithQuery
|
|
* @param mapper: A function that takes the data from the query and returns a new value
|
|
*/
|
|
export const mapQueryAtom = <Data, Variables extends AnyVariables, NewData>(
|
|
queryAtom: AtomWithQuery<Data, Variables>,
|
|
mapper: (data: Data) => NewData
|
|
): GqlAtom<NewData> => {
|
|
return atom(
|
|
async (get): Promise<GqlResult<NewData>> => {
|
|
const result = await get(queryAtom);
|
|
if (result.error) {
|
|
return err(result.error);
|
|
}
|
|
|
|
if (result.data === undefined) {
|
|
throw new Error("Query result is undefined");
|
|
}
|
|
|
|
return ok(mapper(result.data));
|
|
},
|
|
|
|
(_get, set, context) => {
|
|
set(queryAtom, context);
|
|
}
|
|
);
|
|
};
|
|
|
|
export const HydrateAtoms: React.FC<{ children: ReactElement }> = ({
|
|
children,
|
|
}) => {
|
|
useHydrateAtoms([[clientAtom, client]]);
|
|
return children;
|
|
};
|
|
|
|
const CURRENT_VIEWER_QUERY = graphql(/* GraphQL */ `
|
|
query CurrentViewerQuery {
|
|
viewer {
|
|
__typename
|
|
... on User {
|
|
id
|
|
}
|
|
|
|
... on Anonymous {
|
|
id
|
|
}
|
|
}
|
|
}
|
|
`);
|
|
|
|
const currentViewerAtom = atomWithQuery({ query: CURRENT_VIEWER_QUERY });
|
|
|
|
export const currentUserIdAtom: GqlAtom<string | null> = mapQueryAtom(
|
|
currentViewerAtom,
|
|
(data) => {
|
|
if (data.viewer.__typename === "User") {
|
|
return data.viewer.id;
|
|
}
|
|
return null;
|
|
}
|
|
);
|
|
|
|
const CURRENT_VIEWER_SESSION_QUERY = graphql(/* GraphQL */ `
|
|
query CurrentViewerSessionQuery {
|
|
viewerSession {
|
|
__typename
|
|
... on BrowserSession {
|
|
id
|
|
}
|
|
|
|
... on Anonymous {
|
|
id
|
|
}
|
|
}
|
|
}
|
|
`);
|
|
|
|
const currentViewerSessionAtom = atomWithQuery({
|
|
query: CURRENT_VIEWER_SESSION_QUERY,
|
|
});
|
|
|
|
export const currentBrowserSessionIdAtom: GqlAtom<string | null> = mapQueryAtom(
|
|
currentViewerSessionAtom,
|
|
(data) => {
|
|
if (data.viewerSession.__typename === "BrowserSession") {
|
|
return data.viewerSession.id;
|
|
}
|
|
return null;
|
|
}
|
|
);
|