@openapi-qraft/react 2.9.0 → 2.10.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,23 @@
1
1
  # @openapi-qraft/react
2
2
 
3
+ ## 2.10.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [4618a66]
8
+ - @openapi-qraft/tanstack-query-react-types@2.10.1
9
+
10
+ ## 2.10.0
11
+
12
+ ### Minor Changes
13
+
14
+ - ea029f5: Refactor `getQueryString` function to use native `URLSearchParams` instead of custom implementation for better maintainability.
15
+
16
+ ### Patch Changes
17
+
18
+ - 16e68c8: Fix URL serialization using `encodeURIComponent` instead of `encodeURI` to avoid issues with slash serialization in path parameters.
19
+ - @openapi-qraft/tanstack-query-react-types@2.10.0
20
+
3
21
  ## 2.9.0
4
22
 
5
23
  ### Minor Changes
@@ -66,7 +66,7 @@ var responseUtils = require('./responseUtils.cjs');
66
66
  */ function urlSerializer(schema, info) {
67
67
  const path = schema.url.replace(/{(.*?)}/g, (substring, group)=>{
68
68
  if (info.parameters?.path && Object.prototype.hasOwnProperty.call(info.parameters.path, group)) {
69
- return encodeURI(String(info.parameters?.path[group]));
69
+ return encodeURIComponent(String(info.parameters?.path[group]));
70
70
  }
71
71
  return substring;
72
72
  });
@@ -77,31 +77,19 @@ var responseUtils = require('./responseUtils.cjs');
77
77
  return `${baseUrl}${path}`;
78
78
  }
79
79
  function getQueryString(params) {
80
- const qs = [];
81
- const append = (key, value)=>{
82
- qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
83
- };
84
- const process = (key, value)=>{
85
- if (typeof value === 'undefined' || value === null) return;
86
- if (Array.isArray(value)) {
87
- value.forEach((v)=>{
88
- process(key, v);
89
- });
90
- } else if (typeof value === 'object') {
91
- Object.entries(value).forEach(([k, v])=>{
92
- process(`${key}[${k}]`, v);
93
- });
94
- } else {
95
- append(key, value);
80
+ const search = new URLSearchParams();
81
+ const walk = (prefix, value)=>{
82
+ if (value == null) return;
83
+ if (value instanceof Date) return search.append(prefix, value.toISOString());
84
+ if (Array.isArray(value)) return value.forEach((v)=>walk(prefix, v));
85
+ if (typeof value === 'object') {
86
+ return Object.entries(value).forEach(([k, v])=>walk(`${prefix}[${k}]`, v));
96
87
  }
88
+ search.append(prefix, String(value));
97
89
  };
98
- Object.entries(params).forEach(([key, value])=>{
99
- process(key, value);
100
- });
101
- if (qs.length > 0) {
102
- return `?${qs.join('&')}`;
103
- }
104
- return '';
90
+ Object.entries(params).forEach(([k, v])=>walk(k, v));
91
+ const searchString = search.toString();
92
+ return searchString ? `?${searchString}` : '';
105
93
  }
106
94
  function mergeHeaders(...allHeaders) {
107
95
  const headers = new Headers();
@@ -1 +1 @@
1
- {"version":3,"file":"requestFn.cjs","sources":["../../../src/lib/requestFn.ts"],"sourcesContent":["import type {\n HeadersOptions,\n OperationSchema,\n RequestFnInfo,\n RequestFnOptions,\n RequestFnResponse,\n} from '@openapi-qraft/tanstack-query-react-types';\nimport { processResponse, resolveResponse } from './responseUtils.js';\n\n/**\n * This function is used to make a request to a specified endpoint.\n *\n * @template T The expected return type of the request.\n *\n * @param schema The schema of the operation to be performed. It includes the OpenAPI path, HTTP method and media type.\n * @param requestInfo The information required to make the request. It includes parameters, headers, body, etc.\n * @param [options] Optional. Additional options for the request. It includes custom urlSerializer, bodySerializer, and fetch function.\n *\n * @returns {Promise<T>} Returns a promise that resolves with the response of the request.\n *\n * @throws {error: object|string, response: Response} Throws an error if the request fails. The error includes the error message and the response from the server.\n */\nexport async function requestFn<TData, TError>(\n schema: OperationSchema,\n requestInfo: RequestFnInfo,\n options?: RequestFnOptions\n): Promise<RequestFnResponse<TData, TError>> {\n return baseRequestFn<TData, TError>(schema, requestInfo, {\n urlSerializer,\n bodySerializer,\n ...options,\n });\n}\n\n/**\n * This function is used to make a request to a specified endpoint.\n * It's necessary to create a custom `requestFn` with a custom `urlSerializer`\n * and `bodySerializer`, with the tree-shaking of the default `requestFn`\n * and its serializers.\n *\n * @template T The expected return type of the request.\n *\n * @param requestSchema The schema of the operation to be performed. It includes the OpenAPI path, HTTP method and media type.\n * @param requestInfo The information required to make the request. It includes parameters, headers, body, etc.\n * @param options The options for the request. It includes urlSerializer, bodySerializer, and fetch function. The 'urlSerializer' and 'bodySerializer' are required.\n *\n * @returns {Promise<T>} Returns a promise that resolves with the response of the request.\n *\n * @throws {error: object|string, response: Response} Throws an error if the request fails. The error includes the error message and the response from the server.\n */\nexport async function baseRequestFn<TData, TError>(\n requestSchema: OperationSchema,\n requestInfo: RequestFnInfo,\n options: WithRequired<RequestFnOptions, 'urlSerializer' | 'bodySerializer'>\n): Promise<RequestFnResponse<TData, TError>> {\n const { parameters, headers, body, ...requestInfoRest } = requestInfo;\n\n const requestPayload = options.bodySerializer(requestSchema, body);\n\n const baseFetch = options.fetch ?? fetch;\n\n return baseFetch(options.urlSerializer(requestSchema, requestInfo), {\n method: requestSchema.method.toUpperCase(),\n body: requestPayload?.body,\n headers: mergeHeaders(\n { Accept: 'application/json' },\n requestPayload?.headers,\n headers,\n parameters?.header\n ),\n ...requestInfoRest,\n })\n .then(processResponse as typeof processResponse<TData, TError>)\n .catch(resolveResponse as typeof resolveResponse<TData, TError>);\n}\n\n/**\n * Serializes the given schema and request payload into a URL string.\n *\n * This function is implemented according to the URI Template standard\n * defined in RFC 6570. It supports the expansion of path and query parameters,\n * correctly handling empty arrays, `null`, and `undefined` values by ignoring\n * them during the expansion process, as specified by the standard.\n *\n * For more information, refer to the official documentation:\n * https://datatracker.ietf.org/doc/html/rfc6570\n *\n * @param schema - The operation schema containing the URL template and method.\n * @param info - The request payload including baseUrl, path parameters, and query parameters.\n * @returns The fully constructed URL string.\n */\nexport function urlSerializer(\n schema: OperationSchema,\n info: Pick<RequestFnInfo, 'baseUrl' | 'parameters'>\n): string {\n const path = schema.url.replace(\n /{(.*?)}/g,\n (substring: string, group: string) => {\n if (\n info.parameters?.path &&\n Object.prototype.hasOwnProperty.call(info.parameters.path, group)\n ) {\n return encodeURI(String(info.parameters?.path[group]));\n }\n return substring;\n }\n );\n\n const baseUrl = info.baseUrl ?? '';\n\n if (info.parameters?.query) {\n return `${baseUrl}${path}${getQueryString(info.parameters.query)}`;\n }\n\n return `${baseUrl}${path}`;\n}\n\nfunction getQueryString(params: Record<string, any>): string {\n const qs: string[] = [];\n\n const append = (key: string, value: any) => {\n qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);\n };\n\n const process = (key: string, value: any) => {\n if (typeof value === 'undefined' || value === null) return;\n\n if (Array.isArray(value)) {\n value.forEach((v) => {\n process(key, v);\n });\n } else if (typeof value === 'object') {\n Object.entries(value).forEach(([k, v]) => {\n process(`${key}[${k}]`, v);\n });\n } else {\n append(key, value);\n }\n };\n\n Object.entries(params).forEach(([key, value]) => {\n process(key, value);\n });\n\n if (qs.length > 0) {\n return `?${qs.join('&')}`;\n }\n\n return '';\n}\n\nexport function mergeHeaders(...allHeaders: (HeadersOptions | undefined)[]) {\n const headers = new Headers();\n\n for (const headerSet of allHeaders) {\n if (!headerSet || typeof headerSet !== 'object') {\n continue;\n }\n\n const headersIterator =\n headerSet instanceof Headers\n ? headerSet.entries()\n : Object.entries(headerSet);\n\n for (const [headerKey, headerValue] of headersIterator) {\n if (headerValue === null) {\n headers.delete(headerKey);\n } else if (headerValue !== undefined) {\n headers.set(headerKey, headerValue);\n }\n }\n }\n\n return headers;\n}\n\nexport function bodySerializer(\n schema: OperationSchema,\n body: RequestFnInfo['body']\n) {\n if (isReadOnlyOperation(schema)) return undefined;\n\n if (body === undefined || body === null) return undefined;\n\n if (typeof body === 'string') {\n return {\n body,\n headers: {\n 'Content-Type':\n // prefer text/* media type\n schema.mediaType?.find((mediaType) => mediaType.includes('text/')) ??\n // prefer JSON media type, assume that body is serialized as JSON\n schema.mediaType?.find((mediaType) => mediaType.includes('/json')) ??\n 'text/plain',\n },\n };\n }\n\n if (body instanceof FormData) {\n return {\n body,\n headers: {\n // remove `Content-Type` if the serialized body is FormData;\n // the browser will correctly set Content-Type & boundary expression\n 'Content-Type': null,\n },\n };\n }\n\n if (body instanceof Blob) {\n return {\n body,\n headers: {\n 'Content-Type':\n body.type ||\n schema.mediaType?.find(\n (mediaType) =>\n !(\n mediaType.includes('text/') &&\n mediaType.includes('/form-data') &&\n mediaType.includes('/json')\n )\n ) ||\n 'application/octet-stream',\n },\n };\n }\n\n let jsonMediaType: string | null = null;\n let formDataMediaType: string | null = null;\n\n if (schema.mediaType) {\n for (let i = 0; i < schema.mediaType.length; i++) {\n const mediaType = schema.mediaType[i];\n if (mediaType.includes('/json')) jsonMediaType = mediaType;\n else if (mediaType.includes('/form-data')) formDataMediaType = mediaType;\n }\n }\n\n if (formDataMediaType) {\n if (\n !jsonMediaType ||\n // Prefer FormData serialization if one of the fields is a Blob\n Object.values(body).some((value) => value instanceof Blob)\n ) {\n return {\n body: getRequestBodyFormData(body),\n headers: {\n // remove `Content-Type` if the serialized body is FormData;\n // the browser will correctly set Content-Type & boundary expression\n 'Content-Type': null,\n },\n };\n }\n }\n\n return {\n body: JSON.stringify(body),\n headers: {\n 'Content-Type': jsonMediaType ?? 'application/json',\n },\n };\n}\n\nfunction getRequestBodyFormData(\n body: NonNullable<RequestFnInfo['body']>\n): FormData {\n if (body instanceof FormData) return body;\n if (typeof body !== 'object')\n throw new Error(`Unsupported body type ${typeof body} in form-data.`);\n\n const formData = new FormData();\n\n const process = (key: string, value: any) => {\n if (typeof value === 'string' || value instanceof Blob) {\n formData.append(key, value);\n } else {\n formData.append(key, JSON.stringify(value));\n }\n };\n\n Object.entries(body)\n .filter(([_, value]) => typeof value !== 'undefined' && value !== null)\n .forEach(([key, value]) => {\n if (Array.isArray(value)) {\n value.forEach((v) => process(key, v));\n } else {\n process(key, value);\n }\n });\n\n return formData;\n}\n\ntype WithRequired<T, K extends keyof T> = T & {\n [_ in K]: {};\n};\n\nexport type {\n RequestFn,\n RequestFnResponse,\n HeadersOptions,\n RequestFnOptions,\n RequestFnInfo,\n OperationSchema,\n} from '@openapi-qraft/tanstack-query-react-types';\n\n/**\n * @deprecated use `RequestFnInfo` instead\n */\nexport type RequestFnPayload = RequestFnInfo;\n\nfunction isReadOnlyOperation(operation: {\n readonly method:\n | 'get'\n | 'put'\n | 'post'\n | 'patch'\n | 'delete'\n | 'options'\n | 'head'\n | 'trace';\n}) {\n return (\n operation.method === 'get' ||\n operation.method === 'head' ||\n operation.method === 'trace' ||\n operation.method === 'options'\n );\n}\n"],"names":["requestFn","schema","requestInfo","options","baseRequestFn","urlSerializer","bodySerializer","requestSchema","parameters","headers","body","requestInfoRest","requestPayload","baseFetch","fetch","method","toUpperCase","mergeHeaders","Accept","header","then","processResponse","catch","resolveResponse","info","path","url","replace","substring","group","Object","prototype","hasOwnProperty","call","encodeURI","String","baseUrl","query","getQueryString","params","qs","append","key","value","push","encodeURIComponent","process","Array","isArray","forEach","v","entries","k","length","join","allHeaders","Headers","headerSet","headersIterator","headerKey","headerValue","delete","undefined","set","isReadOnlyOperation","mediaType","find","includes","FormData","Blob","type","jsonMediaType","formDataMediaType","i","values","some","getRequestBodyFormData","JSON","stringify","Error","formData","filter","_","operation"],"mappings":"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"}
1
+ {"version":3,"file":"requestFn.cjs","sources":["../../../src/lib/requestFn.ts"],"sourcesContent":["import type {\n HeadersOptions,\n OperationSchema,\n RequestFnInfo,\n RequestFnOptions,\n RequestFnResponse,\n} from '@openapi-qraft/tanstack-query-react-types';\nimport { processResponse, resolveResponse } from './responseUtils.js';\n\n/**\n * This function is used to make a request to a specified endpoint.\n *\n * @template T The expected return type of the request.\n *\n * @param schema The schema of the operation to be performed. It includes the OpenAPI path, HTTP method and media type.\n * @param requestInfo The information required to make the request. It includes parameters, headers, body, etc.\n * @param [options] Optional. Additional options for the request. It includes custom urlSerializer, bodySerializer, and fetch function.\n *\n * @returns {Promise<T>} Returns a promise that resolves with the response of the request.\n *\n * @throws {error: object|string, response: Response} Throws an error if the request fails. The error includes the error message and the response from the server.\n */\nexport async function requestFn<TData, TError>(\n schema: OperationSchema,\n requestInfo: RequestFnInfo,\n options?: RequestFnOptions\n): Promise<RequestFnResponse<TData, TError>> {\n return baseRequestFn<TData, TError>(schema, requestInfo, {\n urlSerializer,\n bodySerializer,\n ...options,\n });\n}\n\n/**\n * This function is used to make a request to a specified endpoint.\n * It's necessary to create a custom `requestFn` with a custom `urlSerializer`\n * and `bodySerializer`, with the tree-shaking of the default `requestFn`\n * and its serializers.\n *\n * @template T The expected return type of the request.\n *\n * @param requestSchema The schema of the operation to be performed. It includes the OpenAPI path, HTTP method and media type.\n * @param requestInfo The information required to make the request. It includes parameters, headers, body, etc.\n * @param options The options for the request. It includes urlSerializer, bodySerializer, and fetch function. The 'urlSerializer' and 'bodySerializer' are required.\n *\n * @returns {Promise<T>} Returns a promise that resolves with the response of the request.\n *\n * @throws {error: object|string, response: Response} Throws an error if the request fails. The error includes the error message and the response from the server.\n */\nexport async function baseRequestFn<TData, TError>(\n requestSchema: OperationSchema,\n requestInfo: RequestFnInfo,\n options: WithRequired<RequestFnOptions, 'urlSerializer' | 'bodySerializer'>\n): Promise<RequestFnResponse<TData, TError>> {\n const { parameters, headers, body, ...requestInfoRest } = requestInfo;\n\n const requestPayload = options.bodySerializer(requestSchema, body);\n\n const baseFetch = options.fetch ?? fetch;\n\n return baseFetch(options.urlSerializer(requestSchema, requestInfo), {\n method: requestSchema.method.toUpperCase(),\n body: requestPayload?.body,\n headers: mergeHeaders(\n { Accept: 'application/json' },\n requestPayload?.headers,\n headers,\n parameters?.header\n ),\n ...requestInfoRest,\n })\n .then(processResponse as typeof processResponse<TData, TError>)\n .catch(resolveResponse as typeof resolveResponse<TData, TError>);\n}\n\n/**\n * Serializes the given schema and request payload into a URL string.\n *\n * This function is implemented according to the URI Template standard\n * defined in RFC 6570. It supports the expansion of path and query parameters,\n * correctly handling empty arrays, `null`, and `undefined` values by ignoring\n * them during the expansion process, as specified by the standard.\n *\n * For more information, refer to the official documentation:\n * https://datatracker.ietf.org/doc/html/rfc6570\n *\n * @param schema - The operation schema containing the URL template and method.\n * @param info - The request payload including baseUrl, path parameters, and query parameters.\n * @returns The fully constructed URL string.\n */\nexport function urlSerializer(\n schema: OperationSchema,\n info: Pick<RequestFnInfo, 'baseUrl' | 'parameters'>\n): string {\n const path = schema.url.replace(\n /{(.*?)}/g,\n (substring: string, group: string) => {\n if (\n info.parameters?.path &&\n Object.prototype.hasOwnProperty.call(info.parameters.path, group)\n ) {\n return encodeURIComponent(String(info.parameters?.path[group]));\n }\n return substring;\n }\n );\n\n const baseUrl = info.baseUrl ?? '';\n\n if (info.parameters?.query) {\n return `${baseUrl}${path}${getQueryString(info.parameters.query)}`;\n }\n\n return `${baseUrl}${path}`;\n}\n\nfunction getQueryString(params: Record<string, any>): string {\n const search = new URLSearchParams();\n\n const walk = (prefix: string, value: any) => {\n if (value == null) return;\n if (value instanceof Date)\n return search.append(prefix, value.toISOString());\n if (Array.isArray(value)) return value.forEach((v) => walk(prefix, v));\n if (typeof value === 'object') {\n return Object.entries(value).forEach(([k, v]) =>\n walk(`${prefix}[${k}]`, v)\n );\n }\n search.append(prefix, String(value));\n };\n\n Object.entries(params).forEach(([k, v]) => walk(k, v));\n\n const searchString = search.toString();\n\n return searchString ? `?${searchString}` : '';\n}\n\nexport function mergeHeaders(...allHeaders: (HeadersOptions | undefined)[]) {\n const headers = new Headers();\n\n for (const headerSet of allHeaders) {\n if (!headerSet || typeof headerSet !== 'object') {\n continue;\n }\n\n const headersIterator =\n headerSet instanceof Headers\n ? headerSet.entries()\n : Object.entries(headerSet);\n\n for (const [headerKey, headerValue] of headersIterator) {\n if (headerValue === null) {\n headers.delete(headerKey);\n } else if (headerValue !== undefined) {\n headers.set(headerKey, headerValue);\n }\n }\n }\n\n return headers;\n}\n\nexport function bodySerializer(\n schema: OperationSchema,\n body: RequestFnInfo['body']\n) {\n if (isReadOnlyOperation(schema)) return undefined;\n\n if (body === undefined || body === null) return undefined;\n\n if (typeof body === 'string') {\n return {\n body,\n headers: {\n 'Content-Type':\n // prefer text/* media type\n schema.mediaType?.find((mediaType) => mediaType.includes('text/')) ??\n // prefer JSON media type, assume that body is serialized as JSON\n schema.mediaType?.find((mediaType) => mediaType.includes('/json')) ??\n 'text/plain',\n },\n };\n }\n\n if (body instanceof FormData) {\n return {\n body,\n headers: {\n // remove `Content-Type` if the serialized body is FormData;\n // the browser will correctly set Content-Type & boundary expression\n 'Content-Type': null,\n },\n };\n }\n\n if (body instanceof Blob) {\n return {\n body,\n headers: {\n 'Content-Type':\n body.type ||\n schema.mediaType?.find(\n (mediaType) =>\n !(\n mediaType.includes('text/') &&\n mediaType.includes('/form-data') &&\n mediaType.includes('/json')\n )\n ) ||\n 'application/octet-stream',\n },\n };\n }\n\n let jsonMediaType: string | null = null;\n let formDataMediaType: string | null = null;\n\n if (schema.mediaType) {\n for (let i = 0; i < schema.mediaType.length; i++) {\n const mediaType = schema.mediaType[i];\n if (mediaType.includes('/json')) jsonMediaType = mediaType;\n else if (mediaType.includes('/form-data')) formDataMediaType = mediaType;\n }\n }\n\n if (formDataMediaType) {\n if (\n !jsonMediaType ||\n // Prefer FormData serialization if one of the fields is a Blob\n Object.values(body).some((value) => value instanceof Blob)\n ) {\n return {\n body: getRequestBodyFormData(body),\n headers: {\n // remove `Content-Type` if the serialized body is FormData;\n // the browser will correctly set Content-Type & boundary expression\n 'Content-Type': null,\n },\n };\n }\n }\n\n return {\n body: JSON.stringify(body),\n headers: {\n 'Content-Type': jsonMediaType ?? 'application/json',\n },\n };\n}\n\nfunction getRequestBodyFormData(\n body: NonNullable<RequestFnInfo['body']>\n): FormData {\n if (body instanceof FormData) return body;\n if (typeof body !== 'object')\n throw new Error(`Unsupported body type ${typeof body} in form-data.`);\n\n const formData = new FormData();\n\n const process = (key: string, value: any) => {\n if (typeof value === 'string' || value instanceof Blob) {\n formData.append(key, value);\n } else {\n formData.append(key, JSON.stringify(value));\n }\n };\n\n Object.entries(body)\n .filter(([_, value]) => typeof value !== 'undefined' && value !== null)\n .forEach(([key, value]) => {\n if (Array.isArray(value)) {\n value.forEach((v) => process(key, v));\n } else {\n process(key, value);\n }\n });\n\n return formData;\n}\n\ntype WithRequired<T, K extends keyof T> = T & {\n [_ in K]: {};\n};\n\nexport type {\n RequestFn,\n RequestFnResponse,\n HeadersOptions,\n RequestFnOptions,\n RequestFnInfo,\n OperationSchema,\n} from '@openapi-qraft/tanstack-query-react-types';\n\n/**\n * @deprecated use `RequestFnInfo` instead\n */\nexport type RequestFnPayload = RequestFnInfo;\n\nfunction isReadOnlyOperation(operation: {\n readonly method:\n | 'get'\n | 'put'\n | 'post'\n | 'patch'\n | 'delete'\n | 'options'\n | 'head'\n | 'trace';\n}) {\n return (\n operation.method === 'get' ||\n operation.method === 'head' ||\n operation.method === 'trace' ||\n operation.method === 'options'\n );\n}\n"],"names":["requestFn","schema","requestInfo","options","baseRequestFn","urlSerializer","bodySerializer","requestSchema","parameters","headers","body","requestInfoRest","requestPayload","baseFetch","fetch","method","toUpperCase","mergeHeaders","Accept","header","then","processResponse","catch","resolveResponse","info","path","url","replace","substring","group","Object","prototype","hasOwnProperty","call","encodeURIComponent","String","baseUrl","query","getQueryString","params","search","URLSearchParams","walk","prefix","value","Date","append","toISOString","Array","isArray","forEach","v","entries","k","searchString","toString","allHeaders","Headers","headerSet","headersIterator","headerKey","headerValue","delete","undefined","set","isReadOnlyOperation","mediaType","find","includes","FormData","Blob","type","jsonMediaType","formDataMediaType","i","length","values","some","getRequestBodyFormData","JSON","stringify","Error","formData","process","key","filter","_","operation"],"mappings":"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"}
@@ -64,7 +64,7 @@ import { processResponse, resolveResponse } from './responseUtils.js';
64
64
  */ function urlSerializer(schema, info) {
65
65
  const path = schema.url.replace(/{(.*?)}/g, (substring, group)=>{
66
66
  if (info.parameters?.path && Object.prototype.hasOwnProperty.call(info.parameters.path, group)) {
67
- return encodeURI(String(info.parameters?.path[group]));
67
+ return encodeURIComponent(String(info.parameters?.path[group]));
68
68
  }
69
69
  return substring;
70
70
  });
@@ -75,31 +75,19 @@ import { processResponse, resolveResponse } from './responseUtils.js';
75
75
  return `${baseUrl}${path}`;
76
76
  }
77
77
  function getQueryString(params) {
78
- const qs = [];
79
- const append = (key, value)=>{
80
- qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
81
- };
82
- const process = (key, value)=>{
83
- if (typeof value === 'undefined' || value === null) return;
84
- if (Array.isArray(value)) {
85
- value.forEach((v)=>{
86
- process(key, v);
87
- });
88
- } else if (typeof value === 'object') {
89
- Object.entries(value).forEach(([k, v])=>{
90
- process(`${key}[${k}]`, v);
91
- });
92
- } else {
93
- append(key, value);
78
+ const search = new URLSearchParams();
79
+ const walk = (prefix, value)=>{
80
+ if (value == null) return;
81
+ if (value instanceof Date) return search.append(prefix, value.toISOString());
82
+ if (Array.isArray(value)) return value.forEach((v)=>walk(prefix, v));
83
+ if (typeof value === 'object') {
84
+ return Object.entries(value).forEach(([k, v])=>walk(`${prefix}[${k}]`, v));
94
85
  }
86
+ search.append(prefix, String(value));
95
87
  };
96
- Object.entries(params).forEach(([key, value])=>{
97
- process(key, value);
98
- });
99
- if (qs.length > 0) {
100
- return `?${qs.join('&')}`;
101
- }
102
- return '';
88
+ Object.entries(params).forEach(([k, v])=>walk(k, v));
89
+ const searchString = search.toString();
90
+ return searchString ? `?${searchString}` : '';
103
91
  }
104
92
  function mergeHeaders(...allHeaders) {
105
93
  const headers = new Headers();
@@ -1 +1 @@
1
- {"version":3,"file":"requestFn.js","sources":["../../../src/lib/requestFn.ts"],"sourcesContent":["import type {\n HeadersOptions,\n OperationSchema,\n RequestFnInfo,\n RequestFnOptions,\n RequestFnResponse,\n} from '@openapi-qraft/tanstack-query-react-types';\nimport { processResponse, resolveResponse } from './responseUtils.js';\n\n/**\n * This function is used to make a request to a specified endpoint.\n *\n * @template T The expected return type of the request.\n *\n * @param schema The schema of the operation to be performed. It includes the OpenAPI path, HTTP method and media type.\n * @param requestInfo The information required to make the request. It includes parameters, headers, body, etc.\n * @param [options] Optional. Additional options for the request. It includes custom urlSerializer, bodySerializer, and fetch function.\n *\n * @returns {Promise<T>} Returns a promise that resolves with the response of the request.\n *\n * @throws {error: object|string, response: Response} Throws an error if the request fails. The error includes the error message and the response from the server.\n */\nexport async function requestFn<TData, TError>(\n schema: OperationSchema,\n requestInfo: RequestFnInfo,\n options?: RequestFnOptions\n): Promise<RequestFnResponse<TData, TError>> {\n return baseRequestFn<TData, TError>(schema, requestInfo, {\n urlSerializer,\n bodySerializer,\n ...options,\n });\n}\n\n/**\n * This function is used to make a request to a specified endpoint.\n * It's necessary to create a custom `requestFn` with a custom `urlSerializer`\n * and `bodySerializer`, with the tree-shaking of the default `requestFn`\n * and its serializers.\n *\n * @template T The expected return type of the request.\n *\n * @param requestSchema The schema of the operation to be performed. It includes the OpenAPI path, HTTP method and media type.\n * @param requestInfo The information required to make the request. It includes parameters, headers, body, etc.\n * @param options The options for the request. It includes urlSerializer, bodySerializer, and fetch function. The 'urlSerializer' and 'bodySerializer' are required.\n *\n * @returns {Promise<T>} Returns a promise that resolves with the response of the request.\n *\n * @throws {error: object|string, response: Response} Throws an error if the request fails. The error includes the error message and the response from the server.\n */\nexport async function baseRequestFn<TData, TError>(\n requestSchema: OperationSchema,\n requestInfo: RequestFnInfo,\n options: WithRequired<RequestFnOptions, 'urlSerializer' | 'bodySerializer'>\n): Promise<RequestFnResponse<TData, TError>> {\n const { parameters, headers, body, ...requestInfoRest } = requestInfo;\n\n const requestPayload = options.bodySerializer(requestSchema, body);\n\n const baseFetch = options.fetch ?? fetch;\n\n return baseFetch(options.urlSerializer(requestSchema, requestInfo), {\n method: requestSchema.method.toUpperCase(),\n body: requestPayload?.body,\n headers: mergeHeaders(\n { Accept: 'application/json' },\n requestPayload?.headers,\n headers,\n parameters?.header\n ),\n ...requestInfoRest,\n })\n .then(processResponse as typeof processResponse<TData, TError>)\n .catch(resolveResponse as typeof resolveResponse<TData, TError>);\n}\n\n/**\n * Serializes the given schema and request payload into a URL string.\n *\n * This function is implemented according to the URI Template standard\n * defined in RFC 6570. It supports the expansion of path and query parameters,\n * correctly handling empty arrays, `null`, and `undefined` values by ignoring\n * them during the expansion process, as specified by the standard.\n *\n * For more information, refer to the official documentation:\n * https://datatracker.ietf.org/doc/html/rfc6570\n *\n * @param schema - The operation schema containing the URL template and method.\n * @param info - The request payload including baseUrl, path parameters, and query parameters.\n * @returns The fully constructed URL string.\n */\nexport function urlSerializer(\n schema: OperationSchema,\n info: Pick<RequestFnInfo, 'baseUrl' | 'parameters'>\n): string {\n const path = schema.url.replace(\n /{(.*?)}/g,\n (substring: string, group: string) => {\n if (\n info.parameters?.path &&\n Object.prototype.hasOwnProperty.call(info.parameters.path, group)\n ) {\n return encodeURI(String(info.parameters?.path[group]));\n }\n return substring;\n }\n );\n\n const baseUrl = info.baseUrl ?? '';\n\n if (info.parameters?.query) {\n return `${baseUrl}${path}${getQueryString(info.parameters.query)}`;\n }\n\n return `${baseUrl}${path}`;\n}\n\nfunction getQueryString(params: Record<string, any>): string {\n const qs: string[] = [];\n\n const append = (key: string, value: any) => {\n qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);\n };\n\n const process = (key: string, value: any) => {\n if (typeof value === 'undefined' || value === null) return;\n\n if (Array.isArray(value)) {\n value.forEach((v) => {\n process(key, v);\n });\n } else if (typeof value === 'object') {\n Object.entries(value).forEach(([k, v]) => {\n process(`${key}[${k}]`, v);\n });\n } else {\n append(key, value);\n }\n };\n\n Object.entries(params).forEach(([key, value]) => {\n process(key, value);\n });\n\n if (qs.length > 0) {\n return `?${qs.join('&')}`;\n }\n\n return '';\n}\n\nexport function mergeHeaders(...allHeaders: (HeadersOptions | undefined)[]) {\n const headers = new Headers();\n\n for (const headerSet of allHeaders) {\n if (!headerSet || typeof headerSet !== 'object') {\n continue;\n }\n\n const headersIterator =\n headerSet instanceof Headers\n ? headerSet.entries()\n : Object.entries(headerSet);\n\n for (const [headerKey, headerValue] of headersIterator) {\n if (headerValue === null) {\n headers.delete(headerKey);\n } else if (headerValue !== undefined) {\n headers.set(headerKey, headerValue);\n }\n }\n }\n\n return headers;\n}\n\nexport function bodySerializer(\n schema: OperationSchema,\n body: RequestFnInfo['body']\n) {\n if (isReadOnlyOperation(schema)) return undefined;\n\n if (body === undefined || body === null) return undefined;\n\n if (typeof body === 'string') {\n return {\n body,\n headers: {\n 'Content-Type':\n // prefer text/* media type\n schema.mediaType?.find((mediaType) => mediaType.includes('text/')) ??\n // prefer JSON media type, assume that body is serialized as JSON\n schema.mediaType?.find((mediaType) => mediaType.includes('/json')) ??\n 'text/plain',\n },\n };\n }\n\n if (body instanceof FormData) {\n return {\n body,\n headers: {\n // remove `Content-Type` if the serialized body is FormData;\n // the browser will correctly set Content-Type & boundary expression\n 'Content-Type': null,\n },\n };\n }\n\n if (body instanceof Blob) {\n return {\n body,\n headers: {\n 'Content-Type':\n body.type ||\n schema.mediaType?.find(\n (mediaType) =>\n !(\n mediaType.includes('text/') &&\n mediaType.includes('/form-data') &&\n mediaType.includes('/json')\n )\n ) ||\n 'application/octet-stream',\n },\n };\n }\n\n let jsonMediaType: string | null = null;\n let formDataMediaType: string | null = null;\n\n if (schema.mediaType) {\n for (let i = 0; i < schema.mediaType.length; i++) {\n const mediaType = schema.mediaType[i];\n if (mediaType.includes('/json')) jsonMediaType = mediaType;\n else if (mediaType.includes('/form-data')) formDataMediaType = mediaType;\n }\n }\n\n if (formDataMediaType) {\n if (\n !jsonMediaType ||\n // Prefer FormData serialization if one of the fields is a Blob\n Object.values(body).some((value) => value instanceof Blob)\n ) {\n return {\n body: getRequestBodyFormData(body),\n headers: {\n // remove `Content-Type` if the serialized body is FormData;\n // the browser will correctly set Content-Type & boundary expression\n 'Content-Type': null,\n },\n };\n }\n }\n\n return {\n body: JSON.stringify(body),\n headers: {\n 'Content-Type': jsonMediaType ?? 'application/json',\n },\n };\n}\n\nfunction getRequestBodyFormData(\n body: NonNullable<RequestFnInfo['body']>\n): FormData {\n if (body instanceof FormData) return body;\n if (typeof body !== 'object')\n throw new Error(`Unsupported body type ${typeof body} in form-data.`);\n\n const formData = new FormData();\n\n const process = (key: string, value: any) => {\n if (typeof value === 'string' || value instanceof Blob) {\n formData.append(key, value);\n } else {\n formData.append(key, JSON.stringify(value));\n }\n };\n\n Object.entries(body)\n .filter(([_, value]) => typeof value !== 'undefined' && value !== null)\n .forEach(([key, value]) => {\n if (Array.isArray(value)) {\n value.forEach((v) => process(key, v));\n } else {\n process(key, value);\n }\n });\n\n return formData;\n}\n\ntype WithRequired<T, K extends keyof T> = T & {\n [_ in K]: {};\n};\n\nexport type {\n RequestFn,\n RequestFnResponse,\n HeadersOptions,\n RequestFnOptions,\n RequestFnInfo,\n OperationSchema,\n} from '@openapi-qraft/tanstack-query-react-types';\n\n/**\n * @deprecated use `RequestFnInfo` instead\n */\nexport type RequestFnPayload = RequestFnInfo;\n\nfunction isReadOnlyOperation(operation: {\n readonly method:\n | 'get'\n | 'put'\n | 'post'\n | 'patch'\n | 'delete'\n | 'options'\n | 'head'\n | 'trace';\n}) {\n return (\n operation.method === 'get' ||\n operation.method === 'head' ||\n operation.method === 'trace' ||\n operation.method === 'options'\n );\n}\n"],"names":["requestFn","schema","requestInfo","options","baseRequestFn","urlSerializer","bodySerializer","requestSchema","parameters","headers","body","requestInfoRest","requestPayload","baseFetch","fetch","method","toUpperCase","mergeHeaders","Accept","header","then","processResponse","catch","resolveResponse","info","path","url","replace","substring","group","Object","prototype","hasOwnProperty","call","encodeURI","String","baseUrl","query","getQueryString","params","qs","append","key","value","push","encodeURIComponent","process","Array","isArray","forEach","v","entries","k","length","join","allHeaders","Headers","headerSet","headersIterator","headerKey","headerValue","delete","undefined","set","isReadOnlyOperation","mediaType","find","includes","FormData","Blob","type","jsonMediaType","formDataMediaType","i","values","some","getRequestBodyFormData","JSON","stringify","Error","formData","filter","_","operation"],"mappings":"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"}
1
+ {"version":3,"file":"requestFn.js","sources":["../../../src/lib/requestFn.ts"],"sourcesContent":["import type {\n HeadersOptions,\n OperationSchema,\n RequestFnInfo,\n RequestFnOptions,\n RequestFnResponse,\n} from '@openapi-qraft/tanstack-query-react-types';\nimport { processResponse, resolveResponse } from './responseUtils.js';\n\n/**\n * This function is used to make a request to a specified endpoint.\n *\n * @template T The expected return type of the request.\n *\n * @param schema The schema of the operation to be performed. It includes the OpenAPI path, HTTP method and media type.\n * @param requestInfo The information required to make the request. It includes parameters, headers, body, etc.\n * @param [options] Optional. Additional options for the request. It includes custom urlSerializer, bodySerializer, and fetch function.\n *\n * @returns {Promise<T>} Returns a promise that resolves with the response of the request.\n *\n * @throws {error: object|string, response: Response} Throws an error if the request fails. The error includes the error message and the response from the server.\n */\nexport async function requestFn<TData, TError>(\n schema: OperationSchema,\n requestInfo: RequestFnInfo,\n options?: RequestFnOptions\n): Promise<RequestFnResponse<TData, TError>> {\n return baseRequestFn<TData, TError>(schema, requestInfo, {\n urlSerializer,\n bodySerializer,\n ...options,\n });\n}\n\n/**\n * This function is used to make a request to a specified endpoint.\n * It's necessary to create a custom `requestFn` with a custom `urlSerializer`\n * and `bodySerializer`, with the tree-shaking of the default `requestFn`\n * and its serializers.\n *\n * @template T The expected return type of the request.\n *\n * @param requestSchema The schema of the operation to be performed. It includes the OpenAPI path, HTTP method and media type.\n * @param requestInfo The information required to make the request. It includes parameters, headers, body, etc.\n * @param options The options for the request. It includes urlSerializer, bodySerializer, and fetch function. The 'urlSerializer' and 'bodySerializer' are required.\n *\n * @returns {Promise<T>} Returns a promise that resolves with the response of the request.\n *\n * @throws {error: object|string, response: Response} Throws an error if the request fails. The error includes the error message and the response from the server.\n */\nexport async function baseRequestFn<TData, TError>(\n requestSchema: OperationSchema,\n requestInfo: RequestFnInfo,\n options: WithRequired<RequestFnOptions, 'urlSerializer' | 'bodySerializer'>\n): Promise<RequestFnResponse<TData, TError>> {\n const { parameters, headers, body, ...requestInfoRest } = requestInfo;\n\n const requestPayload = options.bodySerializer(requestSchema, body);\n\n const baseFetch = options.fetch ?? fetch;\n\n return baseFetch(options.urlSerializer(requestSchema, requestInfo), {\n method: requestSchema.method.toUpperCase(),\n body: requestPayload?.body,\n headers: mergeHeaders(\n { Accept: 'application/json' },\n requestPayload?.headers,\n headers,\n parameters?.header\n ),\n ...requestInfoRest,\n })\n .then(processResponse as typeof processResponse<TData, TError>)\n .catch(resolveResponse as typeof resolveResponse<TData, TError>);\n}\n\n/**\n * Serializes the given schema and request payload into a URL string.\n *\n * This function is implemented according to the URI Template standard\n * defined in RFC 6570. It supports the expansion of path and query parameters,\n * correctly handling empty arrays, `null`, and `undefined` values by ignoring\n * them during the expansion process, as specified by the standard.\n *\n * For more information, refer to the official documentation:\n * https://datatracker.ietf.org/doc/html/rfc6570\n *\n * @param schema - The operation schema containing the URL template and method.\n * @param info - The request payload including baseUrl, path parameters, and query parameters.\n * @returns The fully constructed URL string.\n */\nexport function urlSerializer(\n schema: OperationSchema,\n info: Pick<RequestFnInfo, 'baseUrl' | 'parameters'>\n): string {\n const path = schema.url.replace(\n /{(.*?)}/g,\n (substring: string, group: string) => {\n if (\n info.parameters?.path &&\n Object.prototype.hasOwnProperty.call(info.parameters.path, group)\n ) {\n return encodeURIComponent(String(info.parameters?.path[group]));\n }\n return substring;\n }\n );\n\n const baseUrl = info.baseUrl ?? '';\n\n if (info.parameters?.query) {\n return `${baseUrl}${path}${getQueryString(info.parameters.query)}`;\n }\n\n return `${baseUrl}${path}`;\n}\n\nfunction getQueryString(params: Record<string, any>): string {\n const search = new URLSearchParams();\n\n const walk = (prefix: string, value: any) => {\n if (value == null) return;\n if (value instanceof Date)\n return search.append(prefix, value.toISOString());\n if (Array.isArray(value)) return value.forEach((v) => walk(prefix, v));\n if (typeof value === 'object') {\n return Object.entries(value).forEach(([k, v]) =>\n walk(`${prefix}[${k}]`, v)\n );\n }\n search.append(prefix, String(value));\n };\n\n Object.entries(params).forEach(([k, v]) => walk(k, v));\n\n const searchString = search.toString();\n\n return searchString ? `?${searchString}` : '';\n}\n\nexport function mergeHeaders(...allHeaders: (HeadersOptions | undefined)[]) {\n const headers = new Headers();\n\n for (const headerSet of allHeaders) {\n if (!headerSet || typeof headerSet !== 'object') {\n continue;\n }\n\n const headersIterator =\n headerSet instanceof Headers\n ? headerSet.entries()\n : Object.entries(headerSet);\n\n for (const [headerKey, headerValue] of headersIterator) {\n if (headerValue === null) {\n headers.delete(headerKey);\n } else if (headerValue !== undefined) {\n headers.set(headerKey, headerValue);\n }\n }\n }\n\n return headers;\n}\n\nexport function bodySerializer(\n schema: OperationSchema,\n body: RequestFnInfo['body']\n) {\n if (isReadOnlyOperation(schema)) return undefined;\n\n if (body === undefined || body === null) return undefined;\n\n if (typeof body === 'string') {\n return {\n body,\n headers: {\n 'Content-Type':\n // prefer text/* media type\n schema.mediaType?.find((mediaType) => mediaType.includes('text/')) ??\n // prefer JSON media type, assume that body is serialized as JSON\n schema.mediaType?.find((mediaType) => mediaType.includes('/json')) ??\n 'text/plain',\n },\n };\n }\n\n if (body instanceof FormData) {\n return {\n body,\n headers: {\n // remove `Content-Type` if the serialized body is FormData;\n // the browser will correctly set Content-Type & boundary expression\n 'Content-Type': null,\n },\n };\n }\n\n if (body instanceof Blob) {\n return {\n body,\n headers: {\n 'Content-Type':\n body.type ||\n schema.mediaType?.find(\n (mediaType) =>\n !(\n mediaType.includes('text/') &&\n mediaType.includes('/form-data') &&\n mediaType.includes('/json')\n )\n ) ||\n 'application/octet-stream',\n },\n };\n }\n\n let jsonMediaType: string | null = null;\n let formDataMediaType: string | null = null;\n\n if (schema.mediaType) {\n for (let i = 0; i < schema.mediaType.length; i++) {\n const mediaType = schema.mediaType[i];\n if (mediaType.includes('/json')) jsonMediaType = mediaType;\n else if (mediaType.includes('/form-data')) formDataMediaType = mediaType;\n }\n }\n\n if (formDataMediaType) {\n if (\n !jsonMediaType ||\n // Prefer FormData serialization if one of the fields is a Blob\n Object.values(body).some((value) => value instanceof Blob)\n ) {\n return {\n body: getRequestBodyFormData(body),\n headers: {\n // remove `Content-Type` if the serialized body is FormData;\n // the browser will correctly set Content-Type & boundary expression\n 'Content-Type': null,\n },\n };\n }\n }\n\n return {\n body: JSON.stringify(body),\n headers: {\n 'Content-Type': jsonMediaType ?? 'application/json',\n },\n };\n}\n\nfunction getRequestBodyFormData(\n body: NonNullable<RequestFnInfo['body']>\n): FormData {\n if (body instanceof FormData) return body;\n if (typeof body !== 'object')\n throw new Error(`Unsupported body type ${typeof body} in form-data.`);\n\n const formData = new FormData();\n\n const process = (key: string, value: any) => {\n if (typeof value === 'string' || value instanceof Blob) {\n formData.append(key, value);\n } else {\n formData.append(key, JSON.stringify(value));\n }\n };\n\n Object.entries(body)\n .filter(([_, value]) => typeof value !== 'undefined' && value !== null)\n .forEach(([key, value]) => {\n if (Array.isArray(value)) {\n value.forEach((v) => process(key, v));\n } else {\n process(key, value);\n }\n });\n\n return formData;\n}\n\ntype WithRequired<T, K extends keyof T> = T & {\n [_ in K]: {};\n};\n\nexport type {\n RequestFn,\n RequestFnResponse,\n HeadersOptions,\n RequestFnOptions,\n RequestFnInfo,\n OperationSchema,\n} from '@openapi-qraft/tanstack-query-react-types';\n\n/**\n * @deprecated use `RequestFnInfo` instead\n */\nexport type RequestFnPayload = RequestFnInfo;\n\nfunction isReadOnlyOperation(operation: {\n readonly method:\n | 'get'\n | 'put'\n | 'post'\n | 'patch'\n | 'delete'\n | 'options'\n | 'head'\n | 'trace';\n}) {\n return (\n operation.method === 'get' ||\n operation.method === 'head' ||\n operation.method === 'trace' ||\n operation.method === 'options'\n );\n}\n"],"names":["requestFn","schema","requestInfo","options","baseRequestFn","urlSerializer","bodySerializer","requestSchema","parameters","headers","body","requestInfoRest","requestPayload","baseFetch","fetch","method","toUpperCase","mergeHeaders","Accept","header","then","processResponse","catch","resolveResponse","info","path","url","replace","substring","group","Object","prototype","hasOwnProperty","call","encodeURIComponent","String","baseUrl","query","getQueryString","params","search","URLSearchParams","walk","prefix","value","Date","append","toISOString","Array","isArray","forEach","v","entries","k","searchString","toString","allHeaders","Headers","headerSet","headersIterator","headerKey","headerValue","delete","undefined","set","isReadOnlyOperation","mediaType","find","includes","FormData","Blob","type","jsonMediaType","formDataMediaType","i","length","values","some","getRequestBodyFormData","JSON","stringify","Error","formData","process","key","filter","_","operation"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"requestFn.d.ts","sourceRoot":"","sources":["../../../src/lib/requestFn.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,2CAA2C,CAAC;AAGnD;;;;;;;;;;;;GAYG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,EAC3C,MAAM,EAAE,eAAe,EACvB,WAAW,EAAE,aAAa,EAC1B,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAM3C;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,EAC/C,aAAa,EAAE,eAAe,EAC9B,WAAW,EAAE,aAAa,EAC1B,OAAO,EAAE,YAAY,CAAC,gBAAgB,EAAE,eAAe,GAAG,gBAAgB,CAAC,GAC1E,OAAO,CAAC,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAoB3C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,SAAS,GAAG,YAAY,CAAC,GAClD,MAAM,CAqBR;AAoCD,wBAAgB,YAAY,CAAC,GAAG,UAAU,EAAE,CAAC,cAAc,GAAG,SAAS,CAAC,EAAE,WAuBzE;AAED,wBAAgB,cAAc,CAC5B,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;cAoF5B;AAgCD,KAAK,YAAY,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,CAAC,GAAG;KAC3C,CAAC,IAAI,CAAC,GAAG,EAAE;CACb,CAAC;AAEF,YAAY,EACV,SAAS,EACT,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,eAAe,GAChB,MAAM,2CAA2C,CAAC;AAEnD;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,aAAa,CAAC"}
1
+ {"version":3,"file":"requestFn.d.ts","sourceRoot":"","sources":["../../../src/lib/requestFn.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,2CAA2C,CAAC;AAGnD;;;;;;;;;;;;GAYG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,EAC3C,MAAM,EAAE,eAAe,EACvB,WAAW,EAAE,aAAa,EAC1B,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAM3C;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,EAC/C,aAAa,EAAE,eAAe,EAC9B,WAAW,EAAE,aAAa,EAC1B,OAAO,EAAE,YAAY,CAAC,gBAAgB,EAAE,eAAe,GAAG,gBAAgB,CAAC,GAC1E,OAAO,CAAC,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAoB3C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,SAAS,GAAG,YAAY,CAAC,GAClD,MAAM,CAqBR;AAyBD,wBAAgB,YAAY,CAAC,GAAG,UAAU,EAAE,CAAC,cAAc,GAAG,SAAS,CAAC,EAAE,WAuBzE;AAED,wBAAgB,cAAc,CAC5B,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;cAoF5B;AAgCD,KAAK,YAAY,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,CAAC,GAAG;KAC3C,CAAC,IAAI,CAAC,GAAG,EAAE;CACb,CAAC;AAEF,YAAY,EACV,SAAS,EACT,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,eAAe,GAChB,MAAM,2CAA2C,CAAC;AAEnD;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,aAAa,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openapi-qraft/react",
3
- "version": "2.9.0",
3
+ "version": "2.10.1",
4
4
  "description": "OpenAPI client for React, providing type-safe requests and dynamic TanStack Query React Hooks via a modular, Proxy-based architecture.",
5
5
  "scripts": {
6
6
  "build": "NODE_ENV=production rollup --config rollup.config.mjs && tsc --project tsconfig.build.json --emitDeclarationOnly",
@@ -15,19 +15,19 @@
15
15
  },
16
16
  "sideEffects": false,
17
17
  "dependencies": {
18
- "@openapi-qraft/tanstack-query-react-types": "2.9.0"
18
+ "@openapi-qraft/tanstack-query-react-types": "2.10.1"
19
19
  },
20
20
  "peerDependencies": {
21
21
  "@tanstack/react-query": "^5.80.0",
22
22
  "react": "^18 || ^19"
23
23
  },
24
24
  "devDependencies": {
25
- "@openapi-qraft/cli": "2.9.0",
25
+ "@openapi-qraft/cli": "2.10.1",
26
26
  "@openapi-qraft/eslint-config": "1.0.1",
27
- "@openapi-qraft/openapi-typescript-plugin": "^1.2.25",
27
+ "@openapi-qraft/openapi-typescript-plugin": "^1.2.27",
28
28
  "@openapi-qraft/rollup-config": "1.1.1",
29
- "@openapi-qraft/tanstack-query-react-plugin": "2.9.0",
30
- "@openapi-qraft/test-fixtures": "1.1.0",
29
+ "@openapi-qraft/tanstack-query-react-plugin": "2.10.1",
30
+ "@openapi-qraft/test-fixtures": "1.1.1",
31
31
  "@tanstack/react-query": "^5.80.6",
32
32
  "@testing-library/dom": "^10.4.0",
33
33
  "@testing-library/react": "^16.2.0",
@@ -100,7 +100,7 @@ export function urlSerializer(
100
100
  info.parameters?.path &&
101
101
  Object.prototype.hasOwnProperty.call(info.parameters.path, group)
102
102
  ) {
103
- return encodeURI(String(info.parameters?.path[group]));
103
+ return encodeURIComponent(String(info.parameters?.path[group]));
104
104
  }
105
105
  return substring;
106
106
  }
@@ -116,37 +116,26 @@ export function urlSerializer(
116
116
  }
117
117
 
118
118
  function getQueryString(params: Record<string, any>): string {
119
- const qs: string[] = [];
120
-
121
- const append = (key: string, value: any) => {
122
- qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
123
- };
124
-
125
- const process = (key: string, value: any) => {
126
- if (typeof value === 'undefined' || value === null) return;
127
-
128
- if (Array.isArray(value)) {
129
- value.forEach((v) => {
130
- process(key, v);
131
- });
132
- } else if (typeof value === 'object') {
133
- Object.entries(value).forEach(([k, v]) => {
134
- process(`${key}[${k}]`, v);
135
- });
136
- } else {
137
- append(key, value);
119
+ const search = new URLSearchParams();
120
+
121
+ const walk = (prefix: string, value: any) => {
122
+ if (value == null) return;
123
+ if (value instanceof Date)
124
+ return search.append(prefix, value.toISOString());
125
+ if (Array.isArray(value)) return value.forEach((v) => walk(prefix, v));
126
+ if (typeof value === 'object') {
127
+ return Object.entries(value).forEach(([k, v]) =>
128
+ walk(`${prefix}[${k}]`, v)
129
+ );
138
130
  }
131
+ search.append(prefix, String(value));
139
132
  };
140
133
 
141
- Object.entries(params).forEach(([key, value]) => {
142
- process(key, value);
143
- });
134
+ Object.entries(params).forEach(([k, v]) => walk(k, v));
144
135
 
145
- if (qs.length > 0) {
146
- return `?${qs.join('&')}`;
147
- }
136
+ const searchString = search.toString();
148
137
 
149
- return '';
138
+ return searchString ? `?${searchString}` : '';
150
139
  }
151
140
 
152
141
  export function mergeHeaders(...allHeaders: (HeadersOptions | undefined)[]) {
@@ -14,6 +14,38 @@ describe('urlSerializer', () => {
14
14
  ).toBe('https://api.example.com/users/123/posts/456');
15
15
  });
16
16
 
17
+ it('should correctly encode complex characters in path and query parameters', () => {
18
+ const info = {
19
+ baseUrl: 'https://api.example.com',
20
+ parameters: {
21
+ path: {
22
+ query: 'hello/world:test@domain.com',
23
+ category: 'books & magazines',
24
+ },
25
+ query: {
26
+ filter: 'price:$10-$50',
27
+ tags: ['tag/with/slash', 'tag:with:colon'],
28
+ special: 'symbols!@#$%^&*()+={}[]|\\:";\'<>?,./~`',
29
+ },
30
+ },
31
+ } as const;
32
+
33
+ const result = urlSerializer(
34
+ { url: '/search/{query}/category/{category}', method: 'get' },
35
+ info
36
+ );
37
+
38
+ const expectedUrl = new URL(
39
+ 'https://api.example.com/search/hello%2Fworld%3Atest%40domain.com/category/books%20%26%20magazines'
40
+ );
41
+ expectedUrl.searchParams.set('filter', info.parameters.query.filter);
42
+ expectedUrl.searchParams.append('tags', info.parameters.query.tags[0]);
43
+ expectedUrl.searchParams.append('tags', info.parameters.query.tags[1]);
44
+ expectedUrl.searchParams.set('special', info.parameters.query.special);
45
+
46
+ expect(result).toBe(expectedUrl.toString());
47
+ });
48
+
17
49
  it('should correctly append query parameters', () => {
18
50
  expect(
19
51
  urlSerializer(
@@ -215,4 +247,237 @@ describe('urlSerializer', () => {
215
247
  )
216
248
  ).toBe('https://api.example.com/users/undefined/posts/456');
217
249
  });
250
+
251
+ it('should correctly serialize query parameters with Date objects', () => {
252
+ expect(
253
+ urlSerializer(
254
+ { url: '/events', method: 'get' },
255
+ {
256
+ baseUrl: 'https://api.example.com',
257
+ parameters: {
258
+ query: {
259
+ startDate: new Date('2023-12-25T10:30:00.000Z'),
260
+ limit: 5,
261
+ },
262
+ },
263
+ }
264
+ )
265
+ ).toBe(
266
+ `https://api.example.com/events?startDate=2023-12-25T10%3A30%3A00.000Z&limit=5`
267
+ );
268
+ });
269
+
270
+ it('should correctly serialize query parameters with Date objects in arrays', () => {
271
+ expect(
272
+ urlSerializer(
273
+ { url: '/events', method: 'get' },
274
+ {
275
+ baseUrl: 'https://api.example.com',
276
+ parameters: {
277
+ query: {
278
+ dates: [
279
+ new Date('2023-01-01T00:00:00.000Z'),
280
+ new Date('2023-12-31T23:59:59.999Z'),
281
+ ],
282
+ active: true,
283
+ },
284
+ },
285
+ }
286
+ )
287
+ ).toBe(
288
+ 'https://api.example.com/events?dates=2023-01-01T00%3A00%3A00.000Z&dates=2023-12-31T23%3A59%3A59.999Z&active=true'
289
+ );
290
+ });
291
+
292
+ it('should correctly serialize query parameters with Date objects in nested objects', () => {
293
+ const startDate = new Date('2023-01-01T00:00:00.000Z');
294
+ expect(
295
+ urlSerializer(
296
+ { url: '/events', method: 'get' },
297
+ {
298
+ baseUrl: 'https://api.example.com',
299
+ parameters: {
300
+ query: {
301
+ timeRange: {
302
+ start: startDate,
303
+ end: null,
304
+ },
305
+ limit: 10,
306
+ },
307
+ },
308
+ }
309
+ )
310
+ ).toBe(
311
+ 'https://api.example.com/events?timeRange%5Bstart%5D=2023-01-01T00%3A00%3A00.000Z&limit=10'
312
+ );
313
+ });
314
+
315
+ it('should correctly serialize query parameters with boolean values', () => {
316
+ expect(
317
+ urlSerializer(
318
+ { url: '/users', method: 'get' },
319
+ {
320
+ baseUrl: 'https://api.example.com',
321
+ parameters: {
322
+ query: {
323
+ active: true,
324
+ verified: false,
325
+ premium: null,
326
+ limit: 10,
327
+ },
328
+ },
329
+ }
330
+ )
331
+ ).toBe('https://api.example.com/users?active=true&verified=false&limit=10');
332
+ });
333
+
334
+ it('should correctly serialize query parameters with numeric values', () => {
335
+ expect(
336
+ urlSerializer(
337
+ { url: '/products', method: 'get' },
338
+ {
339
+ baseUrl: 'https://api.example.com',
340
+ parameters: {
341
+ query: {
342
+ price: 0,
343
+ discount: 25.5,
344
+ quantity: -1,
345
+ maxPrice: 1000,
346
+ },
347
+ },
348
+ }
349
+ )
350
+ ).toBe(
351
+ 'https://api.example.com/products?price=0&discount=25.5&quantity=-1&maxPrice=1000'
352
+ );
353
+ });
354
+
355
+ it('should correctly serialize query parameters with special numeric values', () => {
356
+ expect(
357
+ urlSerializer(
358
+ { url: '/data', method: 'get' },
359
+ {
360
+ baseUrl: 'https://api.example.com',
361
+ parameters: {
362
+ query: {
363
+ infinity: Infinity,
364
+ negativeInfinity: -Infinity,
365
+ notANumber: NaN,
366
+ normal: 42,
367
+ },
368
+ },
369
+ }
370
+ )
371
+ ).toBe(
372
+ 'https://api.example.com/data?infinity=Infinity&negativeInfinity=-Infinity&notANumber=NaN&normal=42'
373
+ );
374
+ });
375
+
376
+ it('should correctly serialize query parameters with empty string values', () => {
377
+ expect(
378
+ urlSerializer(
379
+ { url: '/search', method: 'get' },
380
+ {
381
+ baseUrl: 'https://api.example.com',
382
+ parameters: {
383
+ query: {
384
+ query: '',
385
+ category: 'books',
386
+ sort: null,
387
+ },
388
+ },
389
+ }
390
+ )
391
+ ).toBe('https://api.example.com/search?query=&category=books');
392
+ });
393
+
394
+ it('should correctly serialize deeply nested objects', () => {
395
+ expect(
396
+ urlSerializer(
397
+ { url: '/complex', method: 'get' },
398
+ {
399
+ baseUrl: 'https://api.example.com',
400
+ parameters: {
401
+ query: {
402
+ level1: {
403
+ level2: {
404
+ level3: {
405
+ value: 'deep',
406
+ number: 42,
407
+ },
408
+ array: ['a', 'b'],
409
+ },
410
+ },
411
+ simple: 'value',
412
+ },
413
+ },
414
+ }
415
+ )
416
+ ).toBe(
417
+ 'https://api.example.com/complex?level1%5Blevel2%5D%5Blevel3%5D%5Bvalue%5D=deep&level1%5Blevel2%5D%5Blevel3%5D%5Bnumber%5D=42&level1%5Blevel2%5D%5Barray%5D=a&level1%5Blevel2%5D%5Barray%5D=b&simple=value'
418
+ );
419
+ });
420
+
421
+ it('should correctly serialize mixed arrays with different types', () => {
422
+ const testDate = new Date('2023-06-15T12:00:00.000Z');
423
+ expect(
424
+ urlSerializer(
425
+ { url: '/mixed', method: 'get' },
426
+ {
427
+ baseUrl: 'https://api.example.com',
428
+ parameters: {
429
+ query: {
430
+ mixed: ['string', 123, true, testDate, null, undefined],
431
+ clean: 'value',
432
+ },
433
+ },
434
+ }
435
+ )
436
+ ).toBe(
437
+ 'https://api.example.com/mixed?mixed=string&mixed=123&mixed=true&mixed=2023-06-15T12%3A00%3A00.000Z&clean=value'
438
+ );
439
+ });
440
+
441
+ it('should handle objects with arrays containing objects', () => {
442
+ expect(
443
+ urlSerializer(
444
+ { url: '/nested-array-objects', method: 'get' },
445
+ {
446
+ baseUrl: 'https://api.example.com',
447
+ parameters: {
448
+ query: {
449
+ items: [
450
+ { name: 'item1', value: 100 },
451
+ { name: 'item2', value: null },
452
+ ],
453
+ total: 2,
454
+ },
455
+ },
456
+ }
457
+ )
458
+ ).toBe(
459
+ 'https://api.example.com/nested-array-objects?items%5Bname%5D=item1&items%5Bvalue%5D=100&items%5Bname%5D=item2&total=2'
460
+ );
461
+ });
462
+
463
+ it('should handle edge cases with String() conversion', () => {
464
+ // Test to verify correct processing of different types of data
465
+ expect(
466
+ urlSerializer(
467
+ { url: '/edge-cases', method: 'get' },
468
+ {
469
+ baseUrl: 'https://api.example.com',
470
+ parameters: {
471
+ query: {
472
+ bigint: BigInt(123),
473
+ symbol: 'symbol-as-string', // Symbol cannot be serialized directly
474
+ func: '[Function]', // Functions should not get into query, but if they do - as a string
475
+ },
476
+ },
477
+ }
478
+ )
479
+ ).toBe(
480
+ 'https://api.example.com/edge-cases?bigint=123&symbol=symbol-as-string&func=%5BFunction%5D'
481
+ );
482
+ });
218
483
  });