rewrite client providing & fix sign in redirect
This commit is contained in:
		
							parent
							
								
									f82788495f
								
							
						
					
					
						commit
						00fa334d42
					
				
					 5 changed files with 106 additions and 53 deletions
				
			
		
							
								
								
									
										53
									
								
								src/App.tsx
									
										
									
									
									
								
							
							
						
						
									
										53
									
								
								src/App.tsx
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,12 +1,27 @@
 | 
			
		|||
import { Route, Router } from "@solidjs/router";
 | 
			
		||||
import { ThemeProvider } from "@suid/material";
 | 
			
		||||
import { Component, lazy } from "solid-js";
 | 
			
		||||
import {
 | 
			
		||||
  Component,
 | 
			
		||||
  createRenderEffect,
 | 
			
		||||
  createSignal,
 | 
			
		||||
  ErrorBoundary,
 | 
			
		||||
  lazy,
 | 
			
		||||
} from "solid-js";
 | 
			
		||||
import { useRootTheme } from "./material/mui.js";
 | 
			
		||||
import "./App.css"
 | 
			
		||||
import {
 | 
			
		||||
  Provider as ClientProvider,
 | 
			
		||||
  createMastoClientFor,
 | 
			
		||||
  type Session,
 | 
			
		||||
} from "./masto/clients.js";
 | 
			
		||||
import "./App.css";
 | 
			
		||||
import { $accounts } from "./accounts/stores.js";
 | 
			
		||||
import { useStore } from "@nanostores/solid";
 | 
			
		||||
 | 
			
		||||
const AccountSignIn = lazy(() => import("./accounts/SignIn.js"));
 | 
			
		||||
const AccountMastodonOAuth2Callback = lazy(() => import("./accounts/MastodonOAuth2Callback.js"))
 | 
			
		||||
const TimelineHome = lazy(() => import("./timelines/Home.js"))
 | 
			
		||||
const AccountMastodonOAuth2Callback = lazy(
 | 
			
		||||
  () => import("./accounts/MastodonOAuth2Callback.js"),
 | 
			
		||||
);
 | 
			
		||||
const TimelineHome = lazy(() => import("./timelines/Home.js"));
 | 
			
		||||
 | 
			
		||||
const Routing: Component = () => {
 | 
			
		||||
  return (
 | 
			
		||||
| 
						 | 
				
			
			@ -14,7 +29,10 @@ const Routing: Component = () => {
 | 
			
		|||
      <Route path="/" component={TimelineHome}></Route>
 | 
			
		||||
      <Route path={"/accounts"}>
 | 
			
		||||
        <Route path={"/sign-in"} component={AccountSignIn} />
 | 
			
		||||
        <Route path={"/oauth2/mastodon"} component={AccountMastodonOAuth2Callback} />
 | 
			
		||||
        <Route
 | 
			
		||||
          path={"/oauth2/mastodon"}
 | 
			
		||||
          component={AccountMastodonOAuth2Callback}
 | 
			
		||||
        />
 | 
			
		||||
      </Route>
 | 
			
		||||
    </Router>
 | 
			
		||||
  );
 | 
			
		||||
| 
						 | 
				
			
			@ -22,10 +40,29 @@ const Routing: Component = () => {
 | 
			
		|||
 | 
			
		||||
const App: Component = () => {
 | 
			
		||||
  const theme = useRootTheme();
 | 
			
		||||
  const accts = useStore($accounts);
 | 
			
		||||
  const clientStore = createSignal<Session[]>([]);
 | 
			
		||||
 | 
			
		||||
  createRenderEffect(() => {
 | 
			
		||||
    const [, setClients] = clientStore;
 | 
			
		||||
    setClients(
 | 
			
		||||
      accts().map((x) => ({ account: x, client: createMastoClientFor(x) })),
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <ThemeProvider theme={theme()}>
 | 
			
		||||
      <Routing />
 | 
			
		||||
    </ThemeProvider>
 | 
			
		||||
    <ErrorBoundary
 | 
			
		||||
      fallback={(err, reset) => {
 | 
			
		||||
        console.error(err);
 | 
			
		||||
        return <></>;
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <ThemeProvider theme={theme()}>
 | 
			
		||||
        <ClientProvider value={clientStore}>
 | 
			
		||||
          <Routing />
 | 
			
		||||
        </ClientProvider>
 | 
			
		||||
      </ThemeProvider>
 | 
			
		||||
    </ErrorBoundary>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,6 @@
 | 
			
		|||
import { persistentAtom } from "@nanostores/persistent";
 | 
			
		||||
import { useStore } from "@nanostores/solid";
 | 
			
		||||
import { useNavigate } from "@solidjs/router";
 | 
			
		||||
import { createOAuthAPIClient, createRestAPIClient } from "masto";
 | 
			
		||||
import { action } from "nanostores";
 | 
			
		||||
import { createRenderEffect } from "solid-js";
 | 
			
		||||
 | 
			
		||||
export type Account = {
 | 
			
		||||
  site: string;
 | 
			
		||||
| 
						 | 
				
			
			@ -175,15 +172,3 @@ export const getOrRegisterApp = action(
 | 
			
		|||
    return all[site];
 | 
			
		||||
  },
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export function useAccts() {
 | 
			
		||||
  const accts = useStore($accounts);
 | 
			
		||||
  const naviagte = useNavigate();
 | 
			
		||||
 | 
			
		||||
  createRenderEffect(() => {
 | 
			
		||||
    if (accts().length > 0) return;
 | 
			
		||||
    naviagte("/accounts/sign-in");
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return accts;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,7 @@
 | 
			
		|||
import { Accessor, createResource } from "solid-js";
 | 
			
		||||
import { Account } from "../accounts/stores";
 | 
			
		||||
import { useMastoClientFor } from "./clients";
 | 
			
		||||
import type { mastodon } from "masto";
 | 
			
		||||
 | 
			
		||||
export function useAcctProfile(account: Accessor<Account>) {
 | 
			
		||||
  const client = useMastoClientFor(account)
 | 
			
		||||
export function useAcctProfile(client: Accessor<mastodon.rest.Client>) {
 | 
			
		||||
  return createResource(client, (client) => {
 | 
			
		||||
    return client.v1.accounts.verifyCredentials()
 | 
			
		||||
  }, {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,41 +1,78 @@
 | 
			
		|||
import { Accessor, createMemo, createResource } from "solid-js";
 | 
			
		||||
import {
 | 
			
		||||
  Accessor,
 | 
			
		||||
  createContext,
 | 
			
		||||
  createRenderEffect,
 | 
			
		||||
  createResource,
 | 
			
		||||
  Signal,
 | 
			
		||||
  useContext,
 | 
			
		||||
} from "solid-js";
 | 
			
		||||
import { Account } from "../accounts/stores";
 | 
			
		||||
import { createRestAPIClient, mastodon } from "masto";
 | 
			
		||||
import { useLocation, useNavigate } from "@solidjs/router";
 | 
			
		||||
 | 
			
		||||
const restfulCache: Record<string, mastodon.rest.Client> = {}
 | 
			
		||||
const restfulCache: Record<string, mastodon.rest.Client> = {};
 | 
			
		||||
 | 
			
		||||
export function createMastoClientFor(account: Account) {
 | 
			
		||||
  const cacheKey = [account.site, account.accessToken].join('')
 | 
			
		||||
  const cache = restfulCache[cacheKey]
 | 
			
		||||
  const cacheKey = [account.site, account.accessToken].join("");
 | 
			
		||||
  const cache = restfulCache[cacheKey];
 | 
			
		||||
  if (cache) return cache;
 | 
			
		||||
 | 
			
		||||
  const client = createRestAPIClient({
 | 
			
		||||
    url: account.site,
 | 
			
		||||
    accessToken: account.accessToken,
 | 
			
		||||
  })
 | 
			
		||||
  restfulCache[cacheKey] = client
 | 
			
		||||
  });
 | 
			
		||||
  restfulCache[cacheKey] = client;
 | 
			
		||||
 | 
			
		||||
  return client
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function useMastoClientFor(account: Accessor<Account>) {
 | 
			
		||||
  return createMemo(() => createMastoClientFor(account()))
 | 
			
		||||
  return client;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function createUnauthorizedClient(site: string) {
 | 
			
		||||
  const cache = restfulCache[site]
 | 
			
		||||
  const cache = restfulCache[site];
 | 
			
		||||
  if (cache) return cache;
 | 
			
		||||
 | 
			
		||||
  const client = createRestAPIClient({
 | 
			
		||||
    url: site
 | 
			
		||||
  })
 | 
			
		||||
  restfulCache[site] = client
 | 
			
		||||
    url: site,
 | 
			
		||||
  });
 | 
			
		||||
  restfulCache[site] = client;
 | 
			
		||||
 | 
			
		||||
  return client
 | 
			
		||||
  return client;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function useInstance(client: Accessor<mastodon.rest.Client>) {
 | 
			
		||||
  return createResource(client, async (client) => {
 | 
			
		||||
    return await client.v2.instance.fetch()
 | 
			
		||||
  })
 | 
			
		||||
    return await client.v2.instance.fetch();
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type Session = {
 | 
			
		||||
  account: Account;
 | 
			
		||||
  client: mastodon.rest.Client;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const Context = /* @__PURE__ */ createContext<Signal<Session[]>>();
 | 
			
		||||
 | 
			
		||||
export const Provider = Context.Provider;
 | 
			
		||||
 | 
			
		||||
export function useSessions() {
 | 
			
		||||
  const [sessions] = useSessionsRw();
 | 
			
		||||
  const navigate = useNavigate();
 | 
			
		||||
  const location = useLocation();
 | 
			
		||||
 | 
			
		||||
  createRenderEffect(() => {
 | 
			
		||||
    if (sessions().length > 0) return;
 | 
			
		||||
    navigate(
 | 
			
		||||
      "/accounts/sign-in?back=" + encodeURIComponent(location.pathname),
 | 
			
		||||
      { replace: true },
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return sessions;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function useSessionsRw() {
 | 
			
		||||
  const store = useContext(Context);
 | 
			
		||||
  if (!store) {
 | 
			
		||||
    throw new TypeError("sessions are not provided");
 | 
			
		||||
  }
 | 
			
		||||
  return store;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,15 +3,12 @@ import {
 | 
			
		|||
  For,
 | 
			
		||||
  onCleanup,
 | 
			
		||||
  createSignal,
 | 
			
		||||
  createEffect,
 | 
			
		||||
  Show,
 | 
			
		||||
  untrack,
 | 
			
		||||
  onMount,
 | 
			
		||||
} from "solid-js";
 | 
			
		||||
import { $accounts, useAccts } from "../accounts/stores";
 | 
			
		||||
import { useDocumentTitle } from "../utils";
 | 
			
		||||
import { useStore } from "@nanostores/solid";
 | 
			
		||||
import { useMastoClientFor } from "../masto/clients";
 | 
			
		||||
import {  useSessions } from "../masto/clients";
 | 
			
		||||
import { type mastodon } from "masto";
 | 
			
		||||
import Scaffold from "../material/Scaffold";
 | 
			
		||||
import {
 | 
			
		||||
| 
						 | 
				
			
			@ -24,7 +21,6 @@ import {
 | 
			
		|||
  MenuItem,
 | 
			
		||||
  Switch,
 | 
			
		||||
  Toolbar,
 | 
			
		||||
  Typography,
 | 
			
		||||
} from "@suid/material";
 | 
			
		||||
import { css } from "solid-styled";
 | 
			
		||||
import { TimeSourceProvider, createTimeSource } from "../platform/timesrc";
 | 
			
		||||
| 
						 | 
				
			
			@ -152,11 +148,11 @@ const TimelinePanel: Component<{
 | 
			
		|||
const Home: Component = () => {
 | 
			
		||||
  let panelList: HTMLDivElement;
 | 
			
		||||
  useDocumentTitle("Timelines");
 | 
			
		||||
  const accounts = useAccts();
 | 
			
		||||
  const now = createTimeSource();
 | 
			
		||||
 | 
			
		||||
  const client = useMastoClientFor(() => accounts()[0]);
 | 
			
		||||
  const [profile] = useAcctProfile(() => accounts()[0]);
 | 
			
		||||
  const sessions = useSessions();
 | 
			
		||||
  const client = () => sessions()[0].client;
 | 
			
		||||
  const [profile] = useAcctProfile(client);
 | 
			
		||||
 | 
			
		||||
  const [panelOffset, setPanelOffset] = createSignal(0);
 | 
			
		||||
  const [prefetching, setPrefetching] = createSignal(true);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue