feat: add hydrate data type-safe helper
Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
parent
8372d38c1c
commit
cb6a65b7cc
|
|
@ -2,6 +2,9 @@ import { setOpenInAppDeeplink } from "@client/atoms/app"
|
|||
import type { FeedOrListRespModel } from "@follow/models/types"
|
||||
import { DEEPLINK_SCHEME } from "@follow/shared/constants"
|
||||
|
||||
import type { ApiClient } from "~/lib/api-client"
|
||||
import type { defineMetadata } from "~/meta-handler"
|
||||
|
||||
export const getPreferredTitle = (feed?: FeedOrListRespModel | null) => {
|
||||
if (!feed?.id) {
|
||||
return feed?.title
|
||||
|
|
@ -14,6 +17,44 @@ export const getHydrateData = (key: string) => {
|
|||
return window.__HYDRATE__?.[key]
|
||||
}
|
||||
|
||||
// type ExtractHydrateData<T> = T extends readonly (infer Item)[]
|
||||
// ? Item extends { readonly type: "hydrate"; readonly data: infer D }
|
||||
// ? D
|
||||
// : never
|
||||
// : never
|
||||
|
||||
// export type GetHydrateData<T> = T extends (...args: any[]) => Promise<infer R>
|
||||
// ? ExtractHydrateData<R>
|
||||
// : T extends Promise<infer R>
|
||||
// ? ExtractHydrateData<R>
|
||||
// : ExtractHydrateData<T>
|
||||
|
||||
type ExtractHydrateData<T> = T extends readonly (infer Item)[]
|
||||
? Item extends { readonly type: "hydrate"; readonly data: infer D }
|
||||
? D
|
||||
: never
|
||||
: never
|
||||
|
||||
type UnwrapMetadataFn<T> =
|
||||
T extends <P extends Record<string, string>>(args: {
|
||||
params: P
|
||||
apiClient: ApiClient
|
||||
origin: string
|
||||
throwError: (status: number, message: any) => never
|
||||
}) => Promise<infer R> | infer R
|
||||
? R
|
||||
: never
|
||||
|
||||
export type GetHydrateData<T> = T extends (...args: any[]) => Promise<infer R>
|
||||
? ExtractHydrateData<R>
|
||||
: T extends (...args: any[]) => infer R
|
||||
? ExtractHydrateData<R>
|
||||
: T extends Promise<infer R>
|
||||
? ExtractHydrateData<R>
|
||||
: T extends typeof defineMetadata
|
||||
? ExtractHydrateData<UnwrapMetadataFn<Parameters<T>[0]>>
|
||||
: ExtractHydrateData<T>
|
||||
|
||||
export const askOpenInFollowApp = (deeplink: string, fallback?: () => string): Promise<boolean> => {
|
||||
return new Promise(() => {
|
||||
const deeplinkUrl = `${DEEPLINK_SCHEME}${deeplink}`
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import type { GetHydrateData } from "@client/lib/helper"
|
||||
|
||||
import { defineMetadata } from "~/meta-handler"
|
||||
|
||||
export default defineMetadata(async ({ params, apiClient, origin, throwError }) => {
|
||||
const meta = defineMetadata(async ({ params, apiClient, origin, throwError }) => {
|
||||
const feedId = params.id
|
||||
|
||||
const feed = await apiClient.feeds.$get({ query: { id: feedId } }).catch((e) => {
|
||||
|
|
@ -27,5 +29,8 @@ export default defineMetadata(async ({ params, apiClient, origin, throwError })
|
|||
path: apiClient.feeds.$url({ query: { id: feedId } }).pathname,
|
||||
key: `feeds.$get,query:id=${feedId}`,
|
||||
},
|
||||
]
|
||||
] as const
|
||||
})
|
||||
|
||||
export type FeedHydrateData = GetHydrateData<typeof meta>
|
||||
export default meta
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { apiClient } from "@client/lib/api-fetch"
|
||||
import { getHydrateData } from "@client/lib/helper"
|
||||
import type { FeedHydrateData } from "@client/pages/(main)/share/feeds/[id]/metadata"
|
||||
import { useQuery } from "@tanstack/react-query"
|
||||
|
||||
async function fetchFeedById(id: string) {
|
||||
|
|
@ -14,9 +15,7 @@ export const useFeed = ({ id }: { id: string }) =>
|
|||
useQuery({
|
||||
queryKey: ["feed", id],
|
||||
queryFn: () => fetchFeedById(id),
|
||||
initialData: getHydrateData(`feeds.$get,query:id=${id}`) as any as Awaited<
|
||||
ReturnType<typeof fetchFeedById>
|
||||
>,
|
||||
initialData: getHydrateData(`feeds.$get,query:id=${id}`) as FeedHydrateData,
|
||||
})
|
||||
|
||||
export type Feed = Awaited<ReturnType<typeof fetchFeedById>>
|
||||
|
|
|
|||
|
|
@ -68,22 +68,20 @@ export async function injectMetaHandler(
|
|||
return []
|
||||
}
|
||||
|
||||
export function defineMetadata<Params extends Record<string, string>>(
|
||||
export function defineMetadata<Params extends Record<string, string>, T extends readonly MetaTag[]>(
|
||||
fn: (args: {
|
||||
req: FastifyRequest
|
||||
url: URL
|
||||
params: Params
|
||||
apiClient: ApiClient
|
||||
origin: string
|
||||
|
||||
setStatus: (status: number) => void
|
||||
setStatusText: (statusText: string) => void
|
||||
throwError: (status: number, message: any) => never
|
||||
}) => MetaTag[] | Promise<MetaTag[]>,
|
||||
}) => Promise<T> | T,
|
||||
) {
|
||||
return fn
|
||||
}
|
||||
|
||||
export class MetaError extends Error {
|
||||
status: number
|
||||
metaMessage: object
|
||||
|
|
|
|||
Loading…
Reference in New Issue