@unshared/client 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/HttpHeaders.cjs +4 -0
  2. package/dist/HttpHeaders.cjs.map +1 -0
  3. package/dist/{chunks/8BFCFxqa.d.ts → HttpHeaders.d.ts} +1 -1
  4. package/dist/HttpHeaders.js +5 -0
  5. package/dist/HttpHeaders.js.map +1 -0
  6. package/dist/HttpMethods.cjs +4 -0
  7. package/dist/HttpMethods.cjs.map +1 -0
  8. package/dist/{chunks/DZp6zyqV.d.ts → HttpMethods.d.ts} +1 -98
  9. package/dist/HttpMethods.js +5 -0
  10. package/dist/HttpMethods.js.map +1 -0
  11. package/dist/HttpStatusCodes.cjs +4 -0
  12. package/dist/HttpStatusCodes.cjs.map +1 -0
  13. package/dist/HttpStatusCodes.d.ts +615 -0
  14. package/dist/HttpStatusCodes.js +5 -0
  15. package/dist/HttpStatusCodes.js.map +1 -0
  16. package/dist/chunks/B92aAMq0.d.ts +144 -0
  17. package/dist/chunks/{D-WqCFul.js → Biic1J5b.js} +11 -9
  18. package/dist/chunks/Biic1J5b.js.map +1 -0
  19. package/dist/chunks/CfKxYeRr.cjs +155 -0
  20. package/dist/chunks/CfKxYeRr.cjs.map +1 -0
  21. package/dist/chunks/CjU0376e.d.ts +229 -0
  22. package/dist/chunks/{xRZPkxch.cjs → CtW2aMuA.cjs} +11 -9
  23. package/dist/chunks/CtW2aMuA.cjs.map +1 -0
  24. package/dist/chunks/D51s1VII.js +156 -0
  25. package/dist/chunks/D51s1VII.js.map +1 -0
  26. package/dist/chunks/iA98-4f5.cjs +8 -0
  27. package/dist/chunks/iA98-4f5.cjs.map +1 -0
  28. package/dist/chunks/lMH6B5BV.js +9 -0
  29. package/dist/chunks/lMH6B5BV.js.map +1 -0
  30. package/dist/createClient.cjs +81 -18
  31. package/dist/createClient.cjs.map +1 -1
  32. package/dist/createClient.d.ts +93 -29
  33. package/dist/createClient.js +83 -20
  34. package/dist/createClient.js.map +1 -1
  35. package/dist/createService.cjs +17 -0
  36. package/dist/createService.cjs.map +1 -0
  37. package/dist/createService.d.ts +38 -0
  38. package/dist/createService.js +19 -0
  39. package/dist/createService.js.map +1 -0
  40. package/dist/index.cjs +22 -20
  41. package/dist/index.cjs.map +1 -1
  42. package/dist/index.d.ts +10 -624
  43. package/dist/index.js +24 -19
  44. package/dist/index.js.map +1 -1
  45. package/dist/openapi.cjs +3 -15
  46. package/dist/openapi.cjs.map +1 -1
  47. package/dist/openapi.d.ts +7 -35
  48. package/dist/openapi.js +3 -15
  49. package/dist/openapi.js.map +1 -1
  50. package/dist/utils.cjs +13 -11
  51. package/dist/utils.cjs.map +1 -1
  52. package/dist/utils.d.ts +57 -27
  53. package/dist/utils.js +11 -9
  54. package/package.json +23 -8
  55. package/dist/chunks/B2OrSen1.d.ts +0 -185
  56. package/dist/chunks/B5hc73Po.js +0 -96
  57. package/dist/chunks/B5hc73Po.js.map +0 -1
  58. package/dist/chunks/CKfJvIQ8.js +0 -50
  59. package/dist/chunks/CKfJvIQ8.js.map +0 -1
  60. package/dist/chunks/Cx8m1YzL.cjs +0 -49
  61. package/dist/chunks/Cx8m1YzL.cjs.map +0 -1
  62. package/dist/chunks/D-WqCFul.js.map +0 -1
  63. package/dist/chunks/D8Tsm7xC.cjs +0 -95
  64. package/dist/chunks/D8Tsm7xC.cjs.map +0 -1
  65. package/dist/chunks/r8pYO6Hx.d.ts +0 -38
  66. package/dist/chunks/xRZPkxch.cjs.map +0 -1
  67. package/dist/fetch.cjs +0 -8
  68. package/dist/fetch.cjs.map +0 -1
  69. package/dist/fetch.d.ts +0 -16
  70. package/dist/fetch.js +0 -9
  71. package/dist/fetch.js.map +0 -1
@@ -1,24 +1,87 @@
1
1
  "use strict";
2
- var fetch = require("./fetch.cjs"), getOperationById = require("./chunks/xRZPkxch.cjs"), handleResponse = require("./chunks/Cx8m1YzL.cjs");
3
- require("./chunks/D8Tsm7xC.cjs");
2
+ var attempt = require("@unshared/functions/attempt"), handleResponse = require("./chunks/CfKxYeRr.cjs"), request = require("./chunks/iA98-4f5.cjs");
4
3
  require("@unshared/functions/awaitable");
5
- function createClient(documentOrUrl, initialOptions = {}) {
6
- const specifications = typeof documentOrUrl == "string" ? void 0 : documentOrUrl;
7
- typeof documentOrUrl == "string" && (initialOptions.baseUrl = documentOrUrl);
8
- async function fetchByOperationId(operationId, options) {
9
- if (!specifications) throw new Error("No OpenAPI specification provided.");
10
- const operation = getOperationById.getOperationById(specifications, operationId);
11
- if (!operation) throw new Error(`Operation ID "${operationId}" not found.`);
12
- const { method, path, responses = {} } = operation, fetchOptions = { method, baseUrl: getOperationById.getBaseUrl(specifications), ...initialOptions, ...options }, response = await fetch.fetch(path, fetchOptions);
13
- if (response.ok) return handleResponse.handleResponse(response, fetchOptions);
14
- const status = response.status.toString();
15
- throw status in responses && typeof responses[status] == "object" && responses[status] !== null && "description" in responses[status] && typeof responses[status].description == "string" ? new Error(responses[status].description) : new Error(response.statusText);
4
+ class Client {
5
+ /**
6
+ * Create a new client for the application.
7
+ *
8
+ * @param initialOptions The options to pass to the client.
9
+ * @example new Client({ baseUrl: 'https://api.example.com' })
10
+ */
11
+ constructor(initialOptions = {}) {
12
+ this.initialOptions = initialOptions;
16
13
  }
17
- return new Proxy({}, {
18
- get(_, property) {
19
- return property === "fetch" ? (route, options) => fetch.fetch(route, { ...initialOptions, ...options }) : (options) => fetchByOperationId(property, options);
20
- }
21
- });
14
+ /**
15
+ * Fetch a route from the API and return the `Response` object. If the client was instantiated with an
16
+ * application, the route name will be inferred from the application routes. Otherwise, you
17
+ * can pass the route name as a string.
18
+ *
19
+ * @param route The name of the route to fetch.
20
+ * @param options The options to pass to the request.
21
+ * @returns The response from the server.
22
+ */
23
+ async fetch(route, options) {
24
+ return await handleResponse.fetch(route, { ...this.initialOptions, ...options });
25
+ }
26
+ /**
27
+ * Fetch a route from the API and return the data. If the client was instantiated with an
28
+ * application, the route name will be inferred from the application routes. Otherwise, you
29
+ * can pass the route name as a string.
30
+ *
31
+ * @param route The name of the route to fetch.
32
+ * @param options The options to pass to the request.
33
+ * @returns The data from the API.
34
+ * @example
35
+ * // Declare the application type.
36
+ * type App = Application<[ModuleProduct]>
37
+ *
38
+ * // Create a type-safe client for the application.
39
+ * const request = createClient<App>()
40
+ *
41
+ * // Fetch the data from the API.
42
+ * const data = request('GET /api/product/:id', { data: { id: '1' } })
43
+ */
44
+ async request(route, options) {
45
+ return await request.request(route, { ...this.initialOptions, ...options });
46
+ }
47
+ /**
48
+ * Attempt to fetch a route from the API and return the data. If the client was instantiated with an
49
+ * application, the route name will be inferred from the application routes. Otherwise, you
50
+ * can pass the route name as a string.
51
+ *
52
+ * @param name The name of the route to fetch.
53
+ * @param options The options to pass to the request.
54
+ * @returns A result object with either the data or an error.
55
+ * @example
56
+ * // Declare the application type.
57
+ * type App = Application<[ModuleProduct]>
58
+ *
59
+ * // Create a type-safe client for the application.
60
+ * const request = createClient<App>()
61
+ *
62
+ * // Fetch the data from the API.
63
+ * const { data, error } = requestAttempt('GET /api/product/:id', { data: { id: '1' } })
64
+ * if (error) console.error(error)
65
+ * else console.log(data)
66
+ */
67
+ async requestAttempt(name, options) {
68
+ return await attempt.attempt(() => this.request(name, options));
69
+ }
70
+ /**
71
+ * Create a new WebSocket connection to the server with the given path. The connection will
72
+ * automatically reconnect if the connection is closed unexpectedly.
73
+ *
74
+ * @param name The path to connect to.
75
+ * @param options The options to pass to the connection.
76
+ * @returns The WebSocket connection.
77
+ */
78
+ // public connect<P extends RouteName<T>>(name: P, options: Partial<ConnectOptions<T, P>> = {}): WebSocketConnection<T, P> {
79
+ // return connect<T, P>(name, { baseUrl: this.baseUrl, ...options })
80
+ // }
81
+ }
82
+ function createClient(options) {
83
+ return new Client(options);
22
84
  }
85
+ exports.Client = Client;
23
86
  exports.createClient = createClient;
24
87
  //# sourceMappingURL=createClient.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"createClient.cjs","sources":["../createClient.ts"],"sourcesContent":["import type { MaybeLiteral, Override, Pretty } from '@unshared/types'\nimport type { OpenAPI, OpenAPIV2 as V2, OpenAPIV3 as V3, OpenAPIV3_1 as V3_1 } from 'openapi-types'\nimport type { OpenAPIV2, OpenAPIV3 } from './openapi/index'\nimport type { RequestHooks } from './utils/handleResponse'\nimport type { RequestMethod, RequestOptions } from './utils/parseRequest'\nimport { fetch } from './fetch'\nimport { getBaseUrl } from './openapi/getBaseUrl'\nimport { getOperationById } from './openapi/getOperationById'\nimport { handleResponse } from './utils/handleResponse'\n\ntype ClientBaseUrl<T> =\n MaybeLiteral<\n T extends V2.Document ? OpenAPIV2.ServerUrl<T>\n : T extends V3.Document ? OpenAPIV3.ServerUrl<T>\n : T extends V3_1.Document ? OpenAPIV3.ServerUrl<T>\n : string\n >\n\ntype ClientFetch<T> =\n T extends V2.Document ? <P extends OpenAPIV2.Route<T>>(name: P, options: OpenAPIV2.RequestInit<T, OpenAPIV2.OperationByRoute<T, P>>) => Promise<OpenAPIV2.Response<OpenAPIV2.OperationByRoute<T, P>>>\n : T extends V3.Document ? <P extends OpenAPIV2.Route<T>>(name: P, options: OpenAPIV3.RequestInit<T, OpenAPIV2.OperationByRoute<T, P>>) => Promise<OpenAPIV3.Response<OpenAPIV2.OperationByRoute<T, P>>>\n : T extends V3_1.Document ? <P extends OpenAPIV2.Route<T>>(name: P, options: OpenAPIV3.RequestInit<T, OpenAPIV2.OperationByRoute<T, P>>) => Promise<OpenAPIV3.Response<OpenAPIV2.OperationByRoute<T, P>>>\n : typeof globalThis.fetch\n\ntype ClientFetchOperation<T, U extends OpenAPIV2.OperationId<T>> =\n T extends V2.Document ? (options: OpenAPIV2.RequestInit<T, OpenAPIV2.OperationById<T, U>>) => Promise<OpenAPIV2.ResponseBody<OpenAPIV2.OperationById<T, U>>>\n : T extends V3.Document ? (options: OpenAPIV3.RequestInit<T, OpenAPIV2.OperationById<T, U>>) => Promise<OpenAPIV3.ResponseBody<OpenAPIV2.OperationById<T, U>>>\n : T extends V3_1.Document ? (options: OpenAPIV3.RequestInit<T, OpenAPIV2.OperationById<T, U>>) => Promise<OpenAPIV3.ResponseBody<OpenAPIV2.OperationById<T, U>>>\n : (options: RequestOptions) => Promise<Response>\n\nexport type Client<T = OpenAPI.Document> =\n Pretty<\n & { [K in OpenAPIV2.OperationId<T>]: ClientFetchOperation<T, K> }\n & { fetch: ClientFetch<T> }\n >\n\nexport type ClientOptions<T = any> = Override<RequestHooks & RequestOptions, {\n baseUrl?: ClientBaseUrl<T>\n\n /**\n * The headers to include in every request made by the client.\n *\n * @example { 'Authorization': 'Bearer ...' }\n */\n headers?: T extends V3.Document\n ? OpenAPIV3.ServerHeaders<T>\n : never\n}>\n\n/**\n * Create a new client instance for the given OpenAPI specification.\n *\n * @param document The OpenAPI specification document.\n * @param initialOptions The initial options to use for every request.\n * @returns The client instance.\n * @example\n * const client = createClient(document)\n * await client.fetch({ ... })\n */\n// @ts-expect-error: `ClientOptions` is not assignable to `ClientOptions<T>`.\nexport function createClient<T extends OpenAPI.Document>(document: Readonly<T>, initialOptions?: ClientOptions<T>): Client<T>\nexport function createClient<T extends OpenAPI.Document>(url: ClientBaseUrl<T>, initialOptions?: ClientOptions<T>): Client<T>\nexport function createClient(documentOrUrl: Readonly<OpenAPI.Document> | string, initialOptions: ClientOptions = {}): Client {\n const specifications = typeof documentOrUrl === 'string' ? undefined : documentOrUrl\n if (typeof documentOrUrl === 'string') initialOptions.baseUrl = documentOrUrl\n\n async function fetchByOperationId(operationId: string, options: ClientOptions<any>) {\n if (!specifications) throw new Error('No OpenAPI specification provided.')\n const operation = getOperationById(specifications, operationId) as { method: RequestMethod; path: string } & OpenAPI.Operation\n if (!operation) throw new Error(`Operation ID \"${operationId}\" not found.`)\n const { method, path, responses = {} } = operation\n const fetchOptions = { method, baseUrl: getBaseUrl(specifications), ...initialOptions, ...options }\n const response = await fetch(path, fetchOptions)\n\n // --- Return the JSON response if successful.\n if (response.ok) return handleResponse(response, fetchOptions)\n\n // --- Throw an error if the response was not successful.\n const status = response.status.toString()\n if (status in responses\n && typeof responses[status] === 'object'\n && responses[status] !== null\n && 'description' in responses[status]\n && typeof responses[status].description === 'string')\n throw new Error(responses[status].description)\n\n // --- Throw a generic error if the response was not successful.\n throw new Error(response.statusText)\n }\n\n return new Proxy({}, {\n get(_, property: string) {\n if (property === 'fetch') return (route: string, options: RequestOptions) => fetch(route, ({ ...initialOptions, ...options }))\n return (options: Record<string, unknown>) => fetchByOperationId(property, options)\n },\n }) as unknown as Client\n}\n"],"names":["getOperationById","getBaseUrl","fetch","handleResponse"],"mappings":";;;;AA8DO,SAAS,aAAa,eAAoD,iBAAgC,IAAY;AAC3H,QAAM,iBAAiB,OAAO,iBAAkB,WAAW,SAAY;AACnE,SAAO,iBAAkB,aAAU,eAAe,UAAU;AAEjD,iBAAA,mBAAmB,aAAqB,SAA6B;AAClF,QAAI,CAAC,eAAsB,OAAA,IAAI,MAAM,oCAAoC;AACnE,UAAA,YAAYA,iBAAAA,iBAAiB,gBAAgB,WAAW;AAC9D,QAAI,CAAC,UAAW,OAAM,IAAI,MAAM,iBAAiB,WAAW,cAAc;AACpE,UAAA,EAAE,QAAQ,MAAM,YAAY,CAAA,EAAO,IAAA,WACnC,eAAe,EAAE,QAAQ,SAASC,4BAAW,cAAc,GAAG,GAAG,gBAAgB,GAAG,QAAA,GACpF,WAAW,MAAMC,MAAAA,MAAM,MAAM,YAAY;AAG/C,QAAI,SAAS,GAAW,QAAAC,eAAAA,eAAe,UAAU,YAAY;AAGvD,UAAA,SAAS,SAAS,OAAO,SAAS;AACxC,UAAI,UAAU,aACT,OAAO,UAAU,MAAM,KAAM,YAC7B,UAAU,MAAM,MAAM,QACtB,iBAAiB,UAAU,MAAM,KACjC,OAAO,UAAU,MAAM,EAAE,eAAgB,WACtC,IAAI,MAAM,UAAU,MAAM,EAAE,WAAW,IAGzC,IAAI,MAAM,SAAS,UAAU;AAAA,EAAA;AAG9B,SAAA,IAAI,MAAM,IAAI;AAAA,IACnB,IAAI,GAAG,UAAkB;AACvB,aAAI,aAAa,UAAgB,CAAC,OAAe,YAA4BD,MAAA,MAAM,OAAQ,EAAE,GAAG,gBAAgB,GAAG,SAAU,IACtH,CAAC,YAAqC,mBAAmB,UAAU,OAAO;AAAA,IAAA;AAAA,EACnF,CACD;AACH;;"}
1
+ {"version":3,"file":"createClient.cjs","sources":["../createClient.ts"],"sourcesContent":["import type { Result } from '@unshared/functions/attempt'\nimport type { ObjectLike } from '@unshared/types'\nimport type { ServiceOptions } from './createService'\nimport type { OpenAPIRoutes } from './openapi'\nimport type { RequestOptions } from './utils/request'\nimport { attempt } from '@unshared/functions/attempt'\nimport { fetch } from './utils/fetch'\nimport { request } from './utils/request'\n\n/** Define the routes that can be fetched from the API and their related options. */\nexport type ClientRoutes = Record<string, RequestOptions>\n\n/** The route name that can be fetched from the API. */\ntype Route<T extends ClientRoutes> =\n T extends Record<infer P extends string, RequestOptions> ? P : string\n\n/** The options to pass to the request based on the route name. */\ntype Options<T extends ClientRoutes, P extends keyof T> =\n T extends Record<P, infer R> ? R : RequestOptions\n\n/** The data returned from the API based on the route name. */\ntype Data<T extends ClientRoutes, P extends keyof T> =\n Options<T, P> extends RequestOptions<any, any, any, any, any, any, infer R extends ObjectLike, any>\n ? R\n : unknown\n\nexport class Client<T extends ClientRoutes = ClientRoutes> {\n\n /**\n * Create a new client for the application.\n *\n * @param initialOptions The options to pass to the client.\n * @example new Client({ baseUrl: 'https://api.example.com' })\n */\n constructor(private initialOptions: RequestOptions = {}) {}\n\n /**\n * Fetch a route from the API and return the `Response` object. 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 response from the server.\n */\n public async fetch<P extends Route<T>>(route: P, options?: Options<T, P>): Promise<Response> {\n return await fetch(route, { ...this.initialOptions, ...options })\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 */\n public async request<P extends Route<T>>(route: P, options?: Options<T, P>): Promise<Data<T, P>> {\n return await request(route, { ...this.initialOptions, ...options }) as Data<T, P>\n }\n\n /**\n * Attempt to 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 name The name of the route to fetch.\n * @param options The options to pass to the request.\n * @returns A result object with either the data or an error.\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, error } = requestAttempt('GET /api/product/:id', { data: { id: '1' } })\n * if (error) console.error(error)\n * else console.log(data)\n */\n public async requestAttempt<P extends Route<T>>(name: P, options?: Options<T, P>): Promise<Result<Data<T, P>>> {\n return await attempt(() => this.request<P>(name, options))\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 name The path to connect to.\n * @param options The options to pass to the connection.\n * @returns The WebSocket connection.\n */\n // public connect<P extends RouteName<T>>(name: P, options: Partial<ConnectOptions<T, P>> = {}): WebSocketConnection<T, P> {\n // return connect<T, P>(name, { baseUrl: this.baseUrl, ...options })\n // }\n}\n\n/**\n * Create a new type-safe client for the application. The client can be used to fetch data from\n * the API and connect to the server using WebSockets with the given path.\n *\n * @param options The options to pass to the client.\n * @returns The client object with the request method.\n * @example\n * // Create a type-safe client for the application.\n * const client = createClient<[ModuleUser]>()\n *\n * // Fetch the data from the API.\n * const data = await client.request('GET /api/user/:id', { id: '1' })\n *\n * // Use the data from the API.\n * console.log(data) // { id: '1', name: 'John Doe' }\n */\nexport function createClient<T extends ClientRoutes>(options?: RequestOptions): Client<T>\nexport function createClient<T extends { swagger: string }>(options?: ServiceOptions<T>): Client<OpenAPIRoutes<T>>\nexport function createClient<T extends { openapi: string }>(options?: ServiceOptions<T>): Client<OpenAPIRoutes<T>>\nexport function createClient(options?: RequestOptions): Client {\n return new Client(options)\n}\n"],"names":["fetch","request","attempt"],"mappings":";;;AA0BO,MAAM,OAA8C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQzD,YAAoB,iBAAiC,IAAI;AAArC,SAAA,iBAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWpB,MAAa,MAA0B,OAAU,SAA4C;AACpF,WAAA,MAAMA,qBAAM,OAAO,EAAE,GAAG,KAAK,gBAAgB,GAAG,SAAS;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBlE,MAAa,QAA4B,OAAU,SAA8C;AACxF,WAAA,MAAMC,gBAAQ,OAAO,EAAE,GAAG,KAAK,gBAAgB,GAAG,SAAS;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuBpE,MAAa,eAAmC,MAAS,SAAsD;AAC7G,WAAO,MAAMC,QAAQ,QAAA,MAAM,KAAK,QAAW,MAAM,OAAO,CAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAc7D;AAqBO,SAAS,aAAa,SAAkC;AACtD,SAAA,IAAI,OAAO,OAAO;AAC3B;;;"}
@@ -1,38 +1,102 @@
1
- import { Pretty, Override, MaybeLiteral } from '@unshared/types';
2
- import { OpenAPI, OpenAPIV3, OpenAPIV2 as OpenAPIV2$1, OpenAPIV3_1 } from 'openapi-types';
3
- import { O as OpenAPIV2, a as OpenAPIV3$1 } from './chunks/B2OrSen1.js';
4
- import { R as RequestHooks } from './chunks/r8pYO6Hx.js';
5
- import { c as RequestOptions } from './chunks/DZp6zyqV.js';
6
- import './chunks/8BFCFxqa.js';
1
+ import { Result } from '@unshared/functions/attempt';
2
+ import { ObjectLike } from '@unshared/types';
3
+ import { ServiceOptions } from './createService.js';
4
+ import { k as OpenAPIRoutes } from './chunks/CjU0376e.js';
5
+ import { c as RequestOptions } from './chunks/B92aAMq0.js';
6
+ import 'openapi-types';
7
+ import './HttpHeaders.js';
8
+ import './HttpMethods.js';
7
9
 
8
- type ClientBaseUrl<T> = MaybeLiteral<T extends OpenAPIV2$1.Document ? OpenAPIV2.ServerUrl<T> : T extends OpenAPIV3.Document ? OpenAPIV3$1.ServerUrl<T> : T extends OpenAPIV3_1.Document ? OpenAPIV3$1.ServerUrl<T> : string>;
9
- type ClientFetch<T> = T extends OpenAPIV2$1.Document ? <P extends OpenAPIV2.Route<T>>(name: P, options: OpenAPIV2.RequestInit<T, OpenAPIV2.OperationByRoute<T, P>>) => Promise<OpenAPIV2.Response<OpenAPIV2.OperationByRoute<T, P>>> : T extends OpenAPIV3.Document ? <P extends OpenAPIV2.Route<T>>(name: P, options: OpenAPIV3$1.RequestInit<T, OpenAPIV2.OperationByRoute<T, P>>) => Promise<OpenAPIV3$1.Response<OpenAPIV2.OperationByRoute<T, P>>> : T extends OpenAPIV3_1.Document ? <P extends OpenAPIV2.Route<T>>(name: P, options: OpenAPIV3$1.RequestInit<T, OpenAPIV2.OperationByRoute<T, P>>) => Promise<OpenAPIV3$1.Response<OpenAPIV2.OperationByRoute<T, P>>> : typeof globalThis.fetch;
10
- type ClientFetchOperation<T, U extends OpenAPIV2.OperationId<T>> = T extends OpenAPIV2$1.Document ? (options: OpenAPIV2.RequestInit<T, OpenAPIV2.OperationById<T, U>>) => Promise<OpenAPIV2.ResponseBody<OpenAPIV2.OperationById<T, U>>> : T extends OpenAPIV3.Document ? (options: OpenAPIV3$1.RequestInit<T, OpenAPIV2.OperationById<T, U>>) => Promise<OpenAPIV3$1.ResponseBody<OpenAPIV2.OperationById<T, U>>> : T extends OpenAPIV3_1.Document ? (options: OpenAPIV3$1.RequestInit<T, OpenAPIV2.OperationById<T, U>>) => Promise<OpenAPIV3$1.ResponseBody<OpenAPIV2.OperationById<T, U>>> : (options: RequestOptions) => Promise<Response>;
11
- type Client<T = OpenAPI.Document> = Pretty<{
12
- [K in OpenAPIV2.OperationId<T>]: ClientFetchOperation<T, K>;
13
- } & {
14
- fetch: ClientFetch<T>;
15
- }>;
16
- type ClientOptions<T = any> = Override<RequestHooks & RequestOptions, {
17
- baseUrl?: ClientBaseUrl<T>;
10
+ /** Define the routes that can be fetched from the API and their related options. */
11
+ type ClientRoutes = Record<string, RequestOptions>;
12
+ /** The route name that can be fetched from the API. */
13
+ type Route<T extends ClientRoutes> = T extends Record<infer P extends string, RequestOptions> ? P : string;
14
+ /** The options to pass to the request based on the route name. */
15
+ type Options<T extends ClientRoutes, P extends keyof T> = T extends Record<P, infer R> ? R : RequestOptions;
16
+ /** The data returned from the API based on the route name. */
17
+ type Data<T extends ClientRoutes, P extends keyof T> = Options<T, P> extends RequestOptions<any, any, any, any, any, any, infer R extends ObjectLike, any> ? R : unknown;
18
+ declare class Client<T extends ClientRoutes = ClientRoutes> {
19
+ private initialOptions;
18
20
  /**
19
- * The headers to include in every request made by the client.
21
+ * Create a new client for the application.
20
22
  *
21
- * @example { 'Authorization': 'Bearer ...' }
23
+ * @param initialOptions The options to pass to the client.
24
+ * @example new Client({ baseUrl: 'https://api.example.com' })
22
25
  */
23
- headers?: T extends OpenAPIV3.Document ? OpenAPIV3$1.ServerHeaders<T> : never;
24
- }>;
26
+ constructor(initialOptions?: RequestOptions);
27
+ /**
28
+ * Fetch a route from the API and return the `Response` object. If the client was instantiated with an
29
+ * application, the route name will be inferred from the application routes. Otherwise, you
30
+ * can pass the route name as a string.
31
+ *
32
+ * @param route The name of the route to fetch.
33
+ * @param options The options to pass to the request.
34
+ * @returns The response from the server.
35
+ */
36
+ fetch<P extends Route<T>>(route: P, options?: Options<T, P>): Promise<Response>;
37
+ /**
38
+ * Fetch a route from the API and return the data. If the client was instantiated with an
39
+ * application, the route name will be inferred from the application routes. Otherwise, you
40
+ * can pass the route name as a string.
41
+ *
42
+ * @param route The name of the route to fetch.
43
+ * @param options The options to pass to the request.
44
+ * @returns The data from the API.
45
+ * @example
46
+ * // Declare the application type.
47
+ * type App = Application<[ModuleProduct]>
48
+ *
49
+ * // Create a type-safe client for the application.
50
+ * const request = createClient<App>()
51
+ *
52
+ * // Fetch the data from the API.
53
+ * const data = request('GET /api/product/:id', { data: { id: '1' } })
54
+ */
55
+ request<P extends Route<T>>(route: P, options?: Options<T, P>): Promise<Data<T, P>>;
56
+ /**
57
+ * Attempt to fetch a route from the API and return the data. If the client was instantiated with an
58
+ * application, the route name will be inferred from the application routes. Otherwise, you
59
+ * can pass the route name as a string.
60
+ *
61
+ * @param name The name of the route to fetch.
62
+ * @param options The options to pass to the request.
63
+ * @returns A result object with either the data or an error.
64
+ * @example
65
+ * // Declare the application type.
66
+ * type App = Application<[ModuleProduct]>
67
+ *
68
+ * // Create a type-safe client for the application.
69
+ * const request = createClient<App>()
70
+ *
71
+ * // Fetch the data from the API.
72
+ * const { data, error } = requestAttempt('GET /api/product/:id', { data: { id: '1' } })
73
+ * if (error) console.error(error)
74
+ * else console.log(data)
75
+ */
76
+ requestAttempt<P extends Route<T>>(name: P, options?: Options<T, P>): Promise<Result<Data<T, P>>>;
77
+ }
25
78
  /**
26
- * Create a new client instance for the given OpenAPI specification.
79
+ * Create a new type-safe client for the application. The client can be used to fetch data from
80
+ * the API and connect to the server using WebSockets with the given path.
27
81
  *
28
- * @param document The OpenAPI specification document.
29
- * @param initialOptions The initial options to use for every request.
30
- * @returns The client instance.
82
+ * @param options The options to pass to the client.
83
+ * @returns The client object with the request method.
31
84
  * @example
32
- * const client = createClient(document)
33
- * await client.fetch({ ... })
85
+ * // Create a type-safe client for the application.
86
+ * const client = createClient<[ModuleUser]>()
87
+ *
88
+ * // Fetch the data from the API.
89
+ * const data = await client.request('GET /api/user/:id', { id: '1' })
90
+ *
91
+ * // Use the data from the API.
92
+ * console.log(data) // { id: '1', name: 'John Doe' }
34
93
  */
35
- declare function createClient<T extends OpenAPI.Document>(document: Readonly<T>, initialOptions?: ClientOptions<T>): Client<T>;
36
- declare function createClient<T extends OpenAPI.Document>(url: ClientBaseUrl<T>, initialOptions?: ClientOptions<T>): Client<T>;
94
+ declare function createClient<T extends ClientRoutes>(options?: RequestOptions): Client<T>;
95
+ declare function createClient<T extends {
96
+ swagger: string;
97
+ }>(options?: ServiceOptions<T>): Client<OpenAPIRoutes<T>>;
98
+ declare function createClient<T extends {
99
+ openapi: string;
100
+ }>(options?: ServiceOptions<T>): Client<OpenAPIRoutes<T>>;
37
101
 
38
- export { type Client, type ClientOptions, createClient };
102
+ export { Client, type ClientRoutes, createClient };
@@ -1,27 +1,90 @@
1
- import { fetch } from "./fetch.js";
2
- import { a as getOperationById, g as getBaseUrl } from "./chunks/D-WqCFul.js";
3
- import { h as handleResponse } from "./chunks/CKfJvIQ8.js";
4
- import "./chunks/B5hc73Po.js";
1
+ import { attempt } from "@unshared/functions/attempt";
2
+ import { f as fetch } from "./chunks/D51s1VII.js";
3
+ import { r as request } from "./chunks/lMH6B5BV.js";
5
4
  import "@unshared/functions/awaitable";
6
- function createClient(documentOrUrl, initialOptions = {}) {
7
- const specifications = typeof documentOrUrl == "string" ? void 0 : documentOrUrl;
8
- typeof documentOrUrl == "string" && (initialOptions.baseUrl = documentOrUrl);
9
- async function fetchByOperationId(operationId, options) {
10
- if (!specifications) throw new Error("No OpenAPI specification provided.");
11
- const operation = getOperationById(specifications, operationId);
12
- if (!operation) throw new Error(`Operation ID "${operationId}" not found.`);
13
- const { method, path, responses = {} } = operation, fetchOptions = { method, baseUrl: getBaseUrl(specifications), ...initialOptions, ...options }, response = await fetch(path, fetchOptions);
14
- if (response.ok) return handleResponse(response, fetchOptions);
15
- const status = response.status.toString();
16
- throw status in responses && typeof responses[status] == "object" && responses[status] !== null && "description" in responses[status] && typeof responses[status].description == "string" ? new Error(responses[status].description) : new Error(response.statusText);
5
+ class Client {
6
+ /**
7
+ * Create a new client for the application.
8
+ *
9
+ * @param initialOptions The options to pass to the client.
10
+ * @example new Client({ baseUrl: 'https://api.example.com' })
11
+ */
12
+ constructor(initialOptions = {}) {
13
+ this.initialOptions = initialOptions;
17
14
  }
18
- return new Proxy({}, {
19
- get(_, property) {
20
- return property === "fetch" ? (route, options) => fetch(route, { ...initialOptions, ...options }) : (options) => fetchByOperationId(property, options);
21
- }
22
- });
15
+ /**
16
+ * Fetch a route from the API and return the `Response` object. If the client was instantiated with an
17
+ * application, the route name will be inferred from the application routes. Otherwise, you
18
+ * can pass the route name as a string.
19
+ *
20
+ * @param route The name of the route to fetch.
21
+ * @param options The options to pass to the request.
22
+ * @returns The response from the server.
23
+ */
24
+ async fetch(route, options) {
25
+ return await fetch(route, { ...this.initialOptions, ...options });
26
+ }
27
+ /**
28
+ * Fetch a route from the API and return the data. If the client was instantiated with an
29
+ * application, the route name will be inferred from the application routes. Otherwise, you
30
+ * can pass the route name as a string.
31
+ *
32
+ * @param route The name of the route to fetch.
33
+ * @param options The options to pass to the request.
34
+ * @returns The data from the API.
35
+ * @example
36
+ * // Declare the application type.
37
+ * type App = Application<[ModuleProduct]>
38
+ *
39
+ * // Create a type-safe client for the application.
40
+ * const request = createClient<App>()
41
+ *
42
+ * // Fetch the data from the API.
43
+ * const data = request('GET /api/product/:id', { data: { id: '1' } })
44
+ */
45
+ async request(route, options) {
46
+ return await request(route, { ...this.initialOptions, ...options });
47
+ }
48
+ /**
49
+ * Attempt to fetch a route from the API and return the data. If the client was instantiated with an
50
+ * application, the route name will be inferred from the application routes. Otherwise, you
51
+ * can pass the route name as a string.
52
+ *
53
+ * @param name The name of the route to fetch.
54
+ * @param options The options to pass to the request.
55
+ * @returns A result object with either the data or an error.
56
+ * @example
57
+ * // Declare the application type.
58
+ * type App = Application<[ModuleProduct]>
59
+ *
60
+ * // Create a type-safe client for the application.
61
+ * const request = createClient<App>()
62
+ *
63
+ * // Fetch the data from the API.
64
+ * const { data, error } = requestAttempt('GET /api/product/:id', { data: { id: '1' } })
65
+ * if (error) console.error(error)
66
+ * else console.log(data)
67
+ */
68
+ async requestAttempt(name, options) {
69
+ return await attempt(() => this.request(name, options));
70
+ }
71
+ /**
72
+ * Create a new WebSocket connection to the server with the given path. The connection will
73
+ * automatically reconnect if the connection is closed unexpectedly.
74
+ *
75
+ * @param name The path to connect to.
76
+ * @param options The options to pass to the connection.
77
+ * @returns The WebSocket connection.
78
+ */
79
+ // public connect<P extends RouteName<T>>(name: P, options: Partial<ConnectOptions<T, P>> = {}): WebSocketConnection<T, P> {
80
+ // return connect<T, P>(name, { baseUrl: this.baseUrl, ...options })
81
+ // }
82
+ }
83
+ function createClient(options) {
84
+ return new Client(options);
23
85
  }
24
86
  export {
87
+ Client,
25
88
  createClient
26
89
  };
27
90
  //# sourceMappingURL=createClient.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"createClient.js","sources":["../createClient.ts"],"sourcesContent":["import type { MaybeLiteral, Override, Pretty } from '@unshared/types'\nimport type { OpenAPI, OpenAPIV2 as V2, OpenAPIV3 as V3, OpenAPIV3_1 as V3_1 } from 'openapi-types'\nimport type { OpenAPIV2, OpenAPIV3 } from './openapi/index'\nimport type { RequestHooks } from './utils/handleResponse'\nimport type { RequestMethod, RequestOptions } from './utils/parseRequest'\nimport { fetch } from './fetch'\nimport { getBaseUrl } from './openapi/getBaseUrl'\nimport { getOperationById } from './openapi/getOperationById'\nimport { handleResponse } from './utils/handleResponse'\n\ntype ClientBaseUrl<T> =\n MaybeLiteral<\n T extends V2.Document ? OpenAPIV2.ServerUrl<T>\n : T extends V3.Document ? OpenAPIV3.ServerUrl<T>\n : T extends V3_1.Document ? OpenAPIV3.ServerUrl<T>\n : string\n >\n\ntype ClientFetch<T> =\n T extends V2.Document ? <P extends OpenAPIV2.Route<T>>(name: P, options: OpenAPIV2.RequestInit<T, OpenAPIV2.OperationByRoute<T, P>>) => Promise<OpenAPIV2.Response<OpenAPIV2.OperationByRoute<T, P>>>\n : T extends V3.Document ? <P extends OpenAPIV2.Route<T>>(name: P, options: OpenAPIV3.RequestInit<T, OpenAPIV2.OperationByRoute<T, P>>) => Promise<OpenAPIV3.Response<OpenAPIV2.OperationByRoute<T, P>>>\n : T extends V3_1.Document ? <P extends OpenAPIV2.Route<T>>(name: P, options: OpenAPIV3.RequestInit<T, OpenAPIV2.OperationByRoute<T, P>>) => Promise<OpenAPIV3.Response<OpenAPIV2.OperationByRoute<T, P>>>\n : typeof globalThis.fetch\n\ntype ClientFetchOperation<T, U extends OpenAPIV2.OperationId<T>> =\n T extends V2.Document ? (options: OpenAPIV2.RequestInit<T, OpenAPIV2.OperationById<T, U>>) => Promise<OpenAPIV2.ResponseBody<OpenAPIV2.OperationById<T, U>>>\n : T extends V3.Document ? (options: OpenAPIV3.RequestInit<T, OpenAPIV2.OperationById<T, U>>) => Promise<OpenAPIV3.ResponseBody<OpenAPIV2.OperationById<T, U>>>\n : T extends V3_1.Document ? (options: OpenAPIV3.RequestInit<T, OpenAPIV2.OperationById<T, U>>) => Promise<OpenAPIV3.ResponseBody<OpenAPIV2.OperationById<T, U>>>\n : (options: RequestOptions) => Promise<Response>\n\nexport type Client<T = OpenAPI.Document> =\n Pretty<\n & { [K in OpenAPIV2.OperationId<T>]: ClientFetchOperation<T, K> }\n & { fetch: ClientFetch<T> }\n >\n\nexport type ClientOptions<T = any> = Override<RequestHooks & RequestOptions, {\n baseUrl?: ClientBaseUrl<T>\n\n /**\n * The headers to include in every request made by the client.\n *\n * @example { 'Authorization': 'Bearer ...' }\n */\n headers?: T extends V3.Document\n ? OpenAPIV3.ServerHeaders<T>\n : never\n}>\n\n/**\n * Create a new client instance for the given OpenAPI specification.\n *\n * @param document The OpenAPI specification document.\n * @param initialOptions The initial options to use for every request.\n * @returns The client instance.\n * @example\n * const client = createClient(document)\n * await client.fetch({ ... })\n */\n// @ts-expect-error: `ClientOptions` is not assignable to `ClientOptions<T>`.\nexport function createClient<T extends OpenAPI.Document>(document: Readonly<T>, initialOptions?: ClientOptions<T>): Client<T>\nexport function createClient<T extends OpenAPI.Document>(url: ClientBaseUrl<T>, initialOptions?: ClientOptions<T>): Client<T>\nexport function createClient(documentOrUrl: Readonly<OpenAPI.Document> | string, initialOptions: ClientOptions = {}): Client {\n const specifications = typeof documentOrUrl === 'string' ? undefined : documentOrUrl\n if (typeof documentOrUrl === 'string') initialOptions.baseUrl = documentOrUrl\n\n async function fetchByOperationId(operationId: string, options: ClientOptions<any>) {\n if (!specifications) throw new Error('No OpenAPI specification provided.')\n const operation = getOperationById(specifications, operationId) as { method: RequestMethod; path: string } & OpenAPI.Operation\n if (!operation) throw new Error(`Operation ID \"${operationId}\" not found.`)\n const { method, path, responses = {} } = operation\n const fetchOptions = { method, baseUrl: getBaseUrl(specifications), ...initialOptions, ...options }\n const response = await fetch(path, fetchOptions)\n\n // --- Return the JSON response if successful.\n if (response.ok) return handleResponse(response, fetchOptions)\n\n // --- Throw an error if the response was not successful.\n const status = response.status.toString()\n if (status in responses\n && typeof responses[status] === 'object'\n && responses[status] !== null\n && 'description' in responses[status]\n && typeof responses[status].description === 'string')\n throw new Error(responses[status].description)\n\n // --- Throw a generic error if the response was not successful.\n throw new Error(response.statusText)\n }\n\n return new Proxy({}, {\n get(_, property: string) {\n if (property === 'fetch') return (route: string, options: RequestOptions) => fetch(route, ({ ...initialOptions, ...options }))\n return (options: Record<string, unknown>) => fetchByOperationId(property, options)\n },\n }) as unknown as Client\n}\n"],"names":[],"mappings":";;;;;AA8DO,SAAS,aAAa,eAAoD,iBAAgC,IAAY;AAC3H,QAAM,iBAAiB,OAAO,iBAAkB,WAAW,SAAY;AACnE,SAAO,iBAAkB,aAAU,eAAe,UAAU;AAEjD,iBAAA,mBAAmB,aAAqB,SAA6B;AAClF,QAAI,CAAC,eAAsB,OAAA,IAAI,MAAM,oCAAoC;AACnE,UAAA,YAAY,iBAAiB,gBAAgB,WAAW;AAC9D,QAAI,CAAC,UAAW,OAAM,IAAI,MAAM,iBAAiB,WAAW,cAAc;AACpE,UAAA,EAAE,QAAQ,MAAM,YAAY,CAAA,EAAO,IAAA,WACnC,eAAe,EAAE,QAAQ,SAAS,WAAW,cAAc,GAAG,GAAG,gBAAgB,GAAG,QAAA,GACpF,WAAW,MAAM,MAAM,MAAM,YAAY;AAG/C,QAAI,SAAS,GAAW,QAAA,eAAe,UAAU,YAAY;AAGvD,UAAA,SAAS,SAAS,OAAO,SAAS;AACxC,UAAI,UAAU,aACT,OAAO,UAAU,MAAM,KAAM,YAC7B,UAAU,MAAM,MAAM,QACtB,iBAAiB,UAAU,MAAM,KACjC,OAAO,UAAU,MAAM,EAAE,eAAgB,WACtC,IAAI,MAAM,UAAU,MAAM,EAAE,WAAW,IAGzC,IAAI,MAAM,SAAS,UAAU;AAAA,EAAA;AAG9B,SAAA,IAAI,MAAM,IAAI;AAAA,IACnB,IAAI,GAAG,UAAkB;AACvB,aAAI,aAAa,UAAgB,CAAC,OAAe,YAA4B,MAAM,OAAQ,EAAE,GAAG,gBAAgB,GAAG,SAAU,IACtH,CAAC,YAAqC,mBAAmB,UAAU,OAAO;AAAA,IAAA;AAAA,EACnF,CACD;AACH;"}
1
+ {"version":3,"file":"createClient.js","sources":["../createClient.ts"],"sourcesContent":["import type { Result } from '@unshared/functions/attempt'\nimport type { ObjectLike } from '@unshared/types'\nimport type { ServiceOptions } from './createService'\nimport type { OpenAPIRoutes } from './openapi'\nimport type { RequestOptions } from './utils/request'\nimport { attempt } from '@unshared/functions/attempt'\nimport { fetch } from './utils/fetch'\nimport { request } from './utils/request'\n\n/** Define the routes that can be fetched from the API and their related options. */\nexport type ClientRoutes = Record<string, RequestOptions>\n\n/** The route name that can be fetched from the API. */\ntype Route<T extends ClientRoutes> =\n T extends Record<infer P extends string, RequestOptions> ? P : string\n\n/** The options to pass to the request based on the route name. */\ntype Options<T extends ClientRoutes, P extends keyof T> =\n T extends Record<P, infer R> ? R : RequestOptions\n\n/** The data returned from the API based on the route name. */\ntype Data<T extends ClientRoutes, P extends keyof T> =\n Options<T, P> extends RequestOptions<any, any, any, any, any, any, infer R extends ObjectLike, any>\n ? R\n : unknown\n\nexport class Client<T extends ClientRoutes = ClientRoutes> {\n\n /**\n * Create a new client for the application.\n *\n * @param initialOptions The options to pass to the client.\n * @example new Client({ baseUrl: 'https://api.example.com' })\n */\n constructor(private initialOptions: RequestOptions = {}) {}\n\n /**\n * Fetch a route from the API and return the `Response` object. 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 response from the server.\n */\n public async fetch<P extends Route<T>>(route: P, options?: Options<T, P>): Promise<Response> {\n return await fetch(route, { ...this.initialOptions, ...options })\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 */\n public async request<P extends Route<T>>(route: P, options?: Options<T, P>): Promise<Data<T, P>> {\n return await request(route, { ...this.initialOptions, ...options }) as Data<T, P>\n }\n\n /**\n * Attempt to 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 name The name of the route to fetch.\n * @param options The options to pass to the request.\n * @returns A result object with either the data or an error.\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, error } = requestAttempt('GET /api/product/:id', { data: { id: '1' } })\n * if (error) console.error(error)\n * else console.log(data)\n */\n public async requestAttempt<P extends Route<T>>(name: P, options?: Options<T, P>): Promise<Result<Data<T, P>>> {\n return await attempt(() => this.request<P>(name, options))\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 name The path to connect to.\n * @param options The options to pass to the connection.\n * @returns The WebSocket connection.\n */\n // public connect<P extends RouteName<T>>(name: P, options: Partial<ConnectOptions<T, P>> = {}): WebSocketConnection<T, P> {\n // return connect<T, P>(name, { baseUrl: this.baseUrl, ...options })\n // }\n}\n\n/**\n * Create a new type-safe client for the application. The client can be used to fetch data from\n * the API and connect to the server using WebSockets with the given path.\n *\n * @param options The options to pass to the client.\n * @returns The client object with the request method.\n * @example\n * // Create a type-safe client for the application.\n * const client = createClient<[ModuleUser]>()\n *\n * // Fetch the data from the API.\n * const data = await client.request('GET /api/user/:id', { id: '1' })\n *\n * // Use the data from the API.\n * console.log(data) // { id: '1', name: 'John Doe' }\n */\nexport function createClient<T extends ClientRoutes>(options?: RequestOptions): Client<T>\nexport function createClient<T extends { swagger: string }>(options?: ServiceOptions<T>): Client<OpenAPIRoutes<T>>\nexport function createClient<T extends { openapi: string }>(options?: ServiceOptions<T>): Client<OpenAPIRoutes<T>>\nexport function createClient(options?: RequestOptions): Client {\n return new Client(options)\n}\n"],"names":[],"mappings":";;;;AA0BO,MAAM,OAA8C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQzD,YAAoB,iBAAiC,IAAI;AAArC,SAAA,iBAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWpB,MAAa,MAA0B,OAAU,SAA4C;AACpF,WAAA,MAAM,MAAM,OAAO,EAAE,GAAG,KAAK,gBAAgB,GAAG,SAAS;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBlE,MAAa,QAA4B,OAAU,SAA8C;AACxF,WAAA,MAAM,QAAQ,OAAO,EAAE,GAAG,KAAK,gBAAgB,GAAG,SAAS;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuBpE,MAAa,eAAmC,MAAS,SAAsD;AAC7G,WAAO,MAAM,QAAQ,MAAM,KAAK,QAAW,MAAM,OAAO,CAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAc7D;AAqBO,SAAS,aAAa,SAAkC;AACtD,SAAA,IAAI,OAAO,OAAO;AAC3B;"}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var resolveOperation = require("./chunks/CtW2aMuA.cjs"), handleResponse = require("./chunks/CfKxYeRr.cjs");
3
+ require("@unshared/functions/awaitable");
4
+ function createService(document, initialOptions) {
5
+ return new Proxy({}, {
6
+ get(_, id) {
7
+ return async (data, options) => {
8
+ const baseUrl = resolveOperation.getServerUrl(document), operation = resolveOperation.resolveOperation(document, id), { method, path, responses = {} } = operation, response = await handleResponse.fetch(path, { method, baseUrl, data, ...initialOptions, ...options });
9
+ if (response.ok) return handleResponse.handleResponse(response, { ...initialOptions, ...options });
10
+ const status = response.status.toString();
11
+ throw status in responses && typeof responses[status] == "object" && responses[status] !== null && "description" in responses[status] && typeof responses[status].description == "string" ? new Error(responses[status].description) : new Error(response.statusText);
12
+ };
13
+ }
14
+ });
15
+ }
16
+ exports.createService = createService;
17
+ //# sourceMappingURL=createService.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createService.cjs","sources":["../createService.ts"],"sourcesContent":["import type { MaybeLiteral } from '@unshared/types'\nimport type { OpenAPIV3, Operation, OperationById, OperationId, OperationOptions, OperationResult, ServerUrl } from './openapi'\nimport type { RequestOptions } from './utils/request'\nimport { getServerUrl } from './openapi/getServerUrl'\nimport { resolveOperation } from './openapi/resolveOperation'\nimport { fetch } from './utils/fetch'\nimport { handleResponse } from './utils/handleResponse'\n\n/** A service instance for the given OpenAPI specification. */\nexport type Service<T> = {\n [K in OperationId<T>]:\n OperationById<T, K> extends infer U extends OperationById<T, K>\n ? (data: OperationOptions<T, U>['data'], options?: OperationOptions<T, U>) => Promise<OperationResult<T, U>>\n : never\n}\n\n/** The options to pass to the service client. */\nexport interface ServiceOptions<T = any> extends RequestOptions {\n baseUrl?: MaybeLiteral<ServerUrl<T>>\n headers?: T extends { openapi: string } ? OpenAPIV3.ServerHeaders<T> : never\n}\n\n/**\n * Create a new client instance for the given OpenAPI specification.\n *\n * @param document The OpenAPI specification document.\n * @param initialOptions The initial options to use for every request.\n * @returns The client instance.\n * @example\n *\n * // Import the Giphy OpenAPI specification.\n * import Giphy from './giphy.openapi.json'\n *\n * // Create a new service instance for the Giphy API.\n * const service = createService(Giphy, { headers: { 'Bearer' } })\n *\n * // Request the \"searchGifs\" operation from the Giphy API.\n * await service.getGifs({ limit: 10, offset: 0, q: 'cats' }) // => { data: [...] }\n */\nexport function createService<T extends object>(document: Readonly<T>, initialOptions?: ServiceOptions<T>): Service<T> {\n return new Proxy({}, {\n get(_, id: OperationId<T>) {\n return async(data: object, options: RequestOptions) => {\n\n // --- Find the operation in the OpenAPI specification.\n const baseUrl = getServerUrl(document)\n const operation = resolveOperation(document, id) as Operation\n\n // --- Fetch the relevant resource from the server.\n const { method, path, responses = {} } = operation\n const response = await fetch(path, { method, baseUrl, data, ...initialOptions, ...options })\n if (response.ok) return handleResponse(response, { ...initialOptions, ...options })\n\n // --- Throw an error if the response was not successful.\n const status = response.status.toString()\n if (status in responses\n && typeof responses[status] === 'object'\n && responses[status] !== null\n && 'description' in responses[status]\n && typeof responses[status].description === 'string')\n throw new Error(responses[status].description)\n\n // --- Throw a generic error if the response was not successful.\n throw new Error(response.statusText)\n }\n },\n }) as Service<T>\n}\n"],"names":["getServerUrl","resolveOperation","fetch","handleResponse"],"mappings":";;;AAuCgB,SAAA,cAAgC,UAAuB,gBAAgD;AAC9G,SAAA,IAAI,MAAM,IAAI;AAAA,IACnB,IAAI,GAAG,IAAoB;AAClB,aAAA,OAAM,MAAc,YAA4B;AAGrD,cAAM,UAAUA,iBAAAA,aAAa,QAAQ,GAC/B,YAAYC,iBAAAA,iBAAiB,UAAU,EAAE,GAGzC,EAAE,QAAQ,MAAM,YAAY,GAAG,IAAI,WACnC,WAAW,MAAMC,eAAAA,MAAM,MAAM,EAAE,QAAQ,SAAS,MAAM,GAAG,gBAAgB,GAAG,SAAS;AACvF,YAAA,SAAS,GAAI,QAAOC,eAAe,eAAA,UAAU,EAAE,GAAG,gBAAgB,GAAG,SAAS;AAG5E,cAAA,SAAS,SAAS,OAAO,SAAS;AACxC,cAAI,UAAU,aACT,OAAO,UAAU,MAAM,KAAM,YAC7B,UAAU,MAAM,MAAM,QACtB,iBAAiB,UAAU,MAAM,KACjC,OAAO,UAAU,MAAM,EAAE,eAAgB,WACtC,IAAI,MAAM,UAAU,MAAM,EAAE,WAAW,IAGzC,IAAI,MAAM,SAAS,UAAU;AAAA,MACrC;AAAA,IAAA;AAAA,EACF,CACD;AACH;;"}
@@ -0,0 +1,38 @@
1
+ import { MaybeLiteral } from '@unshared/types';
2
+ import { b as OperationId, d as OperationById, e as OperationOptions, f as OperationResult, S as ServerUrl, a as OpenAPIV3 } from './chunks/CjU0376e.js';
3
+ import { c as RequestOptions } from './chunks/B92aAMq0.js';
4
+ import 'openapi-types';
5
+ import './HttpHeaders.js';
6
+ import './HttpMethods.js';
7
+
8
+ /** A service instance for the given OpenAPI specification. */
9
+ type Service<T> = {
10
+ [K in OperationId<T>]: OperationById<T, K> extends infer U extends OperationById<T, K> ? (data: OperationOptions<T, U>['data'], options?: OperationOptions<T, U>) => Promise<OperationResult<T, U>> : never;
11
+ };
12
+ /** The options to pass to the service client. */
13
+ interface ServiceOptions<T = any> extends RequestOptions {
14
+ baseUrl?: MaybeLiteral<ServerUrl<T>>;
15
+ headers?: T extends {
16
+ openapi: string;
17
+ } ? OpenAPIV3.ServerHeaders<T> : never;
18
+ }
19
+ /**
20
+ * Create a new client instance for the given OpenAPI specification.
21
+ *
22
+ * @param document The OpenAPI specification document.
23
+ * @param initialOptions The initial options to use for every request.
24
+ * @returns The client instance.
25
+ * @example
26
+ *
27
+ * // Import the Giphy OpenAPI specification.
28
+ * import Giphy from './giphy.openapi.json'
29
+ *
30
+ * // Create a new service instance for the Giphy API.
31
+ * const service = createService(Giphy, { headers: { 'Bearer' } })
32
+ *
33
+ * // Request the "searchGifs" operation from the Giphy API.
34
+ * await service.getGifs({ limit: 10, offset: 0, q: 'cats' }) // => { data: [...] }
35
+ */
36
+ declare function createService<T extends object>(document: Readonly<T>, initialOptions?: ServiceOptions<T>): Service<T>;
37
+
38
+ export { type Service, type ServiceOptions, createService };
@@ -0,0 +1,19 @@
1
+ import { g as getServerUrl, r as resolveOperation } from "./chunks/Biic1J5b.js";
2
+ import { f as fetch, h as handleResponse } from "./chunks/D51s1VII.js";
3
+ import "@unshared/functions/awaitable";
4
+ function createService(document, initialOptions) {
5
+ return new Proxy({}, {
6
+ get(_, id) {
7
+ return async (data, options) => {
8
+ const baseUrl = getServerUrl(document), operation = resolveOperation(document, id), { method, path, responses = {} } = operation, response = await fetch(path, { method, baseUrl, data, ...initialOptions, ...options });
9
+ if (response.ok) return handleResponse(response, { ...initialOptions, ...options });
10
+ const status = response.status.toString();
11
+ throw status in responses && typeof responses[status] == "object" && responses[status] !== null && "description" in responses[status] && typeof responses[status].description == "string" ? new Error(responses[status].description) : new Error(response.statusText);
12
+ };
13
+ }
14
+ });
15
+ }
16
+ export {
17
+ createService
18
+ };
19
+ //# sourceMappingURL=createService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createService.js","sources":["../createService.ts"],"sourcesContent":["import type { MaybeLiteral } from '@unshared/types'\nimport type { OpenAPIV3, Operation, OperationById, OperationId, OperationOptions, OperationResult, ServerUrl } from './openapi'\nimport type { RequestOptions } from './utils/request'\nimport { getServerUrl } from './openapi/getServerUrl'\nimport { resolveOperation } from './openapi/resolveOperation'\nimport { fetch } from './utils/fetch'\nimport { handleResponse } from './utils/handleResponse'\n\n/** A service instance for the given OpenAPI specification. */\nexport type Service<T> = {\n [K in OperationId<T>]:\n OperationById<T, K> extends infer U extends OperationById<T, K>\n ? (data: OperationOptions<T, U>['data'], options?: OperationOptions<T, U>) => Promise<OperationResult<T, U>>\n : never\n}\n\n/** The options to pass to the service client. */\nexport interface ServiceOptions<T = any> extends RequestOptions {\n baseUrl?: MaybeLiteral<ServerUrl<T>>\n headers?: T extends { openapi: string } ? OpenAPIV3.ServerHeaders<T> : never\n}\n\n/**\n * Create a new client instance for the given OpenAPI specification.\n *\n * @param document The OpenAPI specification document.\n * @param initialOptions The initial options to use for every request.\n * @returns The client instance.\n * @example\n *\n * // Import the Giphy OpenAPI specification.\n * import Giphy from './giphy.openapi.json'\n *\n * // Create a new service instance for the Giphy API.\n * const service = createService(Giphy, { headers: { 'Bearer' } })\n *\n * // Request the \"searchGifs\" operation from the Giphy API.\n * await service.getGifs({ limit: 10, offset: 0, q: 'cats' }) // => { data: [...] }\n */\nexport function createService<T extends object>(document: Readonly<T>, initialOptions?: ServiceOptions<T>): Service<T> {\n return new Proxy({}, {\n get(_, id: OperationId<T>) {\n return async(data: object, options: RequestOptions) => {\n\n // --- Find the operation in the OpenAPI specification.\n const baseUrl = getServerUrl(document)\n const operation = resolveOperation(document, id) as Operation\n\n // --- Fetch the relevant resource from the server.\n const { method, path, responses = {} } = operation\n const response = await fetch(path, { method, baseUrl, data, ...initialOptions, ...options })\n if (response.ok) return handleResponse(response, { ...initialOptions, ...options })\n\n // --- Throw an error if the response was not successful.\n const status = response.status.toString()\n if (status in responses\n && typeof responses[status] === 'object'\n && responses[status] !== null\n && 'description' in responses[status]\n && typeof responses[status].description === 'string')\n throw new Error(responses[status].description)\n\n // --- Throw a generic error if the response was not successful.\n throw new Error(response.statusText)\n }\n },\n }) as Service<T>\n}\n"],"names":[],"mappings":";;;AAuCgB,SAAA,cAAgC,UAAuB,gBAAgD;AAC9G,SAAA,IAAI,MAAM,IAAI;AAAA,IACnB,IAAI,GAAG,IAAoB;AAClB,aAAA,OAAM,MAAc,YAA4B;AAGrD,cAAM,UAAU,aAAa,QAAQ,GAC/B,YAAY,iBAAiB,UAAU,EAAE,GAGzC,EAAE,QAAQ,MAAM,YAAY,GAAG,IAAI,WACnC,WAAW,MAAM,MAAM,MAAM,EAAE,QAAQ,SAAS,MAAM,GAAG,gBAAgB,GAAG,SAAS;AACvF,YAAA,SAAS,GAAI,QAAO,eAAe,UAAU,EAAE,GAAG,gBAAgB,GAAG,SAAS;AAG5E,cAAA,SAAS,SAAS,OAAO,SAAS;AACxC,cAAI,UAAU,aACT,OAAO,UAAU,MAAM,KAAM,YAC7B,UAAU,MAAM,MAAM,QACtB,iBAAiB,UAAU,MAAM,KACjC,OAAO,UAAU,MAAM,EAAE,eAAgB,WACtC,IAAI,MAAM,UAAU,MAAM,EAAE,WAAW,IAGzC,IAAI,MAAM,SAAS,UAAU;AAAA,MACrC;AAAA,IAAA;AAAA,EACF,CACD;AACH;"}