import type { Pausable } from '@vueuse/core' import type { CreateClientParams, WsEvents, mastodon } from 'masto' import { createClient, fetchV1Instance } from 'masto' import type { Ref } from 'vue' import type { ElkInstance } from '../users' import type { Mutable } from '~/types/utils' import type { UserLogin } from '~/types' export const createMasto = () => { let client = $shallowRef(undefined as never) let params = $ref>() const canStreaming = $computed(() => !!params?.streamingApiUrl) const setParams = (newParams: Partial) => { const p = { ...params, ...newParams } as CreateClientParams client = createClient(p) params = p } return { client: $$(client), params: readonly($$(params)), canStreaming: $$(canStreaming), setParams, } } export type ElkMasto = ReturnType export const useMasto = () => useNuxtApp().$masto as ElkMasto export const useMastoClient = () => useMasto().client.value export function mastoLogin(masto: ElkMasto, user: Pick) { const { setParams } = $(masto) const server = user.server const url = `https://${server}` const instance: ElkInstance = reactive(getInstanceCache(server) || { uri: server, accountDomain: server }) setParams({ url, accessToken: user?.token, disableVersionCheck: true, streamingApiUrl: instance?.urls?.streamingApi, }) fetchV1Instance({ url }).then((newInstance) => { Object.assign(instance, newInstance) setParams({ streamingApiUrl: newInstance.urls.streamingApi, }) instanceStorage.value[server] = newInstance }) return instance } interface UseStreamingOptions { /** * Expose more controls * * @default false */ controls?: Controls /** * Connect on calling * * @default true */ immediate?: boolean } export function useStreaming( cb: (client: mastodon.Client) => Promise, options: UseStreamingOptions, ): { stream: Ref | undefined> } & Pausable export function useStreaming( cb: (client: mastodon.Client) => Promise, options?: UseStreamingOptions, ): Ref | undefined> export function useStreaming( cb: (client: mastodon.Client) => Promise, { immediate = true, controls }: UseStreamingOptions = {}, ): ({ stream: Ref | undefined> } & Pausable) | Ref | undefined> { const { canStreaming, client } = useMasto() const isActive = ref(immediate) const stream = ref>() function pause() { isActive.value = false } function resume() { isActive.value = true } function cleanup() { if (stream.value) { stream.value.then(s => s.disconnect()).catch(() => Promise.resolve()) stream.value = undefined } } watchEffect(() => { cleanup() if (canStreaming.value && isActive.value) stream.value = cb(client.value) }) if (process.client && !process.test) useNuxtApp().$pageLifecycle.addFrozenListener(cleanup) tryOnBeforeUnmount(() => isActive.value = false) if (controls) return { stream, isActive, pause, resume } else return stream }