typedapi-client-helpers 0.1.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/bin/typedapi-generate.js +3 -0
- package/dist/index.cjs +339 -0
- package/dist/index.d.cts +225 -0
- package/dist/index.d.ts +225 -0
- package/dist/index.js +303 -0
- package/package.json +40 -0
- package/scripts/generate-api-minimal.mjs +740 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
TypedApiToastProvider: () => TypedApiToastProvider,
|
|
24
|
+
buildQuery: () => buildQuery,
|
|
25
|
+
extractArgsToastsAndParams: () => extractArgsToastsAndParams,
|
|
26
|
+
getSortDirectionFromSortType: () => getSortDirectionFromSortType,
|
|
27
|
+
getSortTypeFromSortDirection: () => getSortTypeFromSortDirection,
|
|
28
|
+
handleApiResponse: () => handleApiResponse,
|
|
29
|
+
resetUnauthorizedHandling: () => resetUnauthorizedHandling,
|
|
30
|
+
sortTypes: () => sortTypes,
|
|
31
|
+
toFormData: () => toFormData,
|
|
32
|
+
toast: () => toast
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(index_exports);
|
|
35
|
+
|
|
36
|
+
// src/toast/toast.tsx
|
|
37
|
+
var import_react_toastify = require("react-toastify");
|
|
38
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
39
|
+
function ToastContent({ title, message }) {
|
|
40
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
41
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: title }),
|
|
42
|
+
message && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: message })
|
|
43
|
+
] });
|
|
44
|
+
}
|
|
45
|
+
var toast = {
|
|
46
|
+
success(message, title = "Success!") {
|
|
47
|
+
import_react_toastify.toast.success(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToastContent, { title, message }));
|
|
48
|
+
},
|
|
49
|
+
error(message, title = "Error!") {
|
|
50
|
+
import_react_toastify.toast.error(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToastContent, { title, message }));
|
|
51
|
+
},
|
|
52
|
+
warning(message, title = "Warning!") {
|
|
53
|
+
import_react_toastify.toast.warning(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToastContent, { title, message }));
|
|
54
|
+
},
|
|
55
|
+
info(message, title = "Info") {
|
|
56
|
+
import_react_toastify.toast.info(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToastContent, { title, message }));
|
|
57
|
+
},
|
|
58
|
+
async errorResponse(error) {
|
|
59
|
+
let message = "Something went wrong.";
|
|
60
|
+
try {
|
|
61
|
+
if (error instanceof Response) {
|
|
62
|
+
const text = await error.text();
|
|
63
|
+
message = text || message;
|
|
64
|
+
} else if (error instanceof Error) {
|
|
65
|
+
message = error.message;
|
|
66
|
+
} else if (typeof error === "string") {
|
|
67
|
+
message = error;
|
|
68
|
+
} else if (error && typeof error === "object") {
|
|
69
|
+
message = JSON.stringify(error);
|
|
70
|
+
}
|
|
71
|
+
} catch {
|
|
72
|
+
}
|
|
73
|
+
import_react_toastify.toast.error(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToastContent, { title: "Error!", message }));
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// src/toast/ToastProvider.tsx
|
|
78
|
+
var import_react_toastify2 = require("react-toastify");
|
|
79
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
80
|
+
function TypedApiToastProvider() {
|
|
81
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_toastify2.ToastContainer, { position: "bottom-right" });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// src/utils/buildQuery.ts
|
|
85
|
+
function buildQuery(filters, page = 1, pageSize = 100, sortBy = null, sortDirection) {
|
|
86
|
+
let isPageSizeSet = pageSize > 0;
|
|
87
|
+
const query = filters.reduce((queryResult, filter) => {
|
|
88
|
+
const { filterName, filterNameMax, type, value, maxValue, isAList } = filter;
|
|
89
|
+
if ((value === null || value === void 0 || value === "") && (maxValue === null || maxValue === void 0 || maxValue === "")) {
|
|
90
|
+
return queryResult;
|
|
91
|
+
}
|
|
92
|
+
if (isAList && Array.isArray(value)) {
|
|
93
|
+
if (isOptionValueArray(value)) {
|
|
94
|
+
queryResult[filterName] = value.map(
|
|
95
|
+
(item) => convertType(type, item.value)
|
|
96
|
+
);
|
|
97
|
+
return queryResult;
|
|
98
|
+
}
|
|
99
|
+
queryResult[filterName] = value.map(
|
|
100
|
+
(item) => convertType(type, item)
|
|
101
|
+
);
|
|
102
|
+
return queryResult;
|
|
103
|
+
}
|
|
104
|
+
if (value !== "null" && value !== "undefined" && value !== null && value !== void 0 && value !== "") {
|
|
105
|
+
const convertedValue = convertType(type, value);
|
|
106
|
+
if (convertedValue !== null) {
|
|
107
|
+
queryResult[filterName] = convertedValue;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (filterNameMax && maxValue !== null && maxValue !== void 0 && maxValue !== "") {
|
|
111
|
+
const convertedMaxValue = convertType(type, maxValue);
|
|
112
|
+
if (convertedMaxValue !== null) {
|
|
113
|
+
queryResult[filterNameMax] = convertedMaxValue;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (String(filterName) === "pageSize" && !isPageSizeSet) {
|
|
117
|
+
isPageSizeSet = true;
|
|
118
|
+
}
|
|
119
|
+
return queryResult;
|
|
120
|
+
}, {});
|
|
121
|
+
query.pageNumber = page;
|
|
122
|
+
if (isPageSizeSet) {
|
|
123
|
+
query.pageSize = pageSize;
|
|
124
|
+
}
|
|
125
|
+
if (sortBy) {
|
|
126
|
+
query.sortBy = sortBy;
|
|
127
|
+
}
|
|
128
|
+
if (sortDirection !== void 0 && sortDirection !== "Default") {
|
|
129
|
+
query.sortDirection = sortDirection;
|
|
130
|
+
}
|
|
131
|
+
return query;
|
|
132
|
+
}
|
|
133
|
+
function isOptionValue(value) {
|
|
134
|
+
return typeof value === "object" && value !== null && "value" in value;
|
|
135
|
+
}
|
|
136
|
+
function isOptionValueArray(value) {
|
|
137
|
+
return value.every(isOptionValue);
|
|
138
|
+
}
|
|
139
|
+
function convertType(type, value) {
|
|
140
|
+
switch (type) {
|
|
141
|
+
case "date":
|
|
142
|
+
return value instanceof Date ? value.toISOString() : value;
|
|
143
|
+
case "number":
|
|
144
|
+
return Number(value);
|
|
145
|
+
case "boolean":
|
|
146
|
+
return Boolean(value);
|
|
147
|
+
default:
|
|
148
|
+
return value;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// src/utils/extractArgsToastsAndParams.ts
|
|
153
|
+
function isToastOptions(value) {
|
|
154
|
+
return typeof value === "object" && value !== null && ("toastSuccess" in value || "toastError" in value);
|
|
155
|
+
}
|
|
156
|
+
function isRequestParams(value) {
|
|
157
|
+
return typeof value === "object" && value !== null && !isToastOptions(value);
|
|
158
|
+
}
|
|
159
|
+
function extractArgsToastsAndParams(argsWithToast) {
|
|
160
|
+
const args = [...argsWithToast];
|
|
161
|
+
let toastOptions;
|
|
162
|
+
let params;
|
|
163
|
+
const lastArg = args[args.length - 1];
|
|
164
|
+
if (isRequestParams(lastArg)) {
|
|
165
|
+
params = lastArg;
|
|
166
|
+
args.pop();
|
|
167
|
+
}
|
|
168
|
+
const newLastArg = args[args.length - 1];
|
|
169
|
+
if (isToastOptions(newLastArg)) {
|
|
170
|
+
toastOptions = newLastArg;
|
|
171
|
+
args.pop();
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
args,
|
|
175
|
+
toastOptions,
|
|
176
|
+
params
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// src/utils/handleApiResponse.ts
|
|
181
|
+
var isHandlingUnauthorized = false;
|
|
182
|
+
function handleUnauthorized() {
|
|
183
|
+
if (isHandlingUnauthorized) {
|
|
184
|
+
return {
|
|
185
|
+
ok: false,
|
|
186
|
+
status: 401,
|
|
187
|
+
response: void 0,
|
|
188
|
+
error: new Error("Unauthorized")
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
isHandlingUnauthorized = true;
|
|
192
|
+
localStorage.removeItem("loggedInUser");
|
|
193
|
+
sessionStorage.clear();
|
|
194
|
+
toast.error("Your session has expired. Please log in again.", "Session Expired");
|
|
195
|
+
if (window.location.pathname !== "/login") {
|
|
196
|
+
window.dispatchEvent(new Event("unauthorized"));
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
ok: false,
|
|
200
|
+
status: 401,
|
|
201
|
+
response: void 0,
|
|
202
|
+
error: new Error("Unauthorized")
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function resetUnauthorizedHandling() {
|
|
206
|
+
isHandlingUnauthorized = false;
|
|
207
|
+
}
|
|
208
|
+
async function handleApiResponse(call, toastOptions) {
|
|
209
|
+
let response;
|
|
210
|
+
try {
|
|
211
|
+
response = await call();
|
|
212
|
+
if (response.status === 401) {
|
|
213
|
+
return handleUnauthorized();
|
|
214
|
+
}
|
|
215
|
+
let data;
|
|
216
|
+
try {
|
|
217
|
+
const textData = await response.text();
|
|
218
|
+
data = textData ? JSON.parse(textData) : void 0;
|
|
219
|
+
} catch {
|
|
220
|
+
data = void 0;
|
|
221
|
+
}
|
|
222
|
+
if (response.ok) {
|
|
223
|
+
if (toastOptions?.toastSuccess) {
|
|
224
|
+
toast.success(
|
|
225
|
+
toastOptions.toastSuccess.message,
|
|
226
|
+
toastOptions.toastSuccess.title
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
return {
|
|
230
|
+
ok: true,
|
|
231
|
+
status: response.status,
|
|
232
|
+
response: data
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
if (toastOptions?.toastError) {
|
|
236
|
+
toast.error(
|
|
237
|
+
toastOptions.toastError.message,
|
|
238
|
+
toastOptions.toastError.title
|
|
239
|
+
);
|
|
240
|
+
} else {
|
|
241
|
+
await toast.errorResponse(response);
|
|
242
|
+
}
|
|
243
|
+
return {
|
|
244
|
+
ok: false,
|
|
245
|
+
status: response.status,
|
|
246
|
+
response: data,
|
|
247
|
+
error: null
|
|
248
|
+
};
|
|
249
|
+
} catch (error) {
|
|
250
|
+
const status = error instanceof Response ? error.status : response?.status ?? 0;
|
|
251
|
+
if (status === 401) {
|
|
252
|
+
return handleUnauthorized();
|
|
253
|
+
}
|
|
254
|
+
await toast.errorResponse(error);
|
|
255
|
+
return {
|
|
256
|
+
ok: false,
|
|
257
|
+
status,
|
|
258
|
+
response: void 0,
|
|
259
|
+
error
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// src/utils/SortTypeFromSortDirection.ts
|
|
265
|
+
var sortTypes = [
|
|
266
|
+
"Default",
|
|
267
|
+
"Neutral",
|
|
268
|
+
"Ascending",
|
|
269
|
+
"Descending"
|
|
270
|
+
];
|
|
271
|
+
function getSortTypeFromSortDirection(sortDirection) {
|
|
272
|
+
switch (sortDirection) {
|
|
273
|
+
case "Ascending":
|
|
274
|
+
return "Ascending";
|
|
275
|
+
case "Descending":
|
|
276
|
+
return "Descending";
|
|
277
|
+
case "Default":
|
|
278
|
+
default:
|
|
279
|
+
return "Default";
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
function getSortDirectionFromSortType(sortType) {
|
|
283
|
+
switch (sortType) {
|
|
284
|
+
case "Ascending":
|
|
285
|
+
return "Ascending";
|
|
286
|
+
case "Descending":
|
|
287
|
+
return "Descending";
|
|
288
|
+
case "Neutral":
|
|
289
|
+
case "Default":
|
|
290
|
+
default:
|
|
291
|
+
return "Default";
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// src/utils/toFormData.ts
|
|
296
|
+
function toFormData(payload) {
|
|
297
|
+
const formData = new FormData();
|
|
298
|
+
for (const [key, value] of Object.entries(payload)) {
|
|
299
|
+
appendFormDataValue(formData, key, value);
|
|
300
|
+
}
|
|
301
|
+
return formData;
|
|
302
|
+
}
|
|
303
|
+
function appendFormDataValue(formData, key, value) {
|
|
304
|
+
if (value === null || value === void 0) {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (Array.isArray(value)) {
|
|
308
|
+
for (const item of value) {
|
|
309
|
+
appendFormDataValue(formData, key, item);
|
|
310
|
+
}
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (value instanceof File) {
|
|
314
|
+
formData.append(key, value, value.name);
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
if (value instanceof Blob) {
|
|
318
|
+
formData.append(key, value);
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
322
|
+
formData.append(key, String(value));
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
formData.append(key, JSON.stringify(value));
|
|
326
|
+
}
|
|
327
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
328
|
+
0 && (module.exports = {
|
|
329
|
+
TypedApiToastProvider,
|
|
330
|
+
buildQuery,
|
|
331
|
+
extractArgsToastsAndParams,
|
|
332
|
+
getSortDirectionFromSortType,
|
|
333
|
+
getSortTypeFromSortDirection,
|
|
334
|
+
handleApiResponse,
|
|
335
|
+
resetUnauthorizedHandling,
|
|
336
|
+
sortTypes,
|
|
337
|
+
toFormData,
|
|
338
|
+
toast
|
|
339
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
|
|
3
|
+
type QueryParamsType = Record<string | number, any>;
|
|
4
|
+
type ResponseFormat = keyof Omit<Body, "body" | "bodyUsed">;
|
|
5
|
+
interface FullRequestParams extends Omit<RequestInit, "body"> {
|
|
6
|
+
/** set parameter to `true` for call `securityWorker` for this request */
|
|
7
|
+
secure?: boolean;
|
|
8
|
+
/** request path */
|
|
9
|
+
path: string;
|
|
10
|
+
/** content type of request body */
|
|
11
|
+
type?: ContentType;
|
|
12
|
+
/** query params */
|
|
13
|
+
query?: QueryParamsType;
|
|
14
|
+
/** format of response (i.e. response.json() -> format: "json") */
|
|
15
|
+
format?: ResponseFormat;
|
|
16
|
+
/** request body */
|
|
17
|
+
body?: unknown;
|
|
18
|
+
/** base url */
|
|
19
|
+
baseUrl?: string;
|
|
20
|
+
/** request cancellation token */
|
|
21
|
+
cancelToken?: CancelToken;
|
|
22
|
+
}
|
|
23
|
+
type RequestParams = Omit<FullRequestParams, "body" | "method" | "query" | "path">;
|
|
24
|
+
interface HttpResponse$1<D extends unknown, E extends unknown = unknown> extends Response {
|
|
25
|
+
data: D;
|
|
26
|
+
error: E;
|
|
27
|
+
}
|
|
28
|
+
type CancelToken = Symbol | string | number;
|
|
29
|
+
declare enum ContentType {
|
|
30
|
+
Json = "application/json",
|
|
31
|
+
JsonApi = "application/vnd.api+json",
|
|
32
|
+
FormData = "multipart/form-data",
|
|
33
|
+
UrlEncoded = "application/x-www-form-urlencoded",
|
|
34
|
+
Text = "text/plain"
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type ExtractResponse<T> = T extends Promise<HttpResponse$1<infer R, any>> ? R : never;
|
|
38
|
+
type UnwrapArray<T> = T extends (infer U)[] ? U : T;
|
|
39
|
+
type ExtractDataIfPaginated<T> = T extends {
|
|
40
|
+
data?: (infer U)[] | null;
|
|
41
|
+
} ? U : T;
|
|
42
|
+
type SortableKeys<T> = keyof UnwrapArray<ExtractDataIfPaginated<T>>;
|
|
43
|
+
type WithoutRequestParams<T extends any[]> = T extends [
|
|
44
|
+
infer First,
|
|
45
|
+
...infer Rest
|
|
46
|
+
] ? First extends RequestParams ? Rest : [First, ...WithoutRequestParams<Rest>] : [];
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Standard result wrapper for API calls.
|
|
50
|
+
*
|
|
51
|
+
* When `ok` is true, the request succeeded and `response` contains the expected data.
|
|
52
|
+
* When `ok` is false, the request failed and `error` contains the thrown or returned error value.
|
|
53
|
+
*/
|
|
54
|
+
type ApiResult<T> = {
|
|
55
|
+
ok: true;
|
|
56
|
+
status: number;
|
|
57
|
+
response: T;
|
|
58
|
+
} | {
|
|
59
|
+
ok: false;
|
|
60
|
+
status: number;
|
|
61
|
+
response?: T;
|
|
62
|
+
error: unknown;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Supported filter input types used by typed filter forms.
|
|
67
|
+
*
|
|
68
|
+
* These values decide which UI input should be rendered for a filter.
|
|
69
|
+
*/
|
|
70
|
+
type FilterType = "number" | "date" | "string" | "timespan" | "boolean" | "boolean-button" | "OptionValue";
|
|
71
|
+
/**
|
|
72
|
+
* Selectable option value used by option-based filters.
|
|
73
|
+
*
|
|
74
|
+
* `name` is shown in the UI and `value` is sent as the actual filter value.
|
|
75
|
+
*/
|
|
76
|
+
interface OptionValue {
|
|
77
|
+
name: string;
|
|
78
|
+
value: number | string | Date;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Configuration for one filter field in a typed filter form.
|
|
82
|
+
*
|
|
83
|
+
* `filterName` maps the form value to a query property.
|
|
84
|
+
* `filterNameMax` can be used for range filters such as dates or numbers.
|
|
85
|
+
*/
|
|
86
|
+
interface FilterFormValues<TQuery> {
|
|
87
|
+
name: string;
|
|
88
|
+
filterName: keyof TQuery;
|
|
89
|
+
filterNameMax?: keyof TQuery;
|
|
90
|
+
type: FilterType;
|
|
91
|
+
value: number | string | Date | boolean | null | OptionValue[] | string[];
|
|
92
|
+
maxValue?: number | string | Date | null;
|
|
93
|
+
isAList: boolean;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Sort state used by UI components.
|
|
98
|
+
*
|
|
99
|
+
* `Neutral` represents a UI-only state and is sent to the API as `Default`.
|
|
100
|
+
*/
|
|
101
|
+
type SortType = "Default" | "Neutral" | "Ascending" | "Descending";
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Toast helper for showing consistent success, error, warning, and info messages.
|
|
105
|
+
*
|
|
106
|
+
* Wraps `react-toastify` with a shared title/message layout.
|
|
107
|
+
*/
|
|
108
|
+
declare const toast: {
|
|
109
|
+
success(message: string, title?: string): void;
|
|
110
|
+
error(message: string, title?: string): void;
|
|
111
|
+
warning(message: string, title?: string): void;
|
|
112
|
+
info(message: string, title?: string): void;
|
|
113
|
+
errorResponse(error: Response | unknown): Promise<void>;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Shared toast container for TypedApi UI notifications.
|
|
118
|
+
*
|
|
119
|
+
* Add this once near the root of the app to enable toast messages.
|
|
120
|
+
*/
|
|
121
|
+
declare function TypedApiToastProvider(): react.JSX.Element;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Extended fetch response returned by the generated HTTP client.
|
|
125
|
+
*
|
|
126
|
+
* `data` contains the successful response body and `error` contains the error body when available.
|
|
127
|
+
*/
|
|
128
|
+
interface HttpResponse<D extends unknown, E extends unknown = unknown> extends Response {
|
|
129
|
+
data: D;
|
|
130
|
+
error: E;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Runtime request options that can be passed to generated API methods.
|
|
134
|
+
*
|
|
135
|
+
* Used for extra request configuration such as headers, query values, or fetch options.
|
|
136
|
+
*/
|
|
137
|
+
type RuntimeRequestParams = Record<string, unknown>;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Toast message shown after an API action.
|
|
141
|
+
*
|
|
142
|
+
* `title` is optional and `message` contains the main notification text.
|
|
143
|
+
*/
|
|
144
|
+
type ToastMessage = {
|
|
145
|
+
title?: string;
|
|
146
|
+
message: string;
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* Optional toast messages for API success and error states.
|
|
150
|
+
*
|
|
151
|
+
* Use this to show consistent notifications after typed API requests.
|
|
152
|
+
*/
|
|
153
|
+
type ToastOptions = {
|
|
154
|
+
toastSuccess?: ToastMessage;
|
|
155
|
+
toastError?: ToastMessage;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
type SortDirection = number | string;
|
|
159
|
+
/**
|
|
160
|
+
* Builds a typed query object from filter form values, pagination, and sorting.
|
|
161
|
+
*
|
|
162
|
+
* Empty filter values are ignored.
|
|
163
|
+
* List filters are converted item by item.
|
|
164
|
+
* `OptionValue` lists send their `value` fields instead of the display names.
|
|
165
|
+
*/
|
|
166
|
+
declare function buildQuery<TQuery, TSortModel = keyof TQuery>(filters: FilterFormValues<TQuery>[], page?: number, pageSize?: number, sortBy?: keyof TSortModel | null, sortDirection?: SortDirection): Partial<TQuery>;
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Splits API wrapper arguments into actual API arguments, optional toast options,
|
|
170
|
+
* and optional runtime request params.
|
|
171
|
+
*
|
|
172
|
+
* This allows generated wrapper methods to accept toast and request options
|
|
173
|
+
* without changing the original API method arguments.
|
|
174
|
+
*/
|
|
175
|
+
declare function extractArgsToastsAndParams<TArgs extends unknown[]>(argsWithToast: [...TArgs, ToastOptions?, RuntimeRequestParams?]): {
|
|
176
|
+
args: TArgs;
|
|
177
|
+
toastOptions?: ToastOptions;
|
|
178
|
+
params?: RuntimeRequestParams;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Resets the unauthorized handling lock.
|
|
183
|
+
*
|
|
184
|
+
* This allows future `401 Unauthorized` responses to trigger the shared handling again.
|
|
185
|
+
*/
|
|
186
|
+
declare function resetUnauthorizedHandling(): void;
|
|
187
|
+
/**
|
|
188
|
+
* Executes an API call and converts the response into an `ApiResult`.
|
|
189
|
+
*
|
|
190
|
+
* Successful responses return `{ ok: true }`.
|
|
191
|
+
* Failed responses return `{ ok: false }` and show either a custom error toast
|
|
192
|
+
* or the response error message.
|
|
193
|
+
*/
|
|
194
|
+
declare function handleApiResponse<T>(call: () => Promise<HttpResponse<T, unknown>>, toastOptions?: ToastOptions): Promise<ApiResult<T>>;
|
|
195
|
+
|
|
196
|
+
/** Values supported by the generated API SortDirection enum. */
|
|
197
|
+
type ApiSortDirection = "Default" | "Ascending" | "Descending";
|
|
198
|
+
/**
|
|
199
|
+
* Sort states supported by TypedApi UI components.
|
|
200
|
+
*
|
|
201
|
+
* Includes `Neutral`, which is a UI-only state and is sent to the API as `Default`.
|
|
202
|
+
*/
|
|
203
|
+
declare const sortTypes: readonly ["Default", "Neutral", "Ascending", "Descending"];
|
|
204
|
+
/**
|
|
205
|
+
* Converts an API sort direction to the sort state used by UI components.
|
|
206
|
+
*
|
|
207
|
+
* Unknown or missing values safely fall back to `Default`.
|
|
208
|
+
*/
|
|
209
|
+
declare function getSortTypeFromSortDirection(sortDirection: ApiSortDirection | null | undefined): SortType;
|
|
210
|
+
/**
|
|
211
|
+
* Converts a UI sort state to a value accepted by the generated API.
|
|
212
|
+
*
|
|
213
|
+
* `Neutral` means no explicit sorting is active, so it maps to `Default`.
|
|
214
|
+
*/
|
|
215
|
+
declare function getSortDirectionFromSortType(sortType: SortType | null | undefined): ApiSortDirection;
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Converts an object payload into `FormData`.
|
|
219
|
+
*
|
|
220
|
+
* Supports single files, file arrays, primitive values, and nested objects.
|
|
221
|
+
* Arrays are appended as repeated fields with the same key.
|
|
222
|
+
*/
|
|
223
|
+
declare function toFormData<T extends object>(payload: T): FormData;
|
|
224
|
+
|
|
225
|
+
export { type ApiResult, type ApiSortDirection, type ExtractDataIfPaginated, type ExtractResponse, type FilterFormValues, type FilterType, type HttpResponse, type OptionValue, type RuntimeRequestParams, type SortDirection, type SortType, type SortableKeys, type ToastMessage, type ToastOptions, TypedApiToastProvider, type UnwrapArray, type WithoutRequestParams, buildQuery, extractArgsToastsAndParams, getSortDirectionFromSortType, getSortTypeFromSortDirection, handleApiResponse, resetUnauthorizedHandling, sortTypes, toFormData, toast };
|