import { Accessor, createContext, createMemo, createRenderEffect, createResource, useContext, } from "solid-js"; import { Account } from "../accounts/stores"; import { createRestAPIClient, mastodon } from "masto"; import { useLocation } from "@solidjs/router"; import { useNavigator } from "~platform/StackedRouter"; const restfulCache: Record = {}; export function createMastoClientFor(account: Account) { 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; return client; } export function createUnauthorizedClient(site: string) { const cache = restfulCache[site]; if (cache) return cache; const client = createRestAPIClient({ url: site, }); restfulCache[site] = client; return client; } export function useInstance(client: Accessor) { return createResource(client, async (client) => { return await client.v2.instance.fetch(); }); } export type Session = { account: Account; client: mastodon.rest.Client; }; const Context = /* @__PURE__ */ createContext[]>>(); export const Provider = Context.Provider; export function useSessions() { const sessions = useSessionsRaw(); const {push} = useNavigator(); const location = useLocation(); createRenderEffect(() => { if (sessions().length > 0) return; push( "/accounts/sign-in?back=" + encodeURIComponent(location.pathname), { replace: true }, ); }); return sessions; } function useSessionsRaw() { const store = useContext(Context); if (!store) { throw new TypeError("sessions are not provided"); } return store; } const DefaultSessionContext = /* @__PURE__ */ createContext>( () => 0, ); export const DefaultSessionProvider = DefaultSessionContext.Provider; /** * Return the default session (the first session). * * This function may return `undefined`, but it will try to redirect the user to the sign in. */ export function useDefaultSession() { const sessions = useSessions(); const sessionIndex = useContext(DefaultSessionContext); return () => { if (sessions().length > 0) { return sessions()[sessionIndex()]; } }; } /** * Get a session for the specific acct string. * * Acct string is a string in the pattern of `{username}@{site_with_protocol}`, * like `@thislight@https://mastodon.social`, can be used to identify (tempoarily) * an session on the tutu instance. * * The `site_with_protocol` is required. * * - If the username is present, the session matches the username and the site is returned; or, * - If the username is not present, any session on the site is returned; or, * - If no available session available for the pattern, an unauthorised session is returned. * * In an unauthorised session, the `.account` is `undefined` and the `client` is an * unauthorised client for the site. This client may not available for some operations. */ export function useSessionForAcctStr(acct: Accessor) { const allSessions = useSessions(); return createMemo(() => { const [inputUsername, inputSite] = acct().split("@", 2); const authedSession = allSessions().find( (x) => x.account.site === inputSite && x.account.inf?.username === inputUsername, ); return ( authedSession ?? { client: createUnauthorizedClient(inputSite), account: undefined, } ); }); } export function makeAcctText(session: Session) { return `${session.account.inf?.username}@${session.account.site}`; }