kimu-core 0.4.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/.editorconfig +30 -0
- package/.gitattributes +11 -0
- package/.github/FUNDING.yml +8 -0
- package/.github/copilot-instructions.md +103 -0
- package/.github/kimu-copilot-instructions.md +3779 -0
- package/.github/workflows/deploy-demo.yml +39 -0
- package/AUTHORS.md +20 -0
- package/CHANGELOG.md +20 -0
- package/CODE_GUIDELINES.md +165 -0
- package/CODE_OF_CONDUCT.md +47 -0
- package/CONTRIBUTING.md +62 -0
- package/FUNDING.md +31 -0
- package/ISSUE_GUIDELINES.md +74 -0
- package/LICENSE +17 -0
- package/LICENSE.it.md +17 -0
- package/MPL-2.0.txt +373 -0
- package/NOTICE +65 -0
- package/README-KIMU.md +40 -0
- package/README.it.md +208 -0
- package/README.md +266 -0
- package/SECURITY.md +64 -0
- package/docs/get-started-en.md +207 -0
- package/docs/images/icon.svg +64 -0
- package/docs/images/logo_kimu.png +0 -0
- package/docs/index.md +29 -0
- package/env/dev.config.json +6 -0
- package/env/local.config.json +6 -0
- package/env/prod.config.json +6 -0
- package/env/staging.config.json +6 -0
- package/env/test.config.json +4 -0
- package/icon.svg +10 -0
- package/logo_kimu.png +0 -0
- package/package.json +79 -0
- package/public/favicon.svg +64 -0
- package/public/logo_kimu.svg +1 -0
- package/scripts/build-all-config.js +59 -0
- package/scripts/build-all-core.js +65 -0
- package/scripts/build-all-extensions.js +64 -0
- package/scripts/build-all-modules.js +99 -0
- package/scripts/build-extension.js +60 -0
- package/scripts/clear-kimu-build.js +31 -0
- package/scripts/generate-kimu-build-config.js +79 -0
- package/scripts/install-module.js +162 -0
- package/scripts/list-modules.js +109 -0
- package/scripts/minify-css-assets.js +82 -0
- package/scripts/remove-module.js +122 -0
- package/scripts/utils/fix-imports.js +85 -0
- package/src/assets/index.css +43 -0
- package/src/assets/kimu-style.css +84 -0
- package/src/assets/style.css +116 -0
- package/src/config/kimu-base-config.json +5 -0
- package/src/core/index.ts +47 -0
- package/src/core/kimu-app.ts +76 -0
- package/src/core/kimu-asset-manager.ts +167 -0
- package/src/core/kimu-component-element.ts +325 -0
- package/src/core/kimu-component.ts +33 -0
- package/src/core/kimu-engine.ts +188 -0
- package/src/core/kimu-extension-manager.ts +281 -0
- package/src/core/kimu-global-styles.ts +136 -0
- package/src/core/kimu-module-manager.ts +69 -0
- package/src/core/kimu-module.ts +21 -0
- package/src/core/kimu-path-config.ts +127 -0
- package/src/core/kimu-reactive.ts +196 -0
- package/src/core/kimu-render.ts +91 -0
- package/src/core/kimu-store.ts +147 -0
- package/src/core/kimu-types.ts +65 -0
- package/src/extensions/.gitkeep +0 -0
- package/src/extensions/extensions-manifest.json +13 -0
- package/src/extensions/kimu-home/component.ts +80 -0
- package/src/extensions/kimu-home/lang/en.json +5 -0
- package/src/extensions/kimu-home/lang/it.json +5 -0
- package/src/extensions/kimu-home/style.css +61 -0
- package/src/extensions/kimu-home/view.html +51 -0
- package/src/index.html +26 -0
- package/src/main.ts +68 -0
- package/src/modules/.gitkeep +0 -0
- package/src/modules/README.md +79 -0
- package/src/modules/i18n/README.it.md +63 -0
- package/src/modules/i18n/README.md +63 -0
- package/src/modules/i18n/kimu-global-lang.ts +26 -0
- package/src/modules/i18n/kimu-i18n-service.ts +108 -0
- package/src/modules/i18n/manifest.json +22 -0
- package/src/modules/i18n/module.ts +39 -0
- package/src/modules/modules-manifest.json +12 -0
- package/src/modules-repository/README.md +108 -0
- package/src/modules-repository/api-axios/CHANGELOG.md +48 -0
- package/src/modules-repository/api-axios/QUICK-REFERENCE.md +178 -0
- package/src/modules-repository/api-axios/README.md +304 -0
- package/src/modules-repository/api-axios/api-axios-service.ts +355 -0
- package/src/modules-repository/api-axios/examples.ts +293 -0
- package/src/modules-repository/api-axios/index.ts +19 -0
- package/src/modules-repository/api-axios/interfaces.ts +71 -0
- package/src/modules-repository/api-axios/module.ts +41 -0
- package/src/modules-repository/api-core/CHANGELOG.md +42 -0
- package/src/modules-repository/api-core/QUICK-REFERENCE.md +192 -0
- package/src/modules-repository/api-core/README.md +435 -0
- package/src/modules-repository/api-core/api-core-service.ts +289 -0
- package/src/modules-repository/api-core/examples.ts +432 -0
- package/src/modules-repository/api-core/index.ts +8 -0
- package/src/modules-repository/api-core/interfaces.ts +83 -0
- package/src/modules-repository/api-core/module.ts +30 -0
- package/src/modules-repository/event-bus/README.md +273 -0
- package/src/modules-repository/event-bus/event-bus-service.ts +176 -0
- package/src/modules-repository/event-bus/module.ts +30 -0
- package/src/modules-repository/i18n/README.it.md +63 -0
- package/src/modules-repository/i18n/README.md +63 -0
- package/src/modules-repository/i18n/kimu-global-lang.ts +26 -0
- package/src/modules-repository/i18n/kimu-i18n-service.ts +108 -0
- package/src/modules-repository/i18n/manifest.json +22 -0
- package/src/modules-repository/i18n/module.ts +39 -0
- package/src/modules-repository/notification/README.md +423 -0
- package/src/modules-repository/notification/module.ts +30 -0
- package/src/modules-repository/notification/notification-service.ts +436 -0
- package/src/modules-repository/router/README.it.md +39 -0
- package/src/modules-repository/router/README.md +39 -0
- package/src/modules-repository/router/manifest.json +21 -0
- package/src/modules-repository/router/module.ts +23 -0
- package/src/modules-repository/router/router.ts +144 -0
- package/src/modules-repository/state/README.md +409 -0
- package/src/modules-repository/state/module.ts +30 -0
- package/src/modules-repository/state/state-service.ts +296 -0
- package/src/modules-repository/theme/README.md +267 -0
- package/src/modules-repository/theme/module.ts +30 -0
- package/src/modules-repository/theme/pre-build.js +40 -0
- package/src/modules-repository/theme/theme-service.ts +389 -0
- package/src/modules-repository/theme/themes/theme-cherry-blossom.css +78 -0
- package/src/modules-repository/theme/themes/theme-cozy.css +111 -0
- package/src/modules-repository/theme/themes/theme-cyberpunk.css +150 -0
- package/src/modules-repository/theme/themes/theme-dark.css +79 -0
- package/src/modules-repository/theme/themes/theme-forest.css +171 -0
- package/src/modules-repository/theme/themes/theme-gold.css +100 -0
- package/src/modules-repository/theme/themes/theme-high-contrast.css +126 -0
- package/src/modules-repository/theme/themes/theme-lava.css +101 -0
- package/src/modules-repository/theme/themes/theme-lavender.css +90 -0
- package/src/modules-repository/theme/themes/theme-light.css +79 -0
- package/src/modules-repository/theme/themes/theme-matrix.css +103 -0
- package/src/modules-repository/theme/themes/theme-midnight.css +81 -0
- package/src/modules-repository/theme/themes/theme-nord.css +94 -0
- package/src/modules-repository/theme/themes/theme-ocean.css +84 -0
- package/src/modules-repository/theme/themes/theme-retro80s.css +343 -0
- package/src/modules-repository/theme/themes/theme-sunset.css +62 -0
- package/src/modules-repository/theme/themes-config.d.ts +27 -0
- package/src/modules-repository/theme/themes-config.json +213 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +33 -0
- package/vite.config.ts +99 -0
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Axios Service
|
|
3
|
+
*
|
|
4
|
+
* Advanced HTTP client based on Axios library.
|
|
5
|
+
* Provides additional features over api-core:
|
|
6
|
+
* - Request/response interceptors
|
|
7
|
+
* - Automatic retries with exponential backoff
|
|
8
|
+
* - Request cancellation
|
|
9
|
+
* - Upload/download progress tracking
|
|
10
|
+
* - Better error handling and transformation
|
|
11
|
+
* - Request/response caching
|
|
12
|
+
*
|
|
13
|
+
* @module api-axios
|
|
14
|
+
* @author UnicòVerso
|
|
15
|
+
* @version 1.0.0
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, CancelTokenSource, InternalAxiosRequestConfig } from 'axios';
|
|
19
|
+
import {
|
|
20
|
+
ApiRequestConfig,
|
|
21
|
+
ApiResponse,
|
|
22
|
+
ApiError,
|
|
23
|
+
HttpMethod,
|
|
24
|
+
RequestInterceptor,
|
|
25
|
+
ResponseInterceptor,
|
|
26
|
+
ErrorInterceptor
|
|
27
|
+
} from './interfaces';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* ApiAxiosService - Advanced HTTP client with Axios
|
|
31
|
+
*
|
|
32
|
+
* Features:
|
|
33
|
+
* - Interceptors for requests and responses
|
|
34
|
+
* - Automatic retry logic with exponential backoff
|
|
35
|
+
* - Request cancellation support
|
|
36
|
+
* - Progress tracking for uploads/downloads
|
|
37
|
+
* - Response caching
|
|
38
|
+
* - Better error handling
|
|
39
|
+
*/
|
|
40
|
+
export class ApiAxiosService {
|
|
41
|
+
private axiosInstance: AxiosInstance;
|
|
42
|
+
private requestInterceptors: RequestInterceptor[] = [];
|
|
43
|
+
private responseInterceptors: ResponseInterceptor[] = [];
|
|
44
|
+
private errorInterceptors: ErrorInterceptor[] = [];
|
|
45
|
+
private cache: Map<string, { data: any; timestamp: number }> = new Map();
|
|
46
|
+
private cacheTTL: number = 5 * 60 * 1000; // 5 minutes default
|
|
47
|
+
|
|
48
|
+
constructor() {
|
|
49
|
+
this.axiosInstance = axios.create({
|
|
50
|
+
timeout: 30000,
|
|
51
|
+
headers: {
|
|
52
|
+
'Content-Type': 'application/json'
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
this.setupInterceptors();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Setup default Axios interceptors
|
|
61
|
+
*/
|
|
62
|
+
private setupInterceptors(): void {
|
|
63
|
+
// Request interceptor
|
|
64
|
+
this.axiosInstance.interceptors.request.use(
|
|
65
|
+
async (config: InternalAxiosRequestConfig) => {
|
|
66
|
+
// Apply custom request interceptors
|
|
67
|
+
for (const interceptor of this.requestInterceptors) {
|
|
68
|
+
const modifiedConfig = await interceptor(config as any);
|
|
69
|
+
Object.assign(config, modifiedConfig);
|
|
70
|
+
}
|
|
71
|
+
return config;
|
|
72
|
+
},
|
|
73
|
+
(error: any) => Promise.reject(error)
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
// Response interceptor
|
|
77
|
+
this.axiosInstance.interceptors.response.use(
|
|
78
|
+
async (response: AxiosResponse) => {
|
|
79
|
+
const apiResponse = this.transformResponse(response);
|
|
80
|
+
|
|
81
|
+
// Apply custom response interceptors
|
|
82
|
+
for (const interceptor of this.responseInterceptors) {
|
|
83
|
+
await interceptor(apiResponse);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return response;
|
|
87
|
+
},
|
|
88
|
+
async (error: any) => {
|
|
89
|
+
const apiError = this.transformError(error);
|
|
90
|
+
|
|
91
|
+
// Apply custom error interceptors
|
|
92
|
+
for (const interceptor of this.errorInterceptors) {
|
|
93
|
+
await interceptor(apiError);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return Promise.reject(apiError);
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Add a request interceptor
|
|
103
|
+
*/
|
|
104
|
+
addRequestInterceptor(interceptor: RequestInterceptor): void {
|
|
105
|
+
this.requestInterceptors.push(interceptor);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Add a response interceptor
|
|
110
|
+
*/
|
|
111
|
+
addResponseInterceptor(interceptor: ResponseInterceptor): void {
|
|
112
|
+
this.responseInterceptors.push(interceptor);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Add an error interceptor
|
|
117
|
+
*/
|
|
118
|
+
addErrorInterceptor(interceptor: ErrorInterceptor): void {
|
|
119
|
+
this.errorInterceptors.push(interceptor);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Transform Axios response to ApiResponse format
|
|
124
|
+
*/
|
|
125
|
+
private transformResponse(response: AxiosResponse): ApiResponse {
|
|
126
|
+
return {
|
|
127
|
+
data: response.data,
|
|
128
|
+
status: response.status,
|
|
129
|
+
statusText: response.statusText,
|
|
130
|
+
headers: response.headers as Record<string, string>,
|
|
131
|
+
config: response.config as ApiRequestConfig
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Transform Axios error to ApiError format
|
|
137
|
+
*/
|
|
138
|
+
private transformError(error: any): ApiError {
|
|
139
|
+
if (error.response) {
|
|
140
|
+
return {
|
|
141
|
+
message: error.message || 'Request failed',
|
|
142
|
+
status: error.response.status,
|
|
143
|
+
data: error.response.data,
|
|
144
|
+
originalError: error
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
message: error.message || 'Network error',
|
|
150
|
+
originalError: error
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Generate cache key from URL and config
|
|
156
|
+
*/
|
|
157
|
+
private getCacheKey(url: string, config?: ApiRequestConfig): string {
|
|
158
|
+
const params = config?.params ? JSON.stringify(config.params) : '';
|
|
159
|
+
return `${url}${params}`;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Check if cached response is still valid
|
|
164
|
+
*/
|
|
165
|
+
private isCacheValid(timestamp: number): boolean {
|
|
166
|
+
return Date.now() - timestamp < this.cacheTTL;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Set cache TTL (time-to-live) in milliseconds
|
|
171
|
+
*/
|
|
172
|
+
setCacheTTL(ttl: number): void {
|
|
173
|
+
this.cacheTTL = ttl;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Clear all cached responses
|
|
178
|
+
*/
|
|
179
|
+
clearCache(): void {
|
|
180
|
+
this.cache.clear();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Create a cancel token for request cancellation
|
|
185
|
+
*/
|
|
186
|
+
createCancelToken(): CancelTokenSource {
|
|
187
|
+
return axios.CancelToken.source();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Perform HTTP GET request
|
|
192
|
+
*/
|
|
193
|
+
async get<T = any>(url: string, config?: ApiRequestConfig & { useCache?: boolean }): Promise<ApiResponse<T>> {
|
|
194
|
+
const useCache = config?.useCache ?? false;
|
|
195
|
+
const cacheKey = this.getCacheKey(url, config);
|
|
196
|
+
|
|
197
|
+
// Check cache
|
|
198
|
+
if (useCache && this.cache.has(cacheKey)) {
|
|
199
|
+
const cached = this.cache.get(cacheKey)!;
|
|
200
|
+
if (this.isCacheValid(cached.timestamp)) {
|
|
201
|
+
return {
|
|
202
|
+
data: cached.data,
|
|
203
|
+
status: 200,
|
|
204
|
+
statusText: 'OK (cached)',
|
|
205
|
+
headers: {},
|
|
206
|
+
config: config || {}
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const axiosConfig: AxiosRequestConfig = {
|
|
212
|
+
...config?.axiosConfig,
|
|
213
|
+
headers: config?.headers,
|
|
214
|
+
params: config?.params,
|
|
215
|
+
timeout: config?.timeout,
|
|
216
|
+
withCredentials: config?.withCredentials,
|
|
217
|
+
responseType: config?.responseType,
|
|
218
|
+
onUploadProgress: config?.onUploadProgress,
|
|
219
|
+
onDownloadProgress: config?.onDownloadProgress
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const response = await this.axiosInstance.get<T>(url, axiosConfig);
|
|
223
|
+
const apiResponse = this.transformResponse(response);
|
|
224
|
+
|
|
225
|
+
// Store in cache if enabled
|
|
226
|
+
if (useCache) {
|
|
227
|
+
this.cache.set(cacheKey, {
|
|
228
|
+
data: apiResponse.data,
|
|
229
|
+
timestamp: Date.now()
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return apiResponse;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Perform HTTP POST request
|
|
238
|
+
*/
|
|
239
|
+
async post<T = any>(url: string, data?: any, config?: ApiRequestConfig): Promise<ApiResponse<T>> {
|
|
240
|
+
const axiosConfig: AxiosRequestConfig = {
|
|
241
|
+
...config?.axiosConfig,
|
|
242
|
+
headers: config?.headers,
|
|
243
|
+
params: config?.params,
|
|
244
|
+
timeout: config?.timeout,
|
|
245
|
+
withCredentials: config?.withCredentials,
|
|
246
|
+
responseType: config?.responseType,
|
|
247
|
+
onUploadProgress: config?.onUploadProgress,
|
|
248
|
+
onDownloadProgress: config?.onDownloadProgress
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
const response = await this.axiosInstance.post<T>(url, data, axiosConfig);
|
|
252
|
+
return this.transformResponse(response);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Perform HTTP PUT request
|
|
257
|
+
*/
|
|
258
|
+
async put<T = any>(url: string, data?: any, config?: ApiRequestConfig): Promise<ApiResponse<T>> {
|
|
259
|
+
const axiosConfig: AxiosRequestConfig = {
|
|
260
|
+
...config?.axiosConfig,
|
|
261
|
+
headers: config?.headers,
|
|
262
|
+
params: config?.params,
|
|
263
|
+
timeout: config?.timeout,
|
|
264
|
+
withCredentials: config?.withCredentials,
|
|
265
|
+
responseType: config?.responseType,
|
|
266
|
+
onUploadProgress: config?.onUploadProgress,
|
|
267
|
+
onDownloadProgress: config?.onDownloadProgress
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
const response = await this.axiosInstance.put<T>(url, data, axiosConfig);
|
|
271
|
+
return this.transformResponse(response);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Perform HTTP PATCH request
|
|
276
|
+
*/
|
|
277
|
+
async patch<T = any>(url: string, data?: any, config?: ApiRequestConfig): Promise<ApiResponse<T>> {
|
|
278
|
+
const axiosConfig: AxiosRequestConfig = {
|
|
279
|
+
...config?.axiosConfig,
|
|
280
|
+
headers: config?.headers,
|
|
281
|
+
params: config?.params,
|
|
282
|
+
timeout: config?.timeout,
|
|
283
|
+
withCredentials: config?.withCredentials,
|
|
284
|
+
responseType: config?.responseType,
|
|
285
|
+
onUploadProgress: config?.onUploadProgress,
|
|
286
|
+
onDownloadProgress: config?.onDownloadProgress
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
const response = await this.axiosInstance.patch<T>(url, data, axiosConfig);
|
|
290
|
+
return this.transformResponse(response);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Perform HTTP DELETE request
|
|
295
|
+
*/
|
|
296
|
+
async delete<T = any>(url: string, config?: ApiRequestConfig): Promise<ApiResponse<T>> {
|
|
297
|
+
const axiosConfig: AxiosRequestConfig = {
|
|
298
|
+
...config?.axiosConfig,
|
|
299
|
+
headers: config?.headers,
|
|
300
|
+
params: config?.params,
|
|
301
|
+
timeout: config?.timeout,
|
|
302
|
+
withCredentials: config?.withCredentials,
|
|
303
|
+
responseType: config?.responseType
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
const response = await this.axiosInstance.delete<T>(url, axiosConfig);
|
|
307
|
+
return this.transformResponse(response);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Perform a generic HTTP request with automatic retry
|
|
312
|
+
*/
|
|
313
|
+
async request<T = any>(
|
|
314
|
+
method: HttpMethod,
|
|
315
|
+
url: string,
|
|
316
|
+
data?: any,
|
|
317
|
+
config?: ApiRequestConfig & { retries?: number; retryDelay?: number }
|
|
318
|
+
): Promise<ApiResponse<T>> {
|
|
319
|
+
const retries = config?.retries ?? 0;
|
|
320
|
+
const retryDelay = config?.retryDelay ?? 1000;
|
|
321
|
+
|
|
322
|
+
let lastError: ApiError | null = null;
|
|
323
|
+
|
|
324
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
325
|
+
try {
|
|
326
|
+
switch (method) {
|
|
327
|
+
case 'GET':
|
|
328
|
+
return await this.get<T>(url, config);
|
|
329
|
+
case 'POST':
|
|
330
|
+
return await this.post<T>(url, data, config);
|
|
331
|
+
case 'PUT':
|
|
332
|
+
return await this.put<T>(url, data, config);
|
|
333
|
+
case 'PATCH':
|
|
334
|
+
return await this.patch<T>(url, data, config);
|
|
335
|
+
case 'DELETE':
|
|
336
|
+
return await this.delete<T>(url, config);
|
|
337
|
+
default:
|
|
338
|
+
throw new Error(`Unsupported HTTP method: ${method}`);
|
|
339
|
+
}
|
|
340
|
+
} catch (error: any) {
|
|
341
|
+
lastError = error as ApiError;
|
|
342
|
+
|
|
343
|
+
if (attempt < retries) {
|
|
344
|
+
// Exponential backoff
|
|
345
|
+
await new Promise(resolve => setTimeout(resolve, retryDelay * Math.pow(2, attempt)));
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
throw lastError;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Singleton instance
|
|
355
|
+
export const apiAxiosService = new ApiAxiosService();
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Axios Service - Usage Examples
|
|
3
|
+
*
|
|
4
|
+
* Collection of practical examples demonstrating various features
|
|
5
|
+
* of the api-axios module.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { apiAxiosService } from './api-axios-service';
|
|
9
|
+
import type { ApiError } from './interfaces';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Example 1: Simple GET request
|
|
13
|
+
*/
|
|
14
|
+
export async function exampleSimpleGet() {
|
|
15
|
+
try {
|
|
16
|
+
const response = await apiAxiosService.get('https://api.ipify.org?format=json');
|
|
17
|
+
console.log('Your IP:', response.data.ip);
|
|
18
|
+
return response.data;
|
|
19
|
+
} catch (error: any) {
|
|
20
|
+
console.error('Error fetching IP:', error.message);
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Example 2: GET with query parameters
|
|
27
|
+
*/
|
|
28
|
+
export async function exampleGetWithParams() {
|
|
29
|
+
try {
|
|
30
|
+
const response = await apiAxiosService.get('https://api.github.com/search/repositories', {
|
|
31
|
+
params: {
|
|
32
|
+
q: 'kimu',
|
|
33
|
+
sort: 'stars',
|
|
34
|
+
order: 'desc'
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
console.log('Repositories found:', response.data.total_count);
|
|
38
|
+
return response.data;
|
|
39
|
+
} catch (error: any) {
|
|
40
|
+
console.error('Error searching repositories:', error.message);
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Example 3: POST request with data
|
|
47
|
+
*/
|
|
48
|
+
export async function examplePost() {
|
|
49
|
+
try {
|
|
50
|
+
const response = await apiAxiosService.post('https://jsonplaceholder.typicode.com/posts', {
|
|
51
|
+
title: 'My Post',
|
|
52
|
+
body: 'This is the content',
|
|
53
|
+
userId: 1
|
|
54
|
+
});
|
|
55
|
+
console.log('Post created:', response.data);
|
|
56
|
+
return response.data;
|
|
57
|
+
} catch (error: any) {
|
|
58
|
+
console.error('Error creating post:', error.message);
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Example 4: Request with retry logic
|
|
65
|
+
*/
|
|
66
|
+
export async function exampleWithRetry() {
|
|
67
|
+
try {
|
|
68
|
+
const response = await apiAxiosService.request(
|
|
69
|
+
'GET',
|
|
70
|
+
'https://api.ipify.org?format=json',
|
|
71
|
+
null,
|
|
72
|
+
{
|
|
73
|
+
retries: 3,
|
|
74
|
+
retryDelay: 1000
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
console.log('IP (with retry):', response.data.ip);
|
|
78
|
+
return response.data;
|
|
79
|
+
} catch (error: any) {
|
|
80
|
+
console.error('Failed after retries:', error.message);
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Example 5: Cached GET request
|
|
87
|
+
*/
|
|
88
|
+
export async function exampleWithCache() {
|
|
89
|
+
// First call - fetches from server
|
|
90
|
+
console.log('First call (from server)...');
|
|
91
|
+
const response1 = await apiAxiosService.get('https://api.ipify.org?format=json', {
|
|
92
|
+
useCache: true
|
|
93
|
+
});
|
|
94
|
+
console.log('IP:', response1.data.ip);
|
|
95
|
+
|
|
96
|
+
// Second call - returns cached data
|
|
97
|
+
console.log('Second call (from cache)...');
|
|
98
|
+
const response2 = await apiAxiosService.get('https://api.ipify.org?format=json', {
|
|
99
|
+
useCache: true
|
|
100
|
+
});
|
|
101
|
+
console.log('IP:', response2.data.ip);
|
|
102
|
+
|
|
103
|
+
return response2.data;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Example 6: Request with custom headers
|
|
108
|
+
*/
|
|
109
|
+
export async function exampleWithHeaders() {
|
|
110
|
+
try {
|
|
111
|
+
const response = await apiAxiosService.get('https://api.github.com/user', {
|
|
112
|
+
headers: {
|
|
113
|
+
'Authorization': 'Bearer YOUR_TOKEN_HERE',
|
|
114
|
+
'Accept': 'application/vnd.github.v3+json'
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
console.log('User:', response.data.login);
|
|
118
|
+
return response.data;
|
|
119
|
+
} catch (error: any) {
|
|
120
|
+
console.error('Error fetching user:', error.message);
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Example 7: Request with timeout
|
|
127
|
+
*/
|
|
128
|
+
export async function exampleWithTimeout() {
|
|
129
|
+
try {
|
|
130
|
+
const response = await apiAxiosService.get('https://api.ipify.org?format=json', {
|
|
131
|
+
timeout: 5000 // 5 seconds
|
|
132
|
+
});
|
|
133
|
+
console.log('IP:', response.data.ip);
|
|
134
|
+
return response.data;
|
|
135
|
+
} catch (error: any) {
|
|
136
|
+
if (error.message.includes('timeout')) {
|
|
137
|
+
console.error('Request timed out!');
|
|
138
|
+
}
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Example 8: Upload with progress tracking
|
|
145
|
+
*/
|
|
146
|
+
export async function exampleUploadProgress() {
|
|
147
|
+
const formData = new FormData();
|
|
148
|
+
formData.append('file', new Blob(['test content'], { type: 'text/plain' }));
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
const response = await apiAxiosService.post(
|
|
152
|
+
'https://httpbin.org/post',
|
|
153
|
+
formData,
|
|
154
|
+
{
|
|
155
|
+
onUploadProgress: (event) => {
|
|
156
|
+
const percentComplete = Math.round((event.loaded * 100) / (event.total || 1));
|
|
157
|
+
console.log(`Upload progress: ${percentComplete}%`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
);
|
|
161
|
+
console.log('Upload complete:', response.status);
|
|
162
|
+
return response.data;
|
|
163
|
+
} catch (error: any) {
|
|
164
|
+
console.error('Upload failed:', error.message);
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Example 9: Request cancellation
|
|
171
|
+
*/
|
|
172
|
+
export async function exampleCancellation() {
|
|
173
|
+
const cancelToken = apiAxiosService.createCancelToken();
|
|
174
|
+
|
|
175
|
+
// Start the request
|
|
176
|
+
const requestPromise = apiAxiosService.get('https://api.github.com/users/torvalds', {
|
|
177
|
+
axiosConfig: {
|
|
178
|
+
cancelToken: cancelToken.token
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Cancel after 100ms
|
|
183
|
+
setTimeout(() => {
|
|
184
|
+
console.log('Cancelling request...');
|
|
185
|
+
cancelToken.cancel('User cancelled the request');
|
|
186
|
+
}, 100);
|
|
187
|
+
|
|
188
|
+
try {
|
|
189
|
+
const response = await requestPromise;
|
|
190
|
+
console.log('Request completed:', response.data.login);
|
|
191
|
+
return response.data;
|
|
192
|
+
} catch (error: any) {
|
|
193
|
+
if (error.message.includes('cancel')) {
|
|
194
|
+
console.log('Request was cancelled');
|
|
195
|
+
}
|
|
196
|
+
throw error;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Example 10: Using interceptors
|
|
202
|
+
*/
|
|
203
|
+
export function exampleInterceptors() {
|
|
204
|
+
// Add request interceptor to add auth token
|
|
205
|
+
apiAxiosService.addRequestInterceptor(async (config) => {
|
|
206
|
+
console.log('Request interceptor: Adding auth token');
|
|
207
|
+
config.headers = config.headers || {};
|
|
208
|
+
config.headers['X-Custom-Token'] = 'my-token-123';
|
|
209
|
+
return config;
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
// Add response interceptor to log responses
|
|
213
|
+
apiAxiosService.addResponseInterceptor(async (response) => {
|
|
214
|
+
console.log('Response interceptor: Status', response.status);
|
|
215
|
+
return response;
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// Add error interceptor to handle errors globally
|
|
219
|
+
apiAxiosService.addErrorInterceptor(async (error) => {
|
|
220
|
+
console.error('Error interceptor:', error.message);
|
|
221
|
+
if (error.status === 401) {
|
|
222
|
+
console.log('Unauthorized - redirecting to login');
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
console.log('Interceptors configured');
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Example 11: TypeScript with generic types
|
|
231
|
+
*/
|
|
232
|
+
interface User {
|
|
233
|
+
id: number;
|
|
234
|
+
name: string;
|
|
235
|
+
email: string;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export async function exampleWithTypes() {
|
|
239
|
+
try {
|
|
240
|
+
const response = await apiAxiosService.get<User>('https://jsonplaceholder.typicode.com/users/1');
|
|
241
|
+
// response.data is typed as User
|
|
242
|
+
console.log('User name:', response.data.name);
|
|
243
|
+
console.log('User email:', response.data.email);
|
|
244
|
+
return response.data;
|
|
245
|
+
} catch (error: any) {
|
|
246
|
+
console.error('Error fetching user:', error.message);
|
|
247
|
+
throw error;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Example 12: Error handling with detailed information
|
|
253
|
+
*/
|
|
254
|
+
export async function exampleErrorHandling() {
|
|
255
|
+
try {
|
|
256
|
+
const response = await apiAxiosService.get('https://api.github.com/nonexistent');
|
|
257
|
+
return response.data;
|
|
258
|
+
} catch (error: any) {
|
|
259
|
+
const apiError = error as ApiError;
|
|
260
|
+
|
|
261
|
+
console.error('Error details:');
|
|
262
|
+
console.error('- Message:', apiError.message);
|
|
263
|
+
console.error('- Status:', apiError.status);
|
|
264
|
+
console.error('- Response data:', apiError.data);
|
|
265
|
+
console.error('- Original error:', apiError.originalError);
|
|
266
|
+
|
|
267
|
+
throw error;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Example 13: Cache management
|
|
273
|
+
*/
|
|
274
|
+
export async function exampleCacheManagement() {
|
|
275
|
+
// Set cache TTL to 10 minutes
|
|
276
|
+
apiAxiosService.setCacheTTL(10 * 60 * 1000);
|
|
277
|
+
|
|
278
|
+
// Make cached request
|
|
279
|
+
const response1 = await apiAxiosService.get('https://api.ipify.org?format=json', {
|
|
280
|
+
useCache: true
|
|
281
|
+
});
|
|
282
|
+
console.log('First call:', response1.data.ip);
|
|
283
|
+
|
|
284
|
+
// Clear cache
|
|
285
|
+
apiAxiosService.clearCache();
|
|
286
|
+
console.log('Cache cleared');
|
|
287
|
+
|
|
288
|
+
// This will fetch from server again
|
|
289
|
+
const response2 = await apiAxiosService.get('https://api.ipify.org?format=json', {
|
|
290
|
+
useCache: true
|
|
291
|
+
});
|
|
292
|
+
console.log('Second call (after clear):', response2.data.ip);
|
|
293
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Axios Module - Public API
|
|
3
|
+
*
|
|
4
|
+
* Main entry point for the api-axios module.
|
|
5
|
+
*
|
|
6
|
+
* @module api-axios
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export { ApiAxiosService, apiAxiosService } from './api-axios-service';
|
|
10
|
+
export type {
|
|
11
|
+
ApiRequestConfig,
|
|
12
|
+
ApiResponse,
|
|
13
|
+
ApiError,
|
|
14
|
+
HttpMethod,
|
|
15
|
+
RequestInterceptor,
|
|
16
|
+
ResponseInterceptor,
|
|
17
|
+
ErrorInterceptor
|
|
18
|
+
} from './interfaces';
|
|
19
|
+
export { default as ApiAxiosModule } from './module';
|