@unshared/client 0.2.0 → 0.2.2

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.
Files changed (47) hide show
  1. package/dist/chunks/{wF9C7mO0.js → B5hc73Po.js} +16 -24
  2. package/dist/chunks/B5hc73Po.js.map +1 -0
  3. package/dist/chunks/{BIx2AaJH.d.ts → BsMghIPi.d.ts} +12 -14
  4. package/dist/chunks/CKfJvIQ8.js +50 -0
  5. package/dist/chunks/CKfJvIQ8.js.map +1 -0
  6. package/dist/chunks/Cx8m1YzL.cjs +49 -0
  7. package/dist/chunks/Cx8m1YzL.cjs.map +1 -0
  8. package/dist/chunks/D-WqCFul.js +30 -0
  9. package/dist/chunks/D-WqCFul.js.map +1 -0
  10. package/dist/chunks/{C3RyfPUw.cjs → D8Tsm7xC.cjs} +16 -24
  11. package/dist/chunks/D8Tsm7xC.cjs.map +1 -0
  12. package/dist/chunks/{B0duX_ls.d.ts → DZp6zyqV.d.ts} +13 -4
  13. package/dist/chunks/r8pYO6Hx.d.ts +38 -0
  14. package/dist/chunks/xRZPkxch.cjs +29 -0
  15. package/dist/chunks/xRZPkxch.cjs.map +1 -0
  16. package/dist/createClient.cjs +8 -11
  17. package/dist/createClient.cjs.map +1 -1
  18. package/dist/createClient.d.ts +8 -7
  19. package/dist/createClient.js +8 -10
  20. package/dist/createClient.js.map +1 -1
  21. package/dist/fetch.cjs +2 -2
  22. package/dist/fetch.cjs.map +1 -1
  23. package/dist/fetch.d.ts +5 -1
  24. package/dist/fetch.js +2 -2
  25. package/dist/fetch.js.map +1 -1
  26. package/dist/index.cjs +12 -9
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.ts +5 -3
  29. package/dist/index.js +15 -11
  30. package/dist/index.js.map +1 -1
  31. package/dist/openapi.cjs +45 -7
  32. package/dist/openapi.cjs.map +1 -1
  33. package/dist/openapi.d.ts +5 -5
  34. package/dist/openapi.js +43 -5
  35. package/dist/openapi.js.map +1 -1
  36. package/dist/utils.cjs +4 -1
  37. package/dist/utils.cjs.map +1 -1
  38. package/dist/utils.d.ts +17 -3
  39. package/dist/utils.js +6 -2
  40. package/dist/utils.js.map +1 -1
  41. package/package.json +4 -3
  42. package/dist/chunks/BzqHK4CV.cjs +0 -71
  43. package/dist/chunks/BzqHK4CV.cjs.map +0 -1
  44. package/dist/chunks/C3RyfPUw.cjs.map +0 -1
  45. package/dist/chunks/CRISqhP7.js +0 -72
  46. package/dist/chunks/CRISqhP7.js.map +0 -1
  47. package/dist/chunks/wF9C7mO0.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"wF9C7mO0.js","sources":["../../utils/isFormDataLike.ts","../../utils/isObjectLike.ts","../../utils/toFormData.ts","../../utils/parseRequestBody.ts","../../utils/parseRequestHeaders.ts","../../utils/parseRequestParameters.ts","../../utils/toSearchParams.ts","../../utils/parseRequestQuery.ts","../../utils/parseRequestUrl.ts","../../utils/parseRequest.ts"],"sourcesContent":["/**\n * A type that represents a FormData-like object, which is a plain object with\n * nested Blob, File, or FileList values. Or a FormData instance.\n */\nexport type FormDataLike = FormData | Record<string, Blob | File | FileList>\n\n/**\n * Predicate to check if a value is FormData-like, meaning it is a plain object\n * with nested Blob, File, or FileList values.\n *\n * @param value The value to check.\n * @returns `true` if the value is FormData-like, `false` otherwise.\n * @example isFormDataLike({ file: new File(['test'], 'test.txt') }) // true\n */\nexport function isFormDataLike(value: unknown): value is FormDataLike {\n if (typeof value !== 'object' || value === null) return false\n if (value instanceof FormData) return true\n return Object.values(value).some((x) => {\n if (x instanceof File) return true\n if (Array.isArray(x)) return x.some(item => item instanceof File)\n return x instanceof Blob\n })\n}\n","/**\n * Predicate to check if a value is an object-like value.\n *\n * @param value The value to check.\n * @returns `true` if the value is an object-like value, `false` otherwise.\n * @example isObjectLike({}) // true\n */\nexport function isObjectLike(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && value.constructor === Object\n}\n","import type { FormDataLike } from './isFormDataLike'\n\n/**\n * Casts an object that may contain `Blob`, `File`, or `FileList` values to a `FormData` object.\n *\n * @param object The object to cast to a `FormData` object.\n * @returns The `FormData` object.\n */\nexport function toFormData(object: FormDataLike): FormData {\n if (object instanceof FormData) return object\n const formData = new FormData()\n for (const key in object) {\n const value = object[key]\n if (value === undefined) continue\n if (Array.isArray(value)) {\n for (const item of value)\n formData.append(key, item as Blob | string)\n }\n else {\n formData.append(key, value as Blob | string)\n }\n }\n return formData\n}\n","import type { RequestContext, RequestOptions } from './parseRequest'\nimport { isFormDataLike } from './isFormDataLike'\nimport { isObjectLike } from './isObjectLike'\nimport { toFormData } from './toFormData'\n\n/**\n * Parse the request body based on the provided data and options.\n *\n * @param route The route path.\n * @param options The request options.\n * @param context The request context.\n */\nexport function parseRequestBody(route: string, options: Pick<RequestOptions, 'body' | 'data'>, context: RequestContext): void {\n const { data, body } = options\n const { init } = context\n init.headers = init.headers ?? {}\n\n // --- If the `body` is provided, return early.\n if (body !== undefined) {\n init.body = body\n return\n }\n\n // --- If the method is `GET`, `HEAD`, or `DELETE`, return early.\n if (['get', 'head', 'delete'].includes(init.method ?? 'get')) return\n\n // --- If no data is provided, return early.\n if (data === null || data === undefined) return\n\n // --- If data contains a `File` object, create a FormData object.\n if (isFormDataLike(data)) {\n init.body = toFormData(data)\n init.headers = { ...init.headers, 'Content-Type': 'multipart/form-data' }\n }\n\n // --- If the data is a `ReadableStream`, pass it directly to the body.\n else if (data instanceof ReadableStream) {\n init.body = data\n }\n\n // --- If the data is a Blob, pass it directly to the body.\n else if (data instanceof File) {\n init.body = data.stream()\n init.headers = { ...init.headers, 'Content-Type': 'application/octet-stream' }\n }\n\n // --- Otherwise, stringify the data and set the content type to JSON.\n else if (isObjectLike(data)) {\n init.body = JSON.stringify(data)\n init.headers = { ...init.headers, 'Content-Type': 'application/json' }\n }\n}\n","import type { RequestContext, RequestOptions } from './parseRequest'\n\n/**\n * Parse the request headers based on the provided data and options.\n *\n * @param route The route path.\n * @param options The request options.\n * @param context The request context.\n */\nexport function parseRequestHeaders(route: string, options: Pick<RequestOptions, 'headers'>, context: RequestContext): void {\n const { headers } = options\n const { init } = context\n init.headers = init.headers ?? {}\n\n // --- If no headers are provided, return early.\n if (!headers) return\n\n // --- Merge the headers with the existing headers.\n for (const key in headers) {\n const value = headers[key]\n if (value === undefined) continue\n if (typeof value !== 'string') continue\n init.headers = { ...init.headers, [key]: value }\n }\n}\n","import type { RequestContext, RequestOptions } from './parseRequest'\nimport { isObjectLike } from './isObjectLike'\n\n/** Regular expression to match path parameters in the URL. */\nconst EXP_PATH_PARAMETER = /:([\\w-]+)|%7B([\\w-]+)%7D/g\n\n/**\n * Parse the request parameters from the request data. This function will append\n * the path parameters to the URL based on the method and the data provided.\n *\n * @param route The name of the route to fetch. (ignored)\n * @param options The options to pass to the request.\n * @param context The request context to modify.\n * @example\n * // Using `express` style path parameters.\n * parseRequestParameters('GET /users/:id', { data: { id: 1 } }, context)\n *\n * // Using `OpenAPI` style path parameters.\n * parseRequestParameters('GET /users/{id}', { data: { id: 1 } }, context)\n */\nexport function parseRequestParameters(route: string, options: Pick<RequestOptions, 'data' | 'parameters'>, context: RequestContext): void {\n const { url } = context\n const { data, parameters = {} } = options\n\n // --- If the method has a parameter, fill the path with the data.\n if (!url) throw new Error('Could not resolve the `RequestInit` object: the `url` is missing.')\n const pathParameters = url.pathname.match(EXP_PATH_PARAMETER)\n if (!pathParameters) return\n\n // --- If a path parameter is provided in the data, fill the path with the data.\n if (isObjectLike(data)) {\n for (const key in data) {\n const value = data[key]\n if (value === undefined) continue\n if (typeof value !== 'string') continue\n if (parameters[key] !== undefined) continue\n parameters[key] = value\n delete data[key]\n }\n }\n\n // --- Apply the path parameters to the URL.\n for (const parameter of pathParameters.values()) {\n const key = parameter.replaceAll(EXP_PATH_PARAMETER, '$1$2')\n const value = parameters[key]\n if (value === undefined) continue\n if (typeof value !== 'string') continue\n url.pathname = url.pathname.replace(parameter, value)\n }\n}\n","/* eslint-disable unicorn/prevent-abbreviations */\nimport type { MaybeArray } from '@unshared/types'\n\n/** An object that can be converted to a query string. */\nexport type SearchParamsObject = Record<string, MaybeArray<boolean | number | string> | undefined>\n\n/** The search array format options. */\nexport type SearchArrayFormat = 'brackets' | 'comma' | 'flat' | 'indices' | 'path'\n\n/** Options for the query string conversion. */\nexport interface ToSearchParamsOptions {\n\n /**\n * Defines how to handle arrays in the object. There is no standard way to\n * represent arrays in query strings, so this option allows you to choose\n * how to handle them. Additionally, you can provide a custom function to\n * handle it yourself.\n *\n * - `brackets` (default): Convert arrays to `key[]=value&key[]=value` format.\n * - `indices`: Convert arrays to `key[0]=value&key[1]=value` format.\n * - `comma`: Convert arrays to `key=value1,value2` format.\n * - `path`: Convert arrays to `key.0=value&key.1=value` format.\n * - `flat`: Convert arrays to `key=value1&key=value2` format.\n *\n * @default 'flat'\n */\n searchArrayFormat?: SearchArrayFormat\n}\n\n/**\n * Convert object to query string parameters. Converting all values to strings\n * and arrays to `key[0]=value&key[1]=value` format.\n *\n * @param object The object to convert to a query string.\n * @param options The query string options.\n * @returns The `URLSearchParams` object.\n */\nexport function toSearchParams(object: SearchParamsObject, options: ToSearchParamsOptions = {}): URLSearchParams {\n const { searchArrayFormat = 'flat' } = options\n const search = new URLSearchParams()\n for (const key in object) {\n const value = object[key]\n if (value === undefined) continue\n\n // --- Convert arrays based on the format.\n if (Array.isArray(value)) {\n if (searchArrayFormat === 'brackets') for (const v of value) search.append(`${key}[]`, String(v))\n else if (searchArrayFormat === 'indices') for (const [i, v] of value.entries()) search.append(`${key}[${i}]`, String(v))\n else if (searchArrayFormat === 'comma') search.append(key, value.join(','))\n else if (searchArrayFormat === 'path') for (const [i, v] of value.entries()) search.append(`${key}.${i}`, String(v))\n else if (searchArrayFormat === 'flat') for (const v of value) search.append(key, String(v))\n }\n\n // --- Convert all values to strings.\n else { search.append(key, value.toString()) }\n }\n\n // --- Return the query string.\n return search\n}\n","/* eslint-disable unicorn/prevent-abbreviations */\nimport type { RequestContext, RequestOptions } from './parseRequest'\nimport { isObjectLike } from './isObjectLike'\nimport { toSearchParams } from './toSearchParams'\n\n/**\n * Parse the query parameters from the request data. This function will append\n * the query parameters to the URL based on the method and the data provided.\n *\n * @param route The name of the route to fetch. (ignored)\n * @param options The options to pass to the request.\n * @param context The request context to modify.\n */\nexport function parseRequestQuery(route: string, options: Pick<RequestOptions, 'data' | 'query' | 'searchArrayFormat'>, context: RequestContext): void {\n const { url, init } = context\n const { data, query = {}, searchArrayFormat } = options\n if (!url) throw new Error('Could not resolve the `RequestInit` object: the `url` is missing.')\n\n // --- Append the `data` to the query parameters if the method does not expect a body.\n const isExpectingBody = ['post', 'put', 'patch'].includes(init.method ?? 'get')\n if (!isExpectingBody && isObjectLike(data)) {\n for (const key in data) {\n if (data[key] === undefined) continue\n if (query[key] !== undefined) continue\n // @ts-expect-error: Ignore type mismatch.\n query[key] = data[key]\n delete data[key]\n }\n }\n\n // --- Apply the query parameters to the URL.\n url.search = toSearchParams(query, { searchArrayFormat }).toString()\n}\n","import type { RequestContext, RequestOptions } from './parseRequest'\n\n/** Regular expression to match the request method and URL. */\nconst EXP_REQUEST = /^((?<method>[a-z]+) )?(?<url>[^:]+?:\\/{2}[^/]+)?(?<path>\\/[^\\s?]*)/i\n\n/** Valid HTTP methods. */\nconst METHODS = new Set(['get', 'post', 'put', 'patch', 'delete', 'head', 'options'])\n\n/**\n * Parses the route name to extract the URL and method. It allows the url and method to be\n * provided in the route name, or in the options object. The method will default to 'get'.\n *\n * @param route The name of the route to fetch.\n * @param options The options to pass to the request.\n * @param context The request context to modify.\n * @example parseRequestUrl('GET /users', { baseUrl: 'https://api.example.com' }, context)\n */\nexport function parseRequestUrl(route: string, options: Pick<RequestOptions, 'baseUrl' | 'method'>, context: RequestContext): void {\n const { method, baseUrl } = options\n\n // --- Extract the path, method, and base URL from the route name.\n const match = EXP_REQUEST.exec(route)\n if (!match?.groups) throw new Error('Could not resolve the `RequestInit` object: Invalid route name.')\n const routeMethod = method ?? match.groups.method ?? 'get'\n const routeBaseUrl = baseUrl ?? match.groups.url\n\n // --- Assert the base URL is provided, either in the options or the route name.\n if (!routeBaseUrl) throw new Error('Could not resolve the `RequestInit` object: the `baseUrl` is missing.')\n\n // --- Assert the method is valid.\n const methodLower = routeMethod.toLowerCase()\n const methodIsValid = METHODS.has(methodLower)\n if (!methodIsValid) throw new Error(`Could not resolve the \\`RequestInit\\` object:, the method \\`${routeMethod}\\` is invalid.`)\n\n // --- Create the url and apply the method.\n context.init = context.init ?? {}\n context.init.method = methodLower\n context.url = new URL(routeBaseUrl)\n\n // --- Append the path to the URL while making sure there are no double slashes.\n context.url.pathname += context.url.pathname.endsWith('/') ? match.groups.path.slice(1) : match.groups.path\n}\n","/* eslint-disable unicorn/prevent-abbreviations */\nimport type { MaybeLiteral } from '@unshared/types'\nimport type { Override } from '@unshared/types'\nimport type { HttpHeader, HttpMethod } from '../types'\nimport type { SearchArrayFormat, SearchParamsObject } from './toSearchParams'\nimport { parseRequestBody } from './parseRequestBody'\nimport { parseRequestHeaders } from './parseRequestHeaders'\nimport { parseRequestParameters } from './parseRequestParameters'\nimport { parseRequestQuery } from './parseRequestQuery'\nimport { parseRequestUrl } from './parseRequestUrl'\n\n/** Headers to include in the request. */\nexport type RequestHeaders = Partial<Record<MaybeLiteral<HttpHeader>, string>>\n\nexport type RequestOptions = Override<RequestInit, {\n\n /**\n * The method to use for the request.\n *\n * @example 'GET'\n */\n method?: Lowercase<keyof typeof HttpMethod> | Uppercase<keyof typeof HttpMethod>\n\n /**\n * The base URL to use for the request. This URL will be used to resolve the\n * path and query parameters of the request.\n *\n * @example 'https://api.example.com'\n */\n baseUrl?: string\n\n /**\n * The data to pass to the request. This data will be used to fill the path\n * parameters, query parameters, body, and form data of the request based on\n * the route method.\n */\n data?: Blob | File | FileList | FormData | ReadableStream | Record<string, unknown> | string\n\n /**\n * The headers to include in the request.\n */\n headers?: RequestHeaders\n\n /**\n * Query parameters to include in the request.\n */\n query?: SearchParamsObject\n\n /**\n * The format to use when serializing the query parameters.\n */\n searchArrayFormat?: SearchArrayFormat\n\n /**\n * The path parameters to include in the request.\n */\n parameters?: Record<string, number | string>\n}>\n\nexport interface RequestContext {\n url?: URL\n init: RequestInit\n}\n\n/**\n * Resolves the request body and/or query parameters based on the method type. This function\n * will mutate the `init` object to include the request body and headers based on the data type.\n *\n * @param route The name of the route to fetch.\n * @param options The options to pass to the request.\n * @returns The URL and the `RequestInit` object.\n */\nexport function parseRequest(route: string, options: RequestOptions = {}) {\n const { data, body, query, headers, parameters, baseUrl, method, searchArrayFormat, ...requestInit } = options\n const context: RequestContext = { init: requestInit }\n parseRequestUrl(route, { baseUrl, method }, context)\n parseRequestParameters(route, { data, parameters }, context)\n parseRequestQuery(route, { data, query, searchArrayFormat }, context)\n parseRequestBody(route, { body, data }, context)\n parseRequestHeaders(route, { headers }, context)\n return context\n}\n"],"names":[],"mappings":"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"}