@bagelink/sdk 1.8.28 → 1.8.32

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/README.md CHANGED
@@ -1,64 +1,95 @@
1
- # @bagelink/vue
1
+ # @bagelink/sdk
2
2
 
3
- Features:
3
+ OpenAPI-based TypeScript SDK generator with Vue 3 composables.
4
4
 
5
- - Build with [unbuild](https://github.com/unjs/unbuild)
6
- - File-to-file transpilation via [mkdist](https://github.com/unjs/mkdist)
7
- - Playground with [vite](https://vitejs.dev/)
5
+ ## Features
8
6
 
9
- ## Usage
7
+ - 🚀 Generate type-safe SDKs from OpenAPI specifications
8
+ - 🎯 Enhanced responses - array + metadata in one object
9
+ - 🔐 Built-in authentication support
10
+ - 🎨 FastAPI/Pydantic error parsing
11
+ - 📡 SSE/Stream support with type safety
12
+ - ⚡ Request state management composables
13
+ - 🔧 Flexible configuration with interceptors
10
14
 
11
- Use component globally
15
+ ## Installation
12
16
 
13
- ```ts
14
- // src/main.ts
15
- import { createApp } from 'vue';
16
- import { BagelVue } from '@bagel/vue';
17
+ ```bash
18
+ pnpm add @bagelink/sdk
19
+ ```
17
20
 
18
- import App from './App.vue';
21
+ ## Quick Start
19
22
 
20
- const BagelConfig = {
21
- host: '/api',
22
- onError: (err: any) => {
23
- // handle error
24
- // example:
25
- // useToast().error(`${$t('anErrorOccurred')}: ${err?.response?.data?.detail || err.message}`);
26
- },
27
- };
23
+ ### 1. Generate SDK
24
+
25
+ ```bash
26
+ # From OpenAPI spec
27
+ VITE_BAGEL_BASE_URL=https://api.example.com bun run bin/index.ts .bagelink
28
+ ```
28
29
 
29
- const app = createApp(App);
30
- app.use(head as Plugin);
30
+ ### 2. Initialize
31
31
 
32
- app.mount('#app');
32
+ ```typescript
33
+ import { createApi } from './.bagelink/api'
34
+
35
+ createApi({
36
+ baseURL: '/api',
37
+ withCredentials: true
38
+ })
33
39
  ```
34
40
 
35
- Import component
41
+ ### 3. Use
42
+
43
+ ```typescript
44
+ import { useApi } from './.bagelink/api'
45
+
46
+ const api = useApi()
47
+ const users = await api.users.get()
36
48
 
37
- ```vue
38
- <script setup lang="ts">
39
- import { useBagel } from '@bagel/vue';
49
+ // Array operations
50
+ for (const user of users) {
51
+ console.log(user.name)
52
+ }
40
53
 
41
- const bagel = useBagel();
42
- </script>
54
+ // Metadata
55
+ console.log(users.totalCount, users.page)
43
56
 
44
- <!-- OR -->
45
- <script lang="ts">
46
- export default defineComponent({
47
- onMounted() {
48
- console.log(this.$bagel.host)
57
+ // Raw access
58
+ console.log(users.$raw.headers)
59
+ ```
60
+
61
+ ## Configuration
62
+
63
+ ```typescript
64
+ createApi({
65
+ baseURL: '/api',
66
+ withCredentials: true,
67
+ auth: {
68
+ getToken: () => localStorage.getItem('token'),
69
+ onUnauthorized: () => router.push('/login')
49
70
  },
50
- });
51
- </script>
52
-
53
- <!-- OR -->
54
- <template>
55
- <div>
56
- {{ $bagel.host }}
57
- </div>
58
- </template>
71
+ onError: (error) => {
72
+ console.error(error.message)
73
+ if (error.fields) {
74
+ // Handle validation errors
75
+ }
76
+ },
77
+ interceptors: {
78
+ request: (config) => {
79
+ // Modify request
80
+ return config
81
+ }
82
+ }
83
+ })
59
84
  ```
60
85
 
86
+ ## State Management
87
+
88
+ ```typescript
89
+ import { useApiRequest } from './.bagelink/api'
61
90
 
62
- ## License
91
+ const { loading, error, data, execute } = useApiRequest(
92
+ () => api.users.get()
93
+ )
94
+ ```
63
95
 
64
- MIT
package/dist/index.cjs CHANGED
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const axios$1 = require('axios');
4
+ const vue = require('vue');
4
5
 
5
6
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
6
7
 
@@ -638,7 +639,11 @@ function generateAxiosFunction(method, formattedPath, allParams, responseTypeStr
638
639
  if (allParams === "undefined") {
639
640
  allParams = "";
640
641
  }
641
- let axiosFunction = `async (${allParams})${responseTypeStr} => {`;
642
+ const apiResponseType = responseTypeStr.replace(
643
+ /Promise<AxiosResponse<(.+)>>/,
644
+ "Promise<ApiResponse<$1>>"
645
+ );
646
+ let axiosFunction = `async (${allParams})${apiResponseType} => {`;
642
647
  const paramStr = parameters.config?.params ? `params: {${parameters.config.params}}` : "";
643
648
  if (requestBodyPayload === "formData") {
644
649
  if (allParams.includes("file: File")) {
@@ -646,20 +651,24 @@ function generateAxiosFunction(method, formattedPath, allParams, responseTypeStr
646
651
  const formData = new FormData()
647
652
  formData.append('file', file)
648
653
  formData.append('upload', file)
649
- return axios.${method}(${formattedPath}, formData, {
654
+ const response = await axios.${method}(${formattedPath}, formData, {
650
655
  headers: { 'Content-Type': 'multipart/form-data' },
651
656
  onUploadProgress: options?.onUploadProgress${paramStr ? `, ${paramStr}` : ""}
652
- })`;
657
+ })
658
+ return ApiResponse.create(response.data, response)`;
653
659
  } else {
654
660
  axiosFunction += `
655
- return axios.${method}(${formattedPath}, formData, {
661
+ const response = await axios.${method}(${formattedPath}, formData, {
656
662
  headers: { 'Content-Type': 'multipart/form-data' }${paramStr ? `, ${paramStr}` : ""}
657
- })`;
663
+ })
664
+ return ApiResponse.create(response.data, response)`;
658
665
  }
659
666
  } else {
660
667
  const configParams = paramStr ? `, { ${paramStr} }` : "";
661
668
  const bodyVar = requestBodyPayload || "{}";
662
- axiosFunction += `return axios.${method}(${formattedPath}${["get", "delete"].includes(method) ? configParams : `, ${bodyVar}${configParams}`})`;
669
+ axiosFunction += `
670
+ const response = await axios.${method}(${formattedPath}${["get", "delete"].includes(method) ? configParams : `, ${bodyVar}${configParams}`})
671
+ return ApiResponse.create(response.data, response)`;
663
672
  }
664
673
  axiosFunction += "}";
665
674
  return axiosFunction;
@@ -818,6 +827,7 @@ function generateFunctions(paths, baseUrl) {
818
827
  }, body);
819
828
  }
820
829
  let tsString = "";
830
+ const apiObjectEntries = [];
821
831
  for (const [parent, object] of Object.entries(body)) {
822
832
  tsString += `
823
833
  /**
@@ -825,7 +835,16 @@ function generateFunctions(paths, baseUrl) {
825
835
  */
826
836
  export const ${parent} = ${JSON.stringify(object, void 0, 2)};
827
837
  `;
838
+ apiObjectEntries.push(parent);
828
839
  }
840
+ tsString += `
841
+ /**
842
+ * Aggregated API object containing all endpoints
843
+ */
844
+ export const api = {
845
+ ${apiObjectEntries.map((name) => ` ${name},`).join("\n")}
846
+ };
847
+ `;
829
848
  Object.entries(functionsInventory).forEach(([key, value]) => {
830
849
  tsString = tsString.replace(`"${key}"`, value);
831
850
  });
@@ -901,11 +920,27 @@ function generateStreamEventTypeDefinitions() {
901
920
  function fileTemplate(tsString, typeForImport, baseURL) {
902
921
  const streamTypeDefs = generateStreamEventTypeDefinitions();
903
922
  const hasStreamEndpoints = Object.keys(streamEventTypes).length > 0;
904
- const streamImports = hasStreamEndpoints ? `import { createSSEStreamPost, StreamController, type SSEStreamOptions } from '@bagelink/sdk';` : "";
923
+ const streamImports = hasStreamEndpoints ? `createSSEStreamPost, createSSEStream, StreamController, type SSEStreamOptions,` : "";
905
924
  const templateCode = `import ax from 'axios';
906
925
  import type { AxiosResponse } from 'axios';
907
926
  import type { ${typeForImport.join(", ")} } from './types.d';
908
- ${streamImports}
927
+ import {
928
+ ApiResponse,
929
+ parseApiError,
930
+ formatFieldErrors,
931
+ useApiRequest,
932
+ useCancellableRequest,
933
+ ${streamImports}
934
+ type ApiConfig,
935
+ type ParsedError,
936
+ type FastAPIValidationError,
937
+ type FastAPIErrorResponse,
938
+ type ResponseMetadata,
939
+ type ApiRequestState,
940
+ type RequestInterceptor,
941
+ type ResponseInterceptor
942
+ } from '@bagelink/sdk';
943
+ import { ref, type Ref } from 'vue';
909
944
 
910
945
  /**
911
946
  * Options for file upload operations
@@ -920,14 +955,154 @@ export interface UploadOptions {
920
955
  }
921
956
 
922
957
  ${streamTypeDefs}
958
+
923
959
  /**
924
960
  * Configured axios instance for API requests
925
- * @example
926
- * // Making a direct request with the axios instance
927
- * const response = await axios.get('/some-endpoint');
928
961
  */
929
962
  export const axios = ax.create({baseURL: '${baseURL}', withCredentials: true});
930
- ${tsString}`;
963
+
964
+ ${tsString}
965
+
966
+ // ============================================================================
967
+ // API Instance & Configuration
968
+ // ============================================================================
969
+
970
+ /**
971
+ * Last response metadata (accessible via useApi().$lastResponse)
972
+ */
973
+ const lastResponse = ref<AxiosResponse | null>(null)
974
+
975
+ /**
976
+ * API instance type with enhanced response objects
977
+ */
978
+ type ApiInstance = typeof api & {
979
+ $raw: typeof api
980
+ $lastResponse: Ref<AxiosResponse | null>
981
+ $axios: typeof axios
982
+ $ApiResponse: typeof ApiResponse
983
+ }
984
+
985
+ // Global state
986
+ let apiConfig: ApiConfig | null = null
987
+ let apiInstance: ApiInstance | null = null
988
+
989
+ /**
990
+ * Create and configure the API instance
991
+ * @param config - API configuration options
992
+ * @returns Configured API instance
993
+ */
994
+ export function createApi(config: ApiConfig = {}): ApiInstance {
995
+ // Store config
996
+ apiConfig = config
997
+
998
+ // Configure axios defaults
999
+ if (config.baseURL) {
1000
+ axios.defaults.baseURL = config.baseURL
1001
+ }
1002
+ if (config.withCredentials !== undefined) {
1003
+ axios.defaults.withCredentials = config.withCredentials
1004
+ }
1005
+ if (config.axiosConfig) {
1006
+ Object.assign(axios.defaults, config.axiosConfig)
1007
+ }
1008
+
1009
+ // Clear existing interceptors
1010
+ axios.interceptors.request.clear()
1011
+ axios.interceptors.response.clear()
1012
+
1013
+ // Setup auth interceptor
1014
+ if (config.auth) {
1015
+ axios.interceptors.request.use(async (reqConfig) => {
1016
+ const token = await config.auth!.getToken?.()
1017
+ if (token) {
1018
+ const prefix = config.auth!.tokenPrefix ?? 'Bearer'
1019
+ reqConfig.headers.Authorization = \`\${prefix} \${token}\`
1020
+ }
1021
+ return reqConfig
1022
+ })
1023
+ }
1024
+
1025
+ // Setup custom request interceptor
1026
+ if (config.interceptors?.request) {
1027
+ axios.interceptors.request.use(config.interceptors.request)
1028
+ }
1029
+
1030
+ // Setup response interceptor for error handling
1031
+ axios.interceptors.response.use(
1032
+ (response) => {
1033
+ // Store last response for metadata access
1034
+ lastResponse.value = response
1035
+
1036
+ // Apply custom response interceptor if provided
1037
+ if (config.interceptors?.response) {
1038
+ return config.interceptors.response(response)
1039
+ }
1040
+ return response
1041
+ },
1042
+ async (error) => {
1043
+ // Handle 401 Unauthorized
1044
+ if (error.response?.status === 401) {
1045
+ await config.auth?.onUnauthorized?.()
1046
+ }
1047
+
1048
+ // Parse and handle error
1049
+ const parsedError = parseApiError(error)
1050
+ config.onError?.(parsedError, error)
1051
+
1052
+ throw error
1053
+ }
1054
+ )
1055
+
1056
+ // API already returns ApiResponse directly!
1057
+ // Just add the special properties
1058
+ apiInstance = {
1059
+ ...api,
1060
+ $raw: api,
1061
+ $lastResponse: lastResponse,
1062
+ $axios: axios,
1063
+ $ApiResponse: ApiResponse
1064
+ } as ApiInstance
1065
+
1066
+ return apiInstance
1067
+ }
1068
+
1069
+ /**
1070
+ * Access the configured API instance
1071
+ * @returns API instance with enhanced response objects
1072
+ * @throws Error if createApi hasn't been called
1073
+ */
1074
+ export function useApi(): ApiInstance {
1075
+ if (!apiInstance) {
1076
+ throw new Error(
1077
+ 'API not initialized. Call createApi() first.\\n\\n' +
1078
+ 'Example:\\n' +
1079
+ 'import { createApi } from \\'./generated/api\\'\\n' +
1080
+ 'createApi({ baseURL: \\'/api\\' })'
1081
+ )
1082
+ }
1083
+ return apiInstance
1084
+ }
1085
+
1086
+ // ============================================================================
1087
+ // Re-export utilities for convenience
1088
+ // ============================================================================
1089
+
1090
+ export {
1091
+ parseApiError,
1092
+ formatFieldErrors,
1093
+ useApiRequest,
1094
+ useCancellableRequest,
1095
+ ApiResponse,
1096
+ type ApiConfig,
1097
+ type ParsedError,
1098
+ type ResponseMetadata,
1099
+ type ApiRequestState,
1100
+ type FastAPIValidationError,
1101
+ type FastAPIErrorResponse,
1102
+ type RequestInterceptor,
1103
+ type ResponseInterceptor
1104
+ }
1105
+ `;
931
1106
  return templateCode.replace(/"([^"]+)":/g, "$1:");
932
1107
  }
933
1108
 
@@ -1249,6 +1424,238 @@ function formatAPIErrorMessage(err) {
1249
1424
  return `An error occurred (Status ${status}): ${error.message || "Unknown error"}`;
1250
1425
  }
1251
1426
 
1427
+ class ApiResponse extends Array {
1428
+ /** Raw axios response */
1429
+ $raw;
1430
+ /** Total number of items (from x-total-count header) */
1431
+ totalCount;
1432
+ /** Current page number (from x-page header) */
1433
+ page;
1434
+ /** Items per page (from x-per-page header) */
1435
+ perPage;
1436
+ /** Total number of pages (calculated) */
1437
+ totalPages;
1438
+ /** Rate limit remaining (from x-ratelimit-remaining header) */
1439
+ rateLimit;
1440
+ /** Rate limit reset timestamp (from x-ratelimit-reset header) */
1441
+ rateLimitReset;
1442
+ /** All response metadata */
1443
+ $metadata;
1444
+ constructor(data, response) {
1445
+ super();
1446
+ if (Array.isArray(data)) {
1447
+ this.push(...data);
1448
+ if (response) {
1449
+ this.$raw = response;
1450
+ this.$metadata = ApiResponse.parseMetadataStatic(response);
1451
+ this.totalCount = this.$metadata.totalCount;
1452
+ this.page = this.$metadata.page;
1453
+ this.perPage = this.$metadata.perPage;
1454
+ this.totalPages = this.$metadata.totalPages;
1455
+ this.rateLimit = this.$metadata.rateLimit;
1456
+ this.rateLimitReset = this.$metadata.rateLimitReset;
1457
+ }
1458
+ }
1459
+ }
1460
+ /**
1461
+ * Create an ApiResponse from data and response
1462
+ * Factory method to handle both arrays and objects
1463
+ */
1464
+ static create(data, response) {
1465
+ if (!Array.isArray(data)) {
1466
+ const obj = Object.assign(/* @__PURE__ */ Object.create(null), data);
1467
+ obj.$raw = response;
1468
+ obj.$metadata = ApiResponse.parseMetadataStatic(response);
1469
+ obj.totalCount = obj.$metadata.totalCount;
1470
+ obj.page = obj.$metadata.page;
1471
+ obj.perPage = obj.$metadata.perPage;
1472
+ obj.totalPages = obj.$metadata.totalPages;
1473
+ obj.rateLimit = obj.$metadata.rateLimit;
1474
+ obj.rateLimitReset = obj.$metadata.rateLimitReset;
1475
+ obj.getHeader = (name) => response?.headers[name.toLowerCase()];
1476
+ obj.hasPagination = obj.totalCount !== void 0 || obj.page !== void 0;
1477
+ obj.hasNextPage = obj.page && obj.totalPages ? obj.page < obj.totalPages : false;
1478
+ obj.hasPrevPage = obj.page ? obj.page > 1 : false;
1479
+ return obj;
1480
+ }
1481
+ const instance = new ApiResponse(data, response);
1482
+ return instance;
1483
+ }
1484
+ static parseMetadataStatic(response) {
1485
+ const { headers } = response;
1486
+ const metadata = {};
1487
+ if (headers["x-total-count"]) {
1488
+ metadata.totalCount = Number(headers["x-total-count"]);
1489
+ }
1490
+ if (headers["x-page"]) {
1491
+ metadata.page = Number(headers["x-page"]);
1492
+ }
1493
+ if (headers["x-per-page"]) {
1494
+ metadata.perPage = Number(headers["x-per-page"]);
1495
+ }
1496
+ if (metadata.totalCount && metadata.perPage) {
1497
+ metadata.totalPages = Math.ceil(metadata.totalCount / metadata.perPage);
1498
+ }
1499
+ if (headers["x-ratelimit-remaining"] || headers["x-rate-limit-remaining"]) {
1500
+ metadata.rateLimit = Number(
1501
+ headers["x-ratelimit-remaining"] || headers["x-rate-limit-remaining"]
1502
+ );
1503
+ }
1504
+ if (headers["x-ratelimit-reset"] || headers["x-rate-limit-reset"]) {
1505
+ metadata.rateLimitReset = Number(
1506
+ headers["x-ratelimit-reset"] || headers["x-rate-limit-reset"]
1507
+ );
1508
+ }
1509
+ Object.keys(headers).forEach((key) => {
1510
+ if (key.startsWith("x-") && !metadata[key]) {
1511
+ metadata[key] = headers[key];
1512
+ }
1513
+ });
1514
+ return metadata;
1515
+ }
1516
+ getHeader(name) {
1517
+ return this.$raw.headers[name.toLowerCase()];
1518
+ }
1519
+ get hasPagination() {
1520
+ return this.totalCount !== void 0 || this.page !== void 0;
1521
+ }
1522
+ get hasNextPage() {
1523
+ if (!this.page || !this.totalPages) return false;
1524
+ return this.page < this.totalPages;
1525
+ }
1526
+ get hasPrevPage() {
1527
+ if (!this.page) return false;
1528
+ return this.page > 1;
1529
+ }
1530
+ }
1531
+ function parseApiError(error) {
1532
+ const axiosError = error;
1533
+ if (!axiosError.response?.data) {
1534
+ return {
1535
+ message: axiosError.message || "An unexpected error occurred",
1536
+ raw: error
1537
+ };
1538
+ }
1539
+ const { detail } = axiosError.response.data;
1540
+ if (typeof detail === "string") {
1541
+ return {
1542
+ message: detail,
1543
+ raw: error
1544
+ };
1545
+ }
1546
+ if (Array.isArray(detail)) {
1547
+ const fields = {};
1548
+ const messages = [];
1549
+ for (const err of detail) {
1550
+ const fieldPath = err.loc.slice(1).join(".");
1551
+ const message = err.msg;
1552
+ if (fieldPath) {
1553
+ if (!fields[fieldPath]) {
1554
+ fields[fieldPath] = [];
1555
+ }
1556
+ fields[fieldPath].push(message);
1557
+ }
1558
+ messages.push(fieldPath ? `${fieldPath}: ${message}` : message);
1559
+ }
1560
+ return {
1561
+ message: messages.join("; "),
1562
+ fields,
1563
+ raw: error
1564
+ };
1565
+ }
1566
+ return {
1567
+ message: "An error occurred",
1568
+ raw: error
1569
+ };
1570
+ }
1571
+ function formatFieldErrors(fields) {
1572
+ return Object.entries(fields).map(([field, errors]) => `${field}: ${errors.join(", ")}`).join("\n");
1573
+ }
1574
+ function useApiRequest(requestFn, options = {}) {
1575
+ const loading = vue.ref(false);
1576
+ const error = vue.ref(null);
1577
+ const data = vue.ref(null);
1578
+ const execute = async () => {
1579
+ loading.value = true;
1580
+ error.value = null;
1581
+ try {
1582
+ const result = await requestFn();
1583
+ data.value = result;
1584
+ return result;
1585
+ } catch (e) {
1586
+ error.value = parseApiError(e);
1587
+ return null;
1588
+ } finally {
1589
+ loading.value = false;
1590
+ }
1591
+ };
1592
+ const reset = () => {
1593
+ loading.value = false;
1594
+ error.value = null;
1595
+ data.value = null;
1596
+ };
1597
+ if (options.immediate) {
1598
+ execute();
1599
+ }
1600
+ return { loading, error, data, execute, reset };
1601
+ }
1602
+ function useCancellableRequest(requestFn) {
1603
+ const controller = vue.ref(null);
1604
+ const loading = vue.ref(false);
1605
+ const error = vue.ref(null);
1606
+ const data = vue.ref(null);
1607
+ const execute = async () => {
1608
+ controller.value?.abort();
1609
+ controller.value = new AbortController();
1610
+ loading.value = true;
1611
+ error.value = null;
1612
+ try {
1613
+ const result = await requestFn(controller.value.signal);
1614
+ data.value = result;
1615
+ return result;
1616
+ } catch (e) {
1617
+ if (e.name !== "AbortError" && e.name !== "CanceledError") {
1618
+ error.value = parseApiError(e);
1619
+ }
1620
+ return null;
1621
+ } finally {
1622
+ loading.value = false;
1623
+ }
1624
+ };
1625
+ const cancel = () => {
1626
+ controller.value?.abort();
1627
+ loading.value = false;
1628
+ };
1629
+ const reset = () => {
1630
+ cancel();
1631
+ error.value = null;
1632
+ data.value = null;
1633
+ };
1634
+ return { loading, error, data, execute, cancel, reset };
1635
+ }
1636
+ function wrapApiForDirectReturn(apiObj) {
1637
+ if (typeof apiObj === "function") {
1638
+ return async (...args) => {
1639
+ const result = await apiObj(...args);
1640
+ if (result && typeof result === "object" && "data" in result && "status" in result) {
1641
+ return ApiResponse.create(result.data, result);
1642
+ }
1643
+ return result;
1644
+ };
1645
+ }
1646
+ if (typeof apiObj === "object" && apiObj !== null) {
1647
+ const wrapped = {};
1648
+ for (const key in apiObj) {
1649
+ if (key === "stream") {
1650
+ wrapped[key] = apiObj[key];
1651
+ } else {
1652
+ wrapped[key] = wrapApiForDirectReturn(apiObj[key]);
1653
+ }
1654
+ }
1655
+ return wrapped;
1656
+ }
1657
+ return apiObj;
1658
+ }
1252
1659
  const axios = axios__default.create({
1253
1660
  withCredentials: true
1254
1661
  });
@@ -1496,6 +1903,7 @@ class Bagel {
1496
1903
  }
1497
1904
  }
1498
1905
 
1906
+ exports.ApiResponse = ApiResponse;
1499
1907
  exports.Bagel = Bagel;
1500
1908
  exports.StreamController = StreamController;
1501
1909
  exports.createSSEStream = createSSEStream;
@@ -1504,8 +1912,13 @@ exports.dereference = dereference;
1504
1912
  exports.extractSSEEventInfo = extractSSEEventInfo;
1505
1913
  exports.extractSSEEventTypes = extractSSEEventTypes;
1506
1914
  exports.formatAPIErrorMessage = formatAPIErrorMessage;
1915
+ exports.formatFieldErrors = formatFieldErrors;
1507
1916
  exports.getPath = getPath;
1508
1917
  exports.isReferenceObject = isReferenceObject;
1509
1918
  exports.isSSEStream = isSSEStream;
1510
1919
  exports.isSchemaObject = isSchemaObject;
1511
1920
  exports.openAPI = index;
1921
+ exports.parseApiError = parseApiError;
1922
+ exports.useApiRequest = useApiRequest;
1923
+ exports.useCancellableRequest = useCancellableRequest;
1924
+ exports.wrapApiForDirectReturn = wrapApiForDirectReturn;