import type { Pausable } from '@vueuse/core' import type { mastodon } from 'masto' import type { Ref } from 'vue' import type { ElkInstance } from '../users' import type { UserLogin } from '~/types' import { createRestAPIClient, createStreamingAPIClient, MastoHttpError } from 'masto' export function createMasto() { return { client: shallowRef(undefined as never), streamingClient: shallowRef(), } } export type ElkMasto = ReturnType export function useMasto() { return useNuxtApp().$masto as ElkMasto } export function useMastoClient() { return useMasto().client.value } export function mastoLogin(masto: ElkMasto, user: Pick) { const server = user.server const url = `https://${server}` const instance: ElkInstance = reactive(getInstanceCache(server) || { uri: server, accountDomain: server }) const accessToken = user.token const createStreamingClient = (streamingApiUrl: string | undefined) => { return streamingApiUrl ? createStreamingAPIClient({ streamingApiUrl, accessToken, implementation: globalThis.WebSocket }) : undefined } const streamingApiUrl = instance?.configuration?.urls?.streaming masto.client.value = createRestAPIClient({ url, accessToken }) masto.streamingClient.value = createStreamingClient(streamingApiUrl) // Refetch instance info in the background on login masto.client.value.v2.instance.fetch().catch(error => new Promise((resolve, reject) => { if (error instanceof MastoHttpError && error.statusCode === 404) { return masto.client.value.v1.instance.fetch().then((newInstance) => { console.warn(`Instance ${server} on version ${newInstance.version} does not support "GET /api/v2/instance" API, try converting to v2 instance... expect some errors`) const v2Instance = { ...newInstance, domain: newInstance.uri, sourceUrl: '', usage: { users: { activeMonth: 0, }, }, icon: [], apiVersions: { mastodon: newInstance.version, }, contact: { email: newInstance.email, }, configuration: { ...(newInstance.configuration ?? {}), urls: { streaming: newInstance.urls.streamingApi, }, }, } as unknown as mastodon.v2.Instance return resolve(v2Instance) }).catch(reject) } return reject(error) })).then((newInstance) => { Object.assign(instance, newInstance) if (newInstance.configuration.urls.streaming !== streamingApiUrl) masto.streamingClient.value = createStreamingClient(newInstance.configuration.urls.streaming) 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.streaming.Client) => mastodon.streaming.Subscription, options: UseStreamingOptions, ): { stream: Ref } & Pausable export function useStreaming( cb: (client: mastodon.streaming.Client) => mastodon.streaming.Subscription, options?: UseStreamingOptions, ): Ref export function useStreaming( cb: (client: mastodon.streaming.Client) => mastodon.streaming.Subscription, { immediate = true, controls }: UseStreamingOptions = {}, ): ({ stream: Ref } & Pausable) | Ref { const { streamingClient } = 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.unsubscribe() stream.value = undefined } } watchEffect(() => { cleanup() if (streamingClient.value && isActive.value) stream.value = cb(streamingClient.value) }) if (import.meta.client && !process.test) useNuxtApp().$pageLifecycle.addFrozenListener(cleanup) tryOnBeforeUnmount(() => isActive.value = false) if (controls) return { stream, isActive, pause, resume } else return stream }