@hashrytech/quick-components-kit 0.14.3 → 0.15.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/CHANGELOG.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export * from './actions/disable-scroll.js';
|
|
|
12
12
|
export * from './actions/on-keydown.js';
|
|
13
13
|
export * from './actions/lock-scroll.js';
|
|
14
14
|
export * from './actions/scroll-to.js';
|
|
15
|
-
export * from './modules/
|
|
15
|
+
export * from './modules/fetch-client.js';
|
|
16
16
|
export * from './modules/api-proxy.js';
|
|
17
17
|
export * from './modules/crypto.js';
|
|
18
18
|
export * from './modules/problem-details.js';
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ export * from './actions/disable-scroll.js';
|
|
|
14
14
|
export * from './actions/on-keydown.js';
|
|
15
15
|
export * from './actions/lock-scroll.js';
|
|
16
16
|
export * from './actions/scroll-to.js';
|
|
17
|
-
export * from './modules/
|
|
17
|
+
export * from './modules/fetch-client.js';
|
|
18
18
|
export * from './modules/api-proxy.js';
|
|
19
19
|
export * from './modules/crypto.js';
|
|
20
20
|
export * from './modules/problem-details.js';
|
|
@@ -6,7 +6,7 @@ export const defaultResponseHeaders = ['content-type', 'content-length', 'cache-
|
|
|
6
6
|
*/
|
|
7
7
|
export function createProxyHandlers(config) {
|
|
8
8
|
if (config.debug)
|
|
9
|
-
console.debug("Creating proxy handlers with config:", config);
|
|
9
|
+
console.debug("API Proxy: Creating proxy handlers with config:", config);
|
|
10
10
|
async function handler(event) {
|
|
11
11
|
const path = event.params.path;
|
|
12
12
|
const queryString = event.url.searchParams.toString();
|
|
@@ -14,7 +14,7 @@ export function createProxyHandlers(config) {
|
|
|
14
14
|
const fullPath = `/${path}${slash}${queryString ? `?${queryString}` : ''}`;
|
|
15
15
|
const url = `${config.host}${fullPath}`;
|
|
16
16
|
if (config.debug)
|
|
17
|
-
console.debug(`Proxying request to: ${url}`);
|
|
17
|
+
console.debug(`API Proxy: Proxying ${event.request.method} request to: ${url}`);
|
|
18
18
|
// Validate the path against allowed prefixes if specified
|
|
19
19
|
if (config.allowedPaths && config.allowedPaths.length > 0) {
|
|
20
20
|
const isAllowed = config.allowedPaths.some((prefix) => path?.startsWith(prefix));
|
|
@@ -15,19 +15,21 @@ export interface AutoRedirectRule {
|
|
|
15
15
|
errorValue?: string;
|
|
16
16
|
redirectTo: string;
|
|
17
17
|
}
|
|
18
|
-
export type
|
|
18
|
+
export type FetchResponse<T> = {
|
|
19
19
|
ok: boolean;
|
|
20
20
|
status: number;
|
|
21
21
|
data?: T;
|
|
22
22
|
error?: ProblemDetail;
|
|
23
23
|
};
|
|
24
|
-
export interface
|
|
24
|
+
export interface FetchClientConfig {
|
|
25
25
|
/** The base URL for your API (e.g., 'https://api.yourapi.com/v1'). */
|
|
26
26
|
baseURL: string;
|
|
27
27
|
/** Default headers to be sent with every request. */
|
|
28
28
|
defaultHeaders?: HeadersInit;
|
|
29
29
|
/** Specified redirects if the response matches the specified rules. */
|
|
30
30
|
autoRedirects?: AutoRedirectRule[];
|
|
31
|
+
/** Optional flag to enable debug logging */
|
|
32
|
+
debug?: boolean;
|
|
31
33
|
}
|
|
32
34
|
export interface RequestOptions extends RequestInit {
|
|
33
35
|
/** If true, the Authorization header will not be added to this request. */
|
|
@@ -55,12 +57,12 @@ export type ErrorHandler = (error: Error) => Promise<void> | void;
|
|
|
55
57
|
* Custom error class for API responses.
|
|
56
58
|
* Provides access to the HTTP status code.
|
|
57
59
|
*/
|
|
58
|
-
export declare class
|
|
60
|
+
export declare class FetchError extends Error {
|
|
59
61
|
status: number;
|
|
60
62
|
json?: object;
|
|
61
63
|
constructor(message: string, status: number, json?: object);
|
|
62
64
|
}
|
|
63
|
-
export interface
|
|
65
|
+
export interface FetchClientEvents {
|
|
64
66
|
onRequest?: (request: Request) => void;
|
|
65
67
|
onResponse?: (response: Response) => void;
|
|
66
68
|
onError?: (error: Error) => void;
|
|
@@ -78,8 +80,9 @@ export interface ApiClientEvents {
|
|
|
78
80
|
* - Supports file downloads (returns Blob).
|
|
79
81
|
* - Integrates with SvelteKit's `fetch` for server-side benefits.
|
|
80
82
|
*/
|
|
81
|
-
export declare class
|
|
83
|
+
export declare class FetchClient {
|
|
82
84
|
private baseURL;
|
|
85
|
+
private debug;
|
|
83
86
|
private defaultHeaders;
|
|
84
87
|
private accessToken;
|
|
85
88
|
private fetchInstance?;
|
|
@@ -92,8 +95,8 @@ export declare class ApiClient {
|
|
|
92
95
|
* Creates an instance of ApiClient.
|
|
93
96
|
* @param config - Configuration for the API client.
|
|
94
97
|
*/
|
|
95
|
-
constructor(config:
|
|
96
|
-
events?:
|
|
98
|
+
constructor(config: FetchClientConfig & {
|
|
99
|
+
events?: FetchClientEvents;
|
|
97
100
|
});
|
|
98
101
|
/**
|
|
99
102
|
* Sets the Bearer token for client-side requests.
|
|
@@ -122,7 +125,7 @@ export declare class ApiClient {
|
|
|
122
125
|
* @param handler - A function that takes an `Error` object.
|
|
123
126
|
*/
|
|
124
127
|
addErrorHandler(handler: ErrorHandler): void;
|
|
125
|
-
setEventHooks(events: Partial<
|
|
128
|
+
setEventHooks(events: Partial<FetchClientEvents>): void;
|
|
126
129
|
/**
|
|
127
130
|
* Processes the request, applying default headers, auth token, and request interceptors.
|
|
128
131
|
* @param endpoint - The API endpoint (e.g., '/products', '/users/123').
|
|
@@ -155,7 +158,7 @@ export declare class ApiClient {
|
|
|
155
158
|
* @returns A Promise resolving to the parsed response data or raw Response/Blob.
|
|
156
159
|
* @template T - Expected type of the response data.
|
|
157
160
|
*/
|
|
158
|
-
request<T>(endpoint: string, method: string, body: BodyInit | object | null | undefined, options?: RequestOptions): Promise<
|
|
161
|
+
request<T>(endpoint: string, method: string, body: BodyInit | object | null | undefined, options?: RequestOptions): Promise<FetchResponse<T>>;
|
|
159
162
|
private evaluateRedirect;
|
|
160
163
|
/**
|
|
161
164
|
* Sends a GET request to the specified API endpoint.
|
|
@@ -165,7 +168,7 @@ export declare class ApiClient {
|
|
|
165
168
|
* @returns A Promise resolving to the parsed response or raw Response object.
|
|
166
169
|
* @template T - Expected shape of the JSON response.
|
|
167
170
|
*/
|
|
168
|
-
get<T>(endpoint: string, options?: RequestOptions): Promise<
|
|
171
|
+
get<T>(endpoint: string, options?: RequestOptions): Promise<FetchResponse<T>>;
|
|
169
172
|
/**
|
|
170
173
|
* Sends a POST request to the specified API endpoint.
|
|
171
174
|
*
|
|
@@ -175,7 +178,7 @@ export declare class ApiClient {
|
|
|
175
178
|
* @returns A Promise resolving to the parsed response or raw Response object.
|
|
176
179
|
* @template T - Expected shape of the JSON response.
|
|
177
180
|
*/
|
|
178
|
-
post<T>(endpoint: string, data?: BodyInit | object | null, options?: RequestOptions): Promise<
|
|
181
|
+
post<T>(endpoint: string, data?: BodyInit | object | null, options?: RequestOptions): Promise<FetchResponse<T>>;
|
|
179
182
|
/**
|
|
180
183
|
* Sends a PUT request to the specified API endpoint.
|
|
181
184
|
* Typically used for full resource replacement.
|
|
@@ -186,7 +189,7 @@ export declare class ApiClient {
|
|
|
186
189
|
* @returns A Promise resolving to the parsed response or raw Response object.
|
|
187
190
|
* @template T - Expected shape of the JSON response.
|
|
188
191
|
*/
|
|
189
|
-
put<T>(endpoint: string, data?: BodyInit | object | null, options?: RequestOptions): Promise<
|
|
192
|
+
put<T>(endpoint: string, data?: BodyInit | object | null, options?: RequestOptions): Promise<FetchResponse<T>>;
|
|
190
193
|
/**
|
|
191
194
|
* Sends a PATCH request to the specified API endpoint.
|
|
192
195
|
* Typically used for partial updates.
|
|
@@ -197,7 +200,7 @@ export declare class ApiClient {
|
|
|
197
200
|
* @returns A Promise resolving to the parsed response or raw Response object.
|
|
198
201
|
* @template T - Expected shape of the JSON response.
|
|
199
202
|
*/
|
|
200
|
-
patch<T>(endpoint: string, data?: BodyInit | object | null, options?: RequestOptions): Promise<
|
|
203
|
+
patch<T>(endpoint: string, data?: BodyInit | object | null, options?: RequestOptions): Promise<FetchResponse<T>>;
|
|
201
204
|
/**
|
|
202
205
|
* Sends a DELETE request to the specified API endpoint.
|
|
203
206
|
*
|
|
@@ -206,7 +209,7 @@ export declare class ApiClient {
|
|
|
206
209
|
* @returns A Promise resolving to the parsed response or raw Response object.
|
|
207
210
|
* @template T - Expected shape of the JSON response (if any).
|
|
208
211
|
*/
|
|
209
|
-
delete<T>(endpoint: string, options?: RequestOptions): Promise<
|
|
212
|
+
delete<T>(endpoint: string, options?: RequestOptions): Promise<FetchResponse<T>>;
|
|
210
213
|
/**
|
|
211
214
|
* Handles file uploads.
|
|
212
215
|
* @param endpoint - The API endpoint for file upload.
|
|
@@ -216,7 +219,7 @@ export declare class ApiClient {
|
|
|
216
219
|
* @returns A Promise resolving to the parsed response data.
|
|
217
220
|
* @template T - Expected type of the response data after upload.
|
|
218
221
|
*/
|
|
219
|
-
uploadFile<T>(endpoint: string, file: File | Blob | FormData, fieldName?: string, options?: RequestOptions): Promise<
|
|
222
|
+
uploadFile<T>(endpoint: string, file: File | Blob | FormData, fieldName?: string, options?: RequestOptions): Promise<FetchResponse<T>>;
|
|
220
223
|
/**
|
|
221
224
|
* Handles file downloads.
|
|
222
225
|
* @param endpoint - The API endpoint for file download.
|
|
@@ -6,12 +6,12 @@ import { browser } from "$app/environment";
|
|
|
6
6
|
* Custom error class for API responses.
|
|
7
7
|
* Provides access to the HTTP status code.
|
|
8
8
|
*/
|
|
9
|
-
export class
|
|
9
|
+
export class FetchError extends Error {
|
|
10
10
|
status;
|
|
11
11
|
json;
|
|
12
12
|
constructor(message, status, json) {
|
|
13
13
|
super(message);
|
|
14
|
-
this.name = '
|
|
14
|
+
this.name = 'FetchError';
|
|
15
15
|
this.status = status;
|
|
16
16
|
this.json = json;
|
|
17
17
|
}
|
|
@@ -29,8 +29,9 @@ export class ApiError extends Error {
|
|
|
29
29
|
* - Supports file downloads (returns Blob).
|
|
30
30
|
* - Integrates with SvelteKit's `fetch` for server-side benefits.
|
|
31
31
|
*/
|
|
32
|
-
export class
|
|
32
|
+
export class FetchClient {
|
|
33
33
|
baseURL;
|
|
34
|
+
debug = false;
|
|
34
35
|
defaultHeaders;
|
|
35
36
|
accessToken;
|
|
36
37
|
fetchInstance;
|
|
@@ -47,6 +48,7 @@ export class ApiClient {
|
|
|
47
48
|
this.baseURL = config.baseURL;
|
|
48
49
|
this.defaultHeaders = config.defaultHeaders || { 'Content-Type': 'application/json' };
|
|
49
50
|
this.autoRedirects = config.autoRedirects || [];
|
|
51
|
+
this.debug = config.debug || false;
|
|
50
52
|
}
|
|
51
53
|
/**
|
|
52
54
|
* Sets the Bearer token for client-side requests.
|
|
@@ -98,6 +100,8 @@ export class ApiClient {
|
|
|
98
100
|
*/
|
|
99
101
|
async processRequest(endpoint, method, body, options) {
|
|
100
102
|
const url = this.baseURL ? new URL(endpoint, this.baseURL).toString() : endpoint; // Resolve endpoint relative to baseURL
|
|
103
|
+
if (this.debug)
|
|
104
|
+
console.debug(`Fetch Client: Processing request to ${url} with method ${method}`);
|
|
101
105
|
const requestHeaders = new Headers(this.defaultHeaders);
|
|
102
106
|
// Merge custom headers from options using Headers constructor for robustness
|
|
103
107
|
if (options.headers) {
|
|
@@ -172,7 +176,7 @@ export class ApiClient {
|
|
|
172
176
|
// If response is not JSON, use default status text or log parsing error
|
|
173
177
|
console.warn('API Client: Failed to parse error response as JSON.', e);
|
|
174
178
|
}
|
|
175
|
-
throw new
|
|
179
|
+
throw new FetchError(errorMessage, response.status, errorJson);
|
|
176
180
|
}
|
|
177
181
|
switch (options.responseType) {
|
|
178
182
|
case 'text':
|
|
@@ -224,6 +228,8 @@ export class ApiClient {
|
|
|
224
228
|
* @template T - Expected type of the response data.
|
|
225
229
|
*/
|
|
226
230
|
async request(endpoint, method, body, options = {}) {
|
|
231
|
+
if (this.debug)
|
|
232
|
+
console.debug(`Fetch Client: ${options.fetchInstance || this.fetchInstance ? "Using sveltekit fetch instance..." : "Using default fetch instance"}`);
|
|
227
233
|
const currentFetch = options.fetchInstance || this.fetchInstance || fetch; // Use provided fetch first then the class instance fetch or the global fetch if not specified.
|
|
228
234
|
try {
|
|
229
235
|
const request = await this.processRequest(endpoint, method, body, options);
|
|
@@ -236,8 +242,10 @@ export class ApiClient {
|
|
|
236
242
|
};
|
|
237
243
|
}
|
|
238
244
|
catch (error) {
|
|
245
|
+
if (this.debug)
|
|
246
|
+
console.debug(`Fetch Client: Error occurred while processing request to ${endpoint} with method ${method}`, error);
|
|
239
247
|
await this.handleError(error);
|
|
240
|
-
const isApiError = error instanceof
|
|
248
|
+
const isApiError = error instanceof FetchError;
|
|
241
249
|
const status = isApiError ? error.status : 503; // Service Unavailable fallback
|
|
242
250
|
const message = error instanceof Error ? error.message : 'Unexpected error occurred';
|
|
243
251
|
const errorObj = isApiError && error.json ? error.json : getProblemDetail({ status, title: "Server fetch error", type: "/exceptions/fetch-error/", detail: message });
|
|
@@ -254,6 +262,8 @@ export class ApiClient {
|
|
|
254
262
|
for (const rule of this.autoRedirects) {
|
|
255
263
|
// Checks if the error matches the redirect rule value can be undefined to match if no value is specified.
|
|
256
264
|
if (status === rule.status && rule.errorKey in errorObj && (rule.errorValue === undefined || errorObj[rule.errorKey] === rule.errorValue)) {
|
|
265
|
+
if (this.debug)
|
|
266
|
+
console.debug(`Fetch Client: Redirecting to ${rule.redirectTo} for status ${status} with error key "${rule.errorKey}" and value "${rule.errorValue}"`);
|
|
257
267
|
if (browser) {
|
|
258
268
|
// Client-side redirect
|
|
259
269
|
import('$app/navigation').then(({ goto }) => {
|
|
@@ -435,7 +445,7 @@ export class ApiClient {
|
|
|
435
445
|
}
|
|
436
446
|
}
|
|
437
447
|
else {
|
|
438
|
-
reject(new
|
|
448
|
+
reject(new FetchError(xhr.statusText, xhr.status));
|
|
439
449
|
}
|
|
440
450
|
};
|
|
441
451
|
xhr.onerror = () => reject(new Error('Upload failed'));
|