elk/composables/masto/masto.ts

123 lines
3.2 KiB
TypeScript

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 function createMasto() {
let client = $shallowRef<mastodon.Client>(undefined as never)
let params = $ref<Mutable<CreateClientParams>>()
const canStreaming = $computed(() => !!params?.streamingApiUrl)
const setParams = (newParams: Partial<CreateClientParams>) => {
const p = { ...params, ...newParams } as CreateClientParams
client = createClient(p)
params = p
}
return {
client: $$(client),
params: readonly($$(params)),
canStreaming: $$(canStreaming),
setParams,
}
}
export type ElkMasto = ReturnType<typeof createMasto>
export function useMasto() {
return useNuxtApp().$masto as ElkMasto
}
export function useMastoClient() {
return useMasto().client.value
}
export function mastoLogin(masto: ElkMasto, user: Pick<UserLogin, 'server' | 'token'>) {
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<Controls extends boolean> {
/**
* Expose more controls
*
* @default false
*/
controls?: Controls
/**
* Connect on calling
*
* @default true
*/
immediate?: boolean
}
export function useStreaming(
cb: (client: mastodon.Client) => Promise<WsEvents>,
options: UseStreamingOptions<true>,
): { stream: Ref<Promise<WsEvents> | undefined> } & Pausable
export function useStreaming(
cb: (client: mastodon.Client) => Promise<WsEvents>,
options?: UseStreamingOptions<false>,
): Ref<Promise<WsEvents> | undefined>
export function useStreaming(
cb: (client: mastodon.Client) => Promise<WsEvents>,
{ immediate = true, controls }: UseStreamingOptions<boolean> = {},
): ({ stream: Ref<Promise<WsEvents> | undefined> } & Pausable) | Ref<Promise<WsEvents> | undefined> {
const { canStreaming, client } = useMasto()
const isActive = ref(immediate)
const stream = ref<Promise<WsEvents>>()
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
}