swr-openapi
Version:
Generate SWR hooks from OpenAPI schemas
1 lines • 11.8 kB
Source Map (JSON)
{"version":3,"file":"index.cjs","sources":["../src/query-base.ts","../src/immutable.ts","../src/infinite.ts","../src/mutate.ts","../src/query.ts"],"sourcesContent":["import type { Client } from \"openapi-fetch\";\nimport type { MediaType, PathsWithMethod, RequiredKeysOf } from \"openapi-typescript-helpers\";\nimport type { Fetcher, SWRHook } from \"swr\";\nimport type { TypesForGetRequest } from \"./types.js\";\nimport { useCallback, useDebugValue, useMemo } from \"react\";\n\n/**\n * @private\n */\nexport function configureBaseQueryHook(useHook: SWRHook) {\n return function createQueryBaseHook<\n Paths extends {},\n IMediaType extends MediaType,\n Prefix extends string,\n FetcherError = never,\n >(client: Client<Paths, IMediaType>, prefix: Prefix) {\n return function useQuery<\n Path extends PathsWithMethod<Paths, \"get\">,\n R extends TypesForGetRequest<Paths, Path>,\n Init extends R[\"Init\"],\n Data extends R[\"Data\"],\n Error extends R[\"Error\"] | FetcherError,\n Config extends R[\"SWRConfig\"],\n >(\n path: Path,\n ...[init, config]: RequiredKeysOf<Init> extends never ? [(Init | null)?, Config?] : [Init | null, Config?]\n ) {\n useDebugValue(`${prefix} - ${path as string}`);\n\n const key = useMemo(() => (init !== null ? ([prefix, path, init] as const) : null), [prefix, path, init]);\n\n type Key = typeof key;\n\n // TODO: Lift up fetcher to and remove useCallback\n const fetcher: Fetcher<Data, Key> = useCallback(\n async ([_, path, init]) => {\n // @ts-expect-error TODO: Improve internal init types\n const res = await client.GET(path, init);\n if (res.error) {\n throw res.error;\n }\n return res.data as Data;\n },\n [client],\n );\n\n // @ts-expect-error TODO: Improve internal config types\n return useHook<Data, Error, Key>(key, fetcher, config);\n };\n };\n}\n","import useSWRImmutable from \"swr/immutable\";\nimport { configureBaseQueryHook } from \"./query-base.js\";\n\n/**\n * Produces a typed wrapper for [`useSWRImmutable`](https://swr.vercel.app/docs/revalidation.en-US#disable-automatic-revalidations).\n *\n * ```ts\n * import createClient from \"openapi-fetch\";\n * const client = createClient();\n *\n * const useImmutable = createImmutableHook(client, \"<unique-key>\");\n *\n * // Fetch the query\n * useImmutable(\"/pets\");\n *\n * // Skip the query\n * useImmutable(\"/pets\", null);\n *\n * // Fetch the query with parameters\n * useImmutable(\"/pets\", {\n * params: { query: { limit: 10 } }\n * });\n *\n * // Fetch the query with parameters and SWR configuration\n * useImmutable(\n * \"/pets\",\n * { params: { query: { limit: 10 } } },\n * { errorRetryCount: 2 },\n * );\n *\n * // Fetch the query with no parameters and SWR configuration\n * useImmutable(\n * \"/pets\",\n * {},\n * { errorRetryCount: 2 },\n * );\n * ```\n */\nexport const createImmutableHook = configureBaseQueryHook(useSWRImmutable);\n","import type { Client } from \"openapi-fetch\";\nimport type { MediaType, PathsWithMethod } from \"openapi-typescript-helpers\";\nimport useSWRInfinite, {\n type SWRInfiniteConfiguration,\n type SWRInfiniteFetcher,\n type SWRInfiniteKeyLoader,\n} from \"swr/infinite\";\nimport type { TypesForGetRequest } from \"./types.js\";\nimport { useCallback, useDebugValue } from \"react\";\n\n/**\n * Produces a typed wrapper for [`useSWRInfinite`](https://swr.vercel.app/docs/pagination#useswrinfinite).\n *\n * ```ts\n * import createClient from \"openapi-fetch\";\n * const client = createClient();\n *\n * const useInfinite = createInfiniteHook(client, \"<unique-key>\");\n *\n * useInfinite(\"/pets\", (index, previousPage) => {\n * if (previousPage && !previousPage.hasMore) {\n * return null;\n * }\n *\n * return {\n * params: {\n * query: {\n * limit: 10,\n * offset: index * 10,\n * },\n * },\n * };\n * });\n * ```\n */\nexport function createInfiniteHook<\n Paths extends {},\n IMediaType extends MediaType,\n Prefix extends string,\n FetcherError = never,\n>(client: Client<Paths, IMediaType>, prefix: Prefix) {\n return function useInfinite<\n Path extends PathsWithMethod<Paths, \"get\">,\n R extends TypesForGetRequest<Paths, Path>,\n Init extends R[\"Init\"],\n Data extends R[\"Data\"],\n Error extends R[\"Error\"] | FetcherError,\n Config extends SWRInfiniteConfiguration<Data, Error>,\n >(path: Path, getInit: SWRInfiniteKeyLoader<Data, Init | null>, config?: Config) {\n type Key = [Prefix, Path, Init | undefined] | null;\n type KeyLoader = SWRInfiniteKeyLoader<Data, Key>;\n\n useDebugValue(`${prefix} - ${path as string}`);\n\n const fetcher: SWRInfiniteFetcher<Data, KeyLoader> = useCallback(\n async ([_, path, init]) => {\n // @ts-expect-error TODO: Improve internal init types\n const res = await client.GET(path, init);\n if (res.error) {\n throw res.error;\n }\n return res.data as Data;\n },\n [client],\n );\n\n const getKey: KeyLoader = (index, previousPageData) => {\n const init = getInit(index, previousPageData);\n if (init === null) {\n return null;\n }\n const key: Key = [prefix, path, init];\n return key;\n };\n\n return useSWRInfinite<Data, Error, KeyLoader>(getKey, fetcher, config);\n };\n}\n","import type { Client } from \"openapi-fetch\";\nimport type { MediaType, PathsWithMethod } from \"openapi-typescript-helpers\";\nimport { useCallback, useDebugValue } from \"react\";\nimport { type MutatorCallback, type MutatorOptions, useSWRConfig } from \"swr\";\nimport type { PartialDeep } from \"type-fest\";\nimport type { TypesForGetRequest } from \"./types.js\";\n\n// Types are loose here to support ecosystem utilities like `_.isMatch`\nexport type CompareFn = (init: any, partialInit: any) => boolean;\n\n/**\n * Produces a typed wrapper for [`useSWRConfig#mutate`](https://swr.vercel.app/docs/mutation).\n *\n * ```ts\n * import createClient from \"openapi-fetch\";\n * import { isMatch } from \"lodash\";\n *\n * const client = createClient();\n *\n * const useMutate = createMutateHook(client, \"<unique-key>\", isMatch);\n *\n * const mutate = useMutate();\n *\n * // Revalidate all keys matching this path\n * await mutate([\"/pets\"]);\n * await mutate([\"/pets\"], newData);\n * await mutate([\"/pets\"], undefined, { revalidate: true });\n *\n * // Revlidate all keys matching this path and this subset of options\n * await mutate(\n * [\"/pets\", { query: { limit: 10 } }],\n * newData,\n * { revalidate: false }\n * );\n * ```\n */\nexport function createMutateHook<Paths extends {}, IMediaType extends MediaType>(\n client: Client<Paths, IMediaType>,\n prefix: string,\n compare: CompareFn,\n) {\n return function useMutate() {\n const { mutate: swrMutate } = useSWRConfig();\n\n useDebugValue(prefix);\n\n return useCallback(\n function mutate<\n Path extends PathsWithMethod<Paths, \"get\">,\n R extends TypesForGetRequest<Paths, Path>,\n Init extends R[\"Init\"],\n >(\n [path, init]: [Path, PartialDeep<Init>?],\n data?: R[\"Data\"] | Promise<R[\"Data\"]> | MutatorCallback<R[\"Data\"]>,\n opts?: boolean | MutatorOptions<R[\"Data\"]>,\n ) {\n return swrMutate<R[\"Data\"], R[\"Data\"]>(\n (key) => {\n if (\n // Must be array\n !Array.isArray(key) ||\n // Must have 2 or 3 elements (prefix, path, optional init)\n ![2, 3].includes(key.length)\n ) {\n return false;\n }\n\n const [keyPrefix, keyPath, keyOptions] = key as unknown[];\n\n return (\n // Matching prefix\n keyPrefix === prefix &&\n // Matching path\n keyPath === path &&\n // Matching options\n (init ? compare(keyOptions, init) : true)\n );\n },\n data,\n opts,\n );\n },\n [swrMutate, prefix, compare],\n );\n };\n}\n","import useSWR from \"swr\";\nimport { configureBaseQueryHook } from \"./query-base.js\";\n\n/**\n * Produces a typed wrapper for [`useSWR`](https://swr.vercel.app/docs/api).\n *\n * ```ts\n * import createClient from \"openapi-fetch\";\n *\n * const client = createClient();\n *\n * const useQuery = createQueryHook(client, \"<unique-key>\");\n *\n * // Fetch the query\n * useQuery(\"/pets\");\n *\n * // Skip the query\n * useQuery(\"/pets\", null);\n *\n * // Fetch the query with parameters\n * useQuery(\"/pets\", {\n * params: { query: { limit: 10 } }\n * });\n *\n * // Fetch the query with parameters and SWR configuration\n * useQuery(\n * \"/pets\",\n * { params: { query: { limit: 10 } } },\n * { errorRetryCount: 2 },\n * );\n *\n * // Fetch the query with no parameters and SWR configuration\n * useQuery(\n * \"/pets\",\n * {},\n * { errorRetryCount: 2 },\n * );\n * ```\n */\nexport const createQueryHook = configureBaseQueryHook(useSWR);\n"],"names":["useDebugValue","useMemo","useCallback","path","init","useSWRImmutable","useSWRInfinite","useSWRConfig","useSWR"],"mappings":"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"}