@unshared/client 0.3.0 → 0.3.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/dist/chunks/0ZzUT3m_.js +46 -0
- package/dist/chunks/0ZzUT3m_.js.map +1 -0
- package/dist/chunks/{D51s1VII.js → BUeqbyph.js} +3 -45
- package/dist/chunks/BUeqbyph.js.map +1 -0
- package/dist/chunks/{B92aAMq0.d.ts → CO11DuYE.d.ts} +1 -1
- package/dist/chunks/CYmaYL5B.cjs +45 -0
- package/dist/chunks/CYmaYL5B.cjs.map +1 -0
- package/dist/chunks/{CfKxYeRr.cjs → Cayg8606.cjs} +4 -47
- package/dist/chunks/Cayg8606.cjs.map +1 -0
- package/dist/chunks/{lMH6B5BV.js → DJJsADWD.js} +2 -2
- package/dist/chunks/{lMH6B5BV.js.map → DJJsADWD.js.map} +1 -1
- package/dist/chunks/{CjU0376e.d.ts → DOZHjge0.d.ts} +12 -17
- package/dist/chunks/Du56lBvc.js +75 -0
- package/dist/chunks/Du56lBvc.js.map +1 -0
- package/dist/chunks/{iA98-4f5.cjs → Du_W5H6e.cjs} +2 -2
- package/dist/chunks/{iA98-4f5.cjs.map → Du_W5H6e.cjs.map} +1 -1
- package/dist/chunks/VkINJoq7.cjs +74 -0
- package/dist/chunks/VkINJoq7.cjs.map +1 -0
- package/dist/createClient.cjs +16 -15
- package/dist/createClient.cjs.map +1 -1
- package/dist/createClient.d.ts +43 -27
- package/dist/createClient.js +18 -16
- package/dist/createClient.js.map +1 -1
- package/dist/createService.cjs +2 -1
- package/dist/createService.cjs.map +1 -1
- package/dist/createService.d.ts +2 -2
- package/dist/createService.js +2 -1
- package/dist/createService.js.map +1 -1
- package/dist/index.cjs +6 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4 -6
- package/dist/index.js +6 -25
- package/dist/openapi.d.ts +2 -2
- package/dist/utils.cjs +4 -4
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +7 -6
- package/dist/utils.js.map +1 -1
- package/dist/websocket.cjs +7 -0
- package/dist/websocket.cjs.map +1 -0
- package/dist/websocket.d.ts +148 -0
- package/dist/websocket.js +8 -0
- package/dist/websocket.js.map +1 -0
- package/package.json +9 -4
- package/dist/chunks/CfKxYeRr.cjs.map +0 -1
- package/dist/chunks/D51s1VII.js.map +0 -1
@@ -0,0 +1,46 @@
|
|
1
|
+
const EXP_PATH_PARAMETER = /:([\w-]+)|%7B([\w-]+)%7D/g;
|
2
|
+
function parseRequestParameters(context, options) {
|
3
|
+
const { url } = context, { parameters } = options;
|
4
|
+
if (typeof parameters != "object" || parameters === null || url === void 0) return;
|
5
|
+
if (!(url instanceof URL)) throw new Error("The `url` must be an instance of `URL`.");
|
6
|
+
const pathParameters = url.pathname.match(EXP_PATH_PARAMETER);
|
7
|
+
if (pathParameters)
|
8
|
+
for (const parameter of pathParameters.values()) {
|
9
|
+
const key = parameter.replaceAll(EXP_PATH_PARAMETER, "$1$2"), value = parameters[key];
|
10
|
+
(typeof value == "string" && value.length > 0 || typeof value == "number" && Number.isFinite(value) || typeof value == "boolean") && (url.pathname = url.pathname.replace(parameter, value.toString()), delete parameters[key]);
|
11
|
+
}
|
12
|
+
}
|
13
|
+
function toSearchParams(object, options = {}) {
|
14
|
+
const { format = "flat" } = options, search = new URLSearchParams();
|
15
|
+
for (const key in object) {
|
16
|
+
const value = object[key];
|
17
|
+
if (value !== void 0)
|
18
|
+
if (Array.isArray(value)) {
|
19
|
+
if (format === "brackets") for (const v of value) search.append(`${key}[]`, String(v));
|
20
|
+
else if (format === "indices") for (const [i, v] of value.entries()) search.append(`${key}[${i}]`, String(v));
|
21
|
+
else if (format === "comma") search.append(key, value.join(","));
|
22
|
+
else if (format === "path") for (const [i, v] of value.entries()) search.append(`${key}.${i}`, String(v));
|
23
|
+
else if (format === "flat") for (const v of value) search.append(key, String(v));
|
24
|
+
} else
|
25
|
+
search.append(key, value.toString());
|
26
|
+
}
|
27
|
+
return search;
|
28
|
+
}
|
29
|
+
function parseRequestQuery(context, options) {
|
30
|
+
const { url } = context, { query, queryArrayFormat } = options;
|
31
|
+
if (url === void 0) return;
|
32
|
+
if (!(url instanceof URL)) throw new Error("The `url` must be an instance of `URL.");
|
33
|
+
if (typeof query != "object" || query === null) return;
|
34
|
+
const queryObject = {};
|
35
|
+
for (const key in query) {
|
36
|
+
const value = query[key];
|
37
|
+
(typeof value == "string" && value.length > 0 || typeof value == "number" && Number.isFinite(value) || typeof value == "boolean" || Array.isArray(value) && value.length > 0 && value.every((v) => typeof v == "string" || typeof v == "number" || typeof v == "boolean")) && (queryObject[key] = value, delete query[key]);
|
38
|
+
}
|
39
|
+
url.search = toSearchParams(queryObject, { format: queryArrayFormat }).toString();
|
40
|
+
}
|
41
|
+
export {
|
42
|
+
parseRequestQuery as a,
|
43
|
+
parseRequestParameters as p,
|
44
|
+
toSearchParams as t
|
45
|
+
};
|
46
|
+
//# sourceMappingURL=0ZzUT3m_.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"0ZzUT3m_.js","sources":["../../utils/parseRequestParameters.ts","../../utils/toSearchParams.ts","../../utils/parseRequestQuery.ts"],"sourcesContent":["import type { FetchOptions, RequestContext } from './parseRequest'\n\n/** Regular expression to match path parameters in the URL. */\nconst EXP_PATH_PARAMETER = /:([\\w-]+)|%7B([\\w-]+)%7D/g\n\n/**\n * Parse the request parameters from the request data. This function will mutate the\n * `url` object of the context to include the path parameters based on the provided data.\n *\n * @param context The request context to mutate.\n * @param options The options to pass to the request.\n * @example\n *\n * // Using `express` style path parameters.\n * const context = { url: new URL('https://api.example.com/users/:id') }\n * parseRequestParameters(context, { parameters: { id: 1 } })\n * console.log(context.url.pathname) // 'https://api.example.com/users/1'\n *\n * // Using `OpenAPI` style path parameters.\n * const context = { url: new URL('https://api.example.com/users/{id}') }\n * parseRequestParameters(context, { parameters: { id: 1 } })\n * console.log(context.url.pathname) // 'https://api.example.com/users/1'\n */\nexport function parseRequestParameters(context: RequestContext, options: FetchOptions): void {\n const { url } = context\n const { parameters } = options\n\n // --- Return early if the parameters is not an object.\n if (typeof parameters !== 'object' || parameters === null) return\n if (url === undefined) return\n if (url instanceof URL === false) throw new Error('The `url` must be an instance of `URL`.')\n\n // --- If the method has a parameter, fill the path with the data.\n const pathParameters = url.pathname.match(EXP_PATH_PARAMETER)\n if (!pathParameters) return\n\n // --- Apply the path parameters to the URL.\n for (const parameter of pathParameters.values()) {\n const key = parameter.replaceAll(EXP_PATH_PARAMETER, '$1$2')\n const value = parameters[key]\n\n // --- If the parameter is provided, replace the path with the value.\n if (\n (typeof value === 'string' && value.length > 0)\n || (typeof value === 'number' && Number.isFinite(value))\n || (typeof value === 'boolean')\n ) {\n url.pathname = url.pathname.replace(parameter, value.toString())\n delete parameters[key]\n }\n }\n}\n","/* eslint-disable unicorn/prevent-abbreviations */\nimport type { MaybeArray } from '@unshared/types'\n\n/** An object that can be converted to a query string. */\nexport type SearchParamsObject = Record<string, MaybeArray<boolean | number | string> | undefined>\n\n/** The search array format options. */\nexport type SearchArrayFormat = 'brackets' | 'comma' | 'flat' | 'indices' | 'path'\n\n/** Options for the query string conversion. */\nexport interface ToSearchParamsOptions {\n\n /**\n * Defines how to handle arrays in the object. There is no standard way to\n * represent arrays in query strings, so this option allows you to choose\n * how to handle them. Additionally, you can provide a custom function to\n * handle it yourself.\n *\n * - `brackets` (default): Convert arrays to `key[]=value&key[]=value` format.\n * - `indices`: Convert arrays to `key[0]=value&key[1]=value` format.\n * - `comma`: Convert arrays to `key=value1,value2` format.\n * - `path`: Convert arrays to `key.0=value&key.1=value` format.\n * - `flat`: Convert arrays to `key=value1&key=value2` format.\n *\n * @default 'flat'\n */\n format?: SearchArrayFormat\n}\n\n/**\n * Convert object to query string parameters. Converting all values to strings\n * and arrays to `key[0]=value&key[1]=value` format.\n *\n * @param object The object to convert to a query string.\n * @param options The query string options.\n * @returns The `URLSearchParams` object.\n */\nexport function toSearchParams(object: SearchParamsObject, options: ToSearchParamsOptions = {}): URLSearchParams {\n const { format = 'flat' } = options\n const search = new URLSearchParams()\n for (const key in object) {\n const value = object[key]\n if (value === undefined) continue\n\n // --- Convert arrays based on the format.\n if (Array.isArray(value)) {\n if (format === 'brackets') for (const v of value) search.append(`${key}[]`, String(v))\n else if (format === 'indices') for (const [i, v] of value.entries()) search.append(`${key}[${i}]`, String(v))\n else if (format === 'comma') search.append(key, value.join(','))\n else if (format === 'path') for (const [i, v] of value.entries()) search.append(`${key}.${i}`, String(v))\n else if (format === 'flat') for (const v of value) search.append(key, String(v))\n }\n\n // --- Convert all values to strings.\n else { search.append(key, value.toString()) }\n }\n\n // --- Return the query string.\n return search\n}\n","/* eslint-disable unicorn/prevent-abbreviations */\nimport type { FetchOptions, RequestContext } from './parseRequest'\nimport type { SearchParamsObject as SearchParametersObject } from './toSearchParams'\nimport { toSearchParams } from './toSearchParams'\n\n/**\n * Parse the query parameters from the request data. This function will append\n * the query parameters to the URL based on the method and the data provided.\n *\n * @param context The request context to modify.\n * @param options The options to pass to the request.\n */\nexport function parseRequestQuery(context: RequestContext, options: FetchOptions): void {\n const { url } = context\n const { query, queryArrayFormat } = options\n\n // --- Return early if the query is not an object or the URL is not provided.\n if (url === undefined) return\n if (url instanceof URL === false) throw new Error('The `url` must be an instance of `URL.')\n if (typeof query !== 'object' || query === null) return\n\n // --- Append the `data` to the query parameters if the method does not expect a body.\n const queryObject: SearchParametersObject = {}\n for (const key in query) {\n const value = query[key]\n if (\n (typeof value === 'string' && value.length > 0)\n || (typeof value === 'number' && Number.isFinite(value))\n || (typeof value === 'boolean')\n || Array.isArray(value) && value.length > 0 && value.every(v => typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean')\n ) {\n queryObject[key] = value\n delete query[key]\n }\n }\n\n // --- Apply the query parameters to the URL.\n url.search = toSearchParams(queryObject, { format: queryArrayFormat }).toString()\n}\n"],"names":[],"mappings":"AAGA,MAAM,qBAAqB;AAoBX,SAAA,uBAAuB,SAAyB,SAA6B;AAC3F,QAAM,EAAE,IAAI,IAAI,SACV,EAAE,WAAe,IAAA;AAIvB,MADI,OAAO,cAAe,YAAY,eAAe,QACjD,QAAQ,OAAW;AACvB,MAAI,EAAe,eAAA,KAAqB,OAAA,IAAI,MAAM,yCAAyC;AAG3F,QAAM,iBAAiB,IAAI,SAAS,MAAM,kBAAkB;AACvD,MAAA;AAGM,eAAA,aAAa,eAAe,UAAU;AACzC,YAAA,MAAM,UAAU,WAAW,oBAAoB,MAAM,GACrD,QAAQ,WAAW,GAAG;AAG5B,OACG,OAAO,SAAU,YAAY,MAAM,SAAS,KACzC,OAAO,SAAU,YAAY,OAAO,SAAS,KAAK,KAClD,OAAO,SAAU,eAErB,IAAI,WAAW,IAAI,SAAS,QAAQ,WAAW,MAAM,SAAA,CAAU,GAC/D,OAAO,WAAW,GAAG;AAAA,IAAA;AAG3B;ACdO,SAAS,eAAe,QAA4B,UAAiC,IAAqB;AAC/G,QAAM,EAAE,SAAS,OAAA,IAAW,SACtB,SAAS,IAAI,gBAAgB;AACnC,aAAW,OAAO,QAAQ;AAClB,UAAA,QAAQ,OAAO,GAAG;AACxB,QAAI,UAAU;AAGV,UAAA,MAAM,QAAQ,KAAK;AACrB,YAAI,WAAW,WAAuB,YAAA,KAAK,MAAO,QAAO,OAAO,GAAG,GAAG,MAAM,OAAO,CAAC,CAAC;AAAA,iBAC5E,WAAW,UAAW,YAAW,CAAC,GAAG,CAAC,KAAK,MAAM,UAAkB,QAAA,OAAO,GAAG,GAAG,IAAI,CAAC,KAAK,OAAO,CAAC,CAAC;AAAA,iBACnG,WAAW,QAAgB,QAAA,OAAO,KAAK,MAAM,KAAK,GAAG,CAAC;AAAA,iBACtD,WAAW,OAAQ,YAAW,CAAC,GAAG,CAAC,KAAK,MAAM,UAAkB,QAAA,OAAO,GAAG,GAAG,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC;AAAA,iBAC/F,WAAW,OAAQ,YAAW,KAAK,cAAc,OAAO,KAAK,OAAO,CAAC,CAAC;AAAA;AAI1E,eAAO,OAAO,KAAK,MAAM,SAAA,CAAU;AAAA,EAAA;AAIrC,SAAA;AACT;AC/CgB,SAAA,kBAAkB,SAAyB,SAA6B;AACtF,QAAM,EAAE,IAAI,IAAI,SACV,EAAE,OAAO,qBAAqB;AAGpC,MAAI,QAAQ,OAAW;AACvB,MAAI,EAAe,eAAA,KAAqB,OAAA,IAAI,MAAM,wCAAwC;AAC1F,MAAI,OAAO,SAAU,YAAY,UAAU,KAAM;AAGjD,QAAM,cAAsC,CAAC;AAC7C,aAAW,OAAO,OAAO;AACjB,UAAA,QAAQ,MAAM,GAAG;AACvB,KACG,OAAO,SAAU,YAAY,MAAM,SAAS,KACzC,OAAO,SAAU,YAAY,OAAO,SAAS,KAAK,KAClD,OAAO,SAAU,aAClB,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS,KAAK,MAAM,MAAM,CAAA,MAAK,OAAO,KAAM,YAAY,OAAO,KAAM,YAAY,OAAO,KAAM,SAAS,OAExI,YAAY,GAAG,IAAI,OACnB,OAAO,MAAM,GAAG;AAAA,EAAA;AAKhB,MAAA,SAAS,eAAe,aAAa,EAAE,QAAQ,iBAAiB,CAAC,EAAE,SAAS;AAClF;"}
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import { p as parseRequestParameters, a as parseRequestQuery } from "./0ZzUT3m_.js";
|
1
2
|
import { awaitable } from "@unshared/functions/awaitable";
|
2
3
|
function isObjectLike(value) {
|
3
4
|
return typeof value == "object" && value !== null && value.constructor === Object;
|
@@ -33,46 +34,6 @@ function parseRequestHeaders(context, options) {
|
|
33
34
|
(typeof value != "string" || value.length === 0) && typeof value != "number" || (context.init = context.init ?? {}, context.init.headers = context.init.headers ?? {}, context.init.headers = { ...context.init.headers, [key]: String(value) });
|
34
35
|
}
|
35
36
|
}
|
36
|
-
const EXP_PATH_PARAMETER = /:([\w-]+)|%7B([\w-]+)%7D/g;
|
37
|
-
function parseRequestParameters(context, options) {
|
38
|
-
const { url } = context, { parameters } = options;
|
39
|
-
if (typeof parameters != "object" || parameters === null || url === void 0) return;
|
40
|
-
if (!(url instanceof URL)) throw new Error("The `url` must be an instance of `URL`.");
|
41
|
-
const pathParameters = url.pathname.match(EXP_PATH_PARAMETER);
|
42
|
-
if (pathParameters)
|
43
|
-
for (const parameter of pathParameters.values()) {
|
44
|
-
const key = parameter.replaceAll(EXP_PATH_PARAMETER, "$1$2"), value = parameters[key];
|
45
|
-
(typeof value == "string" && value.length > 0 || typeof value == "number" && Number.isFinite(value) || typeof value == "boolean") && (url.pathname = url.pathname.replace(parameter, value.toString()), delete parameters[key]);
|
46
|
-
}
|
47
|
-
}
|
48
|
-
function toSearchParams(object, options = {}) {
|
49
|
-
const { format = "flat" } = options, search = new URLSearchParams();
|
50
|
-
for (const key in object) {
|
51
|
-
const value = object[key];
|
52
|
-
if (value !== void 0)
|
53
|
-
if (Array.isArray(value)) {
|
54
|
-
if (format === "brackets") for (const v of value) search.append(`${key}[]`, String(v));
|
55
|
-
else if (format === "indices") for (const [i, v] of value.entries()) search.append(`${key}[${i}]`, String(v));
|
56
|
-
else if (format === "comma") search.append(key, value.join(","));
|
57
|
-
else if (format === "path") for (const [i, v] of value.entries()) search.append(`${key}.${i}`, String(v));
|
58
|
-
else if (format === "flat") for (const v of value) search.append(key, String(v));
|
59
|
-
} else
|
60
|
-
search.append(key, value.toString());
|
61
|
-
}
|
62
|
-
return search;
|
63
|
-
}
|
64
|
-
function parseRequestQuery(context, options) {
|
65
|
-
const { url } = context, { query, queryArrayFormat } = options;
|
66
|
-
if (url === void 0) return;
|
67
|
-
if (!(url instanceof URL)) throw new Error("The `url` must be an instance of `URL.");
|
68
|
-
if (typeof query != "object" || query === null) return;
|
69
|
-
const queryObject = {};
|
70
|
-
for (const key in query) {
|
71
|
-
const value = query[key];
|
72
|
-
(typeof value == "string" && value.length > 0 || typeof value == "number" && Number.isFinite(value) || typeof value == "boolean" || Array.isArray(value) && value.length > 0 && value.every((v) => typeof v == "string" || typeof v == "number" || typeof v == "boolean")) && (queryObject[key] = value, delete query[key]);
|
73
|
-
}
|
74
|
-
url.search = toSearchParams(queryObject, { format: queryArrayFormat }).toString();
|
75
|
-
}
|
76
37
|
const EXP_REQUEST = /^((?<method>[a-z]+) )?(?<url>[^:]+?:\/{2}[^/]+)?(?<path>\/[^\s?]*)/i, METHODS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete", "head", "options"]);
|
77
38
|
function parseRequestUrl(context, route, options) {
|
78
39
|
const { method, baseUrl } = options, match = EXP_REQUEST.exec(route);
|
@@ -143,14 +104,11 @@ export {
|
|
143
104
|
isObjectLike as b,
|
144
105
|
parseRequestBody as c,
|
145
106
|
parseRequestHeaders as d,
|
146
|
-
|
107
|
+
parseRequestUrl as e,
|
147
108
|
fetch as f,
|
148
|
-
parseRequestQuery as g,
|
149
109
|
handleResponse as h,
|
150
110
|
isFormDataLike as i,
|
151
|
-
parseRequestUrl as j,
|
152
|
-
toSearchParams as k,
|
153
111
|
parseRequest as p,
|
154
112
|
toFormData as t
|
155
113
|
};
|
156
|
-
//# sourceMappingURL=
|
114
|
+
//# sourceMappingURL=BUeqbyph.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"BUeqbyph.js","sources":["../../utils/isObjectLike.ts","../../utils/isFormDataLike.ts","../../utils/toFormData.ts","../../utils/parseRequestBody.ts","../../utils/parseRequestHeaders.ts","../../utils/parseRequestUrl.ts","../../utils/parseRequest.ts","../../utils/fetch.ts","../../utils/handleResponseStreamJson.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 * 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 { 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: 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 ?? 'get')) 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 context.init.headers = context.init.headers ?? {}\n context.init.headers = { ...context.init.headers, 'Content-Type': 'multipart/form-data' }\n }\n\n // --- If the data is a `ReadableStream`, pass it directly to the body.\n else if (body instanceof ReadableStream) {\n context.init.body = body\n context.init.headers = context.init.headers ?? {}\n context.init.headers = { ...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 context.init.headers = { ...context.init.headers, 'Content-Type': 'application/octet-stream' }\n }\n\n // --- Otherwise, stringify the data and set the content type to JSON.\n else if (isObjectLike(body)) {\n context.init.body = JSON.stringify(body)\n context.init.headers = context.init.headers ?? {}\n context.init.headers = { ...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'\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: 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 context.init.headers = { ...context.init.headers, [key]: String(value) }\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: 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 { parseRequestBody } from './parseRequestBody'\nimport { parseRequestHeaders } from './parseRequestHeaders'\nimport { parseRequestParameters } from './parseRequestParameters'\nimport { parseRequestQuery } from './parseRequestQuery'\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\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 { data, body, query, parameters, headers, method, baseUrl, queryArrayFormat, ...init } = options\n const context: 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\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 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\n}\n","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 { 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","import type { RequestOptions } from './request'\nimport { handleResponseStreamJson } from './handleResponseStreamJson'\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) 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 text content type, 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 // --- If the response is a application/json, parse the JSON and return it.\n if (contentType === '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 application/stream+json, return an iterator that parses the JSON.\n if (contentType === 'application/stream+json')\n return handleResponseStreamJson(response, options)\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":[],"mappings":"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"}
|
@@ -141,4 +141,4 @@ interface RequestOptions<Method extends FetchMethod = FetchMethod, BaseUrl exten
|
|
141
141
|
*/
|
142
142
|
declare function request(route: string, options?: RequestOptions): Promise<unknown>;
|
143
143
|
|
144
|
-
export { type FetchMethod as F, type
|
144
|
+
export { type FetchMethod as F, type RequestOptions as R, type SearchParamsObject as S, type ToSearchParamsOptions as T, type FetchOptions as a, type RequestContext as b, type FetchHeaders as c, type SearchArrayFormat as d, parseRequest as p, request as r, toSearchParams as t };
|
@@ -0,0 +1,45 @@
|
|
1
|
+
"use strict";
|
2
|
+
const EXP_PATH_PARAMETER = /:([\w-]+)|%7B([\w-]+)%7D/g;
|
3
|
+
function parseRequestParameters(context, options) {
|
4
|
+
const { url } = context, { parameters } = options;
|
5
|
+
if (typeof parameters != "object" || parameters === null || url === void 0) return;
|
6
|
+
if (!(url instanceof URL)) throw new Error("The `url` must be an instance of `URL`.");
|
7
|
+
const pathParameters = url.pathname.match(EXP_PATH_PARAMETER);
|
8
|
+
if (pathParameters)
|
9
|
+
for (const parameter of pathParameters.values()) {
|
10
|
+
const key = parameter.replaceAll(EXP_PATH_PARAMETER, "$1$2"), value = parameters[key];
|
11
|
+
(typeof value == "string" && value.length > 0 || typeof value == "number" && Number.isFinite(value) || typeof value == "boolean") && (url.pathname = url.pathname.replace(parameter, value.toString()), delete parameters[key]);
|
12
|
+
}
|
13
|
+
}
|
14
|
+
function toSearchParams(object, options = {}) {
|
15
|
+
const { format = "flat" } = options, search = new URLSearchParams();
|
16
|
+
for (const key in object) {
|
17
|
+
const value = object[key];
|
18
|
+
if (value !== void 0)
|
19
|
+
if (Array.isArray(value)) {
|
20
|
+
if (format === "brackets") for (const v of value) search.append(`${key}[]`, String(v));
|
21
|
+
else if (format === "indices") for (const [i, v] of value.entries()) search.append(`${key}[${i}]`, String(v));
|
22
|
+
else if (format === "comma") search.append(key, value.join(","));
|
23
|
+
else if (format === "path") for (const [i, v] of value.entries()) search.append(`${key}.${i}`, String(v));
|
24
|
+
else if (format === "flat") for (const v of value) search.append(key, String(v));
|
25
|
+
} else
|
26
|
+
search.append(key, value.toString());
|
27
|
+
}
|
28
|
+
return search;
|
29
|
+
}
|
30
|
+
function parseRequestQuery(context, options) {
|
31
|
+
const { url } = context, { query, queryArrayFormat } = options;
|
32
|
+
if (url === void 0) return;
|
33
|
+
if (!(url instanceof URL)) throw new Error("The `url` must be an instance of `URL.");
|
34
|
+
if (typeof query != "object" || query === null) return;
|
35
|
+
const queryObject = {};
|
36
|
+
for (const key in query) {
|
37
|
+
const value = query[key];
|
38
|
+
(typeof value == "string" && value.length > 0 || typeof value == "number" && Number.isFinite(value) || typeof value == "boolean" || Array.isArray(value) && value.length > 0 && value.every((v) => typeof v == "string" || typeof v == "number" || typeof v == "boolean")) && (queryObject[key] = value, delete query[key]);
|
39
|
+
}
|
40
|
+
url.search = toSearchParams(queryObject, { format: queryArrayFormat }).toString();
|
41
|
+
}
|
42
|
+
exports.parseRequestParameters = parseRequestParameters;
|
43
|
+
exports.parseRequestQuery = parseRequestQuery;
|
44
|
+
exports.toSearchParams = toSearchParams;
|
45
|
+
//# sourceMappingURL=CYmaYL5B.cjs.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"CYmaYL5B.cjs","sources":["../../utils/parseRequestParameters.ts","../../utils/toSearchParams.ts","../../utils/parseRequestQuery.ts"],"sourcesContent":["import type { FetchOptions, RequestContext } from './parseRequest'\n\n/** Regular expression to match path parameters in the URL. */\nconst EXP_PATH_PARAMETER = /:([\\w-]+)|%7B([\\w-]+)%7D/g\n\n/**\n * Parse the request parameters from the request data. This function will mutate the\n * `url` object of the context to include the path parameters based on the provided data.\n *\n * @param context The request context to mutate.\n * @param options The options to pass to the request.\n * @example\n *\n * // Using `express` style path parameters.\n * const context = { url: new URL('https://api.example.com/users/:id') }\n * parseRequestParameters(context, { parameters: { id: 1 } })\n * console.log(context.url.pathname) // 'https://api.example.com/users/1'\n *\n * // Using `OpenAPI` style path parameters.\n * const context = { url: new URL('https://api.example.com/users/{id}') }\n * parseRequestParameters(context, { parameters: { id: 1 } })\n * console.log(context.url.pathname) // 'https://api.example.com/users/1'\n */\nexport function parseRequestParameters(context: RequestContext, options: FetchOptions): void {\n const { url } = context\n const { parameters } = options\n\n // --- Return early if the parameters is not an object.\n if (typeof parameters !== 'object' || parameters === null) return\n if (url === undefined) return\n if (url instanceof URL === false) throw new Error('The `url` must be an instance of `URL`.')\n\n // --- If the method has a parameter, fill the path with the data.\n const pathParameters = url.pathname.match(EXP_PATH_PARAMETER)\n if (!pathParameters) return\n\n // --- Apply the path parameters to the URL.\n for (const parameter of pathParameters.values()) {\n const key = parameter.replaceAll(EXP_PATH_PARAMETER, '$1$2')\n const value = parameters[key]\n\n // --- If the parameter is provided, replace the path with the value.\n if (\n (typeof value === 'string' && value.length > 0)\n || (typeof value === 'number' && Number.isFinite(value))\n || (typeof value === 'boolean')\n ) {\n url.pathname = url.pathname.replace(parameter, value.toString())\n delete parameters[key]\n }\n }\n}\n","/* eslint-disable unicorn/prevent-abbreviations */\nimport type { MaybeArray } from '@unshared/types'\n\n/** An object that can be converted to a query string. */\nexport type SearchParamsObject = Record<string, MaybeArray<boolean | number | string> | undefined>\n\n/** The search array format options. */\nexport type SearchArrayFormat = 'brackets' | 'comma' | 'flat' | 'indices' | 'path'\n\n/** Options for the query string conversion. */\nexport interface ToSearchParamsOptions {\n\n /**\n * Defines how to handle arrays in the object. There is no standard way to\n * represent arrays in query strings, so this option allows you to choose\n * how to handle them. Additionally, you can provide a custom function to\n * handle it yourself.\n *\n * - `brackets` (default): Convert arrays to `key[]=value&key[]=value` format.\n * - `indices`: Convert arrays to `key[0]=value&key[1]=value` format.\n * - `comma`: Convert arrays to `key=value1,value2` format.\n * - `path`: Convert arrays to `key.0=value&key.1=value` format.\n * - `flat`: Convert arrays to `key=value1&key=value2` format.\n *\n * @default 'flat'\n */\n format?: SearchArrayFormat\n}\n\n/**\n * Convert object to query string parameters. Converting all values to strings\n * and arrays to `key[0]=value&key[1]=value` format.\n *\n * @param object The object to convert to a query string.\n * @param options The query string options.\n * @returns The `URLSearchParams` object.\n */\nexport function toSearchParams(object: SearchParamsObject, options: ToSearchParamsOptions = {}): URLSearchParams {\n const { format = 'flat' } = options\n const search = new URLSearchParams()\n for (const key in object) {\n const value = object[key]\n if (value === undefined) continue\n\n // --- Convert arrays based on the format.\n if (Array.isArray(value)) {\n if (format === 'brackets') for (const v of value) search.append(`${key}[]`, String(v))\n else if (format === 'indices') for (const [i, v] of value.entries()) search.append(`${key}[${i}]`, String(v))\n else if (format === 'comma') search.append(key, value.join(','))\n else if (format === 'path') for (const [i, v] of value.entries()) search.append(`${key}.${i}`, String(v))\n else if (format === 'flat') for (const v of value) search.append(key, String(v))\n }\n\n // --- Convert all values to strings.\n else { search.append(key, value.toString()) }\n }\n\n // --- Return the query string.\n return search\n}\n","/* eslint-disable unicorn/prevent-abbreviations */\nimport type { FetchOptions, RequestContext } from './parseRequest'\nimport type { SearchParamsObject as SearchParametersObject } from './toSearchParams'\nimport { toSearchParams } from './toSearchParams'\n\n/**\n * Parse the query parameters from the request data. This function will append\n * the query parameters to the URL based on the method and the data provided.\n *\n * @param context The request context to modify.\n * @param options The options to pass to the request.\n */\nexport function parseRequestQuery(context: RequestContext, options: FetchOptions): void {\n const { url } = context\n const { query, queryArrayFormat } = options\n\n // --- Return early if the query is not an object or the URL is not provided.\n if (url === undefined) return\n if (url instanceof URL === false) throw new Error('The `url` must be an instance of `URL.')\n if (typeof query !== 'object' || query === null) return\n\n // --- Append the `data` to the query parameters if the method does not expect a body.\n const queryObject: SearchParametersObject = {}\n for (const key in query) {\n const value = query[key]\n if (\n (typeof value === 'string' && value.length > 0)\n || (typeof value === 'number' && Number.isFinite(value))\n || (typeof value === 'boolean')\n || Array.isArray(value) && value.length > 0 && value.every(v => typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean')\n ) {\n queryObject[key] = value\n delete query[key]\n }\n }\n\n // --- Apply the query parameters to the URL.\n url.search = toSearchParams(queryObject, { format: queryArrayFormat }).toString()\n}\n"],"names":[],"mappings":";AAGA,MAAM,qBAAqB;AAoBX,SAAA,uBAAuB,SAAyB,SAA6B;AAC3F,QAAM,EAAE,IAAI,IAAI,SACV,EAAE,WAAe,IAAA;AAIvB,MADI,OAAO,cAAe,YAAY,eAAe,QACjD,QAAQ,OAAW;AACvB,MAAI,EAAe,eAAA,KAAqB,OAAA,IAAI,MAAM,yCAAyC;AAG3F,QAAM,iBAAiB,IAAI,SAAS,MAAM,kBAAkB;AACvD,MAAA;AAGM,eAAA,aAAa,eAAe,UAAU;AACzC,YAAA,MAAM,UAAU,WAAW,oBAAoB,MAAM,GACrD,QAAQ,WAAW,GAAG;AAG5B,OACG,OAAO,SAAU,YAAY,MAAM,SAAS,KACzC,OAAO,SAAU,YAAY,OAAO,SAAS,KAAK,KAClD,OAAO,SAAU,eAErB,IAAI,WAAW,IAAI,SAAS,QAAQ,WAAW,MAAM,SAAA,CAAU,GAC/D,OAAO,WAAW,GAAG;AAAA,IAAA;AAG3B;ACdO,SAAS,eAAe,QAA4B,UAAiC,IAAqB;AAC/G,QAAM,EAAE,SAAS,OAAA,IAAW,SACtB,SAAS,IAAI,gBAAgB;AACnC,aAAW,OAAO,QAAQ;AAClB,UAAA,QAAQ,OAAO,GAAG;AACxB,QAAI,UAAU;AAGV,UAAA,MAAM,QAAQ,KAAK;AACrB,YAAI,WAAW,WAAuB,YAAA,KAAK,MAAO,QAAO,OAAO,GAAG,GAAG,MAAM,OAAO,CAAC,CAAC;AAAA,iBAC5E,WAAW,UAAW,YAAW,CAAC,GAAG,CAAC,KAAK,MAAM,UAAkB,QAAA,OAAO,GAAG,GAAG,IAAI,CAAC,KAAK,OAAO,CAAC,CAAC;AAAA,iBACnG,WAAW,QAAgB,QAAA,OAAO,KAAK,MAAM,KAAK,GAAG,CAAC;AAAA,iBACtD,WAAW,OAAQ,YAAW,CAAC,GAAG,CAAC,KAAK,MAAM,UAAkB,QAAA,OAAO,GAAG,GAAG,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC;AAAA,iBAC/F,WAAW,OAAQ,YAAW,KAAK,cAAc,OAAO,KAAK,OAAO,CAAC,CAAC;AAAA;AAI1E,eAAO,OAAO,KAAK,MAAM,SAAA,CAAU;AAAA,EAAA;AAIrC,SAAA;AACT;AC/CgB,SAAA,kBAAkB,SAAyB,SAA6B;AACtF,QAAM,EAAE,IAAI,IAAI,SACV,EAAE,OAAO,qBAAqB;AAGpC,MAAI,QAAQ,OAAW;AACvB,MAAI,EAAe,eAAA,KAAqB,OAAA,IAAI,MAAM,wCAAwC;AAC1F,MAAI,OAAO,SAAU,YAAY,UAAU,KAAM;AAGjD,QAAM,cAAsC,CAAC;AAC7C,aAAW,OAAO,OAAO;AACjB,UAAA,QAAQ,MAAM,GAAG;AACvB,KACG,OAAO,SAAU,YAAY,MAAM,SAAS,KACzC,OAAO,SAAU,YAAY,OAAO,SAAS,KAAK,KAClD,OAAO,SAAU,aAClB,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS,KAAK,MAAM,MAAM,CAAA,MAAK,OAAO,KAAM,YAAY,OAAO,KAAM,YAAY,OAAO,KAAM,SAAS,OAExI,YAAY,GAAG,IAAI,OACnB,OAAO,MAAM,GAAG;AAAA,EAAA;AAKhB,MAAA,SAAS,eAAe,aAAa,EAAE,QAAQ,iBAAiB,CAAC,EAAE,SAAS;AAClF;;;;"}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
"use strict";
|
2
|
-
var awaitable = require("@unshared/functions/awaitable");
|
2
|
+
var parseRequestQuery = require("./CYmaYL5B.cjs"), awaitable = require("@unshared/functions/awaitable");
|
3
3
|
function isObjectLike(value) {
|
4
4
|
return typeof value == "object" && value !== null && value.constructor === Object;
|
5
5
|
}
|
@@ -34,46 +34,6 @@ function parseRequestHeaders(context, options) {
|
|
34
34
|
(typeof value != "string" || value.length === 0) && typeof value != "number" || (context.init = context.init ?? {}, context.init.headers = context.init.headers ?? {}, context.init.headers = { ...context.init.headers, [key]: String(value) });
|
35
35
|
}
|
36
36
|
}
|
37
|
-
const EXP_PATH_PARAMETER = /:([\w-]+)|%7B([\w-]+)%7D/g;
|
38
|
-
function parseRequestParameters(context, options) {
|
39
|
-
const { url } = context, { parameters } = options;
|
40
|
-
if (typeof parameters != "object" || parameters === null || url === void 0) return;
|
41
|
-
if (!(url instanceof URL)) throw new Error("The `url` must be an instance of `URL`.");
|
42
|
-
const pathParameters = url.pathname.match(EXP_PATH_PARAMETER);
|
43
|
-
if (pathParameters)
|
44
|
-
for (const parameter of pathParameters.values()) {
|
45
|
-
const key = parameter.replaceAll(EXP_PATH_PARAMETER, "$1$2"), value = parameters[key];
|
46
|
-
(typeof value == "string" && value.length > 0 || typeof value == "number" && Number.isFinite(value) || typeof value == "boolean") && (url.pathname = url.pathname.replace(parameter, value.toString()), delete parameters[key]);
|
47
|
-
}
|
48
|
-
}
|
49
|
-
function toSearchParams(object, options = {}) {
|
50
|
-
const { format = "flat" } = options, search = new URLSearchParams();
|
51
|
-
for (const key in object) {
|
52
|
-
const value = object[key];
|
53
|
-
if (value !== void 0)
|
54
|
-
if (Array.isArray(value)) {
|
55
|
-
if (format === "brackets") for (const v of value) search.append(`${key}[]`, String(v));
|
56
|
-
else if (format === "indices") for (const [i, v] of value.entries()) search.append(`${key}[${i}]`, String(v));
|
57
|
-
else if (format === "comma") search.append(key, value.join(","));
|
58
|
-
else if (format === "path") for (const [i, v] of value.entries()) search.append(`${key}.${i}`, String(v));
|
59
|
-
else if (format === "flat") for (const v of value) search.append(key, String(v));
|
60
|
-
} else
|
61
|
-
search.append(key, value.toString());
|
62
|
-
}
|
63
|
-
return search;
|
64
|
-
}
|
65
|
-
function parseRequestQuery(context, options) {
|
66
|
-
const { url } = context, { query, queryArrayFormat } = options;
|
67
|
-
if (url === void 0) return;
|
68
|
-
if (!(url instanceof URL)) throw new Error("The `url` must be an instance of `URL.");
|
69
|
-
if (typeof query != "object" || query === null) return;
|
70
|
-
const queryObject = {};
|
71
|
-
for (const key in query) {
|
72
|
-
const value = query[key];
|
73
|
-
(typeof value == "string" && value.length > 0 || typeof value == "number" && Number.isFinite(value) || typeof value == "boolean" || Array.isArray(value) && value.length > 0 && value.every((v) => typeof v == "string" || typeof v == "number" || typeof v == "boolean")) && (queryObject[key] = value, delete query[key]);
|
74
|
-
}
|
75
|
-
url.search = toSearchParams(queryObject, { format: queryArrayFormat }).toString();
|
76
|
-
}
|
77
37
|
const EXP_REQUEST = /^((?<method>[a-z]+) )?(?<url>[^:]+?:\/{2}[^/]+)?(?<path>\/[^\s?]*)/i, METHODS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete", "head", "options"]);
|
78
38
|
function parseRequestUrl(context, route, options) {
|
79
39
|
const { method, baseUrl } = options, match = EXP_REQUEST.exec(route);
|
@@ -86,9 +46,9 @@ function parseRequestUrl(context, route, options) {
|
|
86
46
|
}
|
87
47
|
function parseRequest(route, options = {}) {
|
88
48
|
const { data, body, query, parameters, headers, method, baseUrl, queryArrayFormat, ...init } = options, context = { init }, dataObject = isObjectLike(data) ? data : void 0;
|
89
|
-
parseRequestUrl(context, route, { baseUrl, method }), parseRequestParameters(context, { parameters: parameters ?? dataObject });
|
49
|
+
parseRequestUrl(context, route, { baseUrl, method }), parseRequestQuery.parseRequestParameters(context, { parameters: parameters ?? dataObject });
|
90
50
|
const requestMethod = context.init?.method?.toLowerCase() ?? "get", requestExpectsBody = ["post", "put", "patch"].includes(requestMethod);
|
91
|
-
return parseRequestQuery(context, { queryArrayFormat, query: requestExpectsBody ? query : query ?? dataObject }), parseRequestBody(context, { body: requestExpectsBody ? body ?? dataObject : void 0 }), parseRequestHeaders(context, { headers }), context;
|
51
|
+
return parseRequestQuery.parseRequestQuery(context, { queryArrayFormat, query: requestExpectsBody ? query : query ?? dataObject }), parseRequestBody(context, { body: requestExpectsBody ? body ?? dataObject : void 0 }), parseRequestHeaders(context, { headers }), context;
|
92
52
|
}
|
93
53
|
async function fetch(route, options = {}) {
|
94
54
|
const { url, init } = parseRequest(route, options);
|
@@ -147,9 +107,6 @@ exports.isObjectLike = isObjectLike;
|
|
147
107
|
exports.parseRequest = parseRequest;
|
148
108
|
exports.parseRequestBody = parseRequestBody;
|
149
109
|
exports.parseRequestHeaders = parseRequestHeaders;
|
150
|
-
exports.parseRequestParameters = parseRequestParameters;
|
151
|
-
exports.parseRequestQuery = parseRequestQuery;
|
152
110
|
exports.parseRequestUrl = parseRequestUrl;
|
153
111
|
exports.toFormData = toFormData;
|
154
|
-
|
155
|
-
//# sourceMappingURL=CfKxYeRr.cjs.map
|
112
|
+
//# sourceMappingURL=Cayg8606.cjs.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"Cayg8606.cjs","sources":["../../utils/isObjectLike.ts","../../utils/isFormDataLike.ts","../../utils/toFormData.ts","../../utils/parseRequestBody.ts","../../utils/parseRequestHeaders.ts","../../utils/parseRequestUrl.ts","../../utils/parseRequest.ts","../../utils/fetch.ts","../../utils/handleResponseStreamJson.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 * 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 { 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: 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 ?? 'get')) 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 context.init.headers = context.init.headers ?? {}\n context.init.headers = { ...context.init.headers, 'Content-Type': 'multipart/form-data' }\n }\n\n // --- If the data is a `ReadableStream`, pass it directly to the body.\n else if (body instanceof ReadableStream) {\n context.init.body = body\n context.init.headers = context.init.headers ?? {}\n context.init.headers = { ...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 context.init.headers = { ...context.init.headers, 'Content-Type': 'application/octet-stream' }\n }\n\n // --- Otherwise, stringify the data and set the content type to JSON.\n else if (isObjectLike(body)) {\n context.init.body = JSON.stringify(body)\n context.init.headers = context.init.headers ?? {}\n context.init.headers = { ...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'\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: 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 context.init.headers = { ...context.init.headers, [key]: String(value) }\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: 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 { parseRequestBody } from './parseRequestBody'\nimport { parseRequestHeaders } from './parseRequestHeaders'\nimport { parseRequestParameters } from './parseRequestParameters'\nimport { parseRequestQuery } from './parseRequestQuery'\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\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 { data, body, query, parameters, headers, method, baseUrl, queryArrayFormat, ...init } = options\n const context: 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\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 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\n}\n","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 { 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","import type { RequestOptions } from './request'\nimport { handleResponseStreamJson } from './handleResponseStreamJson'\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) 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 text content type, 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 // --- If the response is a application/json, parse the JSON and return it.\n if (contentType === '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 application/stream+json, return an iterator that parses the JSON.\n if (contentType === 'application/stream+json')\n return handleResponseStreamJson(response, options)\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":["parseRequestParameters","parseRequestQuery","awaitable"],"mappings":"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"}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { f as fetch, h as handleResponse } from "./
|
1
|
+
import { f as fetch, h as handleResponse } from "./BUeqbyph.js";
|
2
2
|
async function request(route, options = {}) {
|
3
3
|
const response = await fetch(route, options);
|
4
4
|
return await handleResponse(response, options);
|
@@ -6,4 +6,4 @@ async function request(route, options = {}) {
|
|
6
6
|
export {
|
7
7
|
request as r
|
8
8
|
};
|
9
|
-
//# sourceMappingURL=
|
9
|
+
//# sourceMappingURL=DJJsADWD.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"
|
1
|
+
{"version":3,"file":"DJJsADWD.js","sources":["../../utils/request.ts"],"sourcesContent":["import type { ObjectLike } from '@unshared/types'\nimport type { FetchMethod, FetchOptions } from './parseRequest'\nimport { fetch } from './fetch'\nimport { handleResponse } from './handleResponse'\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?: (data: Data) => any\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":";AAkEA,eAAsB,QAAQ,OAAe,UAA0B,IAAsB;AAC3F,QAAM,WAAW,MAAM,MAAM,OAAO,OAAO;AACpC,SAAA,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 { F as FetchMethod,
|
2
|
+
import { F as FetchMethod, R as RequestOptions } from './CO11DuYE.js';
|
3
3
|
import { OpenAPI } from 'openapi-types';
|
4
4
|
|
5
5
|
/** Get the base URL of an OpenAPI specification. */
|
@@ -190,24 +190,19 @@ type OperationById<T, U extends OperationId<T>> = T extends {
|
|
190
190
|
*/
|
191
191
|
declare function resolveOperation<T, U extends OperationId<T>>(document: T, operationId: U): OperationById<T, U>;
|
192
192
|
|
193
|
-
|
194
|
-
type OperationOptions<T, V extends Operation> = T extends {
|
193
|
+
interface OpenAPIV2Like {
|
195
194
|
swagger: string;
|
196
|
-
}
|
195
|
+
}
|
196
|
+
interface OpenAPIV3Like {
|
197
197
|
openapi: string;
|
198
|
-
}
|
198
|
+
}
|
199
|
+
type OpenAPILike = OpenAPIV2Like | OpenAPIV3Like;
|
200
|
+
/** The options to pass to the request. */
|
201
|
+
type OperationOptions<T, V extends Operation> = T extends OpenAPIV2Like ? RequestOptions<never, MaybeLiteral<ServerUrl<T>>, OpenAPIV2.RequestParameters<V>, OpenAPIV2.RequestQuery<V>, OpenAPIV2.RequestBody<V>, OpenAPIV2.RequestHeaders<V>, OpenAPIV2.ResponseBody<V>> : T extends OpenAPIV3Like ? RequestOptions<never, MaybeLiteral<ServerUrl<T>>, OpenAPIV2.RequestParameters<V>, OpenAPIV3.RequestQuery<V> & OpenAPIV3.ServerQuery<T>, OpenAPIV3.RequestBody<V>, OpenAPIV2.RequestHeaders<V>, OpenAPIV3.ResponseBody<V>> : RequestOptions;
|
199
202
|
/** The response data from the operation. */
|
200
|
-
type OperationResult<T, V extends Operation> = T extends
|
201
|
-
swagger: string;
|
202
|
-
} ? OpenAPIV2.ResponseBody<V> : T extends {
|
203
|
-
openapi: string;
|
204
|
-
} ? OpenAPIV3.ResponseBody<V> : unknown;
|
203
|
+
type OperationResult<T, V extends Operation> = T extends OpenAPIV2Like ? OpenAPIV2.ResponseBody<V> : T extends OpenAPIV3Like ? OpenAPIV3.ResponseBody<V> : unknown;
|
205
204
|
/** The `Response` object from the operation. */
|
206
|
-
type OperationResponse<T, V extends Operation> = T extends
|
207
|
-
swagger: string;
|
208
|
-
} ? OpenAPIV2.Response<V> : T extends {
|
209
|
-
openapi: string;
|
210
|
-
} ? OpenAPIV3.Response<V> : globalThis.Response;
|
205
|
+
type OperationResponse<T, V extends Operation> = T extends OpenAPIV2Like ? OpenAPIV2.Response<V> : T extends OpenAPIV3Like ? OpenAPIV3.Response<V> : globalThis.Response;
|
211
206
|
/** Union of all operation route names in the specification. */
|
212
207
|
type OperationRoute<T> = T extends {
|
213
208
|
paths: infer P;
|
@@ -222,8 +217,8 @@ type OperationByRoute<T, U extends OperationRoute<T>> = StringSplit<U, ' '> exte
|
|
222
217
|
path: P;
|
223
218
|
} & O> : never : never : never : never;
|
224
219
|
/** The `ClientRoutes` inferred from the OpenAPI specification. */
|
225
|
-
type
|
220
|
+
type OpenAPIOptionsMap<T> = {
|
226
221
|
[K in OperationRoute<T>]: OperationOptions<T, OperationByRoute<T, K>>;
|
227
222
|
};
|
228
223
|
|
229
|
-
export {
|
224
|
+
export { type OpenAPILike as O, type ServerUrl as S, type OpenAPIOptionsMap as a, type OperationId as b, type OperationById as c, type OperationOptions as d, type OperationResult as e, OpenAPIV3 as f, getServerUrl as g, OpenAPIV2 as h, type Operation as i, type OpenAPIV2Like as j, type OpenAPIV3Like as k, type OperationResponse as l, type OperationRoute as m, type OperationByRoute as n, resolveOperation as r };
|
@@ -0,0 +1,75 @@
|
|
1
|
+
import { p as parseRequestParameters, a as parseRequestQuery } from "./0ZzUT3m_.js";
|
2
|
+
const EXP_CONNECTION_CHANNEL = /^((?<protocol>[a-z]+) )?(?<url>[^:]+?:\/{2}[^/]+)?(?<path>\/[^\s?]*)/i, PROTOCOLS = /* @__PURE__ */ new Set(["ws", "wss"]);
|
3
|
+
function parseConnectUrl(parameters, channel, options) {
|
4
|
+
const { baseUrl, protocol } = options, match = EXP_CONNECTION_CHANNEL.exec(channel);
|
5
|
+
if (!match?.groups) throw new Error("Could not resolve the `RequestInit` object: Invalid route name.");
|
6
|
+
const routeProtocol = protocol ?? match.groups.protocol ?? "ws", routeBaseUrl = baseUrl ?? match.groups.url;
|
7
|
+
if (!routeBaseUrl) throw new Error("Could not resolve the `RequestInit` object: the `baseUrl` is missing.");
|
8
|
+
const protocolLower = routeProtocol.toLowerCase();
|
9
|
+
if (!PROTOCOLS.has(protocolLower)) throw new Error(`Could not resolve the \`RequestInit\` object:, the method \`${routeProtocol}\` is invalid.`);
|
10
|
+
parameters.url = new URL(routeBaseUrl), parameters.url.pathname += parameters.url.pathname.endsWith("/") ? match.groups.path.slice(1) : match.groups.path, parameters.protocol = protocolLower;
|
11
|
+
}
|
12
|
+
function parseConnectOptions(channel, options) {
|
13
|
+
const { baseUrl, protocol, data, parameters = data, query = data } = options, context = { url: new URL("about:blank") };
|
14
|
+
return parseConnectUrl(context, channel, { baseUrl, protocol }), parseRequestParameters(context, { parameters }), parseRequestQuery(context, { query }), context;
|
15
|
+
}
|
16
|
+
class WebSocketChannel {
|
17
|
+
constructor(channel, options) {
|
18
|
+
this.channel = channel, this.options = options;
|
19
|
+
}
|
20
|
+
/** The WebSocket connection to the server. */
|
21
|
+
webSocket;
|
22
|
+
/**
|
23
|
+
* Open a new WebSocket connection to the server. The connection will be opened with the given
|
24
|
+
* URL and protocols. If the connection is already open, the connection will be closed before
|
25
|
+
* opening a new connection. Also add the event listeners that were passed in the options.
|
26
|
+
*/
|
27
|
+
async open() {
|
28
|
+
this.webSocket && await this.close();
|
29
|
+
const { url, protocol } = parseConnectOptions(this.channel, this.options);
|
30
|
+
return this.webSocket = new WebSocket(url, protocol), this.options.onOpen && this.on("open", this.options.onOpen), this.options.onClose && this.on("close", this.options.onClose), this.options.onError && this.on("error", this.options.onError), this.options.onMessage && this.on("message", (message) => this.options.onMessage(message)), this.webSocket.addEventListener("close", (event) => {
|
31
|
+
event.code !== 1e3 && this.options.autoReconnect && (this.options.reconnectLimit && event.wasClean || setTimeout(() => void this.open(), this.options.reconnectDelay ?? 0));
|
32
|
+
}), new Promise((resolve, rejects) => {
|
33
|
+
this.webSocket.addEventListener("open", () => resolve()), this.webSocket.addEventListener("error", () => rejects(new Error("Failed to open the WebSocket connection")));
|
34
|
+
});
|
35
|
+
}
|
36
|
+
/**
|
37
|
+
* Send a payload to the server. The payload will be serialized to JSON before sending.
|
38
|
+
*
|
39
|
+
* @param payload The data to send to the server.
|
40
|
+
*/
|
41
|
+
send(payload) {
|
42
|
+
if (!this.webSocket) throw new Error("WebSocket connection is not open");
|
43
|
+
const json = JSON.stringify(payload);
|
44
|
+
this.webSocket.send(json);
|
45
|
+
}
|
46
|
+
on(event, callback) {
|
47
|
+
if (!this.webSocket) throw new Error("WebSocket connection has not been opened yet");
|
48
|
+
const listener = (event2) => {
|
49
|
+
let data = event2.data;
|
50
|
+
try {
|
51
|
+
data = JSON.parse(data);
|
52
|
+
} catch {
|
53
|
+
}
|
54
|
+
callback(data);
|
55
|
+
};
|
56
|
+
return this.webSocket.addEventListener(event, listener), () => this.webSocket.removeEventListener(event, listener);
|
57
|
+
}
|
58
|
+
/**
|
59
|
+
* Close the WebSocket connection to the server. The connection will not be able to send or receive
|
60
|
+
* messages after it is closed.
|
61
|
+
*/
|
62
|
+
async close() {
|
63
|
+
if (!this.webSocket) throw new Error("WebSocket connection has not been opened yet");
|
64
|
+
this.webSocket.readyState !== WebSocket.CLOSED && this.webSocket.readyState !== WebSocket.CLOSING && (this.webSocket.close(1e3, "Client closed the connection"), await new Promise((resolve) => this.webSocket.addEventListener("close", () => resolve())));
|
65
|
+
}
|
66
|
+
}
|
67
|
+
function connect(route, options) {
|
68
|
+
return new WebSocketChannel(route, options);
|
69
|
+
}
|
70
|
+
export {
|
71
|
+
WebSocketChannel as W,
|
72
|
+
connect as c,
|
73
|
+
parseConnectOptions as p
|
74
|
+
};
|
75
|
+
//# sourceMappingURL=Du56lBvc.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"Du56lBvc.js","sources":["../../websocket/parseConnectOptions.ts","../../websocket/connect.ts"],"sourcesContent":["import type { Loose, ObjectLike, UnionMerge } from '@unshared/types'\nimport { parseRequestParameters } from '../utils/parseRequestParameters'\nimport { parseRequestQuery } from '../utils/parseRequestQuery'\n\n/** Regular expression to match the request method and URL. */\nconst EXP_CONNECTION_CHANNEL = /^((?<protocol>[a-z]+) )?(?<url>[^:]+?:\\/{2}[^/]+)?(?<path>\\/[^\\s?]*)/i\n\n/** Valid WebSocket protocols. */\nconst PROTOCOLS = new Set(['ws', 'wss'])\n\n/** The protocols to use for the connection. */\nexport type ConnectProtocol = 'WS' | 'WSS'\n\n/** Options to pass to the `createChannel` function. */\nexport interface ConnectOptions<\n BaseUrl extends string = string,\n Query extends ObjectLike = ObjectLike,\n Parameters extends ObjectLike = ObjectLike,\n ClientData extends ObjectLike = ObjectLike,\n ServerData extends ObjectLike = ObjectLike,\n> {\n\n /** The protocol to use when connecting to the server. */\n protocol?: Lowercase<ConnectProtocol> | Uppercase<ConnectProtocol>\n\n /** The base URL to connect to. */\n baseUrl?: BaseUrl\n\n /**\n * The path parameters to use when connecting to the server. These parameters will be used to\n * fill in the path parameters of the connection URL.\n *\n * @example { id: 1 }\n */\n parameters?: Parameters\n\n /**\n * The query parameters to use when connecting to the server. These parameters will be used to\n * fill in the query parameters of the connection URL.\n *\n * @example { limit: 10, offset: 0 }\n */\n query?: Loose<Query>\n\n /**\n * The data to send when creating the connection. Namely, the path parameters\n * to use when connecting to the server.\n *\n * @example\n *\n * // Create a new connection to `http://localhost:8080/users/1`.\n * connect('GET /users/:id', {\n * data: { id: 1 },\n * baseUrl: 'http://localhost:8080'\n * })\n */\n data?: UnionMerge<Loose<Query> | Parameters>\n\n /**\n * The payload to send when creating the connection. Namely, the initial message\n * to send to the server when the connection is established.\n */\n initialPayload?: Loose<ClientData>\n\n /**\n * Automatically open the connection when it is created. If `true`, the connection\n * will automatically open when it is created. If `false`, the connection will not\n * open when it is created.\n *\n * @default false\n */\n autoOpen?: boolean\n\n /**\n * Weather to reconnect the connection when it is closed unexpectedly. If `true`,\n * the connection will automatically reconnect when it is closed. If `false`, the\n * connection will not reconnect when it is closed.\n *\n * @default false\n */\n autoReconnect?: boolean\n\n /**\n * The delay in milliseconds to wait before reconnecting the connection. This delay\n * will be used to wait before reconnecting the connection after it is closed.\n *\n * @default 0\n */\n reconnectDelay?: number\n\n /**\n * The maximum number of times to reconnect the connection before giving up. This\n * number will be used to determine when to stop trying to reconnect the connection.\n *\n * @default 3\n */\n reconnectLimit?: number\n\n /**\n * The function to call when the connection is opened. This function will be called\n * when the connection is successfully opened or reconnected.\n */\n onOpen?: (event: Event) => void\n\n /**\n * The function to call when the connection is closed with an error. This function will\n * be called when the connection is closed unexpectedly with an error.\n */\n onError?: (event: Event) => void\n\n /**\n * The function to call when the connection is closed. This function will be called\n * when the connection is closed unexpectedly or when the connection is closed manually.\n */\n onClose?: (event: CloseEvent) => void\n\n /**\n * The function to call when a message is received from the server. This function will\n * be called when a message is received from the server.\n */\n onMessage?: (data: ServerData) => void\n}\n\nexport interface WebSocketParameters {\n url: URL\n protocol?: 'ws' | 'wss'\n}\n\nfunction parseConnectUrl(parameters: WebSocketParameters, channel: string, options: ConnectOptions): void {\n const { baseUrl, protocol } = options\n\n // --- Extract the path, method, and base URL from the route name.\n const match = EXP_CONNECTION_CHANNEL.exec(channel)\n if (!match?.groups) throw new Error('Could not resolve the `RequestInit` object: Invalid route name.')\n const routeProtocol = protocol ?? match.groups.protocol ?? 'ws'\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 protocolLower = routeProtocol.toLowerCase()\n const protocolIsValid = PROTOCOLS.has(protocolLower)\n if (!protocolIsValid) throw new Error(`Could not resolve the \\`RequestInit\\` object:, the method \\`${routeProtocol}\\` is invalid.`)\n\n // --- Create the url and apply the method.\n parameters.url = new URL(routeBaseUrl)\n parameters.url.pathname += parameters.url.pathname.endsWith('/') ? match.groups.path.slice(1) : match.groups.path\n parameters.protocol = protocolLower as 'ws' | 'wss'\n}\n\nexport function parseConnectOptions(channel: string, options: ConnectOptions): WebSocketParameters {\n const { baseUrl, protocol, data, parameters = data, query = data } = options\n const context: WebSocketParameters = { url: new URL('about:blank') }\n parseConnectUrl(context, channel, { baseUrl, protocol })\n parseRequestParameters(context, { parameters })\n parseRequestQuery(context, { query })\n return context\n}\n","import type { ObjectLike } from '@unshared/types'\nimport type { ConnectOptions } from './parseConnectOptions'\nimport { parseConnectOptions } from './parseConnectOptions'\n\ntype RemoveListener = () => void\n\ntype ClientData<T extends ConnectOptions> =\n T extends ConnectOptions<any, any, any, infer R extends ObjectLike, any> ? R : ObjectLike\n\ntype ServerData<T extends ConnectOptions> =\n T extends ConnectOptions<any, any, any, any, infer R extends ObjectLike> ? R : ObjectLike\n\nexport class WebSocketChannel<T extends ConnectOptions = ConnectOptions> {\n constructor(public channel: string, public options: T) {}\n\n /** The WebSocket connection to the server. */\n public webSocket: WebSocket | undefined\n\n /**\n * Open a new WebSocket connection to the server. The connection will be opened with the given\n * URL and protocols. If the connection is already open, the connection will be closed before\n * opening a new connection. Also add the event listeners that were passed in the options.\n */\n async open() {\n if (this.webSocket) await this.close()\n const { url, protocol } = parseConnectOptions(this.channel, this.options)\n this.webSocket = new WebSocket(url, protocol)\n if (this.options.onOpen) this.on('open', this.options.onOpen)\n if (this.options.onClose) this.on('close', this.options.onClose)\n if (this.options.onError) this.on('error', this.options.onError)\n if (this.options.onMessage) this.on('message', message => this.options.onMessage!(message))\n\n // --- Reconnect to the server if the connection is closed unexpectedly.\n this.webSocket.addEventListener('close', (event) => {\n if (event.code === 1000) return\n if (!this.options.autoReconnect) return\n if (this.options.reconnectLimit && event.wasClean) return\n setTimeout(() => void this.open(), this.options.reconnectDelay ?? 0)\n })\n\n // --- Return a promise that resolves when the connection is opened.\n return new Promise<void>((resolve, rejects) => {\n this.webSocket!.addEventListener('open', () => resolve())\n this.webSocket!.addEventListener('error', () => rejects(new Error('Failed to open the WebSocket connection')))\n })\n }\n\n /**\n * Send a payload to the server. The payload will be serialized to JSON before sending.\n *\n * @param payload The data to send to the server.\n */\n send(payload: ClientData<T>) {\n if (!this.webSocket) throw new Error('WebSocket connection is not open')\n const json = JSON.stringify(payload)\n this.webSocket.send(json)\n }\n\n /**\n * Listen for events from the server. The event will be deserialized from JSON before calling the callback.\n *\n * @param event The event to listen for.\n * @param callback The callback to call when the event is received.\n * @returns A function to remove the event listener.\n */\n on(event: 'message', callback: (data: ServerData<T>) => void): RemoveListener\n on(event: 'close', callback: (event: CloseEvent) => void): RemoveListener\n on(event: 'error', callback: (event: Event) => void): RemoveListener\n on(event: 'open', callback: (event: Event) => void): RemoveListener\n on(event: string, callback: (data: any) => void) {\n if (!this.webSocket) throw new Error('WebSocket connection has not been opened yet')\n\n const listener = (event: CloseEvent | Event | MessageEvent<any>) => {\n // @ts-expect-error: `data` exists on the event.\n let data = event.data as unknown\n try { data = JSON.parse(data as string) }\n catch { /* Ignore the error. */ }\n callback(data as T)\n }\n\n this.webSocket.addEventListener(event, listener)\n return () => this.webSocket!.removeEventListener(event, listener)\n }\n\n /**\n * Close the WebSocket connection to the server. The connection will not be able to send or receive\n * messages after it is closed.\n */\n async close() {\n if (!this.webSocket) throw new Error('WebSocket connection has not been opened yet')\n if (this.webSocket.readyState === WebSocket.CLOSED) return\n if (this.webSocket.readyState === WebSocket.CLOSING) return\n this.webSocket.close(1000, 'Client closed the connection')\n await new Promise<void>(resolve => this.webSocket!.addEventListener('close', () => resolve()))\n }\n}\n\n/**\n * Create a new WebSocket connection to the server with the given path. The connection will\n * automatically reconnect if the connection is closed unexpectedly.\n *\n * @param route The name of the route to connect to.\n * @param options The options to pass to the connection.\n * @returns The WebSocket connection.\n */\nexport function connect(route: string, options: ConnectOptions): WebSocketChannel {\n return new WebSocketChannel(route, options)\n}\n"],"names":["event"],"mappings":"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"}
|
@@ -1,8 +1,8 @@
|
|
1
1
|
"use strict";
|
2
|
-
var handleResponse = require("./
|
2
|
+
var handleResponse = require("./Cayg8606.cjs");
|
3
3
|
async function request(route, options = {}) {
|
4
4
|
const response = await handleResponse.fetch(route, options);
|
5
5
|
return await handleResponse.handleResponse(response, options);
|
6
6
|
}
|
7
7
|
exports.request = request;
|
8
|
-
//# sourceMappingURL=
|
8
|
+
//# sourceMappingURL=Du_W5H6e.cjs.map
|