@unshared/client 0.6.6 → 0.7.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/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2024 Stanley Horwood <stanley@hsjm.io>
3
+ Copyright (c) 2025 Stanley Horwood <stanley@hsjm.io>
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -139,14 +139,15 @@ async function* createResponseStreamJsonIterator(response, options) {
139
139
  const parts = new TextDecoder().decode(value).trim().split("\0").filter(Boolean);
140
140
  for (const part of parts) {
141
141
  const payload = JSON.parse(part);
142
- onData && onData(payload), yield payload;
142
+ onData && await onData(payload, options), yield payload;
143
143
  }
144
144
  }
145
- onSuccess && onSuccess(response);
145
+ onSuccess && await onSuccess(response, options);
146
146
  } catch (error) {
147
- onError && onError(error);
147
+ if (onError) await onError(error, options);
148
+ else throw error;
148
149
  } finally {
149
- onEnd && onEnd(response);
150
+ onEnd && await onEnd(response, options);
150
151
  }
151
152
  }
152
153
  function handleResponseStreamJson(response, options) {
@@ -183,7 +184,7 @@ async function* createResponseStreamSseIterator(response, options) {
183
184
  for (const line of lines) {
184
185
  if (line === "") {
185
186
  const event2 = flush2();
186
- event2 && (yield event2), event2 && onData && onData(event2);
187
+ event2 && (yield event2), event2 && onData && await onData(event2, options);
187
188
  continue;
188
189
  }
189
190
  if (line.startsWith(":")) continue;
@@ -194,11 +195,12 @@ async function* createResponseStreamSseIterator(response, options) {
194
195
  }
195
196
  }
196
197
  const event = flush2();
197
- event && (yield event), event && onData && onData(event), onSuccess && onSuccess(response);
198
+ event && (yield event), event && onData && await onData(event, options), onSuccess && await onSuccess(response, options);
198
199
  } catch (error) {
199
- throw onError && onError(error), error;
200
+ if (onError) await onError(error, options);
201
+ else throw error;
200
202
  } finally {
201
- onEnd && onEnd(response);
203
+ onEnd && await onEnd(response, options);
202
204
  }
203
205
  }
204
206
  function handleResponseStreamSse(response, options) {
@@ -208,20 +210,22 @@ function handleResponseStreamSse(response, options) {
208
210
  async function handleResponse(response, options = {}) {
209
211
  const { onError, onSuccess, onData, onEnd, onFailure } = options, contentType = response.headers.get("Content-Type");
210
212
  if (!response.ok)
211
- throw onFailure && await onFailure(response), onEnd && onEnd(response), new Error(response.statusText);
213
+ throw onFailure && await onFailure(response, options), onEnd && await onEnd(response, options), new Error(response.statusText);
212
214
  if (response.status === 204) {
213
- onSuccess && onSuccess(response), onEnd && onEnd(response);
215
+ onSuccess && await onSuccess(response, options), onEnd && await onEnd(response, options);
214
216
  return;
215
217
  }
216
- return contentType?.startsWith("application/stream+json") ? handleResponseStreamJson(response, options) : contentType?.startsWith("text/event-stream") ? handleResponseStreamSse(response, options) : contentType?.startsWith("application/json") ? await response.json().then((data) => (onData && onData(data), onSuccess && onSuccess(response), data)).catch((error) => {
217
- throw onError && onError(error), error;
218
+ return contentType?.startsWith("application/stream+json") ? handleResponseStreamJson(response, options) : contentType?.startsWith("text/event-stream") ? handleResponseStreamSse(response, options) : contentType?.startsWith("application/json") ? await response.json().then(async (data) => (onData && await onData(data, options), onSuccess && await onSuccess(response, options), data)).catch(async (error) => {
219
+ if (onError) await onError(error, options);
220
+ else throw error;
218
221
  }).finally(() => {
219
- onEnd && onEnd(response);
220
- }) : contentType?.startsWith("text/") ? await response.text().then((data) => (onData && onData(data), onSuccess && onSuccess(response), data)).catch((error) => {
221
- throw onError && onError(error), error;
222
+ onEnd && onEnd(response, options);
223
+ }) : contentType?.startsWith("text/") ? await response.text().then(async (data) => (onData && await onData(data, options), onSuccess && await onSuccess(response, options), data)).catch(async (error) => {
224
+ if (onError) await onError(error, options);
225
+ else throw error;
222
226
  }).finally(() => {
223
- onEnd && onEnd(response);
224
- }) : (onSuccess && onSuccess(response), onEnd && onEnd(response), response.body);
227
+ onEnd && onEnd(response, options);
228
+ }) : (onSuccess && onSuccess(response, options), onEnd && onEnd(response, options), response.body);
225
229
  }
226
230
  exports.getCookies = getCookies;
227
231
  exports.getHeader = getHeader;
@@ -239,4 +243,4 @@ exports.parseRequestUrl = parseRequestUrl;
239
243
  exports.setCookie = setCookie;
240
244
  exports.setHeader = setHeader;
241
245
  exports.toFormData = toFormData;
242
- //# sourceMappingURL=CbXCpEzw.cjs.map
246
+ //# sourceMappingURL=-InYnohy.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"CbXCpEzw.cjs","sources":["../../utils/isObjectLike.ts","../../utils/setHeader.ts","../../utils/parseRequestBasicAuth.ts","../../utils/isFormDataLike.ts","../../utils/toFormData.ts","../../utils/parseRequestBody.ts","../../utils/parseRequestHeaders.ts","../../utils/getHeader.ts","../../utils/getCookies.ts","../../utils/setCookie.ts","../../utils/parseRequestToken.ts","../../utils/parseRequestUrl.ts","../../utils/parseRequest.ts","../../utils/handleResponseStreamJson.ts","../../utils/handleResponseStreamSse.ts","../../utils/handleResponse.ts"],"sourcesContent":["import type { ObjectLike } from '@unshared/types'\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 ObjectLike {\n return typeof value === 'object' && value !== null && value.constructor === Object\n}\n","/**\n * Set a header in the `HeadersInit` object whether it is a `Headers` instance, an\n * array of key-value pairs, or an object. It is also case-insensitive, meaning that\n * if a header with the same key but different case is found, it will be replaced.\n *\n * @param headers The headers to set the key-value pair in.\n * @param key The key of the header to set.\n * @param value The value of the header to set.\n * @example\n * const headers = new Headers()\n * setHeader(headers, 'Content-Type', 'application/json')\n * console.log(headers.get('Content-Type')) // 'application/json'\n */\nexport function setHeader(headers: HeadersInit, key: string, value: number | string): void {\n value = String(value)\n if (headers instanceof Headers) {\n headers.set(key, value)\n }\n else if (Array.isArray(headers)) {\n const keyLower = key.toLowerCase()\n const index = headers.findIndex(([k]) => k.toLowerCase() === keyLower)\n if (index === -1) headers.push([key, value])\n headers[index] = [key, value]\n }\n else if (typeof headers === 'object' && headers !== null) {\n const keyLower = key.toLowerCase()\n for (const k in headers) {\n if (k.toLowerCase() !== keyLower) continue\n headers[k] = value\n return\n }\n headers[key] = value\n }\n}\n","import type { FetchOptions, RequestContext } from './parseRequest'\nimport { setHeader } from './setHeader'\n\n/**\n * Parse the basic authentication headers based on the provided username and password.\n *\n * @param context The request context.\n * @param options The request options.\n * @example\n *\n * // Append the `Authorization` header to the request.\n * const context = {}\n * parseRequestBasicAuth(context, { username: 'user', password: 'pass' })\n *\n * // Will mutate the `init` object to include the headers.\n * console.log(context) // => { init: { headers: { 'Authorization': 'Basic dXNlcjpwYXNz' } } }\n */\nexport function parseRequestBasicAuth(context: Partial<RequestContext>, options: FetchOptions): void {\n const { username, password } = options\n\n // --- Return early if the username or password is not provided.\n if (typeof username !== 'string' || typeof password !== 'string') return\n\n // --- Encode the credentials and set the Authorization header.\n const credentials = btoa(`${username}:${password}`)\n context.init = context.init ?? {}\n context.init.headers = context.init.headers ?? {}\n setHeader(context.init.headers, 'Authorization', `Basic ${credentials}`)\n}\n","/**\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 const values = Object.values(value)\n if (values.length === 0) return false\n return values.every((x) => {\n if (x instanceof File) return true\n if (Array.isArray(x)) return x.every(item => item instanceof File)\n return x instanceof Blob\n })\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 { FetchOptions, RequestContext } from './parseRequest'\nimport { isFormDataLike } from './isFormDataLike'\nimport { isObjectLike } from './isObjectLike'\nimport { setHeader } from './setHeader'\nimport { toFormData } from './toFormData'\n\n/**\n * Parse the request body based on the provided data and options.\n *\n * @param context The request context.\n * @param options The request options.\n */\nexport function parseRequestBody(context: Partial<RequestContext>, options: FetchOptions): void {\n const { body } = options\n\n // --- If the method is `GET`, `HEAD`, or `DELETE`, return early.\n if (!context.init?.method) return\n if (['get', 'head', 'delete'].includes(context.init.method)) return\n\n // --- If no data is provided, return early.\n if (body === null || body === undefined) return\n\n // --- If data contains a `File` object, create a FormData object.\n if (isFormDataLike(body)) {\n context.init.body = toFormData(body)\n }\n\n // --- If the data is a `ReadableStream`, pass it directly to the body.\n else if (body instanceof ReadableStream) {\n context.init.body = body\n context.init.headers = context.init.headers ?? {}\n setHeader(context.init.headers, 'Content-Type', 'application/octet-stream')\n }\n\n // --- If the data is a Blob, pass it directly to the body.\n else if (body instanceof File) {\n context.init.body = body.stream()\n context.init.headers = context.init.headers ?? {}\n setHeader(context.init.headers, 'Content-Disposition', `attachment; filename=\"${body.name}\"`)\n setHeader(context.init.headers, 'Content-Type', body.type)\n setHeader(context.init.headers, 'Content-Length', body.size)\n setHeader(context.init.headers, 'Content-Transfer-Encoding', 'binary')\n }\n\n // --- Otherwise, stringify the data and set the content type to JSON.\n else if (isObjectLike(body)) {\n context.init.body = JSON.stringify(body)\n context.init.headers = context.init.headers ?? {}\n setHeader(context.init.headers, 'Content-Type', 'application/json')\n }\n\n // --- For all other data types, set the body directly.\n else {\n context.init.body = body as BodyInit\n }\n}\n","import type { FetchOptions, RequestContext } from './parseRequest'\nimport { setHeader } from './setHeader'\n\n/**\n * Parse the request headers based on the provided data and options.\n *\n * @param context The request context.\n * @param options The request options.\n * @example\n *\n * // Append the `Content-Type` header to the request.\n * const context = {}\n * parseRequestHeaders(context, { headers: { 'Content-Type': 'application/json' } })\n *\n * // Will mutate the `init` object to include the headers.\n * console.log(context) // => { init: { headers: { 'Content-Type': 'application/json' } } }\n */\nexport function parseRequestHeaders(context: Partial<RequestContext>, options: FetchOptions): void {\n const { headers } = options\n\n // --- Merge the headers with the existing headers.\n for (const key in headers) {\n const value = headers[key]\n if (((typeof value !== 'string' || value.length === 0) && typeof value !== 'number')) continue\n context.init = context.init ?? {}\n context.init.headers = context.init.headers ?? {}\n setHeader(context.init.headers, key, value)\n }\n}\n","/**\n * Get a header value from the `HeadersInit` object.\n *\n * @param headers The headers to get the key-value pair from.\n * @param key The key of the header to get.\n * @returns The value of the header.\n * @example\n * const headers = new Headers({ 'Content-Type': 'application/json' })\n * const contentType = getHeader(headers, 'Content-Type')\n * console.log(contentType) // 'application/json'\n */\nexport function getHeader(headers: HeadersInit, key: string): string | undefined {\n if (headers instanceof Headers) {\n return headers.get(key) ?? undefined\n }\n else if (Array.isArray(headers)) {\n const keyLower = key.toLowerCase()\n const header = headers.find(([k]) => k.toLowerCase() === keyLower)\n return header ? header[1] : undefined\n }\n else {\n const keyLower = key.toLowerCase()\n const keys = Object.keys(headers)\n const index = keys.findIndex(k => k.toLowerCase() === keyLower)\n return index === -1 ? undefined : headers[keys[index]]\n }\n}\n","import { getHeader } from './getHeader'\n\n/**\n * Extract the cookies from the `HeadersInit` object.\n *\n * @param headers The headers to extract the cookies from.\n * @returns An array of cookies.\n * @example\n * const headers = new Headers({ Cookie: 'key1=value1; key2=value2' })\n * const cookies = getCookies(headers) // { key1: 'value1', key2: 'value2' }\n */\nexport function getCookies(headers: HeadersInit): Record<string, string> {\n const value = getHeader(headers, 'Cookie')\n if (!value) return {}\n\n // --- Parse the cookie header.\n const cookies: Record<string, string> = {}\n const parts = value.split(';')\n for (const part of parts) {\n const [key, value] = part.trim().split('=').map(v => v.trim())\n if (!key || !value) continue\n cookies[key] = value\n }\n\n // --- Return the cookies.\n return cookies\n}\n","import { getCookies } from './getCookies'\nimport { setHeader } from './setHeader'\n\n/**\n * Set a cookie in the `HeadersInit` object.\n *\n * @param headers The headers to set the cookie in.\n * @param key The key of the cookie to set.\n * @param value The value of the cookie to set.\n * @example\n * const headers = new Headers()\n * const cookie = { key: 'key1', value: 'value1', path: '/', secure: true }\n * setCookie(headers, cookie)\n * console.log(headers.get('Cookie')) // 'key1=value1; Path=/; Secure'\n */\nexport function setCookie(headers: HeadersInit, key: string, value: string): void {\n const cookies = { ...getCookies(headers), [key]: value }\n const header = Object.entries(cookies).map(([key, value]) => `${key}=${value}`).join('; ')\n setHeader(headers, 'Cookie', header)\n}\n","import type { FetchOptions, RequestContext } from './parseRequest'\nimport { setCookie } from './setCookie'\nimport { setHeader } from './setHeader'\n\n/**\n * Parse the token and dynamically extend either the query, headers, or cookies.\n *\n * @param context The request context.\n * @param options The request options.\n * @example\n * // Append the `token` to the query parameters.\n * const context = { url: new URL('https://example.com') }\n * parseRequestToken(context, { token: 'my-token', tokenLocation: 'query', tokenProperty: 'token' })\n * console.log(context.url.searchParams.get('token')) // 'my-token'\n *\n * @example\n * // Append the `token` to the headers.\n * const context = { init: { headers: new Headers() } }\n * parseRequestToken(context, { token: 'my-token', tokenLocation: 'header', tokenProperty: 'Authorization' })\n * console.log(context.init.headers.get('Authorization')) // 'Bearer my-token'\n *\n * @example\n * // Append the `token` to the cookies.\n * const context = { init: { headers: new Headers() } }\n * parseRequestToken(context, { token: 'my-token', tokenLocation: 'cookie', tokenProperty: 'token' })\n * console.log(context.init.headers.get('Cookie')) // 'token=my-token'\n */\nexport function parseRequestToken(context: Partial<RequestContext>, options: FetchOptions): void {\n const { token, tokenLocation = 'headers', tokenProperty } = options\n\n // --- Return early if the token is not provided.\n if (!token) return\n\n // --- Append the token to the query parameters.\n if (tokenLocation === 'query') {\n if (context.url instanceof URL === false) throw new Error('The `url` must be an instance of `URL`.')\n if (!tokenProperty) throw new Error('The `tokenProperty` must be provided when using `tokenLocation` of `query`.')\n context.url.searchParams.set(tokenProperty, token)\n }\n\n // --- Append the token to the path parameters.\n else if (tokenLocation === 'header') {\n context.init = context.init ?? {}\n context.init.headers = context.init.headers ?? {}\n if (tokenProperty) setHeader(context.init.headers, tokenProperty, token)\n else setHeader(context.init.headers, 'Authorization', `Bearer ${token}`)\n }\n\n // --- Append the token to the cookie header.\n else if (tokenLocation === 'cookie') {\n if (!tokenProperty) throw new Error('The `tokenProperty` must be provided when using `tokenLocation` of `cookie`.')\n context.init = context.init ?? {}\n context.init.headers = context.init.headers ?? {}\n setCookie(context.init.headers, tokenProperty, token)\n }\n}\n","import type { FetchOptions, RequestContext } 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 context The request context to mutate.\n * @param route The name of the route to fetch.\n * @param options The options to pass to the request.\n * @example parseRequestUrl('GET /users', { baseUrl: 'https://api.example.com' }, context)\n */\nexport function parseRequestUrl(context: Partial<RequestContext>, route: string, options: FetchOptions): 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","import type { Loose, MaybeLiteral, ObjectLike } from '@unshared/types'\nimport type { UnionMerge } from '@unshared/types'\nimport type { HttpHeader } from '../HttpHeaders'\nimport type { HttpMethod } from '../HttpMethods'\nimport type { SearchArrayFormat } from './toSearchParams'\nimport { isObjectLike } from './isObjectLike'\nimport { parseRequestBasicAuth } from './parseRequestBasicAuth'\nimport { parseRequestBody } from './parseRequestBody'\nimport { parseRequestHeaders } from './parseRequestHeaders'\nimport { parseRequestParameters } from './parseRequestParameters'\nimport { parseRequestQuery } from './parseRequestQuery'\nimport { parseRequestToken } from './parseRequestToken'\nimport { parseRequestUrl } from './parseRequestUrl'\n\n/** The methods to use for the request. */\nexport type FetchMethod = Lowercase<keyof typeof HttpMethod> | Uppercase<keyof typeof HttpMethod>\n\n/** Headers to include in the request. */\nexport type FetchHeaders = Partial<Record<MaybeLiteral<HttpHeader>, number | string>>\n\n/** Options to pass to the request. */\nexport interface FetchOptions<\n Method extends FetchMethod = FetchMethod,\n BaseUrl extends string = string,\n Parameters extends ObjectLike = ObjectLike,\n Query extends ObjectLike = ObjectLike,\n Body = unknown,\n Headers extends ObjectLike = ObjectLike,\n> extends Omit<RequestInit, 'body' | 'headers' | 'method'> {\n\n /**\n * The method to use for the request.\n *\n * @example 'GET'\n */\n method?: Method\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?: BaseUrl\n\n /**\n * The data to include in the request. This data will be used to populate the\n * query parameters, body, and headers of the request based on the method type.\n *\n * @example { id: 1 }\n */\n data?: Loose<UnionMerge<Body | Headers | Query>>\n\n /**\n * The path parameters to include in the request.\n */\n parameters?: Parameters\n\n /**\n * The query parameters to include in the request.\n */\n query?: Loose<Query>\n\n /**\n * The format to use when serializing the query parameters.\n */\n queryArrayFormat?: SearchArrayFormat\n\n /**\n * The body to include in the request.\n */\n body?: Body extends ObjectLike ? Loose<Body> : Body\n\n /**\n * The headers to include in the request.\n */\n headers?: FetchHeaders & Headers\n\n /**\n * The username for basic authentication.\n */\n username?: string\n\n /**\n * The password for basic authentication.\n */\n password?: string\n\n /**\n * The token for API key authentication.\n */\n token?: string\n\n /**\n * The location where the token should be included in the request.\n */\n tokenLocation?: 'cookie' | 'header' | 'query'\n\n /**\n * The name of the key to use in the request for the token.\n */\n tokenProperty?: 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: FetchOptions = {}): RequestContext {\n const {\n username,\n password,\n token,\n tokenLocation,\n tokenProperty,\n data,\n body,\n query,\n parameters,\n headers,\n method,\n baseUrl,\n queryArrayFormat,\n ...init\n } = options\n const context: Partial<RequestContext> = { init }\n const dataObject = isObjectLike(data) ? data : undefined\n\n // --- Parse the URL and insert the path parameters.\n parseRequestUrl(context, route, { baseUrl, method })\n parseRequestParameters(context, { parameters: parameters ?? dataObject })\n parseRequestBasicAuth(context, { username, password })\n\n // --- Depending on the method, parse the query, body, and headers.\n const requestMethod = context.init?.method?.toLowerCase() ?? 'get'\n const requestExpectsBody = ['post', 'put', 'patch'].includes(requestMethod)\n parseRequestQuery(context, { queryArrayFormat, query: requestExpectsBody ? query : query ?? dataObject })\n parseRequestToken(context, { token, tokenLocation, tokenProperty })\n parseRequestBody(context, { body: requestExpectsBody ? body ?? dataObject : undefined })\n parseRequestHeaders(context, { headers })\n\n // --- Return the context with the URL and the `RequestInit` object.\n return context as RequestContext\n}\n","import type { Awaitable } from '@unshared/functions/awaitable'\nimport type { RequestOptions } from './request'\nimport { awaitable } from '@unshared/functions/awaitable'\n\nasync function * createResponseStreamJsonIterator(response: Response, options: RequestOptions): AsyncGenerator<unknown, void, unknown> {\n const { onError, onSuccess, onData, onEnd } = options\n try {\n const body = response.body\n if (body === null) throw new Error('Could not read the response body, it is empty.')\n const reader = body.getReader()\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n const parts = new TextDecoder().decode(value).trim().split('\\0').filter(Boolean)\n\n // --- For each part, parse as JSON and yield the data.\n for (const part of parts) {\n const payload = JSON.parse(part) as unknown\n if (onData) onData(payload)\n yield payload\n }\n }\n if (onSuccess) onSuccess(response)\n }\n catch (error) {\n if (onError) onError(error as Error)\n }\n finally {\n if (onEnd) onEnd(response)\n }\n}\n\n/**\n * Handle a request response where the content type is a stream of JSON objects. This function\n * will parse the JSON objects and yield the data to the caller. If an error occurs, the `onError`\n * callback will be called and the function will return.\n *\n * @param response The response to handle.\n * @param options The options to pass to the request.\n * @returns An awaitable iterator that yields the parsed JSON objects.\n */\nexport function handleResponseStreamJson(response: Response, options: RequestOptions): Awaitable<AsyncIterable<unknown>, unknown[]> {\n const responseIterator = createResponseStreamJsonIterator(response, options)\n return awaitable(responseIterator)\n}\n","/* eslint-disable sonarjs/cognitive-complexity */\nimport type { Awaitable } from '@unshared/functions/awaitable'\nimport type { RequestOptions } from './request'\nimport { awaitable } from '@unshared/functions/awaitable'\n\n/** SSE event data structure */\nexport interface SseEvent<T = string> {\n\n /** The event type */\n event?: string\n\n /** The event data */\n data: T\n\n /** The event ID */\n id?: string\n\n /** The retry timeout in milliseconds */\n retry?: number\n}\n\nasync function * createResponseStreamSseIterator<T>(response: Response, options: RequestOptions): AsyncGenerator<SseEvent<T>, void, unknown> {\n const { onError, onSuccess, onData, onEnd } = options\n try {\n const body = response.body\n if (body === null) throw new Error('Could not read the response body, it is empty.')\n const reader = body.getReader()\n const decoder = new TextDecoder()\n\n // SSE parsing state buffers according to spec\n let buffer = ''\n let bufferData = ''\n let bufferEvent = ''\n let bufferId = ''\n let bufferRetry: number | undefined\n\n function flush() {\n if (bufferData === '') return\n if (bufferData.endsWith('\\n')) bufferData = bufferData.slice(0, -1)\n const sseEvent = {} as SseEvent<unknown>\n\n // --- Set `event`, `id`, and `retry` fields if they are set\n if (bufferEvent !== '') sseEvent.event = bufferEvent\n if (bufferId !== '') sseEvent.id = bufferId\n if (bufferRetry !== undefined) sseEvent.retry = bufferRetry\n\n // --- Attempt to parse the `data` field as JSON if it looks like an object\n try { sseEvent.data = JSON.parse(bufferData) as object }\n catch { sseEvent.data = bufferData }\n\n // --- Reset buffers for the next event\n bufferData = ''\n bufferEvent = ''\n bufferId = ''\n bufferRetry = undefined\n\n return sseEvent as SseEvent<T>\n }\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n // --- Split on all valid line endings: CRLF, LF, CR\n // --- Additionally, keep the last incomplete line in the buffer\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split(/\\r\\n|\\n|\\r/)\n buffer = lines.pop() ?? ''\n\n for (const line of lines) {\n\n // --- Empty line dispatches the event.\n if (line === '') {\n const event = flush()\n if (event) yield event\n if (event && onData) onData(event)\n continue\n }\n\n // --- Skip comment lines (start with colon)\n if (line.startsWith(':')) continue\n\n // --- Parse field name and value by finding the first colon.\n const colonIndex = line.indexOf(':')\n let fieldName: string\n let fieldValue: string\n\n // --- No colon means field name only, empty value\n if (colonIndex === -1) {\n fieldName = line\n fieldValue = ''\n }\n else {\n fieldName = line.slice(0, colonIndex)\n fieldValue = line.slice(colonIndex + 1)\n if (fieldValue.startsWith(' ')) fieldValue = fieldValue.slice(1)\n }\n\n // --- Extract event type, data, id, and retry fields according to spec\n // --- Note that id must not contain null characters and retry must be a valid number.\n if (fieldName === 'event') {\n bufferEvent = fieldValue\n }\n else if (fieldName === 'data') {\n bufferData += `${fieldValue}\\n`\n }\n else if (fieldName === 'id') {\n if (!fieldValue.includes('\\0'))\n bufferId = fieldValue\n }\n else if (fieldName === 'retry' && /^\\d+$/.test(fieldValue)) {\n bufferRetry = Number.parseInt(fieldValue, 10)\n }\n }\n }\n\n // --- Handle any remaining event in buffer at end of stream\n const event = flush()\n if (event) yield event\n if (event && onData) onData(event)\n if (onSuccess) onSuccess(response)\n }\n catch (error) {\n if (onError) onError(error as Error)\n throw error\n }\n finally {\n if (onEnd) onEnd(response)\n }\n}\n\n/**\n * Handle a request response where the content type is a Server-Sent Events stream. This function\n * will parse the SSE events and yield the data to the caller. If an error occurs, the `onError`\n * callback will be called and the function will return.\n *\n * @param response The response to handle.\n * @param options The options to pass to the request.\n * @returns An awaitable iterator that yields the parsed SSE events.\n */\nexport function handleResponseStreamSse<T>(response: Response, options: RequestOptions): Awaitable<AsyncIterable<SseEvent<T>>, Array<SseEvent<T>>> {\n const responseIterator = createResponseStreamSseIterator<T>(response, options)\n return awaitable(responseIterator)\n}\n","import type { RequestOptions } from './request'\nimport { handleResponseStreamJson } from './handleResponseStreamJson'\nimport { handleResponseStreamSse } from './handleResponseStreamSse'\n\n/**\n * Handle a request response. This function will parse the response based on the content type and\n * return the data. If an error occurs, the `onError` callback will be called and the function will\n * throw an error.\n *\n * @param response The response to handle.\n * @param options The options to pass to the request.\n * @returns The parsed data from the response.\n */\nexport async function handleResponse(response: Response, options: RequestOptions = {}): Promise<unknown> {\n const { onError, onSuccess, onData, onEnd, onFailure } = options\n const contentType = response.headers.get('Content-Type')\n\n // --- If the response is not OK, throw an error with the response message.\n if (!response.ok) {\n if (onFailure) await onFailure(response)\n if (onEnd) onEnd(response)\n throw new Error(response.statusText)\n }\n\n // --- If the status code is 204, return an empty response early.\n if (response.status === 204) {\n if (onSuccess) onSuccess(response)\n if (onEnd) onEnd(response)\n return\n }\n\n // --- If the response is a application/stream+json, return an iterator that parses the JSON.\n if (contentType?.startsWith('application/stream+json'))\n return handleResponseStreamJson(response, options)\n\n // --- If the response is a text/event-stream, return an iterator that parses the SSE events.\n if (contentType?.startsWith('text/event-stream'))\n return handleResponseStreamSse(response, options)\n\n // --- If the response is a application/json, parse the JSON and return it.\n if (contentType?.startsWith('application/json')) {\n return await response.json()\n .then((data) => {\n if (onData) onData(data)\n if (onSuccess) onSuccess(response)\n return data as unknown\n })\n .catch((error: Error) => {\n if (onError) onError(error)\n throw error\n })\n .finally(() => {\n if (onEnd) onEnd(response)\n })\n }\n\n // --- If the response is a text content type (but not event-stream), return the text response.\n if (contentType?.startsWith('text/')) {\n return await response.text()\n .then((data) => {\n if (onData) onData(data)\n if (onSuccess) onSuccess(response)\n return data\n })\n .catch((error: Error) => {\n if (onError) onError(error)\n throw error\n })\n .finally(() => {\n if (onEnd) onEnd(response)\n })\n }\n\n // --- Otherwise, fallback to returning the response body as-is.\n if (onSuccess) onSuccess(response)\n if (onEnd) onEnd(response)\n return response.body\n}\n"],"names":["value","key","parseRequestParameters","parseRequestQuery","awaitable","flush","event"],"mappings":"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"}
1
+ {"version":3,"file":"-InYnohy.cjs","sources":["../../utils/isObjectLike.ts","../../utils/setHeader.ts","../../utils/parseRequestBasicAuth.ts","../../utils/isFormDataLike.ts","../../utils/toFormData.ts","../../utils/parseRequestBody.ts","../../utils/parseRequestHeaders.ts","../../utils/getHeader.ts","../../utils/getCookies.ts","../../utils/setCookie.ts","../../utils/parseRequestToken.ts","../../utils/parseRequestUrl.ts","../../utils/parseRequest.ts","../../utils/handleResponseStreamJson.ts","../../utils/handleResponseStreamSse.ts","../../utils/handleResponse.ts"],"sourcesContent":["import type { ObjectLike } from '@unshared/types'\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 ObjectLike {\n return typeof value === 'object' && value !== null && value.constructor === Object\n}\n","/**\n * Set a header in the `HeadersInit` object whether it is a `Headers` instance, an\n * array of key-value pairs, or an object. It is also case-insensitive, meaning that\n * if a header with the same key but different case is found, it will be replaced.\n *\n * @param headers The headers to set the key-value pair in.\n * @param key The key of the header to set.\n * @param value The value of the header to set.\n * @example\n * const headers = new Headers()\n * setHeader(headers, 'Content-Type', 'application/json')\n * console.log(headers.get('Content-Type')) // 'application/json'\n */\nexport function setHeader(headers: HeadersInit, key: string, value: number | string): void {\n value = String(value)\n if (headers instanceof Headers) {\n headers.set(key, value)\n }\n else if (Array.isArray(headers)) {\n const keyLower = key.toLowerCase()\n const index = headers.findIndex(([k]) => k.toLowerCase() === keyLower)\n if (index === -1) headers.push([key, value])\n headers[index] = [key, value]\n }\n else if (typeof headers === 'object' && headers !== null) {\n const keyLower = key.toLowerCase()\n for (const k in headers) {\n if (k.toLowerCase() !== keyLower) continue\n headers[k] = value\n return\n }\n headers[key] = value\n }\n}\n","import type { FetchOptions, RequestContext } from './parseRequest'\nimport { setHeader } from './setHeader'\n\n/**\n * Parse the basic authentication headers based on the provided username and password.\n *\n * @param context The request context.\n * @param options The request options.\n * @example\n *\n * // Append the `Authorization` header to the request.\n * const context = {}\n * parseRequestBasicAuth(context, { username: 'user', password: 'pass' })\n *\n * // Will mutate the `init` object to include the headers.\n * console.log(context) // => { init: { headers: { 'Authorization': 'Basic dXNlcjpwYXNz' } } }\n */\nexport function parseRequestBasicAuth(context: Partial<RequestContext>, options: FetchOptions): void {\n const { username, password } = options\n\n // --- Return early if the username or password is not provided.\n if (typeof username !== 'string' || typeof password !== 'string') return\n\n // --- Encode the credentials and set the Authorization header.\n const credentials = btoa(`${username}:${password}`)\n context.init = context.init ?? {}\n context.init.headers = context.init.headers ?? {}\n setHeader(context.init.headers, 'Authorization', `Basic ${credentials}`)\n}\n","/**\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 const values = Object.values(value)\n if (values.length === 0) return false\n return values.every((x) => {\n if (x instanceof File) return true\n if (Array.isArray(x)) return x.every(item => item instanceof File)\n return x instanceof Blob\n })\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 { FetchOptions, RequestContext } from './parseRequest'\nimport { isFormDataLike } from './isFormDataLike'\nimport { isObjectLike } from './isObjectLike'\nimport { setHeader } from './setHeader'\nimport { toFormData } from './toFormData'\n\n/**\n * Parse the request body based on the provided data and options.\n *\n * @param context The request context.\n * @param options The request options.\n */\nexport function parseRequestBody(context: Partial<RequestContext>, options: FetchOptions): void {\n const { body } = options\n\n // --- If the method is `GET`, `HEAD`, or `DELETE`, return early.\n if (!context.init?.method) return\n if (['get', 'head', 'delete'].includes(context.init.method)) return\n\n // --- If no data is provided, return early.\n if (body === null || body === undefined) return\n\n // --- If data contains a `File` object, create a FormData object.\n if (isFormDataLike(body)) {\n context.init.body = toFormData(body)\n }\n\n // --- If the data is a `ReadableStream`, pass it directly to the body.\n else if (body instanceof ReadableStream) {\n context.init.body = body\n context.init.headers = context.init.headers ?? {}\n setHeader(context.init.headers, 'Content-Type', 'application/octet-stream')\n }\n\n // --- If the data is a Blob, pass it directly to the body.\n else if (body instanceof File) {\n context.init.body = body.stream()\n context.init.headers = context.init.headers ?? {}\n setHeader(context.init.headers, 'Content-Disposition', `attachment; filename=\"${body.name}\"`)\n setHeader(context.init.headers, 'Content-Type', body.type)\n setHeader(context.init.headers, 'Content-Length', body.size)\n setHeader(context.init.headers, 'Content-Transfer-Encoding', 'binary')\n }\n\n // --- Otherwise, stringify the data and set the content type to JSON.\n else if (isObjectLike(body)) {\n context.init.body = JSON.stringify(body)\n context.init.headers = context.init.headers ?? {}\n setHeader(context.init.headers, 'Content-Type', 'application/json')\n }\n\n // --- For all other data types, set the body directly.\n else {\n context.init.body = body as BodyInit\n }\n}\n","import type { FetchOptions, RequestContext } from './parseRequest'\nimport { setHeader } from './setHeader'\n\n/**\n * Parse the request headers based on the provided data and options.\n *\n * @param context The request context.\n * @param options The request options.\n * @example\n *\n * // Append the `Content-Type` header to the request.\n * const context = {}\n * parseRequestHeaders(context, { headers: { 'Content-Type': 'application/json' } })\n *\n * // Will mutate the `init` object to include the headers.\n * console.log(context) // => { init: { headers: { 'Content-Type': 'application/json' } } }\n */\nexport function parseRequestHeaders(context: Partial<RequestContext>, options: FetchOptions): void {\n const { headers } = options\n\n // --- Merge the headers with the existing headers.\n for (const key in headers) {\n const value = headers[key]\n if (((typeof value !== 'string' || value.length === 0) && typeof value !== 'number')) continue\n context.init = context.init ?? {}\n context.init.headers = context.init.headers ?? {}\n setHeader(context.init.headers, key, value)\n }\n}\n","/**\n * Get a header value from the `HeadersInit` object.\n *\n * @param headers The headers to get the key-value pair from.\n * @param key The key of the header to get.\n * @returns The value of the header.\n * @example\n * const headers = new Headers({ 'Content-Type': 'application/json' })\n * const contentType = getHeader(headers, 'Content-Type')\n * console.log(contentType) // 'application/json'\n */\nexport function getHeader(headers: HeadersInit, key: string): string | undefined {\n if (headers instanceof Headers) {\n return headers.get(key) ?? undefined\n }\n else if (Array.isArray(headers)) {\n const keyLower = key.toLowerCase()\n const header = headers.find(([k]) => k.toLowerCase() === keyLower)\n return header ? header[1] : undefined\n }\n else {\n const keyLower = key.toLowerCase()\n const keys = Object.keys(headers)\n const index = keys.findIndex(k => k.toLowerCase() === keyLower)\n return index === -1 ? undefined : headers[keys[index]]\n }\n}\n","import { getHeader } from './getHeader'\n\n/**\n * Extract the cookies from the `HeadersInit` object.\n *\n * @param headers The headers to extract the cookies from.\n * @returns An array of cookies.\n * @example\n * const headers = new Headers({ Cookie: 'key1=value1; key2=value2' })\n * const cookies = getCookies(headers) // { key1: 'value1', key2: 'value2' }\n */\nexport function getCookies(headers: HeadersInit): Record<string, string> {\n const value = getHeader(headers, 'Cookie')\n if (!value) return {}\n\n // --- Parse the cookie header.\n const cookies: Record<string, string> = {}\n const parts = value.split(';')\n for (const part of parts) {\n const [key, value] = part.trim().split('=').map(v => v.trim())\n if (!key || !value) continue\n cookies[key] = value\n }\n\n // --- Return the cookies.\n return cookies\n}\n","import { getCookies } from './getCookies'\nimport { setHeader } from './setHeader'\n\n/**\n * Set a cookie in the `HeadersInit` object.\n *\n * @param headers The headers to set the cookie in.\n * @param key The key of the cookie to set.\n * @param value The value of the cookie to set.\n * @example\n * const headers = new Headers()\n * const cookie = { key: 'key1', value: 'value1', path: '/', secure: true }\n * setCookie(headers, cookie)\n * console.log(headers.get('Cookie')) // 'key1=value1; Path=/; Secure'\n */\nexport function setCookie(headers: HeadersInit, key: string, value: string): void {\n const cookies = { ...getCookies(headers), [key]: value }\n const header = Object.entries(cookies).map(([key, value]) => `${key}=${value}`).join('; ')\n setHeader(headers, 'Cookie', header)\n}\n","import type { FetchOptions, RequestContext } from './parseRequest'\nimport { setCookie } from './setCookie'\nimport { setHeader } from './setHeader'\n\n/**\n * Parse the token and dynamically extend either the query, headers, or cookies.\n *\n * @param context The request context.\n * @param options The request options.\n * @example\n * // Append the `token` to the query parameters.\n * const context = { url: new URL('https://example.com') }\n * parseRequestToken(context, { token: 'my-token', tokenLocation: 'query', tokenProperty: 'token' })\n * console.log(context.url.searchParams.get('token')) // 'my-token'\n *\n * @example\n * // Append the `token` to the headers.\n * const context = { init: { headers: new Headers() } }\n * parseRequestToken(context, { token: 'my-token', tokenLocation: 'header', tokenProperty: 'Authorization' })\n * console.log(context.init.headers.get('Authorization')) // 'Bearer my-token'\n *\n * @example\n * // Append the `token` to the cookies.\n * const context = { init: { headers: new Headers() } }\n * parseRequestToken(context, { token: 'my-token', tokenLocation: 'cookie', tokenProperty: 'token' })\n * console.log(context.init.headers.get('Cookie')) // 'token=my-token'\n */\nexport function parseRequestToken(context: Partial<RequestContext>, options: FetchOptions): void {\n const { token, tokenLocation = 'headers', tokenProperty } = options\n\n // --- Return early if the token is not provided.\n if (!token) return\n\n // --- Append the token to the query parameters.\n if (tokenLocation === 'query') {\n if (context.url instanceof URL === false) throw new Error('The `url` must be an instance of `URL`.')\n if (!tokenProperty) throw new Error('The `tokenProperty` must be provided when using `tokenLocation` of `query`.')\n context.url.searchParams.set(tokenProperty, token)\n }\n\n // --- Append the token to the path parameters.\n else if (tokenLocation === 'header') {\n context.init = context.init ?? {}\n context.init.headers = context.init.headers ?? {}\n if (tokenProperty) setHeader(context.init.headers, tokenProperty, token)\n else setHeader(context.init.headers, 'Authorization', `Bearer ${token}`)\n }\n\n // --- Append the token to the cookie header.\n else if (tokenLocation === 'cookie') {\n if (!tokenProperty) throw new Error('The `tokenProperty` must be provided when using `tokenLocation` of `cookie`.')\n context.init = context.init ?? {}\n context.init.headers = context.init.headers ?? {}\n setCookie(context.init.headers, tokenProperty, token)\n }\n}\n","import type { FetchOptions, RequestContext } 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 context The request context to mutate.\n * @param route The name of the route to fetch.\n * @param options The options to pass to the request.\n * @example parseRequestUrl('GET /users', { baseUrl: 'https://api.example.com' }, context)\n */\nexport function parseRequestUrl(context: Partial<RequestContext>, route: string, options: FetchOptions): 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","import type { Loose, MaybeLiteral, ObjectLike } from '@unshared/types'\nimport type { UnionMerge } from '@unshared/types'\nimport type { HttpHeader } from '../HttpHeaders'\nimport type { HttpMethod } from '../HttpMethods'\nimport type { SearchArrayFormat } from './toSearchParams'\nimport { isObjectLike } from './isObjectLike'\nimport { parseRequestBasicAuth } from './parseRequestBasicAuth'\nimport { parseRequestBody } from './parseRequestBody'\nimport { parseRequestHeaders } from './parseRequestHeaders'\nimport { parseRequestParameters } from './parseRequestParameters'\nimport { parseRequestQuery } from './parseRequestQuery'\nimport { parseRequestToken } from './parseRequestToken'\nimport { parseRequestUrl } from './parseRequestUrl'\n\n/** The methods to use for the request. */\nexport type FetchMethod = Lowercase<keyof typeof HttpMethod> | Uppercase<keyof typeof HttpMethod>\n\n/** Headers to include in the request. */\nexport type FetchHeaders = Partial<Record<MaybeLiteral<HttpHeader>, number | string>>\n\n/** Options to pass to the request. */\nexport interface FetchOptions<\n Method extends FetchMethod = FetchMethod,\n BaseUrl extends string = string,\n Parameters extends ObjectLike = ObjectLike,\n Query extends ObjectLike = ObjectLike,\n Body = unknown,\n Headers extends ObjectLike = ObjectLike,\n> extends Omit<RequestInit, 'body' | 'headers' | 'method'> {\n\n /**\n * The method to use for the request.\n *\n * @example 'GET'\n */\n method?: Method\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?: BaseUrl\n\n /**\n * The data to include in the request. This data will be used to populate the\n * query parameters, body, and headers of the request based on the method type.\n *\n * @example { id: 1 }\n */\n data?: Loose<UnionMerge<Body | Headers | Query>>\n\n /**\n * The path parameters to include in the request.\n */\n parameters?: Parameters\n\n /**\n * The query parameters to include in the request.\n */\n query?: Loose<Query>\n\n /**\n * The format to use when serializing the query parameters.\n */\n queryArrayFormat?: SearchArrayFormat\n\n /**\n * The body to include in the request.\n */\n body?: Body extends ObjectLike ? Loose<Body> : Body\n\n /**\n * The headers to include in the request.\n */\n headers?: FetchHeaders & Headers\n\n /**\n * The username for basic authentication.\n */\n username?: string\n\n /**\n * The password for basic authentication.\n */\n password?: string\n\n /**\n * The token for API key authentication.\n */\n token?: string\n\n /**\n * The location where the token should be included in the request.\n */\n tokenLocation?: 'cookie' | 'header' | 'query'\n\n /**\n * The name of the key to use in the request for the token.\n */\n tokenProperty?: 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: FetchOptions = {}): RequestContext {\n const {\n username,\n password,\n token,\n tokenLocation,\n tokenProperty,\n data,\n body,\n query,\n parameters,\n headers,\n method,\n baseUrl,\n queryArrayFormat,\n ...init\n } = options\n const context: Partial<RequestContext> = { init }\n const dataObject = isObjectLike(data) ? data : undefined\n\n // --- Parse the URL and insert the path parameters.\n parseRequestUrl(context, route, { baseUrl, method })\n parseRequestParameters(context, { parameters: parameters ?? dataObject })\n parseRequestBasicAuth(context, { username, password })\n\n // --- Depending on the method, parse the query, body, and headers.\n const requestMethod = context.init?.method?.toLowerCase() ?? 'get'\n const requestExpectsBody = ['post', 'put', 'patch'].includes(requestMethod)\n parseRequestQuery(context, { queryArrayFormat, query: requestExpectsBody ? query : query ?? dataObject })\n parseRequestToken(context, { token, tokenLocation, tokenProperty })\n parseRequestBody(context, { body: requestExpectsBody ? body ?? dataObject : undefined })\n parseRequestHeaders(context, { headers })\n\n // --- Return the context with the URL and the `RequestInit` object.\n return context as RequestContext\n}\n","import type { Awaitable } from '@unshared/functions/awaitable'\nimport type { RequestOptions } from './request'\nimport { awaitable } from '@unshared/functions/awaitable'\n\nasync function * createResponseStreamJsonIterator(response: Response, options: RequestOptions): AsyncGenerator<unknown, void, unknown> {\n const { onError, onSuccess, onData, onEnd } = options\n try {\n const body = response.body\n if (body === null) throw new Error('Could not read the response body, it is empty.')\n const reader = body.getReader()\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n const parts = new TextDecoder().decode(value).trim().split('\\0').filter(Boolean)\n\n // --- For each part, parse as JSON and yield the data.\n for (const part of parts) {\n const payload = JSON.parse(part) as unknown\n if (onData) await onData(payload, options)\n yield payload\n }\n }\n if (onSuccess) await onSuccess(response, options)\n }\n catch (error) {\n if (onError) await onError(error as Error, options)\n else throw error\n }\n finally {\n if (onEnd) await onEnd(response, options)\n }\n}\n\n/**\n * Handle a request response where the content type is a stream of JSON objects. This function\n * will parse the JSON objects and yield the data to the caller. If an error occurs, the `onError`\n * callback will be called and the function will return.\n *\n * @param response The response to handle.\n * @param options The options to pass to the request.\n * @returns An awaitable iterator that yields the parsed JSON objects.\n */\nexport function handleResponseStreamJson(response: Response, options: RequestOptions): Awaitable<AsyncIterable<unknown>, unknown[]> {\n const responseIterator = createResponseStreamJsonIterator(response, options)\n return awaitable(responseIterator)\n}\n","/* eslint-disable sonarjs/cognitive-complexity */\nimport type { Awaitable } from '@unshared/functions/awaitable'\nimport type { RequestOptions } from './request'\nimport { awaitable } from '@unshared/functions/awaitable'\n\n/** SSE event data structure */\nexport interface SseEvent<T = string> {\n\n /** The event type */\n event?: string\n\n /** The event data */\n data: T\n\n /** The event ID */\n id?: string\n\n /** The retry timeout in milliseconds */\n retry?: number\n}\n\nasync function * createResponseStreamSseIterator<T>(response: Response, options: RequestOptions): AsyncGenerator<SseEvent<T>, void, unknown> {\n const { onError, onSuccess, onData, onEnd } = options\n try {\n const body = response.body\n if (body === null) throw new Error('Could not read the response body, it is empty.')\n const reader = body.getReader()\n const decoder = new TextDecoder()\n\n // SSE parsing state buffers according to spec\n let buffer = ''\n let bufferData = ''\n let bufferEvent = ''\n let bufferId = ''\n let bufferRetry: number | undefined\n\n function flush() {\n if (bufferData === '') return\n if (bufferData.endsWith('\\n')) bufferData = bufferData.slice(0, -1)\n const sseEvent = {} as SseEvent<unknown>\n\n // --- Set `event`, `id`, and `retry` fields if they are set\n if (bufferEvent !== '') sseEvent.event = bufferEvent\n if (bufferId !== '') sseEvent.id = bufferId\n if (bufferRetry !== undefined) sseEvent.retry = bufferRetry\n\n // --- Attempt to parse the `data` field as JSON if it looks like an object\n try { sseEvent.data = JSON.parse(bufferData) as object }\n catch { sseEvent.data = bufferData }\n\n // --- Reset buffers for the next event\n bufferData = ''\n bufferEvent = ''\n bufferId = ''\n bufferRetry = undefined\n\n return sseEvent as SseEvent<T>\n }\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n // --- Split on all valid line endings: CRLF, LF, CR\n // --- Additionally, keep the last incomplete line in the buffer\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split(/\\r\\n|\\n|\\r/)\n buffer = lines.pop() ?? ''\n\n for (const line of lines) {\n\n // --- Empty line dispatches the event.\n if (line === '') {\n const event = flush()\n if (event) yield event\n if (event && onData) await onData(event, options)\n continue\n }\n\n // --- Skip comment lines (start with colon)\n if (line.startsWith(':')) continue\n\n // --- Parse field name and value by finding the first colon.\n const colonIndex = line.indexOf(':')\n let fieldName: string\n let fieldValue: string\n\n // --- No colon means field name only, empty value\n if (colonIndex === -1) {\n fieldName = line\n fieldValue = ''\n }\n else {\n fieldName = line.slice(0, colonIndex)\n fieldValue = line.slice(colonIndex + 1)\n if (fieldValue.startsWith(' ')) fieldValue = fieldValue.slice(1)\n }\n\n // --- Extract event type, data, id, and retry fields according to spec\n // --- Note that id must not contain null characters and retry must be a valid number.\n if (fieldName === 'event') {\n bufferEvent = fieldValue\n }\n else if (fieldName === 'data') {\n bufferData += `${fieldValue}\\n`\n }\n else if (fieldName === 'id') {\n if (!fieldValue.includes('\\0'))\n bufferId = fieldValue\n }\n else if (fieldName === 'retry' && /^\\d+$/.test(fieldValue)) {\n bufferRetry = Number.parseInt(fieldValue, 10)\n }\n }\n }\n\n // --- Handle any remaining event in buffer at end of stream\n const event = flush()\n if (event) yield event\n if (event && onData) await onData(event, options)\n if (onSuccess) await onSuccess(response, options)\n }\n catch (error) {\n if (onError) await onError(error as Error, options)\n else throw error\n }\n finally {\n if (onEnd) await onEnd(response, options)\n }\n}\n\n/**\n * Handle a request response where the content type is a Server-Sent Events stream. This function\n * will parse the SSE events and yield the data to the caller. If an error occurs, the `onError`\n * callback will be called and the function will return.\n *\n * @param response The response to handle.\n * @param options The options to pass to the request.\n * @returns An awaitable iterator that yields the parsed SSE events.\n */\nexport function handleResponseStreamSse<T>(response: Response, options: RequestOptions): Awaitable<AsyncIterable<SseEvent<T>>, Array<SseEvent<T>>> {\n const responseIterator = createResponseStreamSseIterator<T>(response, options)\n return awaitable(responseIterator)\n}\n","import type { RequestOptions } from './request'\nimport { handleResponseStreamJson } from './handleResponseStreamJson'\nimport { handleResponseStreamSse } from './handleResponseStreamSse'\n\n/**\n * Handle a request response. This function will parse the response based on the content type and\n * return the data. If an error occurs, the `onError` callback will be called and the function will\n * throw an error.\n *\n * @param response The response to handle.\n * @param options The options to pass to the request.\n * @returns The parsed data from the response.\n */\nexport async function handleResponse(response: Response, options: RequestOptions = {}): Promise<unknown> {\n const { onError, onSuccess, onData, onEnd, onFailure } = options\n const contentType = response.headers.get('Content-Type')\n\n // --- If the response is not OK, throw an error with the response message.\n if (!response.ok) {\n if (onFailure) await onFailure(response, options)\n if (onEnd) await onEnd(response, options)\n throw new Error(response.statusText)\n }\n\n // --- If the status code is 204, return an empty response early.\n if (response.status === 204) {\n if (onSuccess) await onSuccess(response, options)\n if (onEnd) await onEnd(response, options)\n return\n }\n\n // --- If the response is a application/stream+json, return an iterator that parses the JSON.\n if (contentType?.startsWith('application/stream+json'))\n return handleResponseStreamJson(response, options)\n\n // --- If the response is a text/event-stream, return an iterator that parses the SSE events.\n if (contentType?.startsWith('text/event-stream'))\n return handleResponseStreamSse(response, options)\n\n // --- If the response is a application/json, parse the JSON and return it.\n if (contentType?.startsWith('application/json')) {\n return await response.json()\n .then(async(data) => {\n if (onData) await onData(data, options)\n if (onSuccess) await onSuccess(response, options)\n return data as unknown\n })\n .catch(async(error: Error) => {\n if (onError) await onError(error, options)\n else throw error\n })\n .finally(() => {\n if (onEnd) onEnd(response, options)\n })\n }\n\n // --- If the response is a text content type (but not event-stream), return the text response.\n if (contentType?.startsWith('text/')) {\n return await response.text()\n .then(async(data) => {\n if (onData) await onData(data, options)\n if (onSuccess) await onSuccess(response, options)\n return data\n })\n .catch(async(error: Error) => {\n if (onError) await onError(error, options)\n else throw error\n })\n .finally(() => {\n if (onEnd) onEnd(response, options)\n })\n }\n\n // --- Otherwise, fallback to returning the response body as-is.\n if (onSuccess) onSuccess(response, options)\n if (onEnd) onEnd(response, options)\n return response.body\n}\n"],"names":["value","key","parseRequestParameters","parseRequestQuery","awaitable","flush","event"],"mappings":"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"}
@@ -1,14 +1,18 @@
1
1
  "use strict";
2
- var handleResponse = require("./CbXCpEzw.cjs");
2
+ var handleResponse = require("./-InYnohy.cjs");
3
3
  async function fetch(route, options = {}) {
4
4
  const { url, init } = handleResponse.parseRequest(route, options);
5
5
  if (!url) throw new Error("Could not parse request URL");
6
6
  return await globalThis.fetch(url, init);
7
7
  }
8
8
  async function request(route, options = {}) {
9
- const response = await fetch(route, options);
10
- return await handleResponse.handleResponse(response, options);
9
+ const response = await fetch(route, options).catch((error) => {
10
+ if (options.onError) options.onError(error, options);
11
+ else throw error;
12
+ });
13
+ if (response)
14
+ return await handleResponse.handleResponse(response, options);
11
15
  }
12
16
  exports.fetch = fetch;
13
17
  exports.request = request;
14
- //# sourceMappingURL=DCBEtS8k.cjs.map
18
+ //# sourceMappingURL=CNNxr5Ws.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CNNxr5Ws.cjs","sources":["../../utils/fetch.ts","../../utils/request.ts"],"sourcesContent":["import type { FetchOptions } from './parseRequest'\nimport { parseRequest } from './parseRequest'\n\n/**\n * Fetch a route with the provided options. This function will parse the route and\n * options to create a `Request` object and return the response from the server.\n *\n * @param route The name of the route to fetch.\n * @param options The options to pass to the request.\n * @returns The response from the server.\n * @example fetch('GET /users', { query: { limit: 10 } })\n */\nexport async function fetch(route: string, options?: FetchOptions): Promise<Response>\nexport async function fetch(route: string, options: FetchOptions = {}): Promise<Response> {\n const { url, init } = parseRequest(route, options)\n if (!url) throw new Error('Could not parse request URL')\n return await globalThis.fetch(url, init)\n}\n","import type { Awaitable } from '@unshared/functions/awaitable'\nimport type { ObjectLike } from '@unshared/types'\nimport type { FetchMethod, FetchOptions } from './parseRequest'\nimport { fetch } from './fetch'\nimport { handleResponse } from './handleResponse'\n\nexport type RequestOptionsOnData<T> =\n T extends AsyncGenerator<infer U, any, any> ? (data: U, request: RequestOptions) => any\n : T extends Awaitable<AsyncGenerator<infer U, any, any>> ? (data: U, request: RequestOptions) => any\n : (data: T, request: RequestOptions) => any\n\nexport interface RequestOptions<\n Method extends FetchMethod = FetchMethod,\n BaseUrl extends string = string,\n Parameters extends ObjectLike = ObjectLike,\n Query extends ObjectLike = ObjectLike,\n Body = unknown,\n Headers extends ObjectLike = ObjectLike,\n Data = any,\n Response = globalThis.Response,\n> extends\n FetchOptions<Method, BaseUrl, Parameters, Query, Body, Headers> {\n\n /**\n * The callback that is called when an error occurs during the request. Note that\n * when defined, the function will not throw an error, but instead return `undefined`.\n * If you want to throw an error, you have to throw it manually in the callback.\n */\n onError?: (error: Error, request: RequestOptions) => any\n\n /**\n * The callback that is called when data is received from the request. This callback\n * will be called for each chunk of data that is received from the request.\n */\n onData?: RequestOptionsOnData<Data>\n\n /**\n * The callback that is called when the request is successful. This callback will be\n * called after the request is complete and all data has been received.\n */\n onSuccess?: (response: Response, request: RequestOptions) => any\n\n /**\n * The callback that is called when the status code is not OK (200-299). This callback will be called\n * after the request is complete and before the data is consumed.\n */\n onFailure?: (response: Response, request: RequestOptions) => any\n\n /**\n * The callback that is called when the request is complete. This callback will be called\n * after the request is complete and all data has been received.\n */\n onEnd?: (response: Response, request: RequestOptions) => any\n}\n\n/**\n * Fetch a route from the API and return the data. If the client was instantiated with an\n * application, the route name will be inferred from the application routes. Otherwise, you\n * can pass the route name as a string.\n *\n * @param route The name of the route to fetch.\n * @param options The options to pass to the request.\n * @returns The data from the API.\n * @example\n * // Declare the application type.\n * type App = Application<[ModuleProduct]>\n *\n * // Create a type-safe client for the application.\n * const request = createClient<App>()\n *\n * // Fetch the data from the API.\n * const data = request('GET /api/product/:id', { data: { id: '1' } })\n */\nexport async function request(route: string, options?: RequestOptions): Promise<unknown>\nexport async function request(route: string, options: RequestOptions = {}): Promise<unknown> {\n const response = await fetch(route, options)\n .catch((error: Error) => {\n if (options.onError) options.onError(error, options)\n else throw error\n })\n if (!response) return\n return await handleResponse(response, options)\n}\n"],"names":["parseRequest","handleResponse"],"mappings":";;AAaA,eAAsB,MAAM,OAAe,UAAwB,IAAuB;AACxF,QAAM,EAAE,KAAK,KAAA,IAASA,eAAAA,aAAa,OAAO,OAAO;AACjD,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,6BAA6B;AACvD,SAAO,MAAM,WAAW,MAAM,KAAK,IAAI;AACzC;ACyDA,eAAsB,QAAQ,OAAe,UAA0B,IAAsB;AAC3F,QAAM,WAAW,MAAM,MAAM,OAAO,OAAO,EACxC,MAAM,CAAC,UAAiB;AACvB,QAAI,QAAQ,QAAS,SAAQ,QAAQ,OAAO,OAAO;AAAA,QAC9C,OAAM;AAAA,EACb,CAAC;AACH,MAAK;AACL,WAAO,MAAMC,eAAAA,eAAe,UAAU,OAAO;AAC/C;;;"}
@@ -116,12 +116,14 @@ interface RequestContext {
116
116
  */
117
117
  declare function parseRequest(route: string, options?: FetchOptions): RequestContext;
118
118
 
119
- type RequestOptionsOnData<T> = T extends AsyncGenerator<infer U, any, any> ? (data: U) => any : T extends Awaitable<AsyncGenerator<infer U, any, any>> ? (data: U) => any : (data: T) => any;
119
+ type RequestOptionsOnData<T> = T extends AsyncGenerator<infer U, any, any> ? (data: U, request: RequestOptions) => any : T extends Awaitable<AsyncGenerator<infer U, any, any>> ? (data: U, request: RequestOptions) => any : (data: T, request: RequestOptions) => any;
120
120
  interface RequestOptions<Method extends FetchMethod = FetchMethod, BaseUrl extends string = string, Parameters extends ObjectLike = ObjectLike, Query extends ObjectLike = ObjectLike, Body = unknown, Headers extends ObjectLike = ObjectLike, Data = any, Response = globalThis.Response> extends FetchOptions<Method, BaseUrl, Parameters, Query, Body, Headers> {
121
121
  /**
122
- * The callback that is called when an error occurs during the request.
122
+ * The callback that is called when an error occurs during the request. Note that
123
+ * when defined, the function will not throw an error, but instead return `undefined`.
124
+ * If you want to throw an error, you have to throw it manually in the callback.
123
125
  */
124
- onError?: (error: Error) => any;
126
+ onError?: (error: Error, request: RequestOptions) => any;
125
127
  /**
126
128
  * The callback that is called when data is received from the request. This callback
127
129
  * will be called for each chunk of data that is received from the request.
@@ -131,17 +133,17 @@ interface RequestOptions<Method extends FetchMethod = FetchMethod, BaseUrl exten
131
133
  * The callback that is called when the request is successful. This callback will be
132
134
  * called after the request is complete and all data has been received.
133
135
  */
134
- onSuccess?: (response: Response) => any;
136
+ onSuccess?: (response: Response, request: RequestOptions) => any;
135
137
  /**
136
- * The callback that is called when the status code is not OK. This callback will be called
138
+ * The callback that is called when the status code is not OK (200-299). This callback will be called
137
139
  * after the request is complete and before the data is consumed.
138
140
  */
139
- onFailure?: (response: Response) => any;
141
+ onFailure?: (response: Response, request: RequestOptions) => any;
140
142
  /**
141
143
  * The callback that is called when the request is complete. This callback will be called
142
144
  * after the request is complete and all data has been received.
143
145
  */
144
- onEnd?: (response: Response) => any;
146
+ onEnd?: (response: Response, request: RequestOptions) => any;
145
147
  }
146
148
  /**
147
149
  * Fetch a route from the API and return the data. If the client was instantiated with an
@@ -0,0 +1,19 @@
1
+ import { p as parseRequest, h as handleResponse } from "./DZ2MwV7J.js";
2
+ async function fetch(route, options = {}) {
3
+ const { url, init } = parseRequest(route, options);
4
+ if (!url) throw new Error("Could not parse request URL");
5
+ return await globalThis.fetch(url, init);
6
+ }
7
+ async function request(route, options = {}) {
8
+ const response = await fetch(route, options).catch((error) => {
9
+ if (options.onError) options.onError(error, options);
10
+ else throw error;
11
+ });
12
+ if (response)
13
+ return await handleResponse(response, options);
14
+ }
15
+ export {
16
+ fetch as f,
17
+ request as r
18
+ };
19
+ //# sourceMappingURL=ClHrsaTt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ClHrsaTt.js","sources":["../../utils/fetch.ts","../../utils/request.ts"],"sourcesContent":["import type { FetchOptions } from './parseRequest'\nimport { parseRequest } from './parseRequest'\n\n/**\n * Fetch a route with the provided options. This function will parse the route and\n * options to create a `Request` object and return the response from the server.\n *\n * @param route The name of the route to fetch.\n * @param options The options to pass to the request.\n * @returns The response from the server.\n * @example fetch('GET /users', { query: { limit: 10 } })\n */\nexport async function fetch(route: string, options?: FetchOptions): Promise<Response>\nexport async function fetch(route: string, options: FetchOptions = {}): Promise<Response> {\n const { url, init } = parseRequest(route, options)\n if (!url) throw new Error('Could not parse request URL')\n return await globalThis.fetch(url, init)\n}\n","import type { Awaitable } from '@unshared/functions/awaitable'\nimport type { ObjectLike } from '@unshared/types'\nimport type { FetchMethod, FetchOptions } from './parseRequest'\nimport { fetch } from './fetch'\nimport { handleResponse } from './handleResponse'\n\nexport type RequestOptionsOnData<T> =\n T extends AsyncGenerator<infer U, any, any> ? (data: U, request: RequestOptions) => any\n : T extends Awaitable<AsyncGenerator<infer U, any, any>> ? (data: U, request: RequestOptions) => any\n : (data: T, request: RequestOptions) => any\n\nexport interface RequestOptions<\n Method extends FetchMethod = FetchMethod,\n BaseUrl extends string = string,\n Parameters extends ObjectLike = ObjectLike,\n Query extends ObjectLike = ObjectLike,\n Body = unknown,\n Headers extends ObjectLike = ObjectLike,\n Data = any,\n Response = globalThis.Response,\n> extends\n FetchOptions<Method, BaseUrl, Parameters, Query, Body, Headers> {\n\n /**\n * The callback that is called when an error occurs during the request. Note that\n * when defined, the function will not throw an error, but instead return `undefined`.\n * If you want to throw an error, you have to throw it manually in the callback.\n */\n onError?: (error: Error, request: RequestOptions) => any\n\n /**\n * The callback that is called when data is received from the request. This callback\n * will be called for each chunk of data that is received from the request.\n */\n onData?: RequestOptionsOnData<Data>\n\n /**\n * The callback that is called when the request is successful. This callback will be\n * called after the request is complete and all data has been received.\n */\n onSuccess?: (response: Response, request: RequestOptions) => any\n\n /**\n * The callback that is called when the status code is not OK (200-299). This callback will be called\n * after the request is complete and before the data is consumed.\n */\n onFailure?: (response: Response, request: RequestOptions) => any\n\n /**\n * The callback that is called when the request is complete. This callback will be called\n * after the request is complete and all data has been received.\n */\n onEnd?: (response: Response, request: RequestOptions) => any\n}\n\n/**\n * Fetch a route from the API and return the data. If the client was instantiated with an\n * application, the route name will be inferred from the application routes. Otherwise, you\n * can pass the route name as a string.\n *\n * @param route The name of the route to fetch.\n * @param options The options to pass to the request.\n * @returns The data from the API.\n * @example\n * // Declare the application type.\n * type App = Application<[ModuleProduct]>\n *\n * // Create a type-safe client for the application.\n * const request = createClient<App>()\n *\n * // Fetch the data from the API.\n * const data = request('GET /api/product/:id', { data: { id: '1' } })\n */\nexport async function request(route: string, options?: RequestOptions): Promise<unknown>\nexport async function request(route: string, options: RequestOptions = {}): Promise<unknown> {\n const response = await fetch(route, options)\n .catch((error: Error) => {\n if (options.onError) options.onError(error, options)\n else throw error\n })\n if (!response) return\n return await handleResponse(response, options)\n}\n"],"names":[],"mappings":";AAaA,eAAsB,MAAM,OAAe,UAAwB,IAAuB;AACxF,QAAM,EAAE,KAAK,KAAA,IAAS,aAAa,OAAO,OAAO;AACjD,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,6BAA6B;AACvD,SAAO,MAAM,WAAW,MAAM,KAAK,IAAI;AACzC;ACyDA,eAAsB,QAAQ,OAAe,UAA0B,IAAsB;AAC3F,QAAM,WAAW,MAAM,MAAM,OAAO,OAAO,EACxC,MAAM,CAAC,UAAiB;AACvB,QAAI,QAAQ,QAAS,SAAQ,QAAQ,OAAO,OAAO;AAAA,QAC9C,OAAM;AAAA,EACb,CAAC;AACH,MAAK;AACL,WAAO,MAAM,eAAe,UAAU,OAAO;AAC/C;"}
@@ -1,5 +1,5 @@
1
1
  import { Loose, UnionMerge, Override, Pretty, CollectKey, MaybeLiteral, StringSplit } from '@unshared/types';
2
- import { a as FetchMethod, R as RequestOptions } from './rRfHSRNV.js';
2
+ import { a as FetchMethod, R as RequestOptions } from './CNqEW-S3.js';
3
3
  import { OpenAPI } from 'openapi-types';
4
4
 
5
5
  /** Get the base URL of an OpenAPI specification. */
@@ -139,14 +139,15 @@ async function* createResponseStreamJsonIterator(response, options) {
139
139
  const parts = new TextDecoder().decode(value).trim().split("\0").filter(Boolean);
140
140
  for (const part of parts) {
141
141
  const payload = JSON.parse(part);
142
- onData && onData(payload), yield payload;
142
+ onData && await onData(payload, options), yield payload;
143
143
  }
144
144
  }
145
- onSuccess && onSuccess(response);
145
+ onSuccess && await onSuccess(response, options);
146
146
  } catch (error) {
147
- onError && onError(error);
147
+ if (onError) await onError(error, options);
148
+ else throw error;
148
149
  } finally {
149
- onEnd && onEnd(response);
150
+ onEnd && await onEnd(response, options);
150
151
  }
151
152
  }
152
153
  function handleResponseStreamJson(response, options) {
@@ -183,7 +184,7 @@ async function* createResponseStreamSseIterator(response, options) {
183
184
  for (const line of lines) {
184
185
  if (line === "") {
185
186
  const event2 = flush2();
186
- event2 && (yield event2), event2 && onData && onData(event2);
187
+ event2 && (yield event2), event2 && onData && await onData(event2, options);
187
188
  continue;
188
189
  }
189
190
  if (line.startsWith(":")) continue;
@@ -194,11 +195,12 @@ async function* createResponseStreamSseIterator(response, options) {
194
195
  }
195
196
  }
196
197
  const event = flush2();
197
- event && (yield event), event && onData && onData(event), onSuccess && onSuccess(response);
198
+ event && (yield event), event && onData && await onData(event, options), onSuccess && await onSuccess(response, options);
198
199
  } catch (error) {
199
- throw onError && onError(error), error;
200
+ if (onError) await onError(error, options);
201
+ else throw error;
200
202
  } finally {
201
- onEnd && onEnd(response);
203
+ onEnd && await onEnd(response, options);
202
204
  }
203
205
  }
204
206
  function handleResponseStreamSse(response, options) {
@@ -208,20 +210,22 @@ function handleResponseStreamSse(response, options) {
208
210
  async function handleResponse(response, options = {}) {
209
211
  const { onError, onSuccess, onData, onEnd, onFailure } = options, contentType = response.headers.get("Content-Type");
210
212
  if (!response.ok)
211
- throw onFailure && await onFailure(response), onEnd && onEnd(response), new Error(response.statusText);
213
+ throw onFailure && await onFailure(response, options), onEnd && await onEnd(response, options), new Error(response.statusText);
212
214
  if (response.status === 204) {
213
- onSuccess && onSuccess(response), onEnd && onEnd(response);
215
+ onSuccess && await onSuccess(response, options), onEnd && await onEnd(response, options);
214
216
  return;
215
217
  }
216
- return contentType?.startsWith("application/stream+json") ? handleResponseStreamJson(response, options) : contentType?.startsWith("text/event-stream") ? handleResponseStreamSse(response, options) : contentType?.startsWith("application/json") ? await response.json().then((data) => (onData && onData(data), onSuccess && onSuccess(response), data)).catch((error) => {
217
- throw onError && onError(error), error;
218
+ return contentType?.startsWith("application/stream+json") ? handleResponseStreamJson(response, options) : contentType?.startsWith("text/event-stream") ? handleResponseStreamSse(response, options) : contentType?.startsWith("application/json") ? await response.json().then(async (data) => (onData && await onData(data, options), onSuccess && await onSuccess(response, options), data)).catch(async (error) => {
219
+ if (onError) await onError(error, options);
220
+ else throw error;
218
221
  }).finally(() => {
219
- onEnd && onEnd(response);
220
- }) : contentType?.startsWith("text/") ? await response.text().then((data) => (onData && onData(data), onSuccess && onSuccess(response), data)).catch((error) => {
221
- throw onError && onError(error), error;
222
+ onEnd && onEnd(response, options);
223
+ }) : contentType?.startsWith("text/") ? await response.text().then(async (data) => (onData && await onData(data, options), onSuccess && await onSuccess(response, options), data)).catch(async (error) => {
224
+ if (onError) await onError(error, options);
225
+ else throw error;
222
226
  }).finally(() => {
223
- onEnd && onEnd(response);
224
- }) : (onSuccess && onSuccess(response), onEnd && onEnd(response), response.body);
227
+ onEnd && onEnd(response, options);
228
+ }) : (onSuccess && onSuccess(response, options), onEnd && onEnd(response, options), response.body);
225
229
  }
226
230
  export {
227
231
  getHeader as a,
@@ -241,4 +245,4 @@ export {
241
245
  setCookie as s,
242
246
  toFormData as t
243
247
  };
244
- //# sourceMappingURL=C_VzAX2X.js.map
248
+ //# sourceMappingURL=DZ2MwV7J.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"C_VzAX2X.js","sources":["../../utils/isObjectLike.ts","../../utils/setHeader.ts","../../utils/parseRequestBasicAuth.ts","../../utils/isFormDataLike.ts","../../utils/toFormData.ts","../../utils/parseRequestBody.ts","../../utils/parseRequestHeaders.ts","../../utils/getHeader.ts","../../utils/getCookies.ts","../../utils/setCookie.ts","../../utils/parseRequestToken.ts","../../utils/parseRequestUrl.ts","../../utils/parseRequest.ts","../../utils/handleResponseStreamJson.ts","../../utils/handleResponseStreamSse.ts","../../utils/handleResponse.ts"],"sourcesContent":["import type { ObjectLike } from '@unshared/types'\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 ObjectLike {\n return typeof value === 'object' && value !== null && value.constructor === Object\n}\n","/**\n * Set a header in the `HeadersInit` object whether it is a `Headers` instance, an\n * array of key-value pairs, or an object. It is also case-insensitive, meaning that\n * if a header with the same key but different case is found, it will be replaced.\n *\n * @param headers The headers to set the key-value pair in.\n * @param key The key of the header to set.\n * @param value The value of the header to set.\n * @example\n * const headers = new Headers()\n * setHeader(headers, 'Content-Type', 'application/json')\n * console.log(headers.get('Content-Type')) // 'application/json'\n */\nexport function setHeader(headers: HeadersInit, key: string, value: number | string): void {\n value = String(value)\n if (headers instanceof Headers) {\n headers.set(key, value)\n }\n else if (Array.isArray(headers)) {\n const keyLower = key.toLowerCase()\n const index = headers.findIndex(([k]) => k.toLowerCase() === keyLower)\n if (index === -1) headers.push([key, value])\n headers[index] = [key, value]\n }\n else if (typeof headers === 'object' && headers !== null) {\n const keyLower = key.toLowerCase()\n for (const k in headers) {\n if (k.toLowerCase() !== keyLower) continue\n headers[k] = value\n return\n }\n headers[key] = value\n }\n}\n","import type { FetchOptions, RequestContext } from './parseRequest'\nimport { setHeader } from './setHeader'\n\n/**\n * Parse the basic authentication headers based on the provided username and password.\n *\n * @param context The request context.\n * @param options The request options.\n * @example\n *\n * // Append the `Authorization` header to the request.\n * const context = {}\n * parseRequestBasicAuth(context, { username: 'user', password: 'pass' })\n *\n * // Will mutate the `init` object to include the headers.\n * console.log(context) // => { init: { headers: { 'Authorization': 'Basic dXNlcjpwYXNz' } } }\n */\nexport function parseRequestBasicAuth(context: Partial<RequestContext>, options: FetchOptions): void {\n const { username, password } = options\n\n // --- Return early if the username or password is not provided.\n if (typeof username !== 'string' || typeof password !== 'string') return\n\n // --- Encode the credentials and set the Authorization header.\n const credentials = btoa(`${username}:${password}`)\n context.init = context.init ?? {}\n context.init.headers = context.init.headers ?? {}\n setHeader(context.init.headers, 'Authorization', `Basic ${credentials}`)\n}\n","/**\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 const values = Object.values(value)\n if (values.length === 0) return false\n return values.every((x) => {\n if (x instanceof File) return true\n if (Array.isArray(x)) return x.every(item => item instanceof File)\n return x instanceof Blob\n })\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 { FetchOptions, RequestContext } from './parseRequest'\nimport { isFormDataLike } from './isFormDataLike'\nimport { isObjectLike } from './isObjectLike'\nimport { setHeader } from './setHeader'\nimport { toFormData } from './toFormData'\n\n/**\n * Parse the request body based on the provided data and options.\n *\n * @param context The request context.\n * @param options The request options.\n */\nexport function parseRequestBody(context: Partial<RequestContext>, options: FetchOptions): void {\n const { body } = options\n\n // --- If the method is `GET`, `HEAD`, or `DELETE`, return early.\n if (!context.init?.method) return\n if (['get', 'head', 'delete'].includes(context.init.method)) return\n\n // --- If no data is provided, return early.\n if (body === null || body === undefined) return\n\n // --- If data contains a `File` object, create a FormData object.\n if (isFormDataLike(body)) {\n context.init.body = toFormData(body)\n }\n\n // --- If the data is a `ReadableStream`, pass it directly to the body.\n else if (body instanceof ReadableStream) {\n context.init.body = body\n context.init.headers = context.init.headers ?? {}\n setHeader(context.init.headers, 'Content-Type', 'application/octet-stream')\n }\n\n // --- If the data is a Blob, pass it directly to the body.\n else if (body instanceof File) {\n context.init.body = body.stream()\n context.init.headers = context.init.headers ?? {}\n setHeader(context.init.headers, 'Content-Disposition', `attachment; filename=\"${body.name}\"`)\n setHeader(context.init.headers, 'Content-Type', body.type)\n setHeader(context.init.headers, 'Content-Length', body.size)\n setHeader(context.init.headers, 'Content-Transfer-Encoding', 'binary')\n }\n\n // --- Otherwise, stringify the data and set the content type to JSON.\n else if (isObjectLike(body)) {\n context.init.body = JSON.stringify(body)\n context.init.headers = context.init.headers ?? {}\n setHeader(context.init.headers, 'Content-Type', 'application/json')\n }\n\n // --- For all other data types, set the body directly.\n else {\n context.init.body = body as BodyInit\n }\n}\n","import type { FetchOptions, RequestContext } from './parseRequest'\nimport { setHeader } from './setHeader'\n\n/**\n * Parse the request headers based on the provided data and options.\n *\n * @param context The request context.\n * @param options The request options.\n * @example\n *\n * // Append the `Content-Type` header to the request.\n * const context = {}\n * parseRequestHeaders(context, { headers: { 'Content-Type': 'application/json' } })\n *\n * // Will mutate the `init` object to include the headers.\n * console.log(context) // => { init: { headers: { 'Content-Type': 'application/json' } } }\n */\nexport function parseRequestHeaders(context: Partial<RequestContext>, options: FetchOptions): void {\n const { headers } = options\n\n // --- Merge the headers with the existing headers.\n for (const key in headers) {\n const value = headers[key]\n if (((typeof value !== 'string' || value.length === 0) && typeof value !== 'number')) continue\n context.init = context.init ?? {}\n context.init.headers = context.init.headers ?? {}\n setHeader(context.init.headers, key, value)\n }\n}\n","/**\n * Get a header value from the `HeadersInit` object.\n *\n * @param headers The headers to get the key-value pair from.\n * @param key The key of the header to get.\n * @returns The value of the header.\n * @example\n * const headers = new Headers({ 'Content-Type': 'application/json' })\n * const contentType = getHeader(headers, 'Content-Type')\n * console.log(contentType) // 'application/json'\n */\nexport function getHeader(headers: HeadersInit, key: string): string | undefined {\n if (headers instanceof Headers) {\n return headers.get(key) ?? undefined\n }\n else if (Array.isArray(headers)) {\n const keyLower = key.toLowerCase()\n const header = headers.find(([k]) => k.toLowerCase() === keyLower)\n return header ? header[1] : undefined\n }\n else {\n const keyLower = key.toLowerCase()\n const keys = Object.keys(headers)\n const index = keys.findIndex(k => k.toLowerCase() === keyLower)\n return index === -1 ? undefined : headers[keys[index]]\n }\n}\n","import { getHeader } from './getHeader'\n\n/**\n * Extract the cookies from the `HeadersInit` object.\n *\n * @param headers The headers to extract the cookies from.\n * @returns An array of cookies.\n * @example\n * const headers = new Headers({ Cookie: 'key1=value1; key2=value2' })\n * const cookies = getCookies(headers) // { key1: 'value1', key2: 'value2' }\n */\nexport function getCookies(headers: HeadersInit): Record<string, string> {\n const value = getHeader(headers, 'Cookie')\n if (!value) return {}\n\n // --- Parse the cookie header.\n const cookies: Record<string, string> = {}\n const parts = value.split(';')\n for (const part of parts) {\n const [key, value] = part.trim().split('=').map(v => v.trim())\n if (!key || !value) continue\n cookies[key] = value\n }\n\n // --- Return the cookies.\n return cookies\n}\n","import { getCookies } from './getCookies'\nimport { setHeader } from './setHeader'\n\n/**\n * Set a cookie in the `HeadersInit` object.\n *\n * @param headers The headers to set the cookie in.\n * @param key The key of the cookie to set.\n * @param value The value of the cookie to set.\n * @example\n * const headers = new Headers()\n * const cookie = { key: 'key1', value: 'value1', path: '/', secure: true }\n * setCookie(headers, cookie)\n * console.log(headers.get('Cookie')) // 'key1=value1; Path=/; Secure'\n */\nexport function setCookie(headers: HeadersInit, key: string, value: string): void {\n const cookies = { ...getCookies(headers), [key]: value }\n const header = Object.entries(cookies).map(([key, value]) => `${key}=${value}`).join('; ')\n setHeader(headers, 'Cookie', header)\n}\n","import type { FetchOptions, RequestContext } from './parseRequest'\nimport { setCookie } from './setCookie'\nimport { setHeader } from './setHeader'\n\n/**\n * Parse the token and dynamically extend either the query, headers, or cookies.\n *\n * @param context The request context.\n * @param options The request options.\n * @example\n * // Append the `token` to the query parameters.\n * const context = { url: new URL('https://example.com') }\n * parseRequestToken(context, { token: 'my-token', tokenLocation: 'query', tokenProperty: 'token' })\n * console.log(context.url.searchParams.get('token')) // 'my-token'\n *\n * @example\n * // Append the `token` to the headers.\n * const context = { init: { headers: new Headers() } }\n * parseRequestToken(context, { token: 'my-token', tokenLocation: 'header', tokenProperty: 'Authorization' })\n * console.log(context.init.headers.get('Authorization')) // 'Bearer my-token'\n *\n * @example\n * // Append the `token` to the cookies.\n * const context = { init: { headers: new Headers() } }\n * parseRequestToken(context, { token: 'my-token', tokenLocation: 'cookie', tokenProperty: 'token' })\n * console.log(context.init.headers.get('Cookie')) // 'token=my-token'\n */\nexport function parseRequestToken(context: Partial<RequestContext>, options: FetchOptions): void {\n const { token, tokenLocation = 'headers', tokenProperty } = options\n\n // --- Return early if the token is not provided.\n if (!token) return\n\n // --- Append the token to the query parameters.\n if (tokenLocation === 'query') {\n if (context.url instanceof URL === false) throw new Error('The `url` must be an instance of `URL`.')\n if (!tokenProperty) throw new Error('The `tokenProperty` must be provided when using `tokenLocation` of `query`.')\n context.url.searchParams.set(tokenProperty, token)\n }\n\n // --- Append the token to the path parameters.\n else if (tokenLocation === 'header') {\n context.init = context.init ?? {}\n context.init.headers = context.init.headers ?? {}\n if (tokenProperty) setHeader(context.init.headers, tokenProperty, token)\n else setHeader(context.init.headers, 'Authorization', `Bearer ${token}`)\n }\n\n // --- Append the token to the cookie header.\n else if (tokenLocation === 'cookie') {\n if (!tokenProperty) throw new Error('The `tokenProperty` must be provided when using `tokenLocation` of `cookie`.')\n context.init = context.init ?? {}\n context.init.headers = context.init.headers ?? {}\n setCookie(context.init.headers, tokenProperty, token)\n }\n}\n","import type { FetchOptions, RequestContext } 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 context The request context to mutate.\n * @param route The name of the route to fetch.\n * @param options The options to pass to the request.\n * @example parseRequestUrl('GET /users', { baseUrl: 'https://api.example.com' }, context)\n */\nexport function parseRequestUrl(context: Partial<RequestContext>, route: string, options: FetchOptions): 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","import type { Loose, MaybeLiteral, ObjectLike } from '@unshared/types'\nimport type { UnionMerge } from '@unshared/types'\nimport type { HttpHeader } from '../HttpHeaders'\nimport type { HttpMethod } from '../HttpMethods'\nimport type { SearchArrayFormat } from './toSearchParams'\nimport { isObjectLike } from './isObjectLike'\nimport { parseRequestBasicAuth } from './parseRequestBasicAuth'\nimport { parseRequestBody } from './parseRequestBody'\nimport { parseRequestHeaders } from './parseRequestHeaders'\nimport { parseRequestParameters } from './parseRequestParameters'\nimport { parseRequestQuery } from './parseRequestQuery'\nimport { parseRequestToken } from './parseRequestToken'\nimport { parseRequestUrl } from './parseRequestUrl'\n\n/** The methods to use for the request. */\nexport type FetchMethod = Lowercase<keyof typeof HttpMethod> | Uppercase<keyof typeof HttpMethod>\n\n/** Headers to include in the request. */\nexport type FetchHeaders = Partial<Record<MaybeLiteral<HttpHeader>, number | string>>\n\n/** Options to pass to the request. */\nexport interface FetchOptions<\n Method extends FetchMethod = FetchMethod,\n BaseUrl extends string = string,\n Parameters extends ObjectLike = ObjectLike,\n Query extends ObjectLike = ObjectLike,\n Body = unknown,\n Headers extends ObjectLike = ObjectLike,\n> extends Omit<RequestInit, 'body' | 'headers' | 'method'> {\n\n /**\n * The method to use for the request.\n *\n * @example 'GET'\n */\n method?: Method\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?: BaseUrl\n\n /**\n * The data to include in the request. This data will be used to populate the\n * query parameters, body, and headers of the request based on the method type.\n *\n * @example { id: 1 }\n */\n data?: Loose<UnionMerge<Body | Headers | Query>>\n\n /**\n * The path parameters to include in the request.\n */\n parameters?: Parameters\n\n /**\n * The query parameters to include in the request.\n */\n query?: Loose<Query>\n\n /**\n * The format to use when serializing the query parameters.\n */\n queryArrayFormat?: SearchArrayFormat\n\n /**\n * The body to include in the request.\n */\n body?: Body extends ObjectLike ? Loose<Body> : Body\n\n /**\n * The headers to include in the request.\n */\n headers?: FetchHeaders & Headers\n\n /**\n * The username for basic authentication.\n */\n username?: string\n\n /**\n * The password for basic authentication.\n */\n password?: string\n\n /**\n * The token for API key authentication.\n */\n token?: string\n\n /**\n * The location where the token should be included in the request.\n */\n tokenLocation?: 'cookie' | 'header' | 'query'\n\n /**\n * The name of the key to use in the request for the token.\n */\n tokenProperty?: 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: FetchOptions = {}): RequestContext {\n const {\n username,\n password,\n token,\n tokenLocation,\n tokenProperty,\n data,\n body,\n query,\n parameters,\n headers,\n method,\n baseUrl,\n queryArrayFormat,\n ...init\n } = options\n const context: Partial<RequestContext> = { init }\n const dataObject = isObjectLike(data) ? data : undefined\n\n // --- Parse the URL and insert the path parameters.\n parseRequestUrl(context, route, { baseUrl, method })\n parseRequestParameters(context, { parameters: parameters ?? dataObject })\n parseRequestBasicAuth(context, { username, password })\n\n // --- Depending on the method, parse the query, body, and headers.\n const requestMethod = context.init?.method?.toLowerCase() ?? 'get'\n const requestExpectsBody = ['post', 'put', 'patch'].includes(requestMethod)\n parseRequestQuery(context, { queryArrayFormat, query: requestExpectsBody ? query : query ?? dataObject })\n parseRequestToken(context, { token, tokenLocation, tokenProperty })\n parseRequestBody(context, { body: requestExpectsBody ? body ?? dataObject : undefined })\n parseRequestHeaders(context, { headers })\n\n // --- Return the context with the URL and the `RequestInit` object.\n return context as RequestContext\n}\n","import type { Awaitable } from '@unshared/functions/awaitable'\nimport type { RequestOptions } from './request'\nimport { awaitable } from '@unshared/functions/awaitable'\n\nasync function * createResponseStreamJsonIterator(response: Response, options: RequestOptions): AsyncGenerator<unknown, void, unknown> {\n const { onError, onSuccess, onData, onEnd } = options\n try {\n const body = response.body\n if (body === null) throw new Error('Could not read the response body, it is empty.')\n const reader = body.getReader()\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n const parts = new TextDecoder().decode(value).trim().split('\\0').filter(Boolean)\n\n // --- For each part, parse as JSON and yield the data.\n for (const part of parts) {\n const payload = JSON.parse(part) as unknown\n if (onData) onData(payload)\n yield payload\n }\n }\n if (onSuccess) onSuccess(response)\n }\n catch (error) {\n if (onError) onError(error as Error)\n }\n finally {\n if (onEnd) onEnd(response)\n }\n}\n\n/**\n * Handle a request response where the content type is a stream of JSON objects. This function\n * will parse the JSON objects and yield the data to the caller. If an error occurs, the `onError`\n * callback will be called and the function will return.\n *\n * @param response The response to handle.\n * @param options The options to pass to the request.\n * @returns An awaitable iterator that yields the parsed JSON objects.\n */\nexport function handleResponseStreamJson(response: Response, options: RequestOptions): Awaitable<AsyncIterable<unknown>, unknown[]> {\n const responseIterator = createResponseStreamJsonIterator(response, options)\n return awaitable(responseIterator)\n}\n","/* eslint-disable sonarjs/cognitive-complexity */\nimport type { Awaitable } from '@unshared/functions/awaitable'\nimport type { RequestOptions } from './request'\nimport { awaitable } from '@unshared/functions/awaitable'\n\n/** SSE event data structure */\nexport interface SseEvent<T = string> {\n\n /** The event type */\n event?: string\n\n /** The event data */\n data: T\n\n /** The event ID */\n id?: string\n\n /** The retry timeout in milliseconds */\n retry?: number\n}\n\nasync function * createResponseStreamSseIterator<T>(response: Response, options: RequestOptions): AsyncGenerator<SseEvent<T>, void, unknown> {\n const { onError, onSuccess, onData, onEnd } = options\n try {\n const body = response.body\n if (body === null) throw new Error('Could not read the response body, it is empty.')\n const reader = body.getReader()\n const decoder = new TextDecoder()\n\n // SSE parsing state buffers according to spec\n let buffer = ''\n let bufferData = ''\n let bufferEvent = ''\n let bufferId = ''\n let bufferRetry: number | undefined\n\n function flush() {\n if (bufferData === '') return\n if (bufferData.endsWith('\\n')) bufferData = bufferData.slice(0, -1)\n const sseEvent = {} as SseEvent<unknown>\n\n // --- Set `event`, `id`, and `retry` fields if they are set\n if (bufferEvent !== '') sseEvent.event = bufferEvent\n if (bufferId !== '') sseEvent.id = bufferId\n if (bufferRetry !== undefined) sseEvent.retry = bufferRetry\n\n // --- Attempt to parse the `data` field as JSON if it looks like an object\n try { sseEvent.data = JSON.parse(bufferData) as object }\n catch { sseEvent.data = bufferData }\n\n // --- Reset buffers for the next event\n bufferData = ''\n bufferEvent = ''\n bufferId = ''\n bufferRetry = undefined\n\n return sseEvent as SseEvent<T>\n }\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n // --- Split on all valid line endings: CRLF, LF, CR\n // --- Additionally, keep the last incomplete line in the buffer\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split(/\\r\\n|\\n|\\r/)\n buffer = lines.pop() ?? ''\n\n for (const line of lines) {\n\n // --- Empty line dispatches the event.\n if (line === '') {\n const event = flush()\n if (event) yield event\n if (event && onData) onData(event)\n continue\n }\n\n // --- Skip comment lines (start with colon)\n if (line.startsWith(':')) continue\n\n // --- Parse field name and value by finding the first colon.\n const colonIndex = line.indexOf(':')\n let fieldName: string\n let fieldValue: string\n\n // --- No colon means field name only, empty value\n if (colonIndex === -1) {\n fieldName = line\n fieldValue = ''\n }\n else {\n fieldName = line.slice(0, colonIndex)\n fieldValue = line.slice(colonIndex + 1)\n if (fieldValue.startsWith(' ')) fieldValue = fieldValue.slice(1)\n }\n\n // --- Extract event type, data, id, and retry fields according to spec\n // --- Note that id must not contain null characters and retry must be a valid number.\n if (fieldName === 'event') {\n bufferEvent = fieldValue\n }\n else if (fieldName === 'data') {\n bufferData += `${fieldValue}\\n`\n }\n else if (fieldName === 'id') {\n if (!fieldValue.includes('\\0'))\n bufferId = fieldValue\n }\n else if (fieldName === 'retry' && /^\\d+$/.test(fieldValue)) {\n bufferRetry = Number.parseInt(fieldValue, 10)\n }\n }\n }\n\n // --- Handle any remaining event in buffer at end of stream\n const event = flush()\n if (event) yield event\n if (event && onData) onData(event)\n if (onSuccess) onSuccess(response)\n }\n catch (error) {\n if (onError) onError(error as Error)\n throw error\n }\n finally {\n if (onEnd) onEnd(response)\n }\n}\n\n/**\n * Handle a request response where the content type is a Server-Sent Events stream. This function\n * will parse the SSE events and yield the data to the caller. If an error occurs, the `onError`\n * callback will be called and the function will return.\n *\n * @param response The response to handle.\n * @param options The options to pass to the request.\n * @returns An awaitable iterator that yields the parsed SSE events.\n */\nexport function handleResponseStreamSse<T>(response: Response, options: RequestOptions): Awaitable<AsyncIterable<SseEvent<T>>, Array<SseEvent<T>>> {\n const responseIterator = createResponseStreamSseIterator<T>(response, options)\n return awaitable(responseIterator)\n}\n","import type { RequestOptions } from './request'\nimport { handleResponseStreamJson } from './handleResponseStreamJson'\nimport { handleResponseStreamSse } from './handleResponseStreamSse'\n\n/**\n * Handle a request response. This function will parse the response based on the content type and\n * return the data. If an error occurs, the `onError` callback will be called and the function will\n * throw an error.\n *\n * @param response The response to handle.\n * @param options The options to pass to the request.\n * @returns The parsed data from the response.\n */\nexport async function handleResponse(response: Response, options: RequestOptions = {}): Promise<unknown> {\n const { onError, onSuccess, onData, onEnd, onFailure } = options\n const contentType = response.headers.get('Content-Type')\n\n // --- If the response is not OK, throw an error with the response message.\n if (!response.ok) {\n if (onFailure) await onFailure(response)\n if (onEnd) onEnd(response)\n throw new Error(response.statusText)\n }\n\n // --- If the status code is 204, return an empty response early.\n if (response.status === 204) {\n if (onSuccess) onSuccess(response)\n if (onEnd) onEnd(response)\n return\n }\n\n // --- If the response is a application/stream+json, return an iterator that parses the JSON.\n if (contentType?.startsWith('application/stream+json'))\n return handleResponseStreamJson(response, options)\n\n // --- If the response is a text/event-stream, return an iterator that parses the SSE events.\n if (contentType?.startsWith('text/event-stream'))\n return handleResponseStreamSse(response, options)\n\n // --- If the response is a application/json, parse the JSON and return it.\n if (contentType?.startsWith('application/json')) {\n return await response.json()\n .then((data) => {\n if (onData) onData(data)\n if (onSuccess) onSuccess(response)\n return data as unknown\n })\n .catch((error: Error) => {\n if (onError) onError(error)\n throw error\n })\n .finally(() => {\n if (onEnd) onEnd(response)\n })\n }\n\n // --- If the response is a text content type (but not event-stream), return the text response.\n if (contentType?.startsWith('text/')) {\n return await response.text()\n .then((data) => {\n if (onData) onData(data)\n if (onSuccess) onSuccess(response)\n return data\n })\n .catch((error: Error) => {\n if (onError) onError(error)\n throw error\n })\n .finally(() => {\n if (onEnd) onEnd(response)\n })\n }\n\n // --- Otherwise, fallback to returning the response body as-is.\n if (onSuccess) onSuccess(response)\n if (onEnd) onEnd(response)\n return response.body\n}\n"],"names":["value","key","flush","event"],"mappings":"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"}
1
+ {"version":3,"file":"DZ2MwV7J.js","sources":["../../utils/isObjectLike.ts","../../utils/setHeader.ts","../../utils/parseRequestBasicAuth.ts","../../utils/isFormDataLike.ts","../../utils/toFormData.ts","../../utils/parseRequestBody.ts","../../utils/parseRequestHeaders.ts","../../utils/getHeader.ts","../../utils/getCookies.ts","../../utils/setCookie.ts","../../utils/parseRequestToken.ts","../../utils/parseRequestUrl.ts","../../utils/parseRequest.ts","../../utils/handleResponseStreamJson.ts","../../utils/handleResponseStreamSse.ts","../../utils/handleResponse.ts"],"sourcesContent":["import type { ObjectLike } from '@unshared/types'\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 ObjectLike {\n return typeof value === 'object' && value !== null && value.constructor === Object\n}\n","/**\n * Set a header in the `HeadersInit` object whether it is a `Headers` instance, an\n * array of key-value pairs, or an object. It is also case-insensitive, meaning that\n * if a header with the same key but different case is found, it will be replaced.\n *\n * @param headers The headers to set the key-value pair in.\n * @param key The key of the header to set.\n * @param value The value of the header to set.\n * @example\n * const headers = new Headers()\n * setHeader(headers, 'Content-Type', 'application/json')\n * console.log(headers.get('Content-Type')) // 'application/json'\n */\nexport function setHeader(headers: HeadersInit, key: string, value: number | string): void {\n value = String(value)\n if (headers instanceof Headers) {\n headers.set(key, value)\n }\n else if (Array.isArray(headers)) {\n const keyLower = key.toLowerCase()\n const index = headers.findIndex(([k]) => k.toLowerCase() === keyLower)\n if (index === -1) headers.push([key, value])\n headers[index] = [key, value]\n }\n else if (typeof headers === 'object' && headers !== null) {\n const keyLower = key.toLowerCase()\n for (const k in headers) {\n if (k.toLowerCase() !== keyLower) continue\n headers[k] = value\n return\n }\n headers[key] = value\n }\n}\n","import type { FetchOptions, RequestContext } from './parseRequest'\nimport { setHeader } from './setHeader'\n\n/**\n * Parse the basic authentication headers based on the provided username and password.\n *\n * @param context The request context.\n * @param options The request options.\n * @example\n *\n * // Append the `Authorization` header to the request.\n * const context = {}\n * parseRequestBasicAuth(context, { username: 'user', password: 'pass' })\n *\n * // Will mutate the `init` object to include the headers.\n * console.log(context) // => { init: { headers: { 'Authorization': 'Basic dXNlcjpwYXNz' } } }\n */\nexport function parseRequestBasicAuth(context: Partial<RequestContext>, options: FetchOptions): void {\n const { username, password } = options\n\n // --- Return early if the username or password is not provided.\n if (typeof username !== 'string' || typeof password !== 'string') return\n\n // --- Encode the credentials and set the Authorization header.\n const credentials = btoa(`${username}:${password}`)\n context.init = context.init ?? {}\n context.init.headers = context.init.headers ?? {}\n setHeader(context.init.headers, 'Authorization', `Basic ${credentials}`)\n}\n","/**\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 const values = Object.values(value)\n if (values.length === 0) return false\n return values.every((x) => {\n if (x instanceof File) return true\n if (Array.isArray(x)) return x.every(item => item instanceof File)\n return x instanceof Blob\n })\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 { FetchOptions, RequestContext } from './parseRequest'\nimport { isFormDataLike } from './isFormDataLike'\nimport { isObjectLike } from './isObjectLike'\nimport { setHeader } from './setHeader'\nimport { toFormData } from './toFormData'\n\n/**\n * Parse the request body based on the provided data and options.\n *\n * @param context The request context.\n * @param options The request options.\n */\nexport function parseRequestBody(context: Partial<RequestContext>, options: FetchOptions): void {\n const { body } = options\n\n // --- If the method is `GET`, `HEAD`, or `DELETE`, return early.\n if (!context.init?.method) return\n if (['get', 'head', 'delete'].includes(context.init.method)) return\n\n // --- If no data is provided, return early.\n if (body === null || body === undefined) return\n\n // --- If data contains a `File` object, create a FormData object.\n if (isFormDataLike(body)) {\n context.init.body = toFormData(body)\n }\n\n // --- If the data is a `ReadableStream`, pass it directly to the body.\n else if (body instanceof ReadableStream) {\n context.init.body = body\n context.init.headers = context.init.headers ?? {}\n setHeader(context.init.headers, 'Content-Type', 'application/octet-stream')\n }\n\n // --- If the data is a Blob, pass it directly to the body.\n else if (body instanceof File) {\n context.init.body = body.stream()\n context.init.headers = context.init.headers ?? {}\n setHeader(context.init.headers, 'Content-Disposition', `attachment; filename=\"${body.name}\"`)\n setHeader(context.init.headers, 'Content-Type', body.type)\n setHeader(context.init.headers, 'Content-Length', body.size)\n setHeader(context.init.headers, 'Content-Transfer-Encoding', 'binary')\n }\n\n // --- Otherwise, stringify the data and set the content type to JSON.\n else if (isObjectLike(body)) {\n context.init.body = JSON.stringify(body)\n context.init.headers = context.init.headers ?? {}\n setHeader(context.init.headers, 'Content-Type', 'application/json')\n }\n\n // --- For all other data types, set the body directly.\n else {\n context.init.body = body as BodyInit\n }\n}\n","import type { FetchOptions, RequestContext } from './parseRequest'\nimport { setHeader } from './setHeader'\n\n/**\n * Parse the request headers based on the provided data and options.\n *\n * @param context The request context.\n * @param options The request options.\n * @example\n *\n * // Append the `Content-Type` header to the request.\n * const context = {}\n * parseRequestHeaders(context, { headers: { 'Content-Type': 'application/json' } })\n *\n * // Will mutate the `init` object to include the headers.\n * console.log(context) // => { init: { headers: { 'Content-Type': 'application/json' } } }\n */\nexport function parseRequestHeaders(context: Partial<RequestContext>, options: FetchOptions): void {\n const { headers } = options\n\n // --- Merge the headers with the existing headers.\n for (const key in headers) {\n const value = headers[key]\n if (((typeof value !== 'string' || value.length === 0) && typeof value !== 'number')) continue\n context.init = context.init ?? {}\n context.init.headers = context.init.headers ?? {}\n setHeader(context.init.headers, key, value)\n }\n}\n","/**\n * Get a header value from the `HeadersInit` object.\n *\n * @param headers The headers to get the key-value pair from.\n * @param key The key of the header to get.\n * @returns The value of the header.\n * @example\n * const headers = new Headers({ 'Content-Type': 'application/json' })\n * const contentType = getHeader(headers, 'Content-Type')\n * console.log(contentType) // 'application/json'\n */\nexport function getHeader(headers: HeadersInit, key: string): string | undefined {\n if (headers instanceof Headers) {\n return headers.get(key) ?? undefined\n }\n else if (Array.isArray(headers)) {\n const keyLower = key.toLowerCase()\n const header = headers.find(([k]) => k.toLowerCase() === keyLower)\n return header ? header[1] : undefined\n }\n else {\n const keyLower = key.toLowerCase()\n const keys = Object.keys(headers)\n const index = keys.findIndex(k => k.toLowerCase() === keyLower)\n return index === -1 ? undefined : headers[keys[index]]\n }\n}\n","import { getHeader } from './getHeader'\n\n/**\n * Extract the cookies from the `HeadersInit` object.\n *\n * @param headers The headers to extract the cookies from.\n * @returns An array of cookies.\n * @example\n * const headers = new Headers({ Cookie: 'key1=value1; key2=value2' })\n * const cookies = getCookies(headers) // { key1: 'value1', key2: 'value2' }\n */\nexport function getCookies(headers: HeadersInit): Record<string, string> {\n const value = getHeader(headers, 'Cookie')\n if (!value) return {}\n\n // --- Parse the cookie header.\n const cookies: Record<string, string> = {}\n const parts = value.split(';')\n for (const part of parts) {\n const [key, value] = part.trim().split('=').map(v => v.trim())\n if (!key || !value) continue\n cookies[key] = value\n }\n\n // --- Return the cookies.\n return cookies\n}\n","import { getCookies } from './getCookies'\nimport { setHeader } from './setHeader'\n\n/**\n * Set a cookie in the `HeadersInit` object.\n *\n * @param headers The headers to set the cookie in.\n * @param key The key of the cookie to set.\n * @param value The value of the cookie to set.\n * @example\n * const headers = new Headers()\n * const cookie = { key: 'key1', value: 'value1', path: '/', secure: true }\n * setCookie(headers, cookie)\n * console.log(headers.get('Cookie')) // 'key1=value1; Path=/; Secure'\n */\nexport function setCookie(headers: HeadersInit, key: string, value: string): void {\n const cookies = { ...getCookies(headers), [key]: value }\n const header = Object.entries(cookies).map(([key, value]) => `${key}=${value}`).join('; ')\n setHeader(headers, 'Cookie', header)\n}\n","import type { FetchOptions, RequestContext } from './parseRequest'\nimport { setCookie } from './setCookie'\nimport { setHeader } from './setHeader'\n\n/**\n * Parse the token and dynamically extend either the query, headers, or cookies.\n *\n * @param context The request context.\n * @param options The request options.\n * @example\n * // Append the `token` to the query parameters.\n * const context = { url: new URL('https://example.com') }\n * parseRequestToken(context, { token: 'my-token', tokenLocation: 'query', tokenProperty: 'token' })\n * console.log(context.url.searchParams.get('token')) // 'my-token'\n *\n * @example\n * // Append the `token` to the headers.\n * const context = { init: { headers: new Headers() } }\n * parseRequestToken(context, { token: 'my-token', tokenLocation: 'header', tokenProperty: 'Authorization' })\n * console.log(context.init.headers.get('Authorization')) // 'Bearer my-token'\n *\n * @example\n * // Append the `token` to the cookies.\n * const context = { init: { headers: new Headers() } }\n * parseRequestToken(context, { token: 'my-token', tokenLocation: 'cookie', tokenProperty: 'token' })\n * console.log(context.init.headers.get('Cookie')) // 'token=my-token'\n */\nexport function parseRequestToken(context: Partial<RequestContext>, options: FetchOptions): void {\n const { token, tokenLocation = 'headers', tokenProperty } = options\n\n // --- Return early if the token is not provided.\n if (!token) return\n\n // --- Append the token to the query parameters.\n if (tokenLocation === 'query') {\n if (context.url instanceof URL === false) throw new Error('The `url` must be an instance of `URL`.')\n if (!tokenProperty) throw new Error('The `tokenProperty` must be provided when using `tokenLocation` of `query`.')\n context.url.searchParams.set(tokenProperty, token)\n }\n\n // --- Append the token to the path parameters.\n else if (tokenLocation === 'header') {\n context.init = context.init ?? {}\n context.init.headers = context.init.headers ?? {}\n if (tokenProperty) setHeader(context.init.headers, tokenProperty, token)\n else setHeader(context.init.headers, 'Authorization', `Bearer ${token}`)\n }\n\n // --- Append the token to the cookie header.\n else if (tokenLocation === 'cookie') {\n if (!tokenProperty) throw new Error('The `tokenProperty` must be provided when using `tokenLocation` of `cookie`.')\n context.init = context.init ?? {}\n context.init.headers = context.init.headers ?? {}\n setCookie(context.init.headers, tokenProperty, token)\n }\n}\n","import type { FetchOptions, RequestContext } 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 context The request context to mutate.\n * @param route The name of the route to fetch.\n * @param options The options to pass to the request.\n * @example parseRequestUrl('GET /users', { baseUrl: 'https://api.example.com' }, context)\n */\nexport function parseRequestUrl(context: Partial<RequestContext>, route: string, options: FetchOptions): 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","import type { Loose, MaybeLiteral, ObjectLike } from '@unshared/types'\nimport type { UnionMerge } from '@unshared/types'\nimport type { HttpHeader } from '../HttpHeaders'\nimport type { HttpMethod } from '../HttpMethods'\nimport type { SearchArrayFormat } from './toSearchParams'\nimport { isObjectLike } from './isObjectLike'\nimport { parseRequestBasicAuth } from './parseRequestBasicAuth'\nimport { parseRequestBody } from './parseRequestBody'\nimport { parseRequestHeaders } from './parseRequestHeaders'\nimport { parseRequestParameters } from './parseRequestParameters'\nimport { parseRequestQuery } from './parseRequestQuery'\nimport { parseRequestToken } from './parseRequestToken'\nimport { parseRequestUrl } from './parseRequestUrl'\n\n/** The methods to use for the request. */\nexport type FetchMethod = Lowercase<keyof typeof HttpMethod> | Uppercase<keyof typeof HttpMethod>\n\n/** Headers to include in the request. */\nexport type FetchHeaders = Partial<Record<MaybeLiteral<HttpHeader>, number | string>>\n\n/** Options to pass to the request. */\nexport interface FetchOptions<\n Method extends FetchMethod = FetchMethod,\n BaseUrl extends string = string,\n Parameters extends ObjectLike = ObjectLike,\n Query extends ObjectLike = ObjectLike,\n Body = unknown,\n Headers extends ObjectLike = ObjectLike,\n> extends Omit<RequestInit, 'body' | 'headers' | 'method'> {\n\n /**\n * The method to use for the request.\n *\n * @example 'GET'\n */\n method?: Method\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?: BaseUrl\n\n /**\n * The data to include in the request. This data will be used to populate the\n * query parameters, body, and headers of the request based on the method type.\n *\n * @example { id: 1 }\n */\n data?: Loose<UnionMerge<Body | Headers | Query>>\n\n /**\n * The path parameters to include in the request.\n */\n parameters?: Parameters\n\n /**\n * The query parameters to include in the request.\n */\n query?: Loose<Query>\n\n /**\n * The format to use when serializing the query parameters.\n */\n queryArrayFormat?: SearchArrayFormat\n\n /**\n * The body to include in the request.\n */\n body?: Body extends ObjectLike ? Loose<Body> : Body\n\n /**\n * The headers to include in the request.\n */\n headers?: FetchHeaders & Headers\n\n /**\n * The username for basic authentication.\n */\n username?: string\n\n /**\n * The password for basic authentication.\n */\n password?: string\n\n /**\n * The token for API key authentication.\n */\n token?: string\n\n /**\n * The location where the token should be included in the request.\n */\n tokenLocation?: 'cookie' | 'header' | 'query'\n\n /**\n * The name of the key to use in the request for the token.\n */\n tokenProperty?: 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: FetchOptions = {}): RequestContext {\n const {\n username,\n password,\n token,\n tokenLocation,\n tokenProperty,\n data,\n body,\n query,\n parameters,\n headers,\n method,\n baseUrl,\n queryArrayFormat,\n ...init\n } = options\n const context: Partial<RequestContext> = { init }\n const dataObject = isObjectLike(data) ? data : undefined\n\n // --- Parse the URL and insert the path parameters.\n parseRequestUrl(context, route, { baseUrl, method })\n parseRequestParameters(context, { parameters: parameters ?? dataObject })\n parseRequestBasicAuth(context, { username, password })\n\n // --- Depending on the method, parse the query, body, and headers.\n const requestMethod = context.init?.method?.toLowerCase() ?? 'get'\n const requestExpectsBody = ['post', 'put', 'patch'].includes(requestMethod)\n parseRequestQuery(context, { queryArrayFormat, query: requestExpectsBody ? query : query ?? dataObject })\n parseRequestToken(context, { token, tokenLocation, tokenProperty })\n parseRequestBody(context, { body: requestExpectsBody ? body ?? dataObject : undefined })\n parseRequestHeaders(context, { headers })\n\n // --- Return the context with the URL and the `RequestInit` object.\n return context as RequestContext\n}\n","import type { Awaitable } from '@unshared/functions/awaitable'\nimport type { RequestOptions } from './request'\nimport { awaitable } from '@unshared/functions/awaitable'\n\nasync function * createResponseStreamJsonIterator(response: Response, options: RequestOptions): AsyncGenerator<unknown, void, unknown> {\n const { onError, onSuccess, onData, onEnd } = options\n try {\n const body = response.body\n if (body === null) throw new Error('Could not read the response body, it is empty.')\n const reader = body.getReader()\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n const parts = new TextDecoder().decode(value).trim().split('\\0').filter(Boolean)\n\n // --- For each part, parse as JSON and yield the data.\n for (const part of parts) {\n const payload = JSON.parse(part) as unknown\n if (onData) await onData(payload, options)\n yield payload\n }\n }\n if (onSuccess) await onSuccess(response, options)\n }\n catch (error) {\n if (onError) await onError(error as Error, options)\n else throw error\n }\n finally {\n if (onEnd) await onEnd(response, options)\n }\n}\n\n/**\n * Handle a request response where the content type is a stream of JSON objects. This function\n * will parse the JSON objects and yield the data to the caller. If an error occurs, the `onError`\n * callback will be called and the function will return.\n *\n * @param response The response to handle.\n * @param options The options to pass to the request.\n * @returns An awaitable iterator that yields the parsed JSON objects.\n */\nexport function handleResponseStreamJson(response: Response, options: RequestOptions): Awaitable<AsyncIterable<unknown>, unknown[]> {\n const responseIterator = createResponseStreamJsonIterator(response, options)\n return awaitable(responseIterator)\n}\n","/* eslint-disable sonarjs/cognitive-complexity */\nimport type { Awaitable } from '@unshared/functions/awaitable'\nimport type { RequestOptions } from './request'\nimport { awaitable } from '@unshared/functions/awaitable'\n\n/** SSE event data structure */\nexport interface SseEvent<T = string> {\n\n /** The event type */\n event?: string\n\n /** The event data */\n data: T\n\n /** The event ID */\n id?: string\n\n /** The retry timeout in milliseconds */\n retry?: number\n}\n\nasync function * createResponseStreamSseIterator<T>(response: Response, options: RequestOptions): AsyncGenerator<SseEvent<T>, void, unknown> {\n const { onError, onSuccess, onData, onEnd } = options\n try {\n const body = response.body\n if (body === null) throw new Error('Could not read the response body, it is empty.')\n const reader = body.getReader()\n const decoder = new TextDecoder()\n\n // SSE parsing state buffers according to spec\n let buffer = ''\n let bufferData = ''\n let bufferEvent = ''\n let bufferId = ''\n let bufferRetry: number | undefined\n\n function flush() {\n if (bufferData === '') return\n if (bufferData.endsWith('\\n')) bufferData = bufferData.slice(0, -1)\n const sseEvent = {} as SseEvent<unknown>\n\n // --- Set `event`, `id`, and `retry` fields if they are set\n if (bufferEvent !== '') sseEvent.event = bufferEvent\n if (bufferId !== '') sseEvent.id = bufferId\n if (bufferRetry !== undefined) sseEvent.retry = bufferRetry\n\n // --- Attempt to parse the `data` field as JSON if it looks like an object\n try { sseEvent.data = JSON.parse(bufferData) as object }\n catch { sseEvent.data = bufferData }\n\n // --- Reset buffers for the next event\n bufferData = ''\n bufferEvent = ''\n bufferId = ''\n bufferRetry = undefined\n\n return sseEvent as SseEvent<T>\n }\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n // --- Split on all valid line endings: CRLF, LF, CR\n // --- Additionally, keep the last incomplete line in the buffer\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split(/\\r\\n|\\n|\\r/)\n buffer = lines.pop() ?? ''\n\n for (const line of lines) {\n\n // --- Empty line dispatches the event.\n if (line === '') {\n const event = flush()\n if (event) yield event\n if (event && onData) await onData(event, options)\n continue\n }\n\n // --- Skip comment lines (start with colon)\n if (line.startsWith(':')) continue\n\n // --- Parse field name and value by finding the first colon.\n const colonIndex = line.indexOf(':')\n let fieldName: string\n let fieldValue: string\n\n // --- No colon means field name only, empty value\n if (colonIndex === -1) {\n fieldName = line\n fieldValue = ''\n }\n else {\n fieldName = line.slice(0, colonIndex)\n fieldValue = line.slice(colonIndex + 1)\n if (fieldValue.startsWith(' ')) fieldValue = fieldValue.slice(1)\n }\n\n // --- Extract event type, data, id, and retry fields according to spec\n // --- Note that id must not contain null characters and retry must be a valid number.\n if (fieldName === 'event') {\n bufferEvent = fieldValue\n }\n else if (fieldName === 'data') {\n bufferData += `${fieldValue}\\n`\n }\n else if (fieldName === 'id') {\n if (!fieldValue.includes('\\0'))\n bufferId = fieldValue\n }\n else if (fieldName === 'retry' && /^\\d+$/.test(fieldValue)) {\n bufferRetry = Number.parseInt(fieldValue, 10)\n }\n }\n }\n\n // --- Handle any remaining event in buffer at end of stream\n const event = flush()\n if (event) yield event\n if (event && onData) await onData(event, options)\n if (onSuccess) await onSuccess(response, options)\n }\n catch (error) {\n if (onError) await onError(error as Error, options)\n else throw error\n }\n finally {\n if (onEnd) await onEnd(response, options)\n }\n}\n\n/**\n * Handle a request response where the content type is a Server-Sent Events stream. This function\n * will parse the SSE events and yield the data to the caller. If an error occurs, the `onError`\n * callback will be called and the function will return.\n *\n * @param response The response to handle.\n * @param options The options to pass to the request.\n * @returns An awaitable iterator that yields the parsed SSE events.\n */\nexport function handleResponseStreamSse<T>(response: Response, options: RequestOptions): Awaitable<AsyncIterable<SseEvent<T>>, Array<SseEvent<T>>> {\n const responseIterator = createResponseStreamSseIterator<T>(response, options)\n return awaitable(responseIterator)\n}\n","import type { RequestOptions } from './request'\nimport { handleResponseStreamJson } from './handleResponseStreamJson'\nimport { handleResponseStreamSse } from './handleResponseStreamSse'\n\n/**\n * Handle a request response. This function will parse the response based on the content type and\n * return the data. If an error occurs, the `onError` callback will be called and the function will\n * throw an error.\n *\n * @param response The response to handle.\n * @param options The options to pass to the request.\n * @returns The parsed data from the response.\n */\nexport async function handleResponse(response: Response, options: RequestOptions = {}): Promise<unknown> {\n const { onError, onSuccess, onData, onEnd, onFailure } = options\n const contentType = response.headers.get('Content-Type')\n\n // --- If the response is not OK, throw an error with the response message.\n if (!response.ok) {\n if (onFailure) await onFailure(response, options)\n if (onEnd) await onEnd(response, options)\n throw new Error(response.statusText)\n }\n\n // --- If the status code is 204, return an empty response early.\n if (response.status === 204) {\n if (onSuccess) await onSuccess(response, options)\n if (onEnd) await onEnd(response, options)\n return\n }\n\n // --- If the response is a application/stream+json, return an iterator that parses the JSON.\n if (contentType?.startsWith('application/stream+json'))\n return handleResponseStreamJson(response, options)\n\n // --- If the response is a text/event-stream, return an iterator that parses the SSE events.\n if (contentType?.startsWith('text/event-stream'))\n return handleResponseStreamSse(response, options)\n\n // --- If the response is a application/json, parse the JSON and return it.\n if (contentType?.startsWith('application/json')) {\n return await response.json()\n .then(async(data) => {\n if (onData) await onData(data, options)\n if (onSuccess) await onSuccess(response, options)\n return data as unknown\n })\n .catch(async(error: Error) => {\n if (onError) await onError(error, options)\n else throw error\n })\n .finally(() => {\n if (onEnd) onEnd(response, options)\n })\n }\n\n // --- If the response is a text content type (but not event-stream), return the text response.\n if (contentType?.startsWith('text/')) {\n return await response.text()\n .then(async(data) => {\n if (onData) await onData(data, options)\n if (onSuccess) await onSuccess(response, options)\n return data\n })\n .catch(async(error: Error) => {\n if (onError) await onError(error, options)\n else throw error\n })\n .finally(() => {\n if (onEnd) onEnd(response, options)\n })\n }\n\n // --- Otherwise, fallback to returning the response body as-is.\n if (onSuccess) onSuccess(response, options)\n if (onEnd) onEnd(response, options)\n return response.body\n}\n"],"names":["value","key","flush","event"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
- var attempt = require("@unshared/functions/attempt"), request = require("./chunks/DCBEtS8k.cjs"), connect = require("./chunks/DJyo3R5b.cjs");
3
- require("./chunks/CbXCpEzw.cjs");
2
+ var attempt = require("@unshared/functions/attempt"), request = require("./chunks/CNNxr5Ws.cjs"), connect = require("./chunks/DJyo3R5b.cjs");
3
+ require("./chunks/-InYnohy.cjs");
4
4
  require("./chunks/BDxlAULu.cjs");
5
5
  require("@unshared/functions/awaitable");
6
6
  class Client {
@@ -1,7 +1,7 @@
1
1
  import { Result } from '@unshared/functions/attempt';
2
2
  import { ServiceOptions } from './createService.js';
3
- import { R as RequestOptions, F as FetchOptions } from './chunks/rRfHSRNV.js';
4
- import { O as OpenAPILike, a as OpenAPIOptionsMap } from './chunks/Dil0c6fd.js';
3
+ import { R as RequestOptions, F as FetchOptions } from './chunks/CNqEW-S3.js';
4
+ import { O as OpenAPILike, a as OpenAPIOptionsMap } from './chunks/DKPTfBgy.js';
5
5
  import { ConnectOptions, WebSocketChannel } from './websocket.js';
6
6
  import '@unshared/types';
7
7
  import '@unshared/functions/awaitable';
@@ -1,7 +1,7 @@
1
1
  import { attempt } from "@unshared/functions/attempt";
2
- import { f as fetch, r as request } from "./chunks/Dh-ZK9yy.js";
2
+ import { f as fetch, r as request } from "./chunks/ClHrsaTt.js";
3
3
  import { c as connect } from "./chunks/C83nLcQu.js";
4
- import "./chunks/C_VzAX2X.js";
4
+ import "./chunks/DZ2MwV7J.js";
5
5
  import "./chunks/B6pUErTM.js";
6
6
  import "@unshared/functions/awaitable";
7
7
  class Client {
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- var resolveOperationTokenOptions = require("./chunks/DEyigyGy.cjs"), handleResponse = require("./chunks/CbXCpEzw.cjs");
2
+ var resolveOperationTokenOptions = require("./chunks/DEyigyGy.cjs"), handleResponse = require("./chunks/-InYnohy.cjs");
3
3
  require("./chunks/BDxlAULu.cjs");
4
4
  require("@unshared/functions/awaitable");
5
5
  function createService(document, initialOptions) {
@@ -1,6 +1,6 @@
1
1
  import { MaybeLiteral } from '@unshared/types';
2
- import { S as ServerUrl, b as OpenAPIV3, c as OperationId, d as OperationById, e as OperationOptions, f as OperationResult } from './chunks/Dil0c6fd.js';
3
- import { R as RequestOptions } from './chunks/rRfHSRNV.js';
2
+ import { S as ServerUrl, b as OpenAPIV3, c as OperationId, d as OperationById, e as OperationOptions, f as OperationResult } from './chunks/DKPTfBgy.js';
3
+ import { R as RequestOptions } from './chunks/CNqEW-S3.js';
4
4
  import 'openapi-types';
5
5
  import '@unshared/functions/awaitable';
6
6
  import './HttpHeaders.js';
@@ -1,5 +1,5 @@
1
1
  import { g as getServerUrl, r as resolveOperation, a as resolveOperationTokenOptions } from "./chunks/B_Gz6Yz8.js";
2
- import { p as parseRequest, h as handleResponse } from "./chunks/C_VzAX2X.js";
2
+ import { p as parseRequest, h as handleResponse } from "./chunks/DZ2MwV7J.js";
3
3
  import "./chunks/B6pUErTM.js";
4
4
  import "@unshared/functions/awaitable";
5
5
  function createService(document, initialOptions) {
package/dist/index.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  var createClient = require("./createClient.cjs"), createService = require("./createService.cjs"), HttpHeaders = require("./HttpHeaders.cjs"), HttpMethods = require("./HttpMethods.cjs"), HttpStatusCodes = require("./HttpStatusCodes.cjs");
3
3
  require("@unshared/functions/attempt");
4
- require("./chunks/DCBEtS8k.cjs");
5
- require("./chunks/CbXCpEzw.cjs");
4
+ require("./chunks/CNNxr5Ws.cjs");
5
+ require("./chunks/-InYnohy.cjs");
6
6
  require("./chunks/BDxlAULu.cjs");
7
7
  require("@unshared/functions/awaitable");
8
8
  require("./chunks/DJyo3R5b.cjs");
package/dist/index.d.ts CHANGED
@@ -4,9 +4,9 @@ export { HttpHeader } from './HttpHeaders.js';
4
4
  export { HttpMethod } from './HttpMethods.js';
5
5
  export { HttpStatusCode } from './HttpStatusCodes.js';
6
6
  import '@unshared/functions/attempt';
7
- import './chunks/rRfHSRNV.js';
7
+ import './chunks/CNqEW-S3.js';
8
8
  import '@unshared/functions/awaitable';
9
9
  import '@unshared/types';
10
- import './chunks/Dil0c6fd.js';
10
+ import './chunks/DKPTfBgy.js';
11
11
  import 'openapi-types';
12
12
  import './websocket.js';
package/dist/index.js CHANGED
@@ -4,8 +4,8 @@ import { HttpHeader } from "./HttpHeaders.js";
4
4
  import { HttpMethod } from "./HttpMethods.js";
5
5
  import { HttpStatusCode } from "./HttpStatusCodes.js";
6
6
  import "@unshared/functions/attempt";
7
- import "./chunks/Dh-ZK9yy.js";
8
- import "./chunks/C_VzAX2X.js";
7
+ import "./chunks/ClHrsaTt.js";
8
+ import "./chunks/DZ2MwV7J.js";
9
9
  import "./chunks/B6pUErTM.js";
10
10
  import "@unshared/functions/awaitable";
11
11
  import "./chunks/C83nLcQu.js";
package/dist/openapi.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- export { O as OpenAPILike, a as OpenAPIOptionsMap, h as OpenAPIV2, j as OpenAPIV2Like, b as OpenAPIV3, k as OpenAPIV3Like, i as Operation, d as OperationById, n as OperationByRoute, c as OperationId, e as OperationOptions, l as OperationResponse, f as OperationResult, m as OperationRoute, S as ServerUrl, g as getServerUrl, r as resolveOperation } from './chunks/Dil0c6fd.js';
1
+ export { O as OpenAPILike, a as OpenAPIOptionsMap, h as OpenAPIV2, j as OpenAPIV2Like, b as OpenAPIV3, k as OpenAPIV3Like, i as Operation, d as OperationById, n as OperationByRoute, c as OperationId, e as OperationOptions, l as OperationResponse, f as OperationResult, m as OperationRoute, S as ServerUrl, g as getServerUrl, r as resolveOperation } from './chunks/DKPTfBgy.js';
2
2
  import { OpenAPIV2, OpenAPIV3, OpenAPIV3_1, OpenAPI } from 'openapi-types';
3
3
  import { StringReplace, WriteableDeep, StringJoin, Substract } from '@unshared/types';
4
- import './chunks/rRfHSRNV.js';
4
+ import './chunks/CNqEW-S3.js';
5
5
  import '@unshared/functions/awaitable';
6
6
  import './HttpHeaders.js';
7
7
  import './HttpMethods.js';
package/dist/utils.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- var request = require("./chunks/DCBEtS8k.cjs"), handleResponse = require("./chunks/CbXCpEzw.cjs"), parseRequestQuery = require("./chunks/BDxlAULu.cjs");
2
+ var request = require("./chunks/CNNxr5Ws.cjs"), handleResponse = require("./chunks/-InYnohy.cjs"), parseRequestQuery = require("./chunks/BDxlAULu.cjs");
3
3
  require("@unshared/functions/awaitable");
4
4
  function getCookie(headers, key) {
5
5
  const cookie = handleResponse.getCookies(headers);
package/dist/utils.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { F as FetchOptions, R as RequestOptions, b as RequestContext } from './chunks/rRfHSRNV.js';
2
- export { c as FetchHeaders, a as FetchMethod, d as RequestOptionsOnData, e as SearchArrayFormat, S as SearchParamsObject, T as ToSearchParamsOptions, p as parseRequest, r as request, t as toSearchParams } from './chunks/rRfHSRNV.js';
1
+ import { F as FetchOptions, R as RequestOptions, b as RequestContext } from './chunks/CNqEW-S3.js';
2
+ export { c as FetchHeaders, a as FetchMethod, d as RequestOptionsOnData, e as SearchArrayFormat, S as SearchParamsObject, T as ToSearchParamsOptions, p as parseRequest, r as request, t as toSearchParams } from './chunks/CNqEW-S3.js';
3
3
  import { Awaitable } from '@unshared/functions/awaitable';
4
4
  import { ObjectLike } from '@unshared/types';
5
5
  import './HttpHeaders.js';
package/dist/utils.js CHANGED
@@ -1,6 +1,6 @@
1
- import { f, r } from "./chunks/Dh-ZK9yy.js";
2
- import { g as getCookies } from "./chunks/C_VzAX2X.js";
3
- import { a, h, b, c, i, d, p, e, f as f2, j, k, l, s, m, t } from "./chunks/C_VzAX2X.js";
1
+ import { f, r } from "./chunks/ClHrsaTt.js";
2
+ import { g as getCookies } from "./chunks/DZ2MwV7J.js";
3
+ import { a, h, b, c, i, d, p, e, f as f2, j, k, l, s, m, t } from "./chunks/DZ2MwV7J.js";
4
4
  import { p as p2, a as a2, t as t2 } from "./chunks/B6pUErTM.js";
5
5
  import "@unshared/functions/awaitable";
6
6
  function getCookie(headers, key) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@unshared/client",
3
3
  "type": "module",
4
- "version": "0.6.6",
4
+ "version": "0.7.1",
5
5
  "license": "MIT",
6
6
  "sideEffects": false,
7
7
  "author": "Stanley Horwood <stanley@hsjm.io>",
@@ -68,12 +68,12 @@
68
68
  "LICENSE.md"
69
69
  ],
70
70
  "dependencies": {
71
- "@unshared/functions": "0.6.6",
72
- "@unshared/types": "0.6.6",
71
+ "@unshared/functions": "0.7.1",
72
+ "@unshared/types": "0.7.1",
73
73
  "openapi-types": "12.1.3"
74
74
  },
75
75
  "devDependencies": {
76
- "@unshared/scripts": "0.6.6"
76
+ "@unshared/scripts": "0.7.1"
77
77
  },
78
78
  "scripts": {
79
79
  "build:httpMethods": "tsx ./scripts/buildHttpMethods.ts",
@@ -1 +0,0 @@
1
- {"version":3,"file":"DCBEtS8k.cjs","sources":["../../utils/fetch.ts","../../utils/request.ts"],"sourcesContent":["import type { FetchOptions } from './parseRequest'\nimport { parseRequest } from './parseRequest'\n\n/**\n * Fetch a route with the provided options. This function will parse the route and\n * options to create a `Request` object and return the response from the server.\n *\n * @param route The name of the route to fetch.\n * @param options The options to pass to the request.\n * @returns The response from the server.\n * @example fetch('GET /users', { query: { limit: 10 } })\n */\nexport async function fetch(route: string, options?: FetchOptions): Promise<Response>\nexport async function fetch(route: string, options: FetchOptions = {}): Promise<Response> {\n const { url, init } = parseRequest(route, options)\n if (!url) throw new Error('Could not parse request URL')\n return await globalThis.fetch(url, init)\n}\n","import type { Awaitable } from '@unshared/functions/awaitable'\nimport type { ObjectLike } from '@unshared/types'\nimport type { FetchMethod, FetchOptions } from './parseRequest'\nimport { fetch } from './fetch'\nimport { handleResponse } from './handleResponse'\n\nexport type RequestOptionsOnData<T> =\n T extends AsyncGenerator<infer U, any, any> ? (data: U) => any\n : T extends Awaitable<AsyncGenerator<infer U, any, any>> ? (data: U) => any\n : (data: T) => any\n\nexport interface RequestOptions<\n Method extends FetchMethod = FetchMethod,\n BaseUrl extends string = string,\n Parameters extends ObjectLike = ObjectLike,\n Query extends ObjectLike = ObjectLike,\n Body = unknown,\n Headers extends ObjectLike = ObjectLike,\n Data = any,\n Response = globalThis.Response,\n> extends\n FetchOptions<Method, BaseUrl, Parameters, Query, Body, Headers> {\n\n /**\n * The callback that is called when an error occurs during the request.\n */\n onError?: (error: Error) => any\n\n /**\n * The callback that is called when data is received from the request. This callback\n * will be called for each chunk of data that is received from the request.\n */\n onData?: RequestOptionsOnData<Data>\n\n /**\n * The callback that is called when the request is successful. This callback will be\n * called after the request is complete and all data has been received.\n */\n onSuccess?: (response: Response) => any\n\n /**\n * The callback that is called when the status code is not OK. This callback will be called\n * after the request is complete and before the data is consumed.\n */\n onFailure?: (response: Response) => any\n\n /**\n * The callback that is called when the request is complete. This callback will be called\n * after the request is complete and all data has been received.\n */\n onEnd?: (response: Response) => any\n}\n\n/**\n * Fetch a route from the API and return the data. If the client was instantiated with an\n * application, the route name will be inferred from the application routes. Otherwise, you\n * can pass the route name as a string.\n *\n * @param route The name of the route to fetch.\n * @param options The options to pass to the request.\n * @returns The data from the API.\n * @example\n * // Declare the application type.\n * type App = Application<[ModuleProduct]>\n *\n * // Create a type-safe client for the application.\n * const request = createClient<App>()\n *\n * // Fetch the data from the API.\n * const data = request('GET /api/product/:id', { data: { id: '1' } })\n */\nexport async function request(route: string, options?: RequestOptions): Promise<unknown>\nexport async function request(route: string, options: RequestOptions = {}): Promise<unknown> {\n const response = await fetch(route, options)\n return await handleResponse(response, options)\n}\n"],"names":["parseRequest","handleResponse"],"mappings":";;AAaA,eAAsB,MAAM,OAAe,UAAwB,IAAuB;AACxF,QAAM,EAAE,KAAK,KAAA,IAASA,eAAAA,aAAa,OAAO,OAAO;AACjD,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,6BAA6B;AACvD,SAAO,MAAM,WAAW,MAAM,KAAK,IAAI;AACzC;ACuDA,eAAsB,QAAQ,OAAe,UAA0B,IAAsB;AAC3F,QAAM,WAAW,MAAM,MAAM,OAAO,OAAO;AAC3C,SAAO,MAAMC,eAAAA,eAAe,UAAU,OAAO;AAC/C;;;"}
@@ -1,15 +0,0 @@
1
- import { p as parseRequest, h as handleResponse } from "./C_VzAX2X.js";
2
- async function fetch(route, options = {}) {
3
- const { url, init } = parseRequest(route, options);
4
- if (!url) throw new Error("Could not parse request URL");
5
- return await globalThis.fetch(url, init);
6
- }
7
- async function request(route, options = {}) {
8
- const response = await fetch(route, options);
9
- return await handleResponse(response, options);
10
- }
11
- export {
12
- fetch as f,
13
- request as r
14
- };
15
- //# sourceMappingURL=Dh-ZK9yy.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Dh-ZK9yy.js","sources":["../../utils/fetch.ts","../../utils/request.ts"],"sourcesContent":["import type { FetchOptions } from './parseRequest'\nimport { parseRequest } from './parseRequest'\n\n/**\n * Fetch a route with the provided options. This function will parse the route and\n * options to create a `Request` object and return the response from the server.\n *\n * @param route The name of the route to fetch.\n * @param options The options to pass to the request.\n * @returns The response from the server.\n * @example fetch('GET /users', { query: { limit: 10 } })\n */\nexport async function fetch(route: string, options?: FetchOptions): Promise<Response>\nexport async function fetch(route: string, options: FetchOptions = {}): Promise<Response> {\n const { url, init } = parseRequest(route, options)\n if (!url) throw new Error('Could not parse request URL')\n return await globalThis.fetch(url, init)\n}\n","import type { Awaitable } from '@unshared/functions/awaitable'\nimport type { ObjectLike } from '@unshared/types'\nimport type { FetchMethod, FetchOptions } from './parseRequest'\nimport { fetch } from './fetch'\nimport { handleResponse } from './handleResponse'\n\nexport type RequestOptionsOnData<T> =\n T extends AsyncGenerator<infer U, any, any> ? (data: U) => any\n : T extends Awaitable<AsyncGenerator<infer U, any, any>> ? (data: U) => any\n : (data: T) => any\n\nexport interface RequestOptions<\n Method extends FetchMethod = FetchMethod,\n BaseUrl extends string = string,\n Parameters extends ObjectLike = ObjectLike,\n Query extends ObjectLike = ObjectLike,\n Body = unknown,\n Headers extends ObjectLike = ObjectLike,\n Data = any,\n Response = globalThis.Response,\n> extends\n FetchOptions<Method, BaseUrl, Parameters, Query, Body, Headers> {\n\n /**\n * The callback that is called when an error occurs during the request.\n */\n onError?: (error: Error) => any\n\n /**\n * The callback that is called when data is received from the request. This callback\n * will be called for each chunk of data that is received from the request.\n */\n onData?: RequestOptionsOnData<Data>\n\n /**\n * The callback that is called when the request is successful. This callback will be\n * called after the request is complete and all data has been received.\n */\n onSuccess?: (response: Response) => any\n\n /**\n * The callback that is called when the status code is not OK. This callback will be called\n * after the request is complete and before the data is consumed.\n */\n onFailure?: (response: Response) => any\n\n /**\n * The callback that is called when the request is complete. This callback will be called\n * after the request is complete and all data has been received.\n */\n onEnd?: (response: Response) => any\n}\n\n/**\n * Fetch a route from the API and return the data. If the client was instantiated with an\n * application, the route name will be inferred from the application routes. Otherwise, you\n * can pass the route name as a string.\n *\n * @param route The name of the route to fetch.\n * @param options The options to pass to the request.\n * @returns The data from the API.\n * @example\n * // Declare the application type.\n * type App = Application<[ModuleProduct]>\n *\n * // Create a type-safe client for the application.\n * const request = createClient<App>()\n *\n * // Fetch the data from the API.\n * const data = request('GET /api/product/:id', { data: { id: '1' } })\n */\nexport async function request(route: string, options?: RequestOptions): Promise<unknown>\nexport async function request(route: string, options: RequestOptions = {}): Promise<unknown> {\n const response = await fetch(route, options)\n return await handleResponse(response, options)\n}\n"],"names":[],"mappings":";AAaA,eAAsB,MAAM,OAAe,UAAwB,IAAuB;AACxF,QAAM,EAAE,KAAK,KAAA,IAAS,aAAa,OAAO,OAAO;AACjD,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,6BAA6B;AACvD,SAAO,MAAM,WAAW,MAAM,KAAK,IAAI;AACzC;ACuDA,eAAsB,QAAQ,OAAe,UAA0B,IAAsB;AAC3F,QAAM,WAAW,MAAM,MAAM,OAAO,OAAO;AAC3C,SAAO,MAAM,eAAe,UAAU,OAAO;AAC/C;"}