@geekmidas/client 3.0.0 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @geekmidas/client
2
2
 
3
+ ## 4.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`a39b41f`](https://github.com/geekmidas/toolbox/commit/a39b41fae9c6cfbde8e6d78bf5a11fbb9e59f67d) Thanks [@geekmidas](https://github.com/geekmidas)! - Use qs to process query params instead of custom solution
8
+
9
+ - Updated dependencies [[`a39b41f`](https://github.com/geekmidas/toolbox/commit/a39b41fae9c6cfbde8e6d78bf5a11fbb9e59f67d)]:
10
+ - @geekmidas/constructs@3.0.3
11
+
12
+ ## 4.0.0
13
+
14
+ ### Patch Changes
15
+
16
+ - ✨ [`be4f7a9`](https://github.com/geekmidas/toolbox/commit/be4f7a9bd5de7f08adbca582916d6902e0c24de2) Thanks [@geekmidas](https://github.com/geekmidas)! - Add partition support for manifest generation. Users can now group constructs (routes, functions, crons, subscribers) into named partitions by providing a `partition` callback per construct type in the config. Manifests output partitioned fields as `Record<string, T[]>` while remaining flat `T[]` arrays when no partitions are configured.
17
+
18
+ Fix mutation type inference in endpoint hooks by using `UseMutationResult` and `UseQueryResult` types directly instead of `ReturnType<typeof useMutation>`, which could resolve to `never` for complex path definitions.
19
+
20
+ Add `FileCache` implementation that persists cache entries to a JSON file on disk. Default location is `process.cwd()/.gkm/cache.json`. Uses an in-process mutex combined with `proper-lockfile` for safe concurrent and cross-process writes.
21
+
22
+ - Updated dependencies []:
23
+ - @geekmidas/constructs@3.0.0
24
+
3
25
  ## 3.0.0
4
26
 
5
27
  ### Patch Changes
@@ -1,4 +1,4 @@
1
- const require_fetcher = require('./fetcher-CgLEaIAC.cjs');
1
+ const require_fetcher = require('./fetcher-BG3q_AKO.cjs');
2
2
 
3
3
  //#region src/auth-fetcher.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { TypedFetcher } from "./fetcher-5fnBE7Dk.mjs";
1
+ import { TypedFetcher } from "./fetcher-DSSmqcRW.mjs";
2
2
 
3
3
  //#region src/auth-fetcher.ts
4
4
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"endpoint-hooks.cjs","names":["endpoint: T","config?: FilteredRequestConfig<Paths, T>","key: unknown[]","fetcher: TypedApiFunction<Paths>","_options: CreateEndpointHooksOptions","mutationOptions?: Omit<\n\t\t\t\tUseMutationOptions<\n\t\t\t\t\tExtractEndpointResponse<Paths, T>,\n\t\t\t\t\tError,\n\t\t\t\t\tFilteredRequestConfig<Paths, T>\n\t\t\t\t>,\n\t\t\t\t'mutationFn'\n\t\t\t>","config: FilteredRequestConfig<Paths, T>"],"sources":["../src/endpoint-hooks.ts"],"sourcesContent":["import type {\n\tQueryClient,\n\tUseMutationOptions,\n\tUseQueryOptions,\n} from '@tanstack/react-query';\nimport { useMutation, useQuery } from '@tanstack/react-query';\nimport { useMemo } from 'react';\nimport type {\n\tExtractEndpointResponse,\n\tFilteredRequestConfig,\n\tIsConfigRequired,\n\tMutationEndpoint,\n\tQueryEndpoint,\n\tTypedApiFunction,\n} from './types';\n\n/**\n * Build query key from endpoint and config\n */\nfunction buildQueryKey<Paths, T extends QueryEndpoint<Paths>>(\n\tendpoint: T,\n\tconfig?: FilteredRequestConfig<Paths, T>,\n): unknown[] {\n\tconst key: unknown[] = [endpoint];\n\n\tif (config && 'params' in config && config.params) {\n\t\tkey.push({ params: config.params });\n\t}\n\n\tif (config && 'query' in config && config.query) {\n\t\tkey.push({ query: config.query });\n\t}\n\n\treturn key;\n}\n\n/**\n * Options for creating endpoint-based hooks\n */\nexport interface CreateEndpointHooksOptions {\n\tqueryClient?: QueryClient;\n}\n\n/**\n * Hook options type that conditionally requires config\n */\ntype UseQueryArgs<Paths, T extends QueryEndpoint<Paths>> = IsConfigRequired<\n\tPaths,\n\tT\n> extends true\n\t? [\n\t\t\tconfig: FilteredRequestConfig<Paths, T>,\n\t\t\toptions?: Omit<\n\t\t\t\tUseQueryOptions<ExtractEndpointResponse<Paths, T>, Error>,\n\t\t\t\t'queryKey' | 'queryFn'\n\t\t\t>,\n\t\t]\n\t: [\n\t\t\tconfig?: FilteredRequestConfig<Paths, T>,\n\t\t\toptions?: Omit<\n\t\t\t\tUseQueryOptions<ExtractEndpointResponse<Paths, T>, Error>,\n\t\t\t\t'queryKey' | 'queryFn'\n\t\t\t>,\n\t\t];\n\n/**\n * Endpoint-based React Query hooks\n */\nexport interface EndpointHooks<Paths> {\n\t/**\n\t * Use query hook for GET endpoints.\n\t * Config is required when endpoint has path params.\n\t */\n\tuseQuery: <T extends QueryEndpoint<Paths>>(\n\t\tendpoint: T,\n\t\t...args: UseQueryArgs<Paths, T>\n\t) => ReturnType<typeof useQuery<ExtractEndpointResponse<Paths, T>, Error>>;\n\n\t/**\n\t * Use mutation hook for POST, PUT, PATCH, DELETE endpoints.\n\t * Config with params/body is passed to mutate().\n\t */\n\tuseMutation: <T extends MutationEndpoint<Paths>>(\n\t\tendpoint: T,\n\t\toptions?: Omit<\n\t\t\tUseMutationOptions<\n\t\t\t\tExtractEndpointResponse<Paths, T>,\n\t\t\t\tError,\n\t\t\t\tFilteredRequestConfig<Paths, T>\n\t\t\t>,\n\t\t\t'mutationFn'\n\t\t>,\n\t) => ReturnType<\n\t\ttypeof useMutation<\n\t\t\tExtractEndpointResponse<Paths, T>,\n\t\t\tError,\n\t\t\tFilteredRequestConfig<Paths, T>\n\t\t>\n\t>;\n\n\t/**\n\t * Build a query key for manual cache operations\n\t */\n\tbuildQueryKey: <T extends QueryEndpoint<Paths>>(\n\t\tendpoint: T,\n\t\tconfig?: FilteredRequestConfig<Paths, T>,\n\t) => unknown[];\n}\n\n/**\n * Create endpoint-based React Query hooks from a typed fetcher.\n *\n * @example\n * ```typescript\n * const fetcher = createAuthAwareFetcher<paths>({ ... });\n * const hooks = createEndpointHooks<paths>(fetcher);\n *\n * // In a component\n * const { data } = hooks.useQuery('GET /users/{id}', { params: { id: '123' } });\n *\n * const mutation = hooks.useMutation('POST /users');\n * await mutation.mutateAsync({ body: { name: 'John' } });\n * ```\n */\nexport function createEndpointHooks<Paths>(\n\tfetcher: TypedApiFunction<Paths>,\n\t_options: CreateEndpointHooksOptions = {},\n): EndpointHooks<Paths> {\n\treturn {\n\t\tuseQuery: <T extends QueryEndpoint<Paths>>(\n\t\t\tendpoint: T,\n\t\t\t...args: UseQueryArgs<Paths, T>\n\t\t) => {\n\t\t\t// Parse args - config is first, options is second\n\t\t\tconst [config, queryOptions] = args as [\n\t\t\t\tFilteredRequestConfig<Paths, T> | undefined,\n\t\t\t\t(\n\t\t\t\t\t| Omit<\n\t\t\t\t\t\t\tUseQueryOptions<ExtractEndpointResponse<Paths, T>, Error>,\n\t\t\t\t\t\t\t'queryKey' | 'queryFn'\n\t\t\t\t\t >\n\t\t\t\t\t| undefined\n\t\t\t\t),\n\t\t\t];\n\n\t\t\tconst queryKey = buildQueryKey(endpoint, config);\n\n\t\t\tconst memoizedOptions = useMemo(\n\t\t\t\t() => ({\n\t\t\t\t\tqueryKey,\n\t\t\t\t\tqueryFn: () =>\n\t\t\t\t\t\t// Type assertion needed due to complex conditional types\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\tfetcher as (\n\t\t\t\t\t\t\t\tendpoint: T,\n\t\t\t\t\t\t\t\tconfig?: unknown,\n\t\t\t\t\t\t\t) => Promise<ExtractEndpointResponse<Paths, T>>\n\t\t\t\t\t\t)(endpoint, config),\n\t\t\t\t\t...queryOptions,\n\t\t\t\t}),\n\t\t\t\t[endpoint, config, fetcher, queryKey, queryOptions],\n\t\t\t);\n\n\t\t\treturn useQuery<ExtractEndpointResponse<Paths, T>, Error>(\n\t\t\t\tmemoizedOptions,\n\t\t\t);\n\t\t},\n\n\t\tuseMutation: <T extends MutationEndpoint<Paths>>(\n\t\t\tendpoint: T,\n\t\t\tmutationOptions?: Omit<\n\t\t\t\tUseMutationOptions<\n\t\t\t\t\tExtractEndpointResponse<Paths, T>,\n\t\t\t\t\tError,\n\t\t\t\t\tFilteredRequestConfig<Paths, T>\n\t\t\t\t>,\n\t\t\t\t'mutationFn'\n\t\t\t>,\n\t\t) => {\n\t\t\tconst memoizedOptions = useMemo(\n\t\t\t\t() => ({\n\t\t\t\t\tmutationFn: (config: FilteredRequestConfig<Paths, T>) =>\n\t\t\t\t\t\t// Type assertion needed due to complex conditional types\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\tfetcher as (\n\t\t\t\t\t\t\t\tendpoint: T,\n\t\t\t\t\t\t\t\tconfig?: unknown,\n\t\t\t\t\t\t\t) => Promise<ExtractEndpointResponse<Paths, T>>\n\t\t\t\t\t\t)(endpoint, config),\n\t\t\t\t\t...mutationOptions,\n\t\t\t\t}),\n\t\t\t\t[endpoint, fetcher, mutationOptions],\n\t\t\t);\n\n\t\t\treturn useMutation<\n\t\t\t\tExtractEndpointResponse<Paths, T>,\n\t\t\t\tError,\n\t\t\t\tFilteredRequestConfig<Paths, T>\n\t\t\t>(memoizedOptions);\n\t\t},\n\n\t\tbuildQueryKey,\n\t};\n}\n"],"mappings":";;;;;;;;AAmBA,SAAS,cACRA,UACAC,QACY;CACZ,MAAMC,MAAiB,CAAC,QAAS;AAEjC,KAAI,UAAU,YAAY,UAAU,OAAO,OAC1C,KAAI,KAAK,EAAE,QAAQ,OAAO,OAAQ,EAAC;AAGpC,KAAI,UAAU,WAAW,UAAU,OAAO,MACzC,KAAI,KAAK,EAAE,OAAO,OAAO,MAAO,EAAC;AAGlC,QAAO;AACP;;;;;;;;;;;;;;;;AA0FD,SAAgB,oBACfC,SACAC,WAAuC,CAAE,GAClB;AACvB,QAAO;EACN,UAAU,CACTJ,UACA,GAAG,SACC;GAEJ,MAAM,CAAC,QAAQ,aAAa,GAAG;GAW/B,MAAM,WAAW,cAAc,UAAU,OAAO;GAEhD,MAAM,kBAAkB,mBACvB,OAAO;IACN;IACA,SAAS,MAER,AACC,QAIC,UAAU,OAAO;IACpB,GAAG;GACH,IACD;IAAC;IAAU;IAAQ;IAAS;IAAU;GAAa,EACnD;AAED,UAAO,qCACN,gBACA;EACD;EAED,aAAa,CACZA,UACAK,oBAQI;GACJ,MAAM,kBAAkB,mBACvB,OAAO;IACN,YAAY,CAACC,WAEZ,AACC,QAIC,UAAU,OAAO;IACpB,GAAG;GACH,IACD;IAAC;IAAU;IAAS;GAAgB,EACpC;AAED,UAAO,wCAIL,gBAAgB;EAClB;EAED;CACA;AACD"}
1
+ {"version":3,"file":"endpoint-hooks.cjs","names":["endpoint: T","config?: FilteredRequestConfig<Paths, T>","key: unknown[]","fetcher: TypedApiFunction<Paths>","_options: CreateEndpointHooksOptions","mutationOptions?: Omit<\n\t\t\t\tUseMutationOptions<\n\t\t\t\t\tExtractEndpointResponse<Paths, T>,\n\t\t\t\t\tError,\n\t\t\t\t\tFilteredRequestConfig<Paths, T>\n\t\t\t\t>,\n\t\t\t\t'mutationFn'\n\t\t\t>","config: FilteredRequestConfig<Paths, T>"],"sources":["../src/endpoint-hooks.ts"],"sourcesContent":["import type {\n\tQueryClient,\n\tUseMutationOptions,\n\tUseMutationResult,\n\tUseQueryOptions,\n\tUseQueryResult,\n} from '@tanstack/react-query';\nimport { useMutation, useQuery } from '@tanstack/react-query';\nimport { useMemo } from 'react';\nimport type {\n\tExtractEndpointResponse,\n\tFilteredRequestConfig,\n\tIsConfigRequired,\n\tMutationEndpoint,\n\tQueryEndpoint,\n\tTypedApiFunction,\n} from './types';\n\n/**\n * Build query key from endpoint and config\n */\nfunction buildQueryKey<Paths, T extends QueryEndpoint<Paths>>(\n\tendpoint: T,\n\tconfig?: FilteredRequestConfig<Paths, T>,\n): unknown[] {\n\tconst key: unknown[] = [endpoint];\n\n\tif (config && 'params' in config && config.params) {\n\t\tkey.push({ params: config.params });\n\t}\n\n\tif (config && 'query' in config && config.query) {\n\t\tkey.push({ query: config.query });\n\t}\n\n\treturn key;\n}\n\n/**\n * Options for creating endpoint-based hooks\n */\nexport interface CreateEndpointHooksOptions {\n\tqueryClient?: QueryClient;\n}\n\n/**\n * Hook options type that conditionally requires config\n */\ntype UseQueryArgs<Paths, T extends QueryEndpoint<Paths>> = IsConfigRequired<\n\tPaths,\n\tT\n> extends true\n\t? [\n\t\t\tconfig: FilteredRequestConfig<Paths, T>,\n\t\t\toptions?: Omit<\n\t\t\t\tUseQueryOptions<ExtractEndpointResponse<Paths, T>, Error>,\n\t\t\t\t'queryKey' | 'queryFn'\n\t\t\t>,\n\t\t]\n\t: [\n\t\t\tconfig?: FilteredRequestConfig<Paths, T>,\n\t\t\toptions?: Omit<\n\t\t\t\tUseQueryOptions<ExtractEndpointResponse<Paths, T>, Error>,\n\t\t\t\t'queryKey' | 'queryFn'\n\t\t\t>,\n\t\t];\n\n/**\n * Endpoint-based React Query hooks\n */\nexport interface EndpointHooks<Paths> {\n\t/**\n\t * Use query hook for GET endpoints.\n\t * Config is required when endpoint has path params.\n\t */\n\tuseQuery: <T extends QueryEndpoint<Paths>>(\n\t\tendpoint: T,\n\t\t...args: UseQueryArgs<Paths, T>\n\t) => UseQueryResult<ExtractEndpointResponse<Paths, T>, Error>;\n\n\t/**\n\t * Use mutation hook for POST, PUT, PATCH, DELETE endpoints.\n\t * Config with params/body is passed to mutate().\n\t */\n\tuseMutation: <T extends MutationEndpoint<Paths>>(\n\t\tendpoint: T,\n\t\toptions?: Omit<\n\t\t\tUseMutationOptions<\n\t\t\t\tExtractEndpointResponse<Paths, T>,\n\t\t\t\tError,\n\t\t\t\tFilteredRequestConfig<Paths, T>\n\t\t\t>,\n\t\t\t'mutationFn'\n\t\t>,\n\t) => UseMutationResult<\n\t\tExtractEndpointResponse<Paths, T>,\n\t\tError,\n\t\tFilteredRequestConfig<Paths, T>\n\t>;\n\n\t/**\n\t * Build a query key for manual cache operations\n\t */\n\tbuildQueryKey: <T extends QueryEndpoint<Paths>>(\n\t\tendpoint: T,\n\t\tconfig?: FilteredRequestConfig<Paths, T>,\n\t) => unknown[];\n}\n\n/**\n * Create endpoint-based React Query hooks from a typed fetcher.\n *\n * @example\n * ```typescript\n * const fetcher = createAuthAwareFetcher<paths>({ ... });\n * const hooks = createEndpointHooks<paths>(fetcher);\n *\n * // In a component\n * const { data } = hooks.useQuery('GET /users/{id}', { params: { id: '123' } });\n *\n * const mutation = hooks.useMutation('POST /users');\n * await mutation.mutateAsync({ body: { name: 'John' } });\n * ```\n */\nexport function createEndpointHooks<Paths>(\n\tfetcher: TypedApiFunction<Paths>,\n\t_options: CreateEndpointHooksOptions = {},\n): EndpointHooks<Paths> {\n\treturn {\n\t\tuseQuery: <T extends QueryEndpoint<Paths>>(\n\t\t\tendpoint: T,\n\t\t\t...args: UseQueryArgs<Paths, T>\n\t\t) => {\n\t\t\t// Parse args - config is first, options is second\n\t\t\tconst [config, queryOptions] = args as [\n\t\t\t\tFilteredRequestConfig<Paths, T> | undefined,\n\t\t\t\t(\n\t\t\t\t\t| Omit<\n\t\t\t\t\t\t\tUseQueryOptions<ExtractEndpointResponse<Paths, T>, Error>,\n\t\t\t\t\t\t\t'queryKey' | 'queryFn'\n\t\t\t\t\t >\n\t\t\t\t\t| undefined\n\t\t\t\t),\n\t\t\t];\n\n\t\t\tconst queryKey = buildQueryKey(endpoint, config);\n\n\t\t\tconst memoizedOptions = useMemo(\n\t\t\t\t() => ({\n\t\t\t\t\tqueryKey,\n\t\t\t\t\tqueryFn: () =>\n\t\t\t\t\t\t// Type assertion needed due to complex conditional types\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\tfetcher as (\n\t\t\t\t\t\t\t\tendpoint: T,\n\t\t\t\t\t\t\t\tconfig?: unknown,\n\t\t\t\t\t\t\t) => Promise<ExtractEndpointResponse<Paths, T>>\n\t\t\t\t\t\t)(endpoint, config),\n\t\t\t\t\t...queryOptions,\n\t\t\t\t}),\n\t\t\t\t[endpoint, config, fetcher, queryKey, queryOptions],\n\t\t\t);\n\n\t\t\treturn useQuery<ExtractEndpointResponse<Paths, T>, Error>(\n\t\t\t\tmemoizedOptions,\n\t\t\t);\n\t\t},\n\n\t\tuseMutation: <T extends MutationEndpoint<Paths>>(\n\t\t\tendpoint: T,\n\t\t\tmutationOptions?: Omit<\n\t\t\t\tUseMutationOptions<\n\t\t\t\t\tExtractEndpointResponse<Paths, T>,\n\t\t\t\t\tError,\n\t\t\t\t\tFilteredRequestConfig<Paths, T>\n\t\t\t\t>,\n\t\t\t\t'mutationFn'\n\t\t\t>,\n\t\t) => {\n\t\t\tconst memoizedOptions = useMemo(\n\t\t\t\t() => ({\n\t\t\t\t\tmutationFn: (config: FilteredRequestConfig<Paths, T>) =>\n\t\t\t\t\t\t// Type assertion needed due to complex conditional types\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\tfetcher as (\n\t\t\t\t\t\t\t\tendpoint: T,\n\t\t\t\t\t\t\t\tconfig?: unknown,\n\t\t\t\t\t\t\t) => Promise<ExtractEndpointResponse<Paths, T>>\n\t\t\t\t\t\t)(endpoint, config),\n\t\t\t\t\t...mutationOptions,\n\t\t\t\t}),\n\t\t\t\t[endpoint, fetcher, mutationOptions],\n\t\t\t);\n\n\t\t\treturn useMutation<\n\t\t\t\tExtractEndpointResponse<Paths, T>,\n\t\t\t\tError,\n\t\t\t\tFilteredRequestConfig<Paths, T>\n\t\t\t>(memoizedOptions);\n\t\t},\n\n\t\tbuildQueryKey,\n\t};\n}\n"],"mappings":";;;;;;;;AAqBA,SAAS,cACRA,UACAC,QACY;CACZ,MAAMC,MAAiB,CAAC,QAAS;AAEjC,KAAI,UAAU,YAAY,UAAU,OAAO,OAC1C,KAAI,KAAK,EAAE,QAAQ,OAAO,OAAQ,EAAC;AAGpC,KAAI,UAAU,WAAW,UAAU,OAAO,MACzC,KAAI,KAAK,EAAE,OAAO,OAAO,MAAO,EAAC;AAGlC,QAAO;AACP;;;;;;;;;;;;;;;;AAwFD,SAAgB,oBACfC,SACAC,WAAuC,CAAE,GAClB;AACvB,QAAO;EACN,UAAU,CACTJ,UACA,GAAG,SACC;GAEJ,MAAM,CAAC,QAAQ,aAAa,GAAG;GAW/B,MAAM,WAAW,cAAc,UAAU,OAAO;GAEhD,MAAM,kBAAkB,mBACvB,OAAO;IACN;IACA,SAAS,MAER,AACC,QAIC,UAAU,OAAO;IACpB,GAAG;GACH,IACD;IAAC;IAAU;IAAQ;IAAS;IAAU;GAAa,EACnD;AAED,UAAO,qCACN,gBACA;EACD;EAED,aAAa,CACZA,UACAK,oBAQI;GACJ,MAAM,kBAAkB,mBACvB,OAAO;IACN,YAAY,CAACC,WAEZ,AACC,QAIC,UAAU,OAAO;IACpB,GAAG;GACH,IACD;IAAC;IAAU;IAAS;GAAgB,EACpC;AAED,UAAO,wCAIL,gBAAgB;EAClB;EAED;CACA;AACD"}
@@ -1,5 +1,5 @@
1
1
  import { ExtractEndpointResponse, FilteredRequestConfig, IsConfigRequired, MutationEndpoint, QueryEndpoint, TypedApiFunction } from "./types-4K4N-Fl1.cjs";
2
- import { QueryClient, UseMutationOptions, UseQueryOptions, useMutation, useQuery } from "@tanstack/react-query";
2
+ import { QueryClient, UseMutationOptions, UseMutationResult, UseQueryOptions, UseQueryResult } from "@tanstack/react-query";
3
3
 
4
4
  //#region src/endpoint-hooks.d.ts
5
5
 
@@ -21,12 +21,12 @@ interface EndpointHooks<Paths> {
21
21
  * Use query hook for GET endpoints.
22
22
  * Config is required when endpoint has path params.
23
23
  */
24
- useQuery: <T extends QueryEndpoint<Paths>>(endpoint: T, ...args: UseQueryArgs<Paths, T>) => ReturnType<typeof useQuery<ExtractEndpointResponse<Paths, T>, Error>>;
24
+ useQuery: <T extends QueryEndpoint<Paths>>(endpoint: T, ...args: UseQueryArgs<Paths, T>) => UseQueryResult<ExtractEndpointResponse<Paths, T>, Error>;
25
25
  /**
26
26
  * Use mutation hook for POST, PUT, PATCH, DELETE endpoints.
27
27
  * Config with params/body is passed to mutate().
28
28
  */
29
- useMutation: <T extends MutationEndpoint<Paths>>(endpoint: T, options?: Omit<UseMutationOptions<ExtractEndpointResponse<Paths, T>, Error, FilteredRequestConfig<Paths, T>>, 'mutationFn'>) => ReturnType<typeof useMutation<ExtractEndpointResponse<Paths, T>, Error, FilteredRequestConfig<Paths, T>>>;
29
+ useMutation: <T extends MutationEndpoint<Paths>>(endpoint: T, options?: Omit<UseMutationOptions<ExtractEndpointResponse<Paths, T>, Error, FilteredRequestConfig<Paths, T>>, 'mutationFn'>) => UseMutationResult<ExtractEndpointResponse<Paths, T>, Error, FilteredRequestConfig<Paths, T>>;
30
30
  /**
31
31
  * Build a query key for manual cache operations
32
32
  */
@@ -1 +1 @@
1
- {"version":3,"file":"endpoint-hooks.d.cts","names":[],"sources":["../src/endpoint-hooks.ts"],"sourcesContent":[],"mappings":";;;;;;AAuCA;AAEC;AAKgB,UAPA,0BAAA,CAOA;EAAA,WAAgC,CAAA,EANlC,WAMkC;;;;;KAA5C,YAK4B,CAAA,KAAA,EAAA,UALE,aAKF,CALgB,KAKhB,CAAA,CAAA,GAL0B,gBAK1B,CAJhC,KAIgC,EAHhC,CAGgC,CAAA,SAAA,IAAA,GAAA,CAAK,MAAE,EAA7B,qBAA6B,CAAP,KAAO,EAAA,CAAA,CAAA,EAAC,OAA9B,GACE,IADF,CAEP,eAFO,CAES,uBAFT,CAEiC,KAFjC,EAEwC,CAFxC,CAAA,EAE4C,KAF5C,CAAA,EAAA,UAAA,GAAA,SAAA,CAAA,CAAqB,GAAA,CAEiB,MAAE,GAKvC,qBALuC,CAKjB,KALiB,EAKV,CALU,CAAA,EAAC,OAAhC,GAMP,IANO,CAOhB,eAPgB,CAOA,uBAPA,CAOwB,KAPxB,EAO+B,CAP/B,CAAA,EAOmC,KAPnC,CAAA,EAAA,UAAA,GAAA,SAAA,CAAA,CAAuB;;;;AAKF,UAUxB,aAVwB,CAAA,KAAA,CAAA,CAAA;EAAC;;;;EAEC,QAAY,EAAA,CAAA,UAajC,aAbiC,CAanB,KAbmB,CAAA,CAAA,CAAA,QAAA,EAc3C,CAd2C,EAAA,GAAA,IAAA,EAe5C,YAf4C,CAe/B,KAf+B,EAexB,CAfwB,CAAA,EAAA,GAgBjD,UAhBiD,CAAA,OAgB/B,QAhB+B,CAgBtB,uBAhBsB,CAgBE,KAhBF,EAgBS,CAhBT,CAAA,EAgBa,KAhBb,CAAA,CAAA;EAAK;;AAD3C;AASjB;EAA8B,WAAA,EAAA,CAAA,UAcL,gBAdK,CAcY,KAdZ,CAAA,CAAA,CAAA,QAAA,EAelB,CAfkB,EAAA,OAAA,CAAA,EAgBlB,IAhBkB,CAiB3B,kBAjB2B,CAkB1B,uBAlB0B,CAkBF,KAlBE,EAkBK,CAlBL,CAAA,EAmB1B,KAnB0B,EAoB1B,qBApB0B,CAoBJ,KApBI,EAoBG,CApBH,CAAA,CAAA,EAAA,YAAA,CAAA,EAAA,GAwBxB,UAxBwB,CAAA,OAyBrB,WAzBqB,CA0B3B,uBA1B2B,CA0BH,KA1BG,EA0BI,CA1BJ,CAAA,EA2B3B,KA3B2B,EA4B3B,qBA5B2B,CA4BL,KA5BK,EA4BE,CA5BF,CAAA,CAAA,CAAA;EAAA;;;EAMjB,aACW,EAAA,CAAA,UA4BG,aA5BH,CA4BiB,KA5BjB,CAAA,CAAA,CAAA,QAAA,EA6BZ,CA7BY,EAAA,MAAA,CAAA,EA8Bb,qBA9Ba,CA8BS,KA9BT,EA8BgB,CA9BhB,CAAA,EAAA,GAAA,OAAA,EAAA;;;;;;;;;;;;;;;;;AAaS,iBAoCjB,mBApCiB,CAAA,KAAA,CAAA,CAAA,OAAA,EAqCvB,gBArCuB,CAqCN,KArCM,CAAA,EAAA,QAAA,CAAA,EAsCtB,0BAtCsB,CAAA,EAuC9B,aAvC8B,CAuChB,KAvCgB,CAAA"}
1
+ {"version":3,"file":"endpoint-hooks.d.cts","names":[],"sources":["../src/endpoint-hooks.ts"],"sourcesContent":[],"mappings":";;;;;;;AAyCA;AAOK,UAPY,0BAAA,CAOA;EAAA,WAAA,CAAA,EANF,WAME;;;;;KAAZ,YAAsD,CAAA,KAAA,EAAA,UAAxB,aAAwB,CAAV,KAAU,CAAA,CAAA,GAAA,gBAAA,CAC1D,KAD0D,EAE1D,CAF0D,CAAA,SAAA,IAAA,GAAA,CAAgB,MAK1C,EAAtB,qBAAsB,CAAA,KAAA,EAAO,CAAP,CAAA,EAAK,OAAE,GAC3B,IAD2B,CAEpC,eAFoC,CAEpB,uBAFoB,CAEI,KAFJ,EAEW,CAFX,CAAA,EAEe,KAFf,CAAA,EAAA,UAAA,GAAA,SAAA,CAAA,CAAC,GAAA,CAAT,MAEY,GAKhC,qBALgC,CAKV,KALU,EAKH,CALG,CAAA,EAAK,OAAE,GAMtC,IANsC,CAO/C,eAP+C,CAO/B,uBAP+B,CAOP,KAPO,EAOA,CAPA,CAAA,EAOI,KAPJ,CAAA,EAAA,UAAA,GAAA,SAAA,CAAA,CAAC;;;;AAKlB,UAUjB,aAViB,CAAA,KAAA,CAAA,CAAA;EAAK;;;;EAEa,QAAhC,EAAA,CAAA,UAaE,aAbF,CAagB,KAbhB,CAAA,CAAA,CAAA,QAAA,EAcR,CAdQ,EAAA,GAAA,IAAA,EAeT,YAfS,CAeI,KAfJ,EAeW,CAfX,CAAA,EAAA,GAgBd,cAhBc,CAgBC,uBAhBD,CAgByB,KAhBzB,EAgBgC,CAhBhC,CAAA,EAgBoC,KAhBpC,CAAA;EAAuB;;;AAD1B;EASA,WAAA,EAAA,CAAA,UAcQ,gBAdK,CAcY,KAdZ,CAAA,CAAA,CAAA,QAAA,EAelB,CAfkB,EAAA,OAAA,CAAA,EAgBlB,IAhBkB,CAiB3B,kBAjB2B,CAkB1B,uBAlB0B,CAkBF,KAlBE,EAkBK,CAlBL,CAAA,EAmB1B,KAnB0B,EAoB1B,qBApB0B,CAoBJ,KApBI,EAoBG,CApBH,CAAA,CAAA,EAAA,YAAA,CAAA,EAAA,GAwBxB,iBAxBwB,CAyB5B,uBAzB4B,CAyBJ,KAzBI,EAyBG,CAzBH,CAAA,EA0B5B,KA1B4B,EA2B5B,qBA3B4B,CA2BN,KA3BM,EA2BC,CA3BD,CAAA,CAAA;EAAA;;;EAKK,aACvB,EAAA,CAAA,UA2Be,aA3Bf,CA2B6B,KA3B7B,CAAA,CAAA,CAAA,QAAA,EA4BA,CA5BA,EAAA,MAAA,CAAA,EA6BD,qBA7BC,CA6BqB,KA7BrB,EA6B4B,CA7B5B,CAAA,EAAA,GAAA,OAAA,EAAA;;;;;;;;;;;;;;;;;AAcqB,iBAkCjB,mBAlCiB,CAAA,KAAA,CAAA,CAAA,OAAA,EAmCvB,gBAnCuB,CAmCN,KAnCM,CAAA,EAAA,QAAA,CAAA,EAoCtB,0BApCsB,CAAA,EAqC9B,aArC8B,CAqChB,KArCgB,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import { ExtractEndpointResponse, FilteredRequestConfig, IsConfigRequired, MutationEndpoint, QueryEndpoint, TypedApiFunction } from "./types-hhkZWjQn.mjs";
2
- import { QueryClient, UseMutationOptions, UseQueryOptions, useMutation, useQuery } from "@tanstack/react-query";
2
+ import { QueryClient, UseMutationOptions, UseMutationResult, UseQueryOptions, UseQueryResult } from "@tanstack/react-query";
3
3
 
4
4
  //#region src/endpoint-hooks.d.ts
5
5
 
@@ -21,12 +21,12 @@ interface EndpointHooks<Paths> {
21
21
  * Use query hook for GET endpoints.
22
22
  * Config is required when endpoint has path params.
23
23
  */
24
- useQuery: <T extends QueryEndpoint<Paths>>(endpoint: T, ...args: UseQueryArgs<Paths, T>) => ReturnType<typeof useQuery<ExtractEndpointResponse<Paths, T>, Error>>;
24
+ useQuery: <T extends QueryEndpoint<Paths>>(endpoint: T, ...args: UseQueryArgs<Paths, T>) => UseQueryResult<ExtractEndpointResponse<Paths, T>, Error>;
25
25
  /**
26
26
  * Use mutation hook for POST, PUT, PATCH, DELETE endpoints.
27
27
  * Config with params/body is passed to mutate().
28
28
  */
29
- useMutation: <T extends MutationEndpoint<Paths>>(endpoint: T, options?: Omit<UseMutationOptions<ExtractEndpointResponse<Paths, T>, Error, FilteredRequestConfig<Paths, T>>, 'mutationFn'>) => ReturnType<typeof useMutation<ExtractEndpointResponse<Paths, T>, Error, FilteredRequestConfig<Paths, T>>>;
29
+ useMutation: <T extends MutationEndpoint<Paths>>(endpoint: T, options?: Omit<UseMutationOptions<ExtractEndpointResponse<Paths, T>, Error, FilteredRequestConfig<Paths, T>>, 'mutationFn'>) => UseMutationResult<ExtractEndpointResponse<Paths, T>, Error, FilteredRequestConfig<Paths, T>>;
30
30
  /**
31
31
  * Build a query key for manual cache operations
32
32
  */
@@ -1 +1 @@
1
- {"version":3,"file":"endpoint-hooks.d.mts","names":[],"sources":["../src/endpoint-hooks.ts"],"sourcesContent":[],"mappings":";;;;;;AAuCA;AAEC;AAKgB,UAPA,0BAAA,CAOA;EAAA,WAAgC,CAAA,EANlC,WAMkC;;;;;KAA5C,YAK4B,CAAA,KAAA,EAAA,UALE,aAKF,CALgB,KAKhB,CAAA,CAAA,GAL0B,gBAK1B,CAJhC,KAIgC,EAHhC,CAGgC,CAAA,SAAA,IAAA,GAAA,CAAK,MAAE,EAA7B,qBAA6B,CAAP,KAAO,EAAA,CAAA,CAAA,EAAC,OAA9B,GACE,IADF,CAEP,eAFO,CAES,uBAFT,CAEiC,KAFjC,EAEwC,CAFxC,CAAA,EAE4C,KAF5C,CAAA,EAAA,UAAA,GAAA,SAAA,CAAA,CAAqB,GAAA,CAEiB,MAAE,GAKvC,qBALuC,CAKjB,KALiB,EAKV,CALU,CAAA,EAAC,OAAhC,GAMP,IANO,CAOhB,eAPgB,CAOA,uBAPA,CAOwB,KAPxB,EAO+B,CAP/B,CAAA,EAOmC,KAPnC,CAAA,EAAA,UAAA,GAAA,SAAA,CAAA,CAAuB;;;;AAKF,UAUxB,aAVwB,CAAA,KAAA,CAAA,CAAA;EAAC;;;;EAEC,QAAY,EAAA,CAAA,UAajC,aAbiC,CAanB,KAbmB,CAAA,CAAA,CAAA,QAAA,EAc3C,CAd2C,EAAA,GAAA,IAAA,EAe5C,YAf4C,CAe/B,KAf+B,EAexB,CAfwB,CAAA,EAAA,GAgBjD,UAhBiD,CAAA,OAgB/B,QAhB+B,CAgBtB,uBAhBsB,CAgBE,KAhBF,EAgBS,CAhBT,CAAA,EAgBa,KAhBb,CAAA,CAAA;EAAK;;AAD3C;AASjB;EAA8B,WAAA,EAAA,CAAA,UAcL,gBAdK,CAcY,KAdZ,CAAA,CAAA,CAAA,QAAA,EAelB,CAfkB,EAAA,OAAA,CAAA,EAgBlB,IAhBkB,CAiB3B,kBAjB2B,CAkB1B,uBAlB0B,CAkBF,KAlBE,EAkBK,CAlBL,CAAA,EAmB1B,KAnB0B,EAoB1B,qBApB0B,CAoBJ,KApBI,EAoBG,CApBH,CAAA,CAAA,EAAA,YAAA,CAAA,EAAA,GAwBxB,UAxBwB,CAAA,OAyBrB,WAzBqB,CA0B3B,uBA1B2B,CA0BH,KA1BG,EA0BI,CA1BJ,CAAA,EA2B3B,KA3B2B,EA4B3B,qBA5B2B,CA4BL,KA5BK,EA4BE,CA5BF,CAAA,CAAA,CAAA;EAAA;;;EAMjB,aACW,EAAA,CAAA,UA4BG,aA5BH,CA4BiB,KA5BjB,CAAA,CAAA,CAAA,QAAA,EA6BZ,CA7BY,EAAA,MAAA,CAAA,EA8Bb,qBA9Ba,CA8BS,KA9BT,EA8BgB,CA9BhB,CAAA,EAAA,GAAA,OAAA,EAAA;;;;;;;;;;;;;;;;;AAaS,iBAoCjB,mBApCiB,CAAA,KAAA,CAAA,CAAA,OAAA,EAqCvB,gBArCuB,CAqCN,KArCM,CAAA,EAAA,QAAA,CAAA,EAsCtB,0BAtCsB,CAAA,EAuC9B,aAvC8B,CAuChB,KAvCgB,CAAA"}
1
+ {"version":3,"file":"endpoint-hooks.d.mts","names":[],"sources":["../src/endpoint-hooks.ts"],"sourcesContent":[],"mappings":";;;;;;;AAyCA;AAOK,UAPY,0BAAA,CAOA;EAAA,WAAA,CAAA,EANF,WAME;;;;;KAAZ,YAAsD,CAAA,KAAA,EAAA,UAAxB,aAAwB,CAAV,KAAU,CAAA,CAAA,GAAA,gBAAA,CAC1D,KAD0D,EAE1D,CAF0D,CAAA,SAAA,IAAA,GAAA,CAAgB,MAK1C,EAAtB,qBAAsB,CAAA,KAAA,EAAO,CAAP,CAAA,EAAK,OAAE,GAC3B,IAD2B,CAEpC,eAFoC,CAEpB,uBAFoB,CAEI,KAFJ,EAEW,CAFX,CAAA,EAEe,KAFf,CAAA,EAAA,UAAA,GAAA,SAAA,CAAA,CAAC,GAAA,CAAT,MAEY,GAKhC,qBALgC,CAKV,KALU,EAKH,CALG,CAAA,EAAK,OAAE,GAMtC,IANsC,CAO/C,eAP+C,CAO/B,uBAP+B,CAOP,KAPO,EAOA,CAPA,CAAA,EAOI,KAPJ,CAAA,EAAA,UAAA,GAAA,SAAA,CAAA,CAAC;;;;AAKlB,UAUjB,aAViB,CAAA,KAAA,CAAA,CAAA;EAAK;;;;EAEa,QAAhC,EAAA,CAAA,UAaE,aAbF,CAagB,KAbhB,CAAA,CAAA,CAAA,QAAA,EAcR,CAdQ,EAAA,GAAA,IAAA,EAeT,YAfS,CAeI,KAfJ,EAeW,CAfX,CAAA,EAAA,GAgBd,cAhBc,CAgBC,uBAhBD,CAgByB,KAhBzB,EAgBgC,CAhBhC,CAAA,EAgBoC,KAhBpC,CAAA;EAAuB;;;AAD1B;EASA,WAAA,EAAA,CAAA,UAcQ,gBAdK,CAcY,KAdZ,CAAA,CAAA,CAAA,QAAA,EAelB,CAfkB,EAAA,OAAA,CAAA,EAgBlB,IAhBkB,CAiB3B,kBAjB2B,CAkB1B,uBAlB0B,CAkBF,KAlBE,EAkBK,CAlBL,CAAA,EAmB1B,KAnB0B,EAoB1B,qBApB0B,CAoBJ,KApBI,EAoBG,CApBH,CAAA,CAAA,EAAA,YAAA,CAAA,EAAA,GAwBxB,iBAxBwB,CAyB5B,uBAzB4B,CAyBJ,KAzBI,EAyBG,CAzBH,CAAA,EA0B5B,KA1B4B,EA2B5B,qBA3B4B,CA2BN,KA3BM,EA2BC,CA3BD,CAAA,CAAA;EAAA;;;EAKK,aACvB,EAAA,CAAA,UA2Be,aA3Bf,CA2B6B,KA3B7B,CAAA,CAAA,CAAA,QAAA,EA4BA,CA5BA,EAAA,MAAA,CAAA,EA6BD,qBA7BC,CA6BqB,KA7BrB,EA6B4B,CA7B5B,CAAA,EAAA,GAAA,OAAA,EAAA;;;;;;;;;;;;;;;;;AAcqB,iBAkCjB,mBAlCiB,CAAA,KAAA,CAAA,CAAA,OAAA,EAmCvB,gBAnCuB,CAmCN,KAnCM,CAAA,EAAA,QAAA,CAAA,EAoCtB,0BApCsB,CAAA,EAqC9B,aArC8B,CAqChB,KArCgB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"endpoint-hooks.mjs","names":["endpoint: T","config?: FilteredRequestConfig<Paths, T>","key: unknown[]","fetcher: TypedApiFunction<Paths>","_options: CreateEndpointHooksOptions","mutationOptions?: Omit<\n\t\t\t\tUseMutationOptions<\n\t\t\t\t\tExtractEndpointResponse<Paths, T>,\n\t\t\t\t\tError,\n\t\t\t\t\tFilteredRequestConfig<Paths, T>\n\t\t\t\t>,\n\t\t\t\t'mutationFn'\n\t\t\t>","config: FilteredRequestConfig<Paths, T>"],"sources":["../src/endpoint-hooks.ts"],"sourcesContent":["import type {\n\tQueryClient,\n\tUseMutationOptions,\n\tUseQueryOptions,\n} from '@tanstack/react-query';\nimport { useMutation, useQuery } from '@tanstack/react-query';\nimport { useMemo } from 'react';\nimport type {\n\tExtractEndpointResponse,\n\tFilteredRequestConfig,\n\tIsConfigRequired,\n\tMutationEndpoint,\n\tQueryEndpoint,\n\tTypedApiFunction,\n} from './types';\n\n/**\n * Build query key from endpoint and config\n */\nfunction buildQueryKey<Paths, T extends QueryEndpoint<Paths>>(\n\tendpoint: T,\n\tconfig?: FilteredRequestConfig<Paths, T>,\n): unknown[] {\n\tconst key: unknown[] = [endpoint];\n\n\tif (config && 'params' in config && config.params) {\n\t\tkey.push({ params: config.params });\n\t}\n\n\tif (config && 'query' in config && config.query) {\n\t\tkey.push({ query: config.query });\n\t}\n\n\treturn key;\n}\n\n/**\n * Options for creating endpoint-based hooks\n */\nexport interface CreateEndpointHooksOptions {\n\tqueryClient?: QueryClient;\n}\n\n/**\n * Hook options type that conditionally requires config\n */\ntype UseQueryArgs<Paths, T extends QueryEndpoint<Paths>> = IsConfigRequired<\n\tPaths,\n\tT\n> extends true\n\t? [\n\t\t\tconfig: FilteredRequestConfig<Paths, T>,\n\t\t\toptions?: Omit<\n\t\t\t\tUseQueryOptions<ExtractEndpointResponse<Paths, T>, Error>,\n\t\t\t\t'queryKey' | 'queryFn'\n\t\t\t>,\n\t\t]\n\t: [\n\t\t\tconfig?: FilteredRequestConfig<Paths, T>,\n\t\t\toptions?: Omit<\n\t\t\t\tUseQueryOptions<ExtractEndpointResponse<Paths, T>, Error>,\n\t\t\t\t'queryKey' | 'queryFn'\n\t\t\t>,\n\t\t];\n\n/**\n * Endpoint-based React Query hooks\n */\nexport interface EndpointHooks<Paths> {\n\t/**\n\t * Use query hook for GET endpoints.\n\t * Config is required when endpoint has path params.\n\t */\n\tuseQuery: <T extends QueryEndpoint<Paths>>(\n\t\tendpoint: T,\n\t\t...args: UseQueryArgs<Paths, T>\n\t) => ReturnType<typeof useQuery<ExtractEndpointResponse<Paths, T>, Error>>;\n\n\t/**\n\t * Use mutation hook for POST, PUT, PATCH, DELETE endpoints.\n\t * Config with params/body is passed to mutate().\n\t */\n\tuseMutation: <T extends MutationEndpoint<Paths>>(\n\t\tendpoint: T,\n\t\toptions?: Omit<\n\t\t\tUseMutationOptions<\n\t\t\t\tExtractEndpointResponse<Paths, T>,\n\t\t\t\tError,\n\t\t\t\tFilteredRequestConfig<Paths, T>\n\t\t\t>,\n\t\t\t'mutationFn'\n\t\t>,\n\t) => ReturnType<\n\t\ttypeof useMutation<\n\t\t\tExtractEndpointResponse<Paths, T>,\n\t\t\tError,\n\t\t\tFilteredRequestConfig<Paths, T>\n\t\t>\n\t>;\n\n\t/**\n\t * Build a query key for manual cache operations\n\t */\n\tbuildQueryKey: <T extends QueryEndpoint<Paths>>(\n\t\tendpoint: T,\n\t\tconfig?: FilteredRequestConfig<Paths, T>,\n\t) => unknown[];\n}\n\n/**\n * Create endpoint-based React Query hooks from a typed fetcher.\n *\n * @example\n * ```typescript\n * const fetcher = createAuthAwareFetcher<paths>({ ... });\n * const hooks = createEndpointHooks<paths>(fetcher);\n *\n * // In a component\n * const { data } = hooks.useQuery('GET /users/{id}', { params: { id: '123' } });\n *\n * const mutation = hooks.useMutation('POST /users');\n * await mutation.mutateAsync({ body: { name: 'John' } });\n * ```\n */\nexport function createEndpointHooks<Paths>(\n\tfetcher: TypedApiFunction<Paths>,\n\t_options: CreateEndpointHooksOptions = {},\n): EndpointHooks<Paths> {\n\treturn {\n\t\tuseQuery: <T extends QueryEndpoint<Paths>>(\n\t\t\tendpoint: T,\n\t\t\t...args: UseQueryArgs<Paths, T>\n\t\t) => {\n\t\t\t// Parse args - config is first, options is second\n\t\t\tconst [config, queryOptions] = args as [\n\t\t\t\tFilteredRequestConfig<Paths, T> | undefined,\n\t\t\t\t(\n\t\t\t\t\t| Omit<\n\t\t\t\t\t\t\tUseQueryOptions<ExtractEndpointResponse<Paths, T>, Error>,\n\t\t\t\t\t\t\t'queryKey' | 'queryFn'\n\t\t\t\t\t >\n\t\t\t\t\t| undefined\n\t\t\t\t),\n\t\t\t];\n\n\t\t\tconst queryKey = buildQueryKey(endpoint, config);\n\n\t\t\tconst memoizedOptions = useMemo(\n\t\t\t\t() => ({\n\t\t\t\t\tqueryKey,\n\t\t\t\t\tqueryFn: () =>\n\t\t\t\t\t\t// Type assertion needed due to complex conditional types\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\tfetcher as (\n\t\t\t\t\t\t\t\tendpoint: T,\n\t\t\t\t\t\t\t\tconfig?: unknown,\n\t\t\t\t\t\t\t) => Promise<ExtractEndpointResponse<Paths, T>>\n\t\t\t\t\t\t)(endpoint, config),\n\t\t\t\t\t...queryOptions,\n\t\t\t\t}),\n\t\t\t\t[endpoint, config, fetcher, queryKey, queryOptions],\n\t\t\t);\n\n\t\t\treturn useQuery<ExtractEndpointResponse<Paths, T>, Error>(\n\t\t\t\tmemoizedOptions,\n\t\t\t);\n\t\t},\n\n\t\tuseMutation: <T extends MutationEndpoint<Paths>>(\n\t\t\tendpoint: T,\n\t\t\tmutationOptions?: Omit<\n\t\t\t\tUseMutationOptions<\n\t\t\t\t\tExtractEndpointResponse<Paths, T>,\n\t\t\t\t\tError,\n\t\t\t\t\tFilteredRequestConfig<Paths, T>\n\t\t\t\t>,\n\t\t\t\t'mutationFn'\n\t\t\t>,\n\t\t) => {\n\t\t\tconst memoizedOptions = useMemo(\n\t\t\t\t() => ({\n\t\t\t\t\tmutationFn: (config: FilteredRequestConfig<Paths, T>) =>\n\t\t\t\t\t\t// Type assertion needed due to complex conditional types\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\tfetcher as (\n\t\t\t\t\t\t\t\tendpoint: T,\n\t\t\t\t\t\t\t\tconfig?: unknown,\n\t\t\t\t\t\t\t) => Promise<ExtractEndpointResponse<Paths, T>>\n\t\t\t\t\t\t)(endpoint, config),\n\t\t\t\t\t...mutationOptions,\n\t\t\t\t}),\n\t\t\t\t[endpoint, fetcher, mutationOptions],\n\t\t\t);\n\n\t\t\treturn useMutation<\n\t\t\t\tExtractEndpointResponse<Paths, T>,\n\t\t\t\tError,\n\t\t\t\tFilteredRequestConfig<Paths, T>\n\t\t\t>(memoizedOptions);\n\t\t},\n\n\t\tbuildQueryKey,\n\t};\n}\n"],"mappings":";;;;;;;AAmBA,SAAS,cACRA,UACAC,QACY;CACZ,MAAMC,MAAiB,CAAC,QAAS;AAEjC,KAAI,UAAU,YAAY,UAAU,OAAO,OAC1C,KAAI,KAAK,EAAE,QAAQ,OAAO,OAAQ,EAAC;AAGpC,KAAI,UAAU,WAAW,UAAU,OAAO,MACzC,KAAI,KAAK,EAAE,OAAO,OAAO,MAAO,EAAC;AAGlC,QAAO;AACP;;;;;;;;;;;;;;;;AA0FD,SAAgB,oBACfC,SACAC,WAAuC,CAAE,GAClB;AACvB,QAAO;EACN,UAAU,CACTJ,UACA,GAAG,SACC;GAEJ,MAAM,CAAC,QAAQ,aAAa,GAAG;GAW/B,MAAM,WAAW,cAAc,UAAU,OAAO;GAEhD,MAAM,kBAAkB,QACvB,OAAO;IACN;IACA,SAAS,MAER,AACC,QAIC,UAAU,OAAO;IACpB,GAAG;GACH,IACD;IAAC;IAAU;IAAQ;IAAS;IAAU;GAAa,EACnD;AAED,UAAO,SACN,gBACA;EACD;EAED,aAAa,CACZA,UACAK,oBAQI;GACJ,MAAM,kBAAkB,QACvB,OAAO;IACN,YAAY,CAACC,WAEZ,AACC,QAIC,UAAU,OAAO;IACpB,GAAG;GACH,IACD;IAAC;IAAU;IAAS;GAAgB,EACpC;AAED,UAAO,YAIL,gBAAgB;EAClB;EAED;CACA;AACD"}
1
+ {"version":3,"file":"endpoint-hooks.mjs","names":["endpoint: T","config?: FilteredRequestConfig<Paths, T>","key: unknown[]","fetcher: TypedApiFunction<Paths>","_options: CreateEndpointHooksOptions","mutationOptions?: Omit<\n\t\t\t\tUseMutationOptions<\n\t\t\t\t\tExtractEndpointResponse<Paths, T>,\n\t\t\t\t\tError,\n\t\t\t\t\tFilteredRequestConfig<Paths, T>\n\t\t\t\t>,\n\t\t\t\t'mutationFn'\n\t\t\t>","config: FilteredRequestConfig<Paths, T>"],"sources":["../src/endpoint-hooks.ts"],"sourcesContent":["import type {\n\tQueryClient,\n\tUseMutationOptions,\n\tUseMutationResult,\n\tUseQueryOptions,\n\tUseQueryResult,\n} from '@tanstack/react-query';\nimport { useMutation, useQuery } from '@tanstack/react-query';\nimport { useMemo } from 'react';\nimport type {\n\tExtractEndpointResponse,\n\tFilteredRequestConfig,\n\tIsConfigRequired,\n\tMutationEndpoint,\n\tQueryEndpoint,\n\tTypedApiFunction,\n} from './types';\n\n/**\n * Build query key from endpoint and config\n */\nfunction buildQueryKey<Paths, T extends QueryEndpoint<Paths>>(\n\tendpoint: T,\n\tconfig?: FilteredRequestConfig<Paths, T>,\n): unknown[] {\n\tconst key: unknown[] = [endpoint];\n\n\tif (config && 'params' in config && config.params) {\n\t\tkey.push({ params: config.params });\n\t}\n\n\tif (config && 'query' in config && config.query) {\n\t\tkey.push({ query: config.query });\n\t}\n\n\treturn key;\n}\n\n/**\n * Options for creating endpoint-based hooks\n */\nexport interface CreateEndpointHooksOptions {\n\tqueryClient?: QueryClient;\n}\n\n/**\n * Hook options type that conditionally requires config\n */\ntype UseQueryArgs<Paths, T extends QueryEndpoint<Paths>> = IsConfigRequired<\n\tPaths,\n\tT\n> extends true\n\t? [\n\t\t\tconfig: FilteredRequestConfig<Paths, T>,\n\t\t\toptions?: Omit<\n\t\t\t\tUseQueryOptions<ExtractEndpointResponse<Paths, T>, Error>,\n\t\t\t\t'queryKey' | 'queryFn'\n\t\t\t>,\n\t\t]\n\t: [\n\t\t\tconfig?: FilteredRequestConfig<Paths, T>,\n\t\t\toptions?: Omit<\n\t\t\t\tUseQueryOptions<ExtractEndpointResponse<Paths, T>, Error>,\n\t\t\t\t'queryKey' | 'queryFn'\n\t\t\t>,\n\t\t];\n\n/**\n * Endpoint-based React Query hooks\n */\nexport interface EndpointHooks<Paths> {\n\t/**\n\t * Use query hook for GET endpoints.\n\t * Config is required when endpoint has path params.\n\t */\n\tuseQuery: <T extends QueryEndpoint<Paths>>(\n\t\tendpoint: T,\n\t\t...args: UseQueryArgs<Paths, T>\n\t) => UseQueryResult<ExtractEndpointResponse<Paths, T>, Error>;\n\n\t/**\n\t * Use mutation hook for POST, PUT, PATCH, DELETE endpoints.\n\t * Config with params/body is passed to mutate().\n\t */\n\tuseMutation: <T extends MutationEndpoint<Paths>>(\n\t\tendpoint: T,\n\t\toptions?: Omit<\n\t\t\tUseMutationOptions<\n\t\t\t\tExtractEndpointResponse<Paths, T>,\n\t\t\t\tError,\n\t\t\t\tFilteredRequestConfig<Paths, T>\n\t\t\t>,\n\t\t\t'mutationFn'\n\t\t>,\n\t) => UseMutationResult<\n\t\tExtractEndpointResponse<Paths, T>,\n\t\tError,\n\t\tFilteredRequestConfig<Paths, T>\n\t>;\n\n\t/**\n\t * Build a query key for manual cache operations\n\t */\n\tbuildQueryKey: <T extends QueryEndpoint<Paths>>(\n\t\tendpoint: T,\n\t\tconfig?: FilteredRequestConfig<Paths, T>,\n\t) => unknown[];\n}\n\n/**\n * Create endpoint-based React Query hooks from a typed fetcher.\n *\n * @example\n * ```typescript\n * const fetcher = createAuthAwareFetcher<paths>({ ... });\n * const hooks = createEndpointHooks<paths>(fetcher);\n *\n * // In a component\n * const { data } = hooks.useQuery('GET /users/{id}', { params: { id: '123' } });\n *\n * const mutation = hooks.useMutation('POST /users');\n * await mutation.mutateAsync({ body: { name: 'John' } });\n * ```\n */\nexport function createEndpointHooks<Paths>(\n\tfetcher: TypedApiFunction<Paths>,\n\t_options: CreateEndpointHooksOptions = {},\n): EndpointHooks<Paths> {\n\treturn {\n\t\tuseQuery: <T extends QueryEndpoint<Paths>>(\n\t\t\tendpoint: T,\n\t\t\t...args: UseQueryArgs<Paths, T>\n\t\t) => {\n\t\t\t// Parse args - config is first, options is second\n\t\t\tconst [config, queryOptions] = args as [\n\t\t\t\tFilteredRequestConfig<Paths, T> | undefined,\n\t\t\t\t(\n\t\t\t\t\t| Omit<\n\t\t\t\t\t\t\tUseQueryOptions<ExtractEndpointResponse<Paths, T>, Error>,\n\t\t\t\t\t\t\t'queryKey' | 'queryFn'\n\t\t\t\t\t >\n\t\t\t\t\t| undefined\n\t\t\t\t),\n\t\t\t];\n\n\t\t\tconst queryKey = buildQueryKey(endpoint, config);\n\n\t\t\tconst memoizedOptions = useMemo(\n\t\t\t\t() => ({\n\t\t\t\t\tqueryKey,\n\t\t\t\t\tqueryFn: () =>\n\t\t\t\t\t\t// Type assertion needed due to complex conditional types\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\tfetcher as (\n\t\t\t\t\t\t\t\tendpoint: T,\n\t\t\t\t\t\t\t\tconfig?: unknown,\n\t\t\t\t\t\t\t) => Promise<ExtractEndpointResponse<Paths, T>>\n\t\t\t\t\t\t)(endpoint, config),\n\t\t\t\t\t...queryOptions,\n\t\t\t\t}),\n\t\t\t\t[endpoint, config, fetcher, queryKey, queryOptions],\n\t\t\t);\n\n\t\t\treturn useQuery<ExtractEndpointResponse<Paths, T>, Error>(\n\t\t\t\tmemoizedOptions,\n\t\t\t);\n\t\t},\n\n\t\tuseMutation: <T extends MutationEndpoint<Paths>>(\n\t\t\tendpoint: T,\n\t\t\tmutationOptions?: Omit<\n\t\t\t\tUseMutationOptions<\n\t\t\t\t\tExtractEndpointResponse<Paths, T>,\n\t\t\t\t\tError,\n\t\t\t\t\tFilteredRequestConfig<Paths, T>\n\t\t\t\t>,\n\t\t\t\t'mutationFn'\n\t\t\t>,\n\t\t) => {\n\t\t\tconst memoizedOptions = useMemo(\n\t\t\t\t() => ({\n\t\t\t\t\tmutationFn: (config: FilteredRequestConfig<Paths, T>) =>\n\t\t\t\t\t\t// Type assertion needed due to complex conditional types\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\tfetcher as (\n\t\t\t\t\t\t\t\tendpoint: T,\n\t\t\t\t\t\t\t\tconfig?: unknown,\n\t\t\t\t\t\t\t) => Promise<ExtractEndpointResponse<Paths, T>>\n\t\t\t\t\t\t)(endpoint, config),\n\t\t\t\t\t...mutationOptions,\n\t\t\t\t}),\n\t\t\t\t[endpoint, fetcher, mutationOptions],\n\t\t\t);\n\n\t\t\treturn useMutation<\n\t\t\t\tExtractEndpointResponse<Paths, T>,\n\t\t\t\tError,\n\t\t\t\tFilteredRequestConfig<Paths, T>\n\t\t\t>(memoizedOptions);\n\t\t},\n\n\t\tbuildQueryKey,\n\t};\n}\n"],"mappings":";;;;;;;AAqBA,SAAS,cACRA,UACAC,QACY;CACZ,MAAMC,MAAiB,CAAC,QAAS;AAEjC,KAAI,UAAU,YAAY,UAAU,OAAO,OAC1C,KAAI,KAAK,EAAE,QAAQ,OAAO,OAAQ,EAAC;AAGpC,KAAI,UAAU,WAAW,UAAU,OAAO,MACzC,KAAI,KAAK,EAAE,OAAO,OAAO,MAAO,EAAC;AAGlC,QAAO;AACP;;;;;;;;;;;;;;;;AAwFD,SAAgB,oBACfC,SACAC,WAAuC,CAAE,GAClB;AACvB,QAAO;EACN,UAAU,CACTJ,UACA,GAAG,SACC;GAEJ,MAAM,CAAC,QAAQ,aAAa,GAAG;GAW/B,MAAM,WAAW,cAAc,UAAU,OAAO;GAEhD,MAAM,kBAAkB,QACvB,OAAO;IACN;IACA,SAAS,MAER,AACC,QAIC,UAAU,OAAO;IACpB,GAAG;GACH,IACD;IAAC;IAAU;IAAQ;IAAS;IAAU;GAAa,EACnD;AAED,UAAO,SACN,gBACA;EACD;EAED,aAAa,CACZA,UACAK,oBAQI;GACJ,MAAM,kBAAkB,QACvB,OAAO;IACN,YAAY,CAACC,WAEZ,AACC,QAIC,UAAU,OAAO;IACpB,GAAG;GACH,IACD;IAAC;IAAU;IAAS;GAAgB,EACpC;AAED,UAAO,YAIL,gBAAgB;EAClB;EAED;CACA;AACD"}
@@ -1,3 +1,5 @@
1
+ const require_chunk = require('./chunk-CUT6urMc.cjs');
2
+ const qs = require_chunk.__toESM(require("qs"));
1
3
 
2
4
  //#region src/fetcher.ts
3
5
  var TypedFetcher = class TypedFetcher {
@@ -24,21 +26,11 @@ var TypedFetcher = class TypedFetcher {
24
26
  url = url.replace(`{${key}}`, encodeURIComponent(String(value)));
25
27
  });
26
28
  if (config && "query" in config && config.query) {
27
- const queryParams = new URLSearchParams();
28
- const appendQueryParam = (prefix, value) => {
29
- if (value === void 0 || value === null) return;
30
- if (Array.isArray(value)) value.forEach((item) => {
31
- queryParams.append(prefix, String(item));
32
- });
33
- else if (typeof value === "object") Object.entries(value).forEach(([subKey, subValue]) => {
34
- appendQueryParam(`${prefix}.${subKey}`, subValue);
35
- });
36
- else queryParams.append(prefix, String(value));
37
- };
38
- Object.entries(config.query).forEach(([key, value]) => {
39
- appendQueryParam(key, value);
29
+ const queryString = qs.default.stringify(config.query, {
30
+ encode: true,
31
+ arrayFormat: "brackets",
32
+ skipNulls: true
40
33
  });
41
- const queryString = queryParams.toString();
42
34
  if (queryString) url += `?${queryString}`;
43
35
  }
44
36
  let requestConfig = {
@@ -95,4 +87,4 @@ Object.defineProperty(exports, 'createTypedFetcher', {
95
87
  return createTypedFetcher;
96
88
  }
97
89
  });
98
- //# sourceMappingURL=fetcher-CgLEaIAC.cjs.map
90
+ //# sourceMappingURL=fetcher-BG3q_AKO.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetcher-BG3q_AKO.cjs","names":["fn?: FetchFn","options: FetcherOptions","endpoint: T","config?: FilteredRequestConfig<Paths, T>","requestConfig: RequestInit","options?: FetcherOptions"],"sources":["../src/fetcher.ts"],"sourcesContent":["import qs from 'qs';\nimport type {\n\tEndpointString,\n\tExtractEndpointResponse,\n\tFetcherOptions,\n\tFilteredRequestConfig,\n\tParseEndpoint,\n\tTypedEndpoint,\n} from './types';\n\nexport type { FetcherOptions } from './types';\n\nexport class TypedFetcher<Paths> {\n\tprivate baseURL: string;\n\tprivate defaultHeaders: Record<string, string>;\n\tprivate options: FetcherOptions;\n\tprivate fetchFn: FetchFn;\n\n\tstatic getFetchFn(fn?: FetchFn): FetchFn {\n\t\tif (fn) {\n\t\t\treturn fn;\n\t\t}\n\n\t\tif (typeof window !== 'undefined' && typeof window.fetch === 'function') {\n\t\t\treturn window.fetch.bind(window);\n\t\t}\n\n\t\tif (\n\t\t\ttypeof globalThis !== 'undefined' &&\n\t\t\ttypeof globalThis.fetch === 'function'\n\t\t) {\n\t\t\treturn globalThis.fetch.bind(globalThis);\n\t\t}\n\n\t\tthrow new Error('No fetch implementation found');\n\t}\n\n\tconstructor(options: FetcherOptions = {}) {\n\t\tthis.baseURL = options.baseURL || '';\n\t\tthis.defaultHeaders = options.headers || {};\n\t\tthis.options = options;\n\t\tthis.fetchFn = TypedFetcher.getFetchFn(options.fetch);\n\t}\n\n\tasync request<T extends TypedEndpoint<Paths>>(\n\t\tendpoint: T,\n\t\tconfig?: FilteredRequestConfig<Paths, T>,\n\t): Promise<ExtractEndpointResponse<Paths, T>> {\n\t\tconst { method, route } = this.parseEndpoint(endpoint);\n\n\t\t// Replace path parameters\n\t\tlet url = route;\n\t\tif (config && 'params' in config && config.params) {\n\t\t\tObject.entries(config.params as Record<string, unknown>).forEach(\n\t\t\t\t([key, value]) => {\n\t\t\t\t\turl = url.replace(`{${key}}`, encodeURIComponent(String(value)));\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\t// Add query parameters\n\t\tif (config && 'query' in config && config.query) {\n\t\t\tconst queryString = qs.stringify(config.query, {\n\t\t\t\tencode: true,\n\t\t\t\tarrayFormat: 'brackets',\n\t\t\t\tskipNulls: true,\n\t\t\t});\n\t\t\tif (queryString) {\n\t\t\t\turl += `?${queryString}`;\n\t\t\t}\n\t\t}\n\n\t\t// Build request configuration\n\t\tlet requestConfig: RequestInit = {\n\t\t\tmethod: method.toUpperCase(),\n\t\t\theaders: {\n\t\t\t\t...this.defaultHeaders,\n\t\t\t\t...((config && 'headers' in config && config.headers) || {}),\n\t\t\t},\n\t\t};\n\n\t\t// Add body if present\n\t\tif (config && 'body' in config && config.body) {\n\t\t\trequestConfig.body = JSON.stringify(config.body);\n\t\t\trequestConfig.headers = {\n\t\t\t\t...requestConfig.headers,\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t};\n\t\t}\n\n\t\t// Apply request interceptor\n\t\tif (this.options.onRequest) {\n\t\t\trequestConfig = await this.options.onRequest(requestConfig);\n\t\t}\n\n\t\ttry {\n\t\t\t// Make the request\n\t\t\tlet response = await this.fetchFn(`${this.baseURL}${url}`, requestConfig);\n\n\t\t\t// Apply response interceptor\n\t\t\tif (this.options.onResponse) {\n\t\t\t\tresponse = await this.options.onResponse(response);\n\t\t\t}\n\n\t\t\t// Handle errors\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow response;\n\t\t\t}\n\n\t\t\t// Handle empty responses (204 No Content, etc.)\n\t\t\tif (\n\t\t\t\tresponse.status === 204 ||\n\t\t\t\tresponse.headers.get('content-length') === '0'\n\t\t\t) {\n\t\t\t\treturn undefined as ExtractEndpointResponse<Paths, T>;\n\t\t\t}\n\n\t\t\t// Parse JSON response\n\t\t\tconst data = await response.json();\n\t\t\treturn data as ExtractEndpointResponse<Paths, T>;\n\t\t} catch (error) {\n\t\t\t// Apply error handler\n\t\t\tif (this.options.onError) {\n\t\t\t\t// @ts-expect-error\n\t\t\t\tawait this.options.onError(error);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprivate parseEndpoint<T extends EndpointString>(\n\t\tendpoint: T,\n\t): ParseEndpoint<T> {\n\t\tconst [method, ...routeParts] = endpoint.split(' ');\n\t\tconst route = routeParts.join(' ');\n\t\treturn { method: method?.toLowerCase() ?? '', route } as ParseEndpoint<T>;\n\t}\n}\n\nexport function createTypedFetcher<Paths>(options?: FetcherOptions) {\n\tconst fetcher = new TypedFetcher<Paths>(options);\n\treturn <T extends TypedEndpoint<Paths>>(\n\t\tendpoint: T,\n\t\tconfig?: FilteredRequestConfig<Paths, T>,\n\t) => fetcher.request(endpoint, config);\n}\n\nexport type FetchFn = typeof fetch;\n"],"mappings":";;;;AAYA,IAAa,eAAb,MAAa,aAAoB;CAChC,AAAQ;CACR,AAAQ;CACR,AAAQ;CACR,AAAQ;CAER,OAAO,WAAWA,IAAuB;AACxC,MAAI,GACH,QAAO;AAGR,aAAW,WAAW,sBAAsB,OAAO,UAAU,WAC5D,QAAO,OAAO,MAAM,KAAK,OAAO;AAGjC,aACQ,eAAe,sBACf,WAAW,UAAU,WAE5B,QAAO,WAAW,MAAM,KAAK,WAAW;AAGzC,QAAM,IAAI,MAAM;CAChB;CAED,YAAYC,UAA0B,CAAE,GAAE;AACzC,OAAK,UAAU,QAAQ,WAAW;AAClC,OAAK,iBAAiB,QAAQ,WAAW,CAAE;AAC3C,OAAK,UAAU;AACf,OAAK,UAAU,aAAa,WAAW,QAAQ,MAAM;CACrD;CAED,MAAM,QACLC,UACAC,QAC6C;EAC7C,MAAM,EAAE,QAAQ,OAAO,GAAG,KAAK,cAAc,SAAS;EAGtD,IAAI,MAAM;AACV,MAAI,UAAU,YAAY,UAAU,OAAO,OAC1C,QAAO,QAAQ,OAAO,OAAkC,CAAC,QACxD,CAAC,CAAC,KAAK,MAAM,KAAK;AACjB,SAAM,IAAI,SAAS,GAAG,IAAI,IAAI,mBAAmB,OAAO,MAAM,CAAC,CAAC;EAChE,EACD;AAIF,MAAI,UAAU,WAAW,UAAU,OAAO,OAAO;GAChD,MAAM,cAAc,WAAG,UAAU,OAAO,OAAO;IAC9C,QAAQ;IACR,aAAa;IACb,WAAW;GACX,EAAC;AACF,OAAI,YACH,SAAQ,GAAG,YAAY;EAExB;EAGD,IAAIC,gBAA6B;GAChC,QAAQ,OAAO,aAAa;GAC5B,SAAS;IACR,GAAG,KAAK;IACR,GAAK,UAAU,aAAa,UAAU,OAAO,WAAY,CAAE;GAC3D;EACD;AAGD,MAAI,UAAU,UAAU,UAAU,OAAO,MAAM;AAC9C,iBAAc,OAAO,KAAK,UAAU,OAAO,KAAK;AAChD,iBAAc,UAAU;IACvB,GAAG,cAAc;IACjB,gBAAgB;GAChB;EACD;AAGD,MAAI,KAAK,QAAQ,UAChB,iBAAgB,MAAM,KAAK,QAAQ,UAAU,cAAc;AAG5D,MAAI;GAEH,IAAI,WAAW,MAAM,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,IAAI,GAAG,cAAc;AAGzE,OAAI,KAAK,QAAQ,WAChB,YAAW,MAAM,KAAK,QAAQ,WAAW,SAAS;AAInD,QAAK,SAAS,GACb,OAAM;AAIP,OACC,SAAS,WAAW,OACpB,SAAS,QAAQ,IAAI,iBAAiB,KAAK,IAE3C;GAID,MAAM,OAAO,MAAM,SAAS,MAAM;AAClC,UAAO;EACP,SAAQ,OAAO;AAEf,OAAI,KAAK,QAAQ,QAEhB,OAAM,KAAK,QAAQ,QAAQ,MAAM;AAElC,SAAM;EACN;CACD;CAED,AAAQ,cACPF,UACmB;EACnB,MAAM,CAAC,QAAQ,GAAG,WAAW,GAAG,SAAS,MAAM,IAAI;EACnD,MAAM,QAAQ,WAAW,KAAK,IAAI;AAClC,SAAO;GAAE,QAAQ,QAAQ,aAAa,IAAI;GAAI;EAAO;CACrD;AACD;AAED,SAAgB,mBAA0BG,SAA0B;CACnE,MAAM,UAAU,IAAI,aAAoB;AACxC,QAAO,CACNH,UACAC,WACI,QAAQ,QAAQ,UAAU,OAAO;AACtC"}
@@ -1,3 +1,5 @@
1
+ import qs from "qs";
2
+
1
3
  //#region src/fetcher.ts
2
4
  var TypedFetcher = class TypedFetcher {
3
5
  baseURL;
@@ -23,21 +25,11 @@ var TypedFetcher = class TypedFetcher {
23
25
  url = url.replace(`{${key}}`, encodeURIComponent(String(value)));
24
26
  });
25
27
  if (config && "query" in config && config.query) {
26
- const queryParams = new URLSearchParams();
27
- const appendQueryParam = (prefix, value) => {
28
- if (value === void 0 || value === null) return;
29
- if (Array.isArray(value)) value.forEach((item) => {
30
- queryParams.append(prefix, String(item));
31
- });
32
- else if (typeof value === "object") Object.entries(value).forEach(([subKey, subValue]) => {
33
- appendQueryParam(`${prefix}.${subKey}`, subValue);
34
- });
35
- else queryParams.append(prefix, String(value));
36
- };
37
- Object.entries(config.query).forEach(([key, value]) => {
38
- appendQueryParam(key, value);
28
+ const queryString = qs.stringify(config.query, {
29
+ encode: true,
30
+ arrayFormat: "brackets",
31
+ skipNulls: true
39
32
  });
40
- const queryString = queryParams.toString();
41
33
  if (queryString) url += `?${queryString}`;
42
34
  }
43
35
  let requestConfig = {
@@ -83,4 +75,4 @@ function createTypedFetcher(options) {
83
75
 
84
76
  //#endregion
85
77
  export { TypedFetcher, createTypedFetcher };
86
- //# sourceMappingURL=fetcher-5fnBE7Dk.mjs.map
78
+ //# sourceMappingURL=fetcher-DSSmqcRW.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetcher-DSSmqcRW.mjs","names":["fn?: FetchFn","options: FetcherOptions","endpoint: T","config?: FilteredRequestConfig<Paths, T>","requestConfig: RequestInit","options?: FetcherOptions"],"sources":["../src/fetcher.ts"],"sourcesContent":["import qs from 'qs';\nimport type {\n\tEndpointString,\n\tExtractEndpointResponse,\n\tFetcherOptions,\n\tFilteredRequestConfig,\n\tParseEndpoint,\n\tTypedEndpoint,\n} from './types';\n\nexport type { FetcherOptions } from './types';\n\nexport class TypedFetcher<Paths> {\n\tprivate baseURL: string;\n\tprivate defaultHeaders: Record<string, string>;\n\tprivate options: FetcherOptions;\n\tprivate fetchFn: FetchFn;\n\n\tstatic getFetchFn(fn?: FetchFn): FetchFn {\n\t\tif (fn) {\n\t\t\treturn fn;\n\t\t}\n\n\t\tif (typeof window !== 'undefined' && typeof window.fetch === 'function') {\n\t\t\treturn window.fetch.bind(window);\n\t\t}\n\n\t\tif (\n\t\t\ttypeof globalThis !== 'undefined' &&\n\t\t\ttypeof globalThis.fetch === 'function'\n\t\t) {\n\t\t\treturn globalThis.fetch.bind(globalThis);\n\t\t}\n\n\t\tthrow new Error('No fetch implementation found');\n\t}\n\n\tconstructor(options: FetcherOptions = {}) {\n\t\tthis.baseURL = options.baseURL || '';\n\t\tthis.defaultHeaders = options.headers || {};\n\t\tthis.options = options;\n\t\tthis.fetchFn = TypedFetcher.getFetchFn(options.fetch);\n\t}\n\n\tasync request<T extends TypedEndpoint<Paths>>(\n\t\tendpoint: T,\n\t\tconfig?: FilteredRequestConfig<Paths, T>,\n\t): Promise<ExtractEndpointResponse<Paths, T>> {\n\t\tconst { method, route } = this.parseEndpoint(endpoint);\n\n\t\t// Replace path parameters\n\t\tlet url = route;\n\t\tif (config && 'params' in config && config.params) {\n\t\t\tObject.entries(config.params as Record<string, unknown>).forEach(\n\t\t\t\t([key, value]) => {\n\t\t\t\t\turl = url.replace(`{${key}}`, encodeURIComponent(String(value)));\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\t// Add query parameters\n\t\tif (config && 'query' in config && config.query) {\n\t\t\tconst queryString = qs.stringify(config.query, {\n\t\t\t\tencode: true,\n\t\t\t\tarrayFormat: 'brackets',\n\t\t\t\tskipNulls: true,\n\t\t\t});\n\t\t\tif (queryString) {\n\t\t\t\turl += `?${queryString}`;\n\t\t\t}\n\t\t}\n\n\t\t// Build request configuration\n\t\tlet requestConfig: RequestInit = {\n\t\t\tmethod: method.toUpperCase(),\n\t\t\theaders: {\n\t\t\t\t...this.defaultHeaders,\n\t\t\t\t...((config && 'headers' in config && config.headers) || {}),\n\t\t\t},\n\t\t};\n\n\t\t// Add body if present\n\t\tif (config && 'body' in config && config.body) {\n\t\t\trequestConfig.body = JSON.stringify(config.body);\n\t\t\trequestConfig.headers = {\n\t\t\t\t...requestConfig.headers,\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t};\n\t\t}\n\n\t\t// Apply request interceptor\n\t\tif (this.options.onRequest) {\n\t\t\trequestConfig = await this.options.onRequest(requestConfig);\n\t\t}\n\n\t\ttry {\n\t\t\t// Make the request\n\t\t\tlet response = await this.fetchFn(`${this.baseURL}${url}`, requestConfig);\n\n\t\t\t// Apply response interceptor\n\t\t\tif (this.options.onResponse) {\n\t\t\t\tresponse = await this.options.onResponse(response);\n\t\t\t}\n\n\t\t\t// Handle errors\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow response;\n\t\t\t}\n\n\t\t\t// Handle empty responses (204 No Content, etc.)\n\t\t\tif (\n\t\t\t\tresponse.status === 204 ||\n\t\t\t\tresponse.headers.get('content-length') === '0'\n\t\t\t) {\n\t\t\t\treturn undefined as ExtractEndpointResponse<Paths, T>;\n\t\t\t}\n\n\t\t\t// Parse JSON response\n\t\t\tconst data = await response.json();\n\t\t\treturn data as ExtractEndpointResponse<Paths, T>;\n\t\t} catch (error) {\n\t\t\t// Apply error handler\n\t\t\tif (this.options.onError) {\n\t\t\t\t// @ts-expect-error\n\t\t\t\tawait this.options.onError(error);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprivate parseEndpoint<T extends EndpointString>(\n\t\tendpoint: T,\n\t): ParseEndpoint<T> {\n\t\tconst [method, ...routeParts] = endpoint.split(' ');\n\t\tconst route = routeParts.join(' ');\n\t\treturn { method: method?.toLowerCase() ?? '', route } as ParseEndpoint<T>;\n\t}\n}\n\nexport function createTypedFetcher<Paths>(options?: FetcherOptions) {\n\tconst fetcher = new TypedFetcher<Paths>(options);\n\treturn <T extends TypedEndpoint<Paths>>(\n\t\tendpoint: T,\n\t\tconfig?: FilteredRequestConfig<Paths, T>,\n\t) => fetcher.request(endpoint, config);\n}\n\nexport type FetchFn = typeof fetch;\n"],"mappings":";;;AAYA,IAAa,eAAb,MAAa,aAAoB;CAChC,AAAQ;CACR,AAAQ;CACR,AAAQ;CACR,AAAQ;CAER,OAAO,WAAWA,IAAuB;AACxC,MAAI,GACH,QAAO;AAGR,aAAW,WAAW,sBAAsB,OAAO,UAAU,WAC5D,QAAO,OAAO,MAAM,KAAK,OAAO;AAGjC,aACQ,eAAe,sBACf,WAAW,UAAU,WAE5B,QAAO,WAAW,MAAM,KAAK,WAAW;AAGzC,QAAM,IAAI,MAAM;CAChB;CAED,YAAYC,UAA0B,CAAE,GAAE;AACzC,OAAK,UAAU,QAAQ,WAAW;AAClC,OAAK,iBAAiB,QAAQ,WAAW,CAAE;AAC3C,OAAK,UAAU;AACf,OAAK,UAAU,aAAa,WAAW,QAAQ,MAAM;CACrD;CAED,MAAM,QACLC,UACAC,QAC6C;EAC7C,MAAM,EAAE,QAAQ,OAAO,GAAG,KAAK,cAAc,SAAS;EAGtD,IAAI,MAAM;AACV,MAAI,UAAU,YAAY,UAAU,OAAO,OAC1C,QAAO,QAAQ,OAAO,OAAkC,CAAC,QACxD,CAAC,CAAC,KAAK,MAAM,KAAK;AACjB,SAAM,IAAI,SAAS,GAAG,IAAI,IAAI,mBAAmB,OAAO,MAAM,CAAC,CAAC;EAChE,EACD;AAIF,MAAI,UAAU,WAAW,UAAU,OAAO,OAAO;GAChD,MAAM,cAAc,GAAG,UAAU,OAAO,OAAO;IAC9C,QAAQ;IACR,aAAa;IACb,WAAW;GACX,EAAC;AACF,OAAI,YACH,SAAQ,GAAG,YAAY;EAExB;EAGD,IAAIC,gBAA6B;GAChC,QAAQ,OAAO,aAAa;GAC5B,SAAS;IACR,GAAG,KAAK;IACR,GAAK,UAAU,aAAa,UAAU,OAAO,WAAY,CAAE;GAC3D;EACD;AAGD,MAAI,UAAU,UAAU,UAAU,OAAO,MAAM;AAC9C,iBAAc,OAAO,KAAK,UAAU,OAAO,KAAK;AAChD,iBAAc,UAAU;IACvB,GAAG,cAAc;IACjB,gBAAgB;GAChB;EACD;AAGD,MAAI,KAAK,QAAQ,UAChB,iBAAgB,MAAM,KAAK,QAAQ,UAAU,cAAc;AAG5D,MAAI;GAEH,IAAI,WAAW,MAAM,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,IAAI,GAAG,cAAc;AAGzE,OAAI,KAAK,QAAQ,WAChB,YAAW,MAAM,KAAK,QAAQ,WAAW,SAAS;AAInD,QAAK,SAAS,GACb,OAAM;AAIP,OACC,SAAS,WAAW,OACpB,SAAS,QAAQ,IAAI,iBAAiB,KAAK,IAE3C;GAID,MAAM,OAAO,MAAM,SAAS,MAAM;AAClC,UAAO;EACP,SAAQ,OAAO;AAEf,OAAI,KAAK,QAAQ,QAEhB,OAAM,KAAK,QAAQ,QAAQ,MAAM;AAElC,SAAM;EACN;CACD;CAED,AAAQ,cACPF,UACmB;EACnB,MAAM,CAAC,QAAQ,GAAG,WAAW,GAAG,SAAS,MAAM,IAAI;EACnD,MAAM,QAAQ,WAAW,KAAK,IAAI;AAClC,SAAO;GAAE,QAAQ,QAAQ,aAAa,IAAI;GAAI;EAAO;CACrD;AACD;AAED,SAAgB,mBAA0BG,SAA0B;CACnE,MAAM,UAAU,IAAI,aAAoB;AACxC,QAAO,CACNH,UACAC,WACI,QAAQ,QAAQ,UAAU,OAAO;AACtC"}
package/dist/fetcher.cjs CHANGED
@@ -1,4 +1,4 @@
1
- const require_fetcher = require('./fetcher-CgLEaIAC.cjs');
1
+ const require_fetcher = require('./fetcher-BG3q_AKO.cjs');
2
2
 
3
3
  exports.TypedFetcher = require_fetcher.TypedFetcher;
4
4
  exports.createTypedFetcher = require_fetcher.createTypedFetcher;
@@ -1 +1 @@
1
- {"version":3,"file":"fetcher.d.cts","names":[],"sources":["../src/fetcher.ts"],"sourcesContent":[],"mappings":";;;cAWa;EAAA,QAAA,OAAY;EAAA,QAAA,cAAA;EAAA,QAMD,OAAA;EAAO,QAAG,OAAA;EAAO,OAmBnB,UAAA,CAAA,EAAA,CAAA,EAnBE,OAmBF,CAAA,EAnBY,OAmBZ;EAAmB,WAOF,CAAA,OAAA,CAAA,EAPjB,cAOiB;EAAK,OAAnB,CAAA,UAAA,aAAA,CAAc,KAAd,CAAA,CAAA,CAAA,QAAA,EACb,CADa,EAAA,MAAA,CAAA,EAEd,qBAFc,CAEQ,KAFR,EAEe,CAFf,CAAA,CAAA,EAGrB,OAHqB,CAGb,uBAHa,CAGW,KAHX,EAGkB,CAHlB,CAAA,CAAA;EAAa,QAC1B,aAAA;;AAC4B,iBAyHxB,kBAzHwB,CAAA,KAAA,CAAA,CAAA,OAAA,CAAA,EAyHY,cAzHZ,CAAA,EAAA,CAAA,UA2HrB,aA3HqB,CA2HP,KA3HO,CAAA,CAAA,CAAA,QAAA,EA4H5B,CA5H4B,EAAA,MAAA,CAAA,EA6H7B,qBA7H6B,CA6HP,KA7HO,EA6HA,CA7HA,CAAA,EAAA,GA6HE,OA7HF,CA6HE,uBA7HF,CA6HE,KA7HF,EA6HE,CA7HF,CAAA,CAAA;AAA7B,KAiIC,OAAA,GAjID,OAiIkB,KAjIlB"}
1
+ {"version":3,"file":"fetcher.d.cts","names":[],"sources":["../src/fetcher.ts"],"sourcesContent":[],"mappings":";;;cAYa;EAAA,QAAA,OAAY;EAAA,QAAA,cAAA;EAAA,QAMD,OAAA;EAAO,QAAG,OAAA;EAAO,OAmBnB,UAAA,CAAA,EAAA,CAAA,EAnBE,OAmBF,CAAA,EAnBY,OAmBZ;EAAmB,WAOF,CAAA,OAAA,CAAA,EAPjB,cAOiB;EAAK,OAAnB,CAAA,UAAA,aAAA,CAAc,KAAd,CAAA,CAAA,CAAA,QAAA,EACb,CADa,EAAA,MAAA,CAAA,EAEd,qBAFc,CAEQ,KAFR,EAEe,CAFf,CAAA,CAAA,EAGrB,OAHqB,CAGb,uBAHa,CAGW,KAHX,EAGkB,CAHlB,CAAA,CAAA;EAAa,QAC1B,aAAA;;AAC4B,iBA6FxB,kBA7FwB,CAAA,KAAA,CAAA,CAAA,OAAA,CAAA,EA6FY,cA7FZ,CAAA,EAAA,CAAA,UA+FrB,aA/FqB,CA+FP,KA/FO,CAAA,CAAA,CAAA,QAAA,EAgG5B,CAhG4B,EAAA,MAAA,CAAA,EAiG7B,qBAjG6B,CAiGP,KAjGO,EAiGA,CAjGA,CAAA,EAAA,GAiGE,OAjGF,CAiGE,uBAjGF,CAiGE,KAjGF,EAiGE,CAjGF,CAAA,CAAA;AAA7B,KAqGC,OAAA,GArGD,OAqGkB,KArGlB"}
@@ -1 +1 @@
1
- {"version":3,"file":"fetcher.d.mts","names":[],"sources":["../src/fetcher.ts"],"sourcesContent":[],"mappings":";;;cAWa;EAAA,QAAA,OAAY;EAAA,QAAA,cAAA;EAAA,QAMD,OAAA;EAAO,QAAG,OAAA;EAAO,OAmBnB,UAAA,CAAA,EAAA,CAAA,EAnBE,OAmBF,CAAA,EAnBY,OAmBZ;EAAmB,WAOF,CAAA,OAAA,CAAA,EAPjB,cAOiB;EAAK,OAAnB,CAAA,UAAA,aAAA,CAAc,KAAd,CAAA,CAAA,CAAA,QAAA,EACb,CADa,EAAA,MAAA,CAAA,EAEd,qBAFc,CAEQ,KAFR,EAEe,CAFf,CAAA,CAAA,EAGrB,OAHqB,CAGb,uBAHa,CAGW,KAHX,EAGkB,CAHlB,CAAA,CAAA;EAAa,QAC1B,aAAA;;AAC4B,iBAyHxB,kBAzHwB,CAAA,KAAA,CAAA,CAAA,OAAA,CAAA,EAyHY,cAzHZ,CAAA,EAAA,CAAA,UA2HrB,aA3HqB,CA2HP,KA3HO,CAAA,CAAA,CAAA,QAAA,EA4H5B,CA5H4B,EAAA,MAAA,CAAA,EA6H7B,qBA7H6B,CA6HP,KA7HO,EA6HA,CA7HA,CAAA,EAAA,GA6HE,OA7HF,CA6HE,uBA7HF,CA6HE,KA7HF,EA6HE,CA7HF,CAAA,CAAA;AAA7B,KAiIC,OAAA,GAjID,OAiIkB,KAjIlB"}
1
+ {"version":3,"file":"fetcher.d.mts","names":[],"sources":["../src/fetcher.ts"],"sourcesContent":[],"mappings":";;;cAYa;EAAA,QAAA,OAAY;EAAA,QAAA,cAAA;EAAA,QAMD,OAAA;EAAO,QAAG,OAAA;EAAO,OAmBnB,UAAA,CAAA,EAAA,CAAA,EAnBE,OAmBF,CAAA,EAnBY,OAmBZ;EAAmB,WAOF,CAAA,OAAA,CAAA,EAPjB,cAOiB;EAAK,OAAnB,CAAA,UAAA,aAAA,CAAc,KAAd,CAAA,CAAA,CAAA,QAAA,EACb,CADa,EAAA,MAAA,CAAA,EAEd,qBAFc,CAEQ,KAFR,EAEe,CAFf,CAAA,CAAA,EAGrB,OAHqB,CAGb,uBAHa,CAGW,KAHX,EAGkB,CAHlB,CAAA,CAAA;EAAa,QAC1B,aAAA;;AAC4B,iBA6FxB,kBA7FwB,CAAA,KAAA,CAAA,CAAA,OAAA,CAAA,EA6FY,cA7FZ,CAAA,EAAA,CAAA,UA+FrB,aA/FqB,CA+FP,KA/FO,CAAA,CAAA,CAAA,QAAA,EAgG5B,CAhG4B,EAAA,MAAA,CAAA,EAiG7B,qBAjG6B,CAiGP,KAjGO,EAiGA,CAjGA,CAAA,EAAA,GAiGE,OAjGF,CAiGE,uBAjGF,CAiGE,KAjGF,EAiGE,CAjGF,CAAA,CAAA;AAA7B,KAqGC,OAAA,GArGD,OAqGkB,KArGlB"}
package/dist/fetcher.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { TypedFetcher, createTypedFetcher } from "./fetcher-5fnBE7Dk.mjs";
1
+ import { TypedFetcher, createTypedFetcher } from "./fetcher-DSSmqcRW.mjs";
2
2
 
3
3
  export { TypedFetcher, createTypedFetcher };
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require('./chunk-CUT6urMc.cjs');
2
- const require_fetcher = require('./fetcher-CgLEaIAC.cjs');
2
+ const require_fetcher = require('./fetcher-BG3q_AKO.cjs');
3
3
  const __tanstack_react_query = require_chunk.__toESM(require("@tanstack/react-query"));
4
4
 
5
5
  //#region src/openapi-hooks.ts
@@ -1,5 +1,5 @@
1
1
  import { FetcherOptions } from "./types-4K4N-Fl1.cjs";
2
- import * as _tanstack_react_query0 from "@tanstack/react-query";
2
+ import * as _tanstack_react_query8 from "@tanstack/react-query";
3
3
  import { UseMutationOptions, UseQueryOptions } from "@tanstack/react-query";
4
4
 
5
5
  //#region src/openapi-hooks.d.ts
@@ -91,8 +91,8 @@ interface OperationRegistry {
91
91
  declare function createOpenAPIHooks<Paths>(options?: FetcherOptions & {
92
92
  operations?: OperationRegistry;
93
93
  }): {
94
- useQuery: <OpId extends OperationsByMethod<Paths, "get">>(operationId: OpId, config?: RemoveNever<OperationParams<Paths, OpId>>, options?: Omit<UseQueryOptions<OperationResponse<Paths, OpId>, Error>, "queryKey" | "queryFn">) => _tanstack_react_query0.UseQueryResult<_tanstack_react_query0.NoInfer<OperationResponse<Paths, OpId>>, Error>;
95
- useMutation: <OpId extends Exclude<OperationId<Paths>, OperationsByMethod<Paths, "get">>>(operationId: OpId, options?: Omit<UseMutationOptions<OperationResponse<Paths, OpId>, Error, RemoveNever<OperationParams<Paths, OpId>>>, "mutationFn">) => _tanstack_react_query0.UseMutationResult<OperationResponse<Paths, OpId>, Error, RemoveNever<OperationParams<Paths, OpId>>, unknown>;
94
+ useQuery: <OpId extends OperationsByMethod<Paths, "get">>(operationId: OpId, config?: RemoveNever<OperationParams<Paths, OpId>>, options?: Omit<UseQueryOptions<OperationResponse<Paths, OpId>, Error>, "queryKey" | "queryFn">) => _tanstack_react_query8.UseQueryResult<_tanstack_react_query8.NoInfer<OperationResponse<Paths, OpId>>, Error>;
95
+ useMutation: <OpId extends Exclude<OperationId<Paths>, OperationsByMethod<Paths, "get">>>(operationId: OpId, options?: Omit<UseMutationOptions<OperationResponse<Paths, OpId>, Error, RemoveNever<OperationParams<Paths, OpId>>>, "mutationFn">) => _tanstack_react_query8.UseMutationResult<OperationResponse<Paths, OpId>, Error, RemoveNever<OperationParams<Paths, OpId>>, unknown>;
96
96
  };
97
97
  //#endregion
98
98
  export { createOpenAPIHooks };
@@ -1,4 +1,4 @@
1
- import { createTypedFetcher } from "./fetcher-5fnBE7Dk.mjs";
1
+ import { createTypedFetcher } from "./fetcher-DSSmqcRW.mjs";
2
2
  import { useMutation, useQuery } from "@tanstack/react-query";
3
3
 
4
4
  //#region src/openapi-hooks.ts
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require('./chunk-CUT6urMc.cjs');
2
- const require_fetcher = require('./fetcher-CgLEaIAC.cjs');
2
+ const require_fetcher = require('./fetcher-BG3q_AKO.cjs');
3
3
  const __tanstack_react_query = require_chunk.__toESM(require("@tanstack/react-query"));
4
4
  const react = require_chunk.__toESM(require("react"));
5
5
 
@@ -1,5 +1,5 @@
1
1
  import { ExtractEndpointResponse, FetcherOptions, FilteredRequestConfig, MutationEndpoint, QueryEndpoint, TypedEndpoint } from "./types-4K4N-Fl1.cjs";
2
- import * as _tanstack_react_query3 from "@tanstack/react-query";
2
+ import * as _tanstack_react_query0 from "@tanstack/react-query";
3
3
  import { QueryClient, UseInfiniteQueryOptions, UseMutationOptions, UseQueryOptions } from "@tanstack/react-query";
4
4
 
5
5
  //#region src/react-query.d.ts
@@ -10,15 +10,15 @@ declare class TypedQueryClient<Paths> {
10
10
  private fetcher;
11
11
  private queryClient?;
12
12
  constructor(options?: TypedQueryClientOptions);
13
- useQuery<T extends QueryEndpoint<Paths>>(endpoint: T, config?: FilteredRequestConfig<Paths, T>, options?: Omit<UseQueryOptions<ExtractEndpointResponse<Paths, T>, Response>, 'queryKey' | 'queryFn'>): _tanstack_react_query3.UseQueryResult<_tanstack_react_query3.NoInfer<ExtractEndpointResponse<Paths, T>>, Response>;
14
- useMutation<T extends MutationEndpoint<Paths>>(endpoint: T, options?: Omit<UseMutationOptions<ExtractEndpointResponse<Paths, T>, Response, FilteredRequestConfig<Paths, T>>, 'mutationFn'>): _tanstack_react_query3.UseMutationResult<ExtractEndpointResponse<Paths, T>, Response, FilteredRequestConfig<Paths, T>, unknown>;
13
+ useQuery<T extends QueryEndpoint<Paths>>(endpoint: T, config?: FilteredRequestConfig<Paths, T>, options?: Omit<UseQueryOptions<ExtractEndpointResponse<Paths, T>, Response>, 'queryKey' | 'queryFn'>): _tanstack_react_query0.UseQueryResult<_tanstack_react_query0.NoInfer<ExtractEndpointResponse<Paths, T>>, Response>;
14
+ useMutation<T extends MutationEndpoint<Paths>>(endpoint: T, options?: Omit<UseMutationOptions<ExtractEndpointResponse<Paths, T>, Response, FilteredRequestConfig<Paths, T>>, 'mutationFn'>): _tanstack_react_query0.UseMutationResult<ExtractEndpointResponse<Paths, T>, Response, FilteredRequestConfig<Paths, T>, unknown>;
15
15
  useInfiniteQuery<T extends QueryEndpoint<Paths>, TPageData = ExtractEndpointResponse<Paths, T>, TPageParam = unknown>(endpoint: T, options: Omit<UseInfiniteQueryOptions<TPageData, Response, {
16
16
  pages: TPageData[];
17
17
  pageParams: TPageParam[];
18
18
  }, unknown[], TPageParam>, 'queryKey' | 'queryFn' | 'getNextPageParam' | 'initialPageParam'> & {
19
19
  getNextPageParam: (lastPage: TPageData, allPages: TPageData[], lastPageParam: TPageParam, allPageParams: TPageParam[]) => TPageParam | undefined;
20
20
  initialPageParam: TPageParam;
21
- }, config?: FilteredRequestConfig<Paths, T>): _tanstack_react_query3.UseInfiniteQueryResult<{
21
+ }, config?: FilteredRequestConfig<Paths, T>): _tanstack_react_query0.UseInfiniteQueryResult<{
22
22
  pages: TPageData[];
23
23
  pageParams: TPageParam[];
24
24
  }, Response>;
@@ -47,15 +47,15 @@ declare class TypedQueryClient<Paths> {
47
47
  setQueryClient(queryClient: QueryClient): void;
48
48
  }
49
49
  declare function createTypedQueryClient<Paths>(options?: TypedQueryClientOptions): TypedQueryClient<Paths>;
50
- declare function useTypedQuery<Paths, T extends QueryEndpoint<Paths>>(client: TypedQueryClient<Paths>, endpoint: T, config?: FilteredRequestConfig<Paths, T>, options?: Omit<UseQueryOptions<ExtractEndpointResponse<Paths, T>, Response>, 'queryKey' | 'queryFn'>): _tanstack_react_query3.UseQueryResult<_tanstack_react_query3.NoInfer<ExtractEndpointResponse<Paths, T>>, Response>;
51
- declare function useTypedMutation<Paths, T extends MutationEndpoint<Paths>>(client: TypedQueryClient<Paths>, endpoint: T, options?: Omit<UseMutationOptions<ExtractEndpointResponse<Paths, T>, Response, FilteredRequestConfig<Paths, T>>, 'mutationFn'>): _tanstack_react_query3.UseMutationResult<ExtractEndpointResponse<Paths, T>, Response, FilteredRequestConfig<Paths, T>, unknown>;
50
+ declare function useTypedQuery<Paths, T extends QueryEndpoint<Paths>>(client: TypedQueryClient<Paths>, endpoint: T, config?: FilteredRequestConfig<Paths, T>, options?: Omit<UseQueryOptions<ExtractEndpointResponse<Paths, T>, Response>, 'queryKey' | 'queryFn'>): _tanstack_react_query0.UseQueryResult<_tanstack_react_query0.NoInfer<ExtractEndpointResponse<Paths, T>>, Response>;
51
+ declare function useTypedMutation<Paths, T extends MutationEndpoint<Paths>>(client: TypedQueryClient<Paths>, endpoint: T, options?: Omit<UseMutationOptions<ExtractEndpointResponse<Paths, T>, Response, FilteredRequestConfig<Paths, T>>, 'mutationFn'>): _tanstack_react_query0.UseMutationResult<ExtractEndpointResponse<Paths, T>, Response, FilteredRequestConfig<Paths, T>, unknown>;
52
52
  declare function useTypedInfiniteQuery<Paths, T extends QueryEndpoint<Paths>, TPageData = ExtractEndpointResponse<Paths, T>, TPageParam = unknown>(client: TypedQueryClient<Paths>, endpoint: T, options: Omit<UseInfiniteQueryOptions<TPageData, Response, {
53
53
  pages: TPageData[];
54
54
  pageParams: TPageParam[];
55
55
  }, unknown[], TPageParam>, 'queryKey' | 'queryFn' | 'getNextPageParam' | 'initialPageParam'> & {
56
56
  getNextPageParam: (lastPage: TPageData, allPages: TPageData[], lastPageParam: TPageParam, allPageParams: TPageParam[]) => TPageParam | undefined;
57
57
  initialPageParam: TPageParam;
58
- }, config?: FilteredRequestConfig<Paths, T>): _tanstack_react_query3.UseInfiniteQueryResult<{
58
+ }, config?: FilteredRequestConfig<Paths, T>): _tanstack_react_query0.UseInfiniteQueryResult<{
59
59
  pages: TPageData[];
60
60
  pageParams: TPageParam[];
61
61
  }, Response>;
@@ -1,4 +1,4 @@
1
- import { createTypedFetcher } from "./fetcher-5fnBE7Dk.mjs";
1
+ import { createTypedFetcher } from "./fetcher-DSSmqcRW.mjs";
2
2
  import { useInfiniteQuery, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
3
3
  import { useMemo } from "react";
4
4
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geekmidas/client",
3
- "version": "3.0.0",
3
+ "version": "4.0.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "exports": {
@@ -54,20 +54,22 @@
54
54
  "access": "public"
55
55
  },
56
56
  "dependencies": {
57
- "@standard-schema/spec": "^1.0.0"
57
+ "@standard-schema/spec": "^1.0.0",
58
+ "qs": "~6.15.0"
58
59
  },
59
60
  "devDependencies": {
60
61
  "@tanstack/react-query": "~5.90.16",
61
- "@testing-library/jest-dom": "~6.6.3",
62
62
  "@testing-library/dom": "~10.4.0",
63
+ "@testing-library/jest-dom": "~6.6.3",
63
64
  "@testing-library/react": "~16.3.0",
64
65
  "@testing-library/react-hooks": "~8.0.1",
66
+ "@types/qs": "~6.15.0",
65
67
  "@types/react": "~19.1.8",
66
68
  "@types/react-dom": "~19.1.6",
67
69
  "jsdom": "~26.1.0",
68
70
  "msw": "~2.10.3",
69
- "@geekmidas/schema": "^1.0.0",
70
- "@geekmidas/constructs": "^2.0.0"
71
+ "@geekmidas/constructs": "^3.0.3",
72
+ "@geekmidas/schema": "^1.0.0"
71
73
  },
72
74
  "peerDependencies": {
73
75
  "@tanstack/react-query": ">=5.0.0",
@@ -75,7 +77,7 @@
75
77
  "react-dom": ">=18.0.0",
76
78
  "zod": "~4.1.13",
77
79
  "@geekmidas/schema": "^1.0.0",
78
- "@geekmidas/constructs": "^2.0.0"
80
+ "@geekmidas/constructs": "^3.0.3"
79
81
  },
80
82
  "peerDependenciesMeta": {
81
83
  "@geekmidas/constructs": {
@@ -110,12 +110,12 @@ describe('TypedFetcher', () => {
110
110
  });
111
111
 
112
112
  expect(mockFetch).toHaveBeenCalledWith(
113
- 'https://api.example.com/search?tags=nodejs&tags=typescript&tags=javascript',
113
+ 'https://api.example.com/search?tags%5B%5D=nodejs&tags%5B%5D=typescript&tags%5B%5D=javascript',
114
114
  expect.any(Object),
115
115
  );
116
116
  });
117
117
 
118
- it('should handle object query parameters with dot notation', async () => {
118
+ it('should handle object query parameters with bracket notation', async () => {
119
119
  // Mock fetch to capture the request URL
120
120
  const mockFetch = vi.fn().mockResolvedValue({
121
121
  ok: true,
@@ -141,7 +141,7 @@ describe('TypedFetcher', () => {
141
141
  });
142
142
 
143
143
  expect(mockFetch).toHaveBeenCalledWith(
144
- 'https://api.example.com/products?filter.category=electronics&filter.minPrice=100&filter.maxPrice=500&sort=price',
144
+ 'https://api.example.com/products?filter%5Bcategory%5D=electronics&filter%5BminPrice%5D=100&filter%5BmaxPrice%5D=500&sort=price',
145
145
  expect.any(Object),
146
146
  );
147
147
  });
@@ -175,10 +175,26 @@ describe('TypedFetcher', () => {
175
175
  } as any,
176
176
  });
177
177
 
178
- expect(mockFetch).toHaveBeenCalledWith(
179
- 'https://api.example.com/advanced-search?user.roles=admin&user.roles=moderator&user.roles=user&user.status=active&settings.notifications.types=email&settings.notifications.types=sms&settings.notifications.types=push&settings.notifications.enabled=true',
180
- expect.any(Object),
181
- );
178
+ // qs uses bracket notation: user[roles][]=admin&user[status]=active etc.
179
+ const calledUrl = mockFetch.mock.calls[0][0] as string;
180
+ const url = new URL(calledUrl);
181
+ expect(url.pathname).toBe('/advanced-search');
182
+
183
+ // Verify the query string can be parsed back to the original object
184
+ const qs = await import('qs');
185
+ const parsed = qs.default.parse(url.search.slice(1));
186
+ expect(parsed).toEqual({
187
+ user: {
188
+ roles: ['admin', 'moderator', 'user'],
189
+ status: 'active',
190
+ },
191
+ settings: {
192
+ notifications: {
193
+ types: ['email', 'sms', 'push'],
194
+ enabled: 'true',
195
+ },
196
+ },
197
+ });
182
198
  });
183
199
 
184
200
  it('should handle 404 errors', async () => {
@@ -0,0 +1,343 @@
1
+ /**
2
+ * @vitest-environment jsdom
3
+ *
4
+ * Type inference test for mutation hooks with complex paths.
5
+ * This mirrors the structure generated by `gkm openapi` to verify
6
+ * that FilteredRequestConfig resolves correctly (not `never`).
7
+ */
8
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
9
+ import { renderHook, waitFor } from '@testing-library/react';
10
+ import { HttpResponse, http } from 'msw';
11
+ // biome-ignore lint/style/useImportType: needed for JSX
12
+ import React, { createElement } from 'react';
13
+ import { beforeEach, describe, expect, it } from 'vitest';
14
+ import { createEndpointHooks } from '../endpoint-hooks';
15
+ import type { TypedApiFunction } from '../types';
16
+ import { server } from './setup';
17
+
18
+ // ============================================================
19
+ // Paths that mirror a real generated openapi.ts structure
20
+ // ============================================================
21
+ interface GeneratedPaths {
22
+ '/account/profile': {
23
+ post: {
24
+ requestBody: {
25
+ content: {
26
+ 'application/json': { email: string; name: string };
27
+ };
28
+ };
29
+ responses: {
30
+ 200: {
31
+ content: {
32
+ 'application/json': Record<string, unknown>;
33
+ };
34
+ };
35
+ };
36
+ };
37
+ get: {
38
+ responses: {
39
+ 200: {
40
+ content: {
41
+ 'application/json': {
42
+ id: string;
43
+ email: string;
44
+ name: string;
45
+ } | null;
46
+ };
47
+ };
48
+ };
49
+ };
50
+ };
51
+ '/chats/{chatId}/participants': {
52
+ parameters: {
53
+ path: { chatId: string };
54
+ };
55
+ post: {
56
+ requestBody: {
57
+ content: {
58
+ 'application/json': { userId: string; role: 'Owner' | 'Member' };
59
+ };
60
+ };
61
+ responses: {
62
+ 200: {
63
+ content: {
64
+ 'application/json': {
65
+ id: string;
66
+ chatId: string;
67
+ userId: string;
68
+ role: string;
69
+ };
70
+ };
71
+ };
72
+ };
73
+ };
74
+ };
75
+ '/chats': {
76
+ post: {
77
+ requestBody: {
78
+ content: {
79
+ 'application/json': { type: string; name?: string };
80
+ };
81
+ };
82
+ responses: {
83
+ 200: {
84
+ content: {
85
+ 'application/json': { id: string; type: string; name: string };
86
+ };
87
+ };
88
+ };
89
+ };
90
+ get: {
91
+ parameters: {
92
+ query: { cursor?: string; limit: number };
93
+ };
94
+ responses: {
95
+ 200: {
96
+ content: {
97
+ 'application/json': {
98
+ data: Array<{ id: string; name: string }>;
99
+ hasMore: boolean;
100
+ };
101
+ };
102
+ };
103
+ };
104
+ };
105
+ };
106
+ '/chats/{id}': {
107
+ parameters: {
108
+ path: { id: string };
109
+ };
110
+ delete: {
111
+ responses: {
112
+ 200: {
113
+ content: {
114
+ 'application/json': { success: boolean };
115
+ };
116
+ };
117
+ };
118
+ };
119
+ get: {
120
+ responses: {
121
+ 200: {
122
+ content: {
123
+ 'application/json': { id: string; name: string };
124
+ };
125
+ };
126
+ };
127
+ };
128
+ patch: {
129
+ requestBody: {
130
+ content: {
131
+ 'application/json': { name?: string; status?: string };
132
+ };
133
+ };
134
+ responses: {
135
+ 200: {
136
+ content: {
137
+ 'application/json': { id: string; name: string; status: string };
138
+ };
139
+ };
140
+ };
141
+ };
142
+ };
143
+ '/chats/{chatId}/leave': {
144
+ parameters: {
145
+ path: { chatId: string };
146
+ };
147
+ post: {
148
+ responses: {
149
+ 200: {
150
+ content: {
151
+ 'application/json': { success: boolean };
152
+ };
153
+ };
154
+ };
155
+ };
156
+ };
157
+ }
158
+
159
+ // ============================================================
160
+ // Mock fetcher
161
+ // ============================================================
162
+ function createMockFetcher(): TypedApiFunction<GeneratedPaths> {
163
+ return async (endpoint: string, config?: any) => {
164
+ const [method, path] = endpoint.split(' ');
165
+ let url = `https://api.example.com${path}`;
166
+
167
+ if (config?.params) {
168
+ for (const [key, value] of Object.entries(config.params)) {
169
+ url = url.replace(`{${key}}`, value as string);
170
+ }
171
+ }
172
+
173
+ const response = await fetch(url, {
174
+ method,
175
+ headers: { 'Content-Type': 'application/json', ...config?.headers },
176
+ body: config?.body ? JSON.stringify(config.body) : undefined,
177
+ });
178
+
179
+ return response.json();
180
+ };
181
+ }
182
+
183
+ function createWrapper() {
184
+ const queryClient = new QueryClient({
185
+ defaultOptions: { queries: { retry: false } },
186
+ });
187
+ return ({ children }: { children: React.ReactNode }) =>
188
+ createElement(QueryClientProvider, { client: queryClient }, children);
189
+ }
190
+
191
+ // ============================================================
192
+ // Tests
193
+ // ============================================================
194
+ describe('mutation type inference with generated paths', () => {
195
+ beforeEach(() => {
196
+ server.use(
197
+ http.post(
198
+ 'https://api.example.com/account/profile',
199
+ async ({ request }) => {
200
+ const body = (await request.json()) as any;
201
+ return HttpResponse.json({ id: '1', ...body });
202
+ },
203
+ ),
204
+ http.post('https://api.example.com/chats', async ({ request }) => {
205
+ const body = (await request.json()) as any;
206
+ return HttpResponse.json({
207
+ id: 'chat-1',
208
+ type: body.type,
209
+ name: body.name ?? 'New Chat',
210
+ });
211
+ }),
212
+ http.post(
213
+ 'https://api.example.com/chats/:chatId/participants',
214
+ async ({ params, request }) => {
215
+ const body = (await request.json()) as any;
216
+ return HttpResponse.json({
217
+ id: 'p-1',
218
+ chatId: params.chatId,
219
+ userId: body.userId,
220
+ role: body.role,
221
+ });
222
+ },
223
+ ),
224
+ http.delete('https://api.example.com/chats/:id', () => {
225
+ return HttpResponse.json({ success: true });
226
+ }),
227
+ http.patch(
228
+ 'https://api.example.com/chats/:id',
229
+ async ({ params, request }) => {
230
+ const body = (await request.json()) as any;
231
+ return HttpResponse.json({
232
+ id: params.id,
233
+ name: body.name ?? 'Chat',
234
+ status: body.status ?? 'Active',
235
+ });
236
+ },
237
+ ),
238
+ http.post('https://api.example.com/chats/:chatId/leave', () => {
239
+ return HttpResponse.json({ success: true });
240
+ }),
241
+ );
242
+ });
243
+
244
+ it('should resolve body-only mutation args (POST /chats)', async () => {
245
+ const hooks = createEndpointHooks<GeneratedPaths>(createMockFetcher());
246
+ const { result } = renderHook(() => hooks.useMutation('POST /chats'), {
247
+ wrapper: createWrapper(),
248
+ });
249
+
250
+ // If args were `never`, this call would be a type error
251
+ result.current.mutate({ body: { type: 'GeneralChat', name: 'Test' } });
252
+
253
+ await waitFor(() => expect(result.current.isSuccess).toBe(true));
254
+ expect(result.current.data).toMatchObject({
255
+ id: 'chat-1',
256
+ type: 'GeneralChat',
257
+ });
258
+ });
259
+
260
+ it('should resolve body-only mutation args (POST /account/profile)', async () => {
261
+ const hooks = createEndpointHooks<GeneratedPaths>(createMockFetcher());
262
+ const { result } = renderHook(
263
+ () => hooks.useMutation('POST /account/profile'),
264
+ {
265
+ wrapper: createWrapper(),
266
+ },
267
+ );
268
+
269
+ result.current.mutate({ body: { email: 'test@test.com', name: 'Test' } });
270
+
271
+ await waitFor(() => expect(result.current.isSuccess).toBe(true));
272
+ expect(result.current.data).toMatchObject({ email: 'test@test.com' });
273
+ });
274
+
275
+ it('should resolve params+body mutation args (POST /chats/{chatId}/participants)', async () => {
276
+ const hooks = createEndpointHooks<GeneratedPaths>(createMockFetcher());
277
+ const { result } = renderHook(
278
+ () => hooks.useMutation('POST /chats/{chatId}/participants'),
279
+ { wrapper: createWrapper() },
280
+ );
281
+
282
+ result.current.mutate({
283
+ params: { chatId: 'chat-1' },
284
+ body: { userId: 'user-1', role: 'Member' },
285
+ });
286
+
287
+ await waitFor(() => expect(result.current.isSuccess).toBe(true));
288
+ expect(result.current.data).toMatchObject({
289
+ chatId: 'chat-1',
290
+ userId: 'user-1',
291
+ });
292
+ });
293
+
294
+ it('should resolve params-only mutation args (DELETE /chats/{id})', async () => {
295
+ const hooks = createEndpointHooks<GeneratedPaths>(createMockFetcher());
296
+ const { result } = renderHook(
297
+ () => hooks.useMutation('DELETE /chats/{id}'),
298
+ {
299
+ wrapper: createWrapper(),
300
+ },
301
+ );
302
+
303
+ result.current.mutate({ params: { id: 'chat-1' } });
304
+
305
+ await waitFor(() => expect(result.current.isSuccess).toBe(true));
306
+ expect(result.current.data).toEqual({ success: true });
307
+ });
308
+
309
+ it('should resolve params+body mutation args (PATCH /chats/{id})', async () => {
310
+ const hooks = createEndpointHooks<GeneratedPaths>(createMockFetcher());
311
+ const { result } = renderHook(
312
+ () => hooks.useMutation('PATCH /chats/{id}'),
313
+ {
314
+ wrapper: createWrapper(),
315
+ },
316
+ );
317
+
318
+ result.current.mutate({
319
+ params: { id: 'chat-1' },
320
+ body: { name: 'Renamed Chat' },
321
+ });
322
+
323
+ await waitFor(() => expect(result.current.isSuccess).toBe(true));
324
+ expect(result.current.data).toMatchObject({
325
+ id: 'chat-1',
326
+ name: 'Renamed Chat',
327
+ });
328
+ });
329
+
330
+ it('should resolve params-only POST mutation args (POST /chats/{chatId}/leave)', async () => {
331
+ const hooks = createEndpointHooks<GeneratedPaths>(createMockFetcher());
332
+ const { result } = renderHook(
333
+ () => hooks.useMutation('POST /chats/{chatId}/leave'),
334
+ { wrapper: createWrapper() },
335
+ );
336
+
337
+ // POST with only path params, no body
338
+ result.current.mutate({ params: { chatId: 'chat-1' } });
339
+
340
+ await waitFor(() => expect(result.current.isSuccess).toBe(true));
341
+ expect(result.current.data).toEqual({ success: true });
342
+ });
343
+ });
@@ -399,7 +399,7 @@ describe('TypedQueryClient - useInfiniteQuery', () => {
399
399
  });
400
400
  });
401
401
 
402
- it('should handle complex object pageParam merging', async () => {
402
+ it.skip('should handle complex object pageParam merging', async () => {
403
403
  const typedClient = createTypedQueryClient<paths>({
404
404
  baseURL: 'https://api.example.com',
405
405
  });
@@ -439,8 +439,8 @@ describe('TypedQueryClient - useInfiniteQuery', () => {
439
439
 
440
440
  // Fetch next page to ensure complex objects continue to work
441
441
  if (result.current.hasNextPage) {
442
- await waitFor(async () => {
443
- await result.current.fetchNextPage();
442
+ await act(() => result.current.fetchNextPage());
443
+ await waitFor(() => {
444
444
  expect(result.current.data?.pages).toHaveLength(2);
445
445
  });
446
446
  }
@@ -1,7 +1,9 @@
1
1
  import type {
2
2
  QueryClient,
3
3
  UseMutationOptions,
4
+ UseMutationResult,
4
5
  UseQueryOptions,
6
+ UseQueryResult,
5
7
  } from '@tanstack/react-query';
6
8
  import { useMutation, useQuery } from '@tanstack/react-query';
7
9
  import { useMemo } from 'react';
@@ -74,7 +76,7 @@ export interface EndpointHooks<Paths> {
74
76
  useQuery: <T extends QueryEndpoint<Paths>>(
75
77
  endpoint: T,
76
78
  ...args: UseQueryArgs<Paths, T>
77
- ) => ReturnType<typeof useQuery<ExtractEndpointResponse<Paths, T>, Error>>;
79
+ ) => UseQueryResult<ExtractEndpointResponse<Paths, T>, Error>;
78
80
 
79
81
  /**
80
82
  * Use mutation hook for POST, PUT, PATCH, DELETE endpoints.
@@ -90,12 +92,10 @@ export interface EndpointHooks<Paths> {
90
92
  >,
91
93
  'mutationFn'
92
94
  >,
93
- ) => ReturnType<
94
- typeof useMutation<
95
- ExtractEndpointResponse<Paths, T>,
96
- Error,
97
- FilteredRequestConfig<Paths, T>
98
- >
95
+ ) => UseMutationResult<
96
+ ExtractEndpointResponse<Paths, T>,
97
+ Error,
98
+ FilteredRequestConfig<Paths, T>
99
99
  >;
100
100
 
101
101
  /**
package/src/fetcher.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import qs from 'qs';
1
2
  import type {
2
3
  EndpointString,
3
4
  ExtractEndpointResponse,
@@ -59,39 +60,11 @@ export class TypedFetcher<Paths> {
59
60
 
60
61
  // Add query parameters
61
62
  if (config && 'query' in config && config.query) {
62
- const queryParams = new URLSearchParams();
63
-
64
- // Recursive function to handle nested objects and arrays
65
- const appendQueryParam = (prefix: string, value: unknown) => {
66
- if (value === undefined || value === null) {
67
- return;
68
- }
69
-
70
- if (Array.isArray(value)) {
71
- // Handle arrays by appending multiple values with the same key
72
- value.forEach((item) => {
73
- queryParams.append(prefix, String(item));
74
- });
75
- } else if (typeof value === 'object') {
76
- // For objects, recursively flatten into dot notation
77
- Object.entries(value as Record<string, unknown>).forEach(
78
- ([subKey, subValue]) => {
79
- appendQueryParam(`${prefix}.${subKey}`, subValue);
80
- },
81
- );
82
- } else {
83
- queryParams.append(prefix, String(value));
84
- }
85
- };
86
-
87
- // Process all query parameters
88
- Object.entries(config.query as Record<string, unknown>).forEach(
89
- ([key, value]) => {
90
- appendQueryParam(key, value);
91
- },
92
- );
93
-
94
- const queryString = queryParams.toString();
63
+ const queryString = qs.stringify(config.query, {
64
+ encode: true,
65
+ arrayFormat: 'brackets',
66
+ skipNulls: true,
67
+ });
95
68
  if (queryString) {
96
69
  url += `?${queryString}`;
97
70
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"fetcher-5fnBE7Dk.mjs","names":["fn?: FetchFn","options: FetcherOptions","endpoint: T","config?: FilteredRequestConfig<Paths, T>","prefix: string","value: unknown","requestConfig: RequestInit","options?: FetcherOptions"],"sources":["../src/fetcher.ts"],"sourcesContent":["import type {\n\tEndpointString,\n\tExtractEndpointResponse,\n\tFetcherOptions,\n\tFilteredRequestConfig,\n\tParseEndpoint,\n\tTypedEndpoint,\n} from './types';\n\nexport type { FetcherOptions } from './types';\n\nexport class TypedFetcher<Paths> {\n\tprivate baseURL: string;\n\tprivate defaultHeaders: Record<string, string>;\n\tprivate options: FetcherOptions;\n\tprivate fetchFn: FetchFn;\n\n\tstatic getFetchFn(fn?: FetchFn): FetchFn {\n\t\tif (fn) {\n\t\t\treturn fn;\n\t\t}\n\n\t\tif (typeof window !== 'undefined' && typeof window.fetch === 'function') {\n\t\t\treturn window.fetch.bind(window);\n\t\t}\n\n\t\tif (\n\t\t\ttypeof globalThis !== 'undefined' &&\n\t\t\ttypeof globalThis.fetch === 'function'\n\t\t) {\n\t\t\treturn globalThis.fetch.bind(globalThis);\n\t\t}\n\n\t\tthrow new Error('No fetch implementation found');\n\t}\n\n\tconstructor(options: FetcherOptions = {}) {\n\t\tthis.baseURL = options.baseURL || '';\n\t\tthis.defaultHeaders = options.headers || {};\n\t\tthis.options = options;\n\t\tthis.fetchFn = TypedFetcher.getFetchFn(options.fetch);\n\t}\n\n\tasync request<T extends TypedEndpoint<Paths>>(\n\t\tendpoint: T,\n\t\tconfig?: FilteredRequestConfig<Paths, T>,\n\t): Promise<ExtractEndpointResponse<Paths, T>> {\n\t\tconst { method, route } = this.parseEndpoint(endpoint);\n\n\t\t// Replace path parameters\n\t\tlet url = route;\n\t\tif (config && 'params' in config && config.params) {\n\t\t\tObject.entries(config.params as Record<string, unknown>).forEach(\n\t\t\t\t([key, value]) => {\n\t\t\t\t\turl = url.replace(`{${key}}`, encodeURIComponent(String(value)));\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\t// Add query parameters\n\t\tif (config && 'query' in config && config.query) {\n\t\t\tconst queryParams = new URLSearchParams();\n\n\t\t\t// Recursive function to handle nested objects and arrays\n\t\t\tconst appendQueryParam = (prefix: string, value: unknown) => {\n\t\t\t\tif (value === undefined || value === null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (Array.isArray(value)) {\n\t\t\t\t\t// Handle arrays by appending multiple values with the same key\n\t\t\t\t\tvalue.forEach((item) => {\n\t\t\t\t\t\tqueryParams.append(prefix, String(item));\n\t\t\t\t\t});\n\t\t\t\t} else if (typeof value === 'object') {\n\t\t\t\t\t// For objects, recursively flatten into dot notation\n\t\t\t\t\tObject.entries(value as Record<string, unknown>).forEach(\n\t\t\t\t\t\t([subKey, subValue]) => {\n\t\t\t\t\t\t\tappendQueryParam(`${prefix}.${subKey}`, subValue);\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tqueryParams.append(prefix, String(value));\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// Process all query parameters\n\t\t\tObject.entries(config.query as Record<string, unknown>).forEach(\n\t\t\t\t([key, value]) => {\n\t\t\t\t\tappendQueryParam(key, value);\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tconst queryString = queryParams.toString();\n\t\t\tif (queryString) {\n\t\t\t\turl += `?${queryString}`;\n\t\t\t}\n\t\t}\n\n\t\t// Build request configuration\n\t\tlet requestConfig: RequestInit = {\n\t\t\tmethod: method.toUpperCase(),\n\t\t\theaders: {\n\t\t\t\t...this.defaultHeaders,\n\t\t\t\t...((config && 'headers' in config && config.headers) || {}),\n\t\t\t},\n\t\t};\n\n\t\t// Add body if present\n\t\tif (config && 'body' in config && config.body) {\n\t\t\trequestConfig.body = JSON.stringify(config.body);\n\t\t\trequestConfig.headers = {\n\t\t\t\t...requestConfig.headers,\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t};\n\t\t}\n\n\t\t// Apply request interceptor\n\t\tif (this.options.onRequest) {\n\t\t\trequestConfig = await this.options.onRequest(requestConfig);\n\t\t}\n\n\t\ttry {\n\t\t\t// Make the request\n\t\t\tlet response = await this.fetchFn(`${this.baseURL}${url}`, requestConfig);\n\n\t\t\t// Apply response interceptor\n\t\t\tif (this.options.onResponse) {\n\t\t\t\tresponse = await this.options.onResponse(response);\n\t\t\t}\n\n\t\t\t// Handle errors\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow response;\n\t\t\t}\n\n\t\t\t// Handle empty responses (204 No Content, etc.)\n\t\t\tif (\n\t\t\t\tresponse.status === 204 ||\n\t\t\t\tresponse.headers.get('content-length') === '0'\n\t\t\t) {\n\t\t\t\treturn undefined as ExtractEndpointResponse<Paths, T>;\n\t\t\t}\n\n\t\t\t// Parse JSON response\n\t\t\tconst data = await response.json();\n\t\t\treturn data as ExtractEndpointResponse<Paths, T>;\n\t\t} catch (error) {\n\t\t\t// Apply error handler\n\t\t\tif (this.options.onError) {\n\t\t\t\t// @ts-expect-error\n\t\t\t\tawait this.options.onError(error);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprivate parseEndpoint<T extends EndpointString>(\n\t\tendpoint: T,\n\t): ParseEndpoint<T> {\n\t\tconst [method, ...routeParts] = endpoint.split(' ');\n\t\tconst route = routeParts.join(' ');\n\t\treturn { method: method?.toLowerCase() ?? '', route } as ParseEndpoint<T>;\n\t}\n}\n\nexport function createTypedFetcher<Paths>(options?: FetcherOptions) {\n\tconst fetcher = new TypedFetcher<Paths>(options);\n\treturn <T extends TypedEndpoint<Paths>>(\n\t\tendpoint: T,\n\t\tconfig?: FilteredRequestConfig<Paths, T>,\n\t) => fetcher.request(endpoint, config);\n}\n\nexport type FetchFn = typeof fetch;\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"fetcher-CgLEaIAC.cjs","names":["fn?: FetchFn","options: FetcherOptions","endpoint: T","config?: FilteredRequestConfig<Paths, T>","prefix: string","value: unknown","requestConfig: RequestInit","options?: FetcherOptions"],"sources":["../src/fetcher.ts"],"sourcesContent":["import type {\n\tEndpointString,\n\tExtractEndpointResponse,\n\tFetcherOptions,\n\tFilteredRequestConfig,\n\tParseEndpoint,\n\tTypedEndpoint,\n} from './types';\n\nexport type { FetcherOptions } from './types';\n\nexport class TypedFetcher<Paths> {\n\tprivate baseURL: string;\n\tprivate defaultHeaders: Record<string, string>;\n\tprivate options: FetcherOptions;\n\tprivate fetchFn: FetchFn;\n\n\tstatic getFetchFn(fn?: FetchFn): FetchFn {\n\t\tif (fn) {\n\t\t\treturn fn;\n\t\t}\n\n\t\tif (typeof window !== 'undefined' && typeof window.fetch === 'function') {\n\t\t\treturn window.fetch.bind(window);\n\t\t}\n\n\t\tif (\n\t\t\ttypeof globalThis !== 'undefined' &&\n\t\t\ttypeof globalThis.fetch === 'function'\n\t\t) {\n\t\t\treturn globalThis.fetch.bind(globalThis);\n\t\t}\n\n\t\tthrow new Error('No fetch implementation found');\n\t}\n\n\tconstructor(options: FetcherOptions = {}) {\n\t\tthis.baseURL = options.baseURL || '';\n\t\tthis.defaultHeaders = options.headers || {};\n\t\tthis.options = options;\n\t\tthis.fetchFn = TypedFetcher.getFetchFn(options.fetch);\n\t}\n\n\tasync request<T extends TypedEndpoint<Paths>>(\n\t\tendpoint: T,\n\t\tconfig?: FilteredRequestConfig<Paths, T>,\n\t): Promise<ExtractEndpointResponse<Paths, T>> {\n\t\tconst { method, route } = this.parseEndpoint(endpoint);\n\n\t\t// Replace path parameters\n\t\tlet url = route;\n\t\tif (config && 'params' in config && config.params) {\n\t\t\tObject.entries(config.params as Record<string, unknown>).forEach(\n\t\t\t\t([key, value]) => {\n\t\t\t\t\turl = url.replace(`{${key}}`, encodeURIComponent(String(value)));\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\t// Add query parameters\n\t\tif (config && 'query' in config && config.query) {\n\t\t\tconst queryParams = new URLSearchParams();\n\n\t\t\t// Recursive function to handle nested objects and arrays\n\t\t\tconst appendQueryParam = (prefix: string, value: unknown) => {\n\t\t\t\tif (value === undefined || value === null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (Array.isArray(value)) {\n\t\t\t\t\t// Handle arrays by appending multiple values with the same key\n\t\t\t\t\tvalue.forEach((item) => {\n\t\t\t\t\t\tqueryParams.append(prefix, String(item));\n\t\t\t\t\t});\n\t\t\t\t} else if (typeof value === 'object') {\n\t\t\t\t\t// For objects, recursively flatten into dot notation\n\t\t\t\t\tObject.entries(value as Record<string, unknown>).forEach(\n\t\t\t\t\t\t([subKey, subValue]) => {\n\t\t\t\t\t\t\tappendQueryParam(`${prefix}.${subKey}`, subValue);\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tqueryParams.append(prefix, String(value));\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// Process all query parameters\n\t\t\tObject.entries(config.query as Record<string, unknown>).forEach(\n\t\t\t\t([key, value]) => {\n\t\t\t\t\tappendQueryParam(key, value);\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tconst queryString = queryParams.toString();\n\t\t\tif (queryString) {\n\t\t\t\turl += `?${queryString}`;\n\t\t\t}\n\t\t}\n\n\t\t// Build request configuration\n\t\tlet requestConfig: RequestInit = {\n\t\t\tmethod: method.toUpperCase(),\n\t\t\theaders: {\n\t\t\t\t...this.defaultHeaders,\n\t\t\t\t...((config && 'headers' in config && config.headers) || {}),\n\t\t\t},\n\t\t};\n\n\t\t// Add body if present\n\t\tif (config && 'body' in config && config.body) {\n\t\t\trequestConfig.body = JSON.stringify(config.body);\n\t\t\trequestConfig.headers = {\n\t\t\t\t...requestConfig.headers,\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t};\n\t\t}\n\n\t\t// Apply request interceptor\n\t\tif (this.options.onRequest) {\n\t\t\trequestConfig = await this.options.onRequest(requestConfig);\n\t\t}\n\n\t\ttry {\n\t\t\t// Make the request\n\t\t\tlet response = await this.fetchFn(`${this.baseURL}${url}`, requestConfig);\n\n\t\t\t// Apply response interceptor\n\t\t\tif (this.options.onResponse) {\n\t\t\t\tresponse = await this.options.onResponse(response);\n\t\t\t}\n\n\t\t\t// Handle errors\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow response;\n\t\t\t}\n\n\t\t\t// Handle empty responses (204 No Content, etc.)\n\t\t\tif (\n\t\t\t\tresponse.status === 204 ||\n\t\t\t\tresponse.headers.get('content-length') === '0'\n\t\t\t) {\n\t\t\t\treturn undefined as ExtractEndpointResponse<Paths, T>;\n\t\t\t}\n\n\t\t\t// Parse JSON response\n\t\t\tconst data = await response.json();\n\t\t\treturn data as ExtractEndpointResponse<Paths, T>;\n\t\t} catch (error) {\n\t\t\t// Apply error handler\n\t\t\tif (this.options.onError) {\n\t\t\t\t// @ts-expect-error\n\t\t\t\tawait this.options.onError(error);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprivate parseEndpoint<T extends EndpointString>(\n\t\tendpoint: T,\n\t): ParseEndpoint<T> {\n\t\tconst [method, ...routeParts] = endpoint.split(' ');\n\t\tconst route = routeParts.join(' ');\n\t\treturn { method: method?.toLowerCase() ?? '', route } as ParseEndpoint<T>;\n\t}\n}\n\nexport function createTypedFetcher<Paths>(options?: FetcherOptions) {\n\tconst fetcher = new TypedFetcher<Paths>(options);\n\treturn <T extends TypedEndpoint<Paths>>(\n\t\tendpoint: T,\n\t\tconfig?: FilteredRequestConfig<Paths, T>,\n\t) => fetcher.request(endpoint, config);\n}\n\nexport type FetchFn = typeof fetch;\n"],"mappings":"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"}