@hichchi/ngx-utils 0.0.1-alpha.1 → 0.0.1-alpha.2

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.
@@ -1,115 +1,503 @@
1
- import * as i0 from '@angular/core';
2
- import { inject, Injectable, computed } from '@angular/core';
3
- import { signalStore, withState, withComputed, withMethods, patchState } from '@ngrx/signals';
4
- import { withStorageSync } from '@angular-architects/ngrx-toolkit';
5
- import { take, map, tap, catchError, EMPTY, ReplaySubject, throwError, switchMap, filter } from 'rxjs';
6
- import { HttpClient } from '@angular/common/http';
7
- import { AuthEndpoint, AuthErrorResponseCode } from '@hichchi/nest-connector/auth';
8
- import { Endpoint, HttpClientErrorStatus } from '@hichchi/nest-connector';
9
- import { Router } from '@angular/router';
1
+ import { FormGroup, FormArray } from '@angular/forms';
10
2
 
11
3
  // noinspection JSUnusedGlobalSymbols
12
- class AuthService {
13
- http = inject(HttpClient);
14
- signIn(dto) {
15
- return this.http.post(`${Endpoint.AUTH}/${AuthEndpoint.SIGN_IN}`, dto).pipe(take(1), map(res => ({
16
- ...res,
17
- accessTokenExpiresOn: new Date(res.accessTokenExpiresOn),
18
- refreshTokenExpiresOn: new Date(res.accessTokenExpiresOn),
19
- })));
20
- }
21
- authenticateSocial(accessToken) {
22
- return this.http
23
- .post(`${Endpoint.AUTH}/${AuthEndpoint.AUTHENTICATE_SOCIAL}`, {
24
- accessToken,
25
- })
26
- .pipe(take(1), map(res => ({
27
- ...res,
28
- accessTokenExpiresOn: new Date(res.accessTokenExpiresOn),
29
- refreshTokenExpiresOn: new Date(res.accessTokenExpiresOn),
30
- })));
31
- }
32
- signUp(dto) {
33
- return this.http.post(`${Endpoint.AUTH}/${AuthEndpoint.SIGN_UP}`, dto).pipe(take(1));
34
- }
35
- refreshToken(refreshToken) {
36
- return this.http
37
- .post(`${Endpoint.AUTH}/${AuthEndpoint.REFRESH_TOKEN}`, {
38
- refreshToken,
39
- })
40
- .pipe(take(1));
41
- }
42
- signOut() {
43
- // this.app.startSpinner();
44
- return this.http.post(`${Endpoint.AUTH}/${AuthEndpoint.SIGN_OUT}`, {}).pipe(take(1));
4
+ /**
5
+ * Recursively marks invalid form controls as dirty and touched
6
+ *
7
+ * This utility function traverses a form hierarchy and marks all invalid controls
8
+ * as dirty and touched, which triggers validation error display in the UI. It works
9
+ * recursively through nested FormGroups and FormArrays to ensure all invalid
10
+ * controls are properly marked for error display.
11
+ *
12
+ * The function is particularly useful when you want to show all validation errors
13
+ * at once, such as when a user attempts to submit a form. It only marks invalid
14
+ * controls, leaving valid controls unchanged.
15
+ *
16
+ * Key features:
17
+ * - Recursive traversal of form hierarchy
18
+ * - Only marks invalid controls as dirty/touched
19
+ * - Handles nested FormGroups and FormArrays
20
+ * - Updates validation state after marking controls
21
+ * - Non-destructive (doesn't affect valid controls)
22
+ *
23
+ * @param form - The FormGroup to process recursively
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * // Mark all invalid controls in a form for error display
28
+ * export class UserFormComponent {
29
+ * userForm = this.fb.group({
30
+ * name: ['', Validators.required],
31
+ * email: ['', [Validators.required, Validators.email]],
32
+ * address: this.fb.group({
33
+ * street: ['', Validators.required],
34
+ * city: ['', Validators.required]
35
+ * })
36
+ * });
37
+ *
38
+ * onSubmit() {
39
+ * if (this.userForm.invalid) {
40
+ * // Mark all invalid fields to show errors
41
+ * markFormDirty(this.userForm);
42
+ * return;
43
+ * }
44
+ * // Process valid form...
45
+ * }
46
+ * }
47
+ * ```
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * // Using with form arrays
52
+ * export class DynamicFormComponent {
53
+ * form = this.fb.group({
54
+ * items: this.fb.array([
55
+ * this.fb.group({
56
+ * name: ['', Validators.required],
57
+ * quantity: [0, Validators.min(1)]
58
+ * })
59
+ * ])
60
+ * });
61
+ *
62
+ * validateAll() {
63
+ * markFormDirty(this.form);
64
+ * // All invalid controls in the array will be marked
65
+ * }
66
+ * }
67
+ * ```
68
+ *
69
+ * @see {@link FormGroup} Angular reactive form group
70
+ * @see {@link FormArray} Angular reactive form array
71
+ * @see {@link validatedFormData} Function that uses this utility for validation
72
+ */
73
+ function markFormDirty(form) {
74
+ const markDirty = (form) => {
75
+ Object.keys(form.controls).forEach(field => {
76
+ const control = form.get(field);
77
+ if (control?.invalid) {
78
+ control?.markAsDirty({ onlySelf: true });
79
+ control?.markAsTouched({ onlySelf: true });
80
+ control.updateValueAndValidity({ onlySelf: true });
81
+ }
82
+ if (control instanceof FormGroup) {
83
+ markDirty(control);
84
+ }
85
+ if (control instanceof FormArray) {
86
+ control.controls.forEach((control) => {
87
+ markDirty(control);
88
+ });
89
+ }
90
+ });
91
+ };
92
+ return markDirty(form);
93
+ }
94
+ /**
95
+ * Removes null values from an object by deleting properties with null values
96
+ *
97
+ * This utility function creates a new object with all null properties removed.
98
+ * It's particularly useful when working with form data where null values should
99
+ * be omitted from API requests or when preparing data for processing that doesn't
100
+ * handle null values well.
101
+ *
102
+ * The function performs a shallow copy of the object and removes any properties
103
+ * that have null values. Properties with undefined values are preserved, as they
104
+ * represent different semantic meaning (missing vs explicitly null).
105
+ *
106
+ * @template T - The type of the object being processed
107
+ * @param obj - Object that may contain null values to be removed
108
+ * @returns A new object with null properties removed
109
+ *
110
+ * @example
111
+ * ```typescript
112
+ * // Remove null values from form data
113
+ * const formData = {
114
+ * name: 'John Doe',
115
+ * email: 'john@example.com',
116
+ * phone: null,
117
+ * address: null,
118
+ * age: 30
119
+ * };
120
+ *
121
+ * const cleanData = replaceNulls(formData);
122
+ * // Result: { name: 'John Doe', email: 'john@example.com', age: 30 }
123
+ * ```
124
+ *
125
+ * @example
126
+ * ```typescript
127
+ * // Using with API request data
128
+ * interface UserUpdate {
129
+ * name?: string | null;
130
+ * email?: string | null;
131
+ * phone?: string | null;
132
+ * }
133
+ *
134
+ * const updateData: UserUpdate = {
135
+ * name: 'Jane Smith',
136
+ * email: null, // Don't update email
137
+ * phone: '555-1234'
138
+ * };
139
+ *
140
+ * const apiPayload = replaceNulls(updateData);
141
+ * // Result: { name: 'Jane Smith', phone: '555-1234' }
142
+ * // API receives only the fields to update
143
+ * ```
144
+ *
145
+ * @example
146
+ * ```typescript
147
+ * // Difference between null and undefined
148
+ * const data = {
149
+ * field1: 'value',
150
+ * field2: null, // Will be removed
151
+ * field3: undefined // Will be preserved
152
+ * };
153
+ *
154
+ * const result = replaceNulls(data);
155
+ * // Result: { field1: 'value', field3: undefined }
156
+ * ```
157
+ *
158
+ * @see {@link validatedFormData} Function that uses this utility to clean form data
159
+ */
160
+ function replaceNulls(obj) {
161
+ const result = { ...obj };
162
+ for (const key in result) {
163
+ if (result[key] === null) {
164
+ delete result[key];
165
+ }
45
166
  }
46
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.7", ngImport: i0, type: AuthService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
47
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.7", ngImport: i0, type: AuthService, providedIn: "root" });
167
+ return result;
48
168
  }
49
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.7", ngImport: i0, type: AuthService, decorators: [{
50
- type: Injectable,
51
- args: [{
52
- providedIn: "root",
53
- }]
54
- }] });
55
-
56
- /* eslint-disable */
57
- // noinspection JSUnusedGlobalSymbols
58
- const initialState = {
59
- signedIn: false,
60
- sessionId: null,
61
- user: null,
62
- accessToken: null,
63
- refreshToken: null,
64
- accessTokenExpiresOn: null,
65
- refreshTokenExpiresOn: null,
66
- };
67
- const AuthState = signalStore({ providedIn: "root" }, withState(initialState), withStorageSync({ key: "auth" }), withComputed(({ accessToken, user }) => ({
68
- hasAccessToken: computed(() => Boolean(accessToken())),
69
- role: computed(() => user()?.role),
70
- emailVerified: computed(() => Boolean(user()?.emailVerified)),
71
- })), withMethods((store, router = inject(Router), authService = inject(AuthService)) => ({
72
- reset() {
73
- patchState(store, initialState);
74
- },
75
- setTokens(tokenResponse) {
76
- const { accessToken, refreshToken, accessTokenExpiresOn, refreshTokenExpiresOn } = tokenResponse;
77
- patchState(store, state => ({
78
- ...state,
79
- accessToken,
80
- refreshToken,
81
- accessTokenExpiresOn,
82
- refreshTokenExpiresOn,
83
- }));
84
- },
85
- signIn(signInBody, redirect) {
86
- return authService.signIn(signInBody).pipe(tap((res) => {
87
- patchState(store, { ...res, signedIn: true });
88
- void router.navigateByUrl(typeof redirect === "string" ? redirect : redirect(res));
89
- }));
90
- },
91
- authenticateSocial: (accessToken, redirect) => {
92
- return authService.authenticateSocial(accessToken).pipe(tap((res) => {
93
- patchState(store, { ...res, signedIn: Boolean(res.user.role) });
94
- void router.navigateByUrl(typeof redirect === "string" ? redirect : redirect(res));
95
- }), catchError(() => EMPTY));
96
- },
97
- signOut: (redirect) => {
98
- return authService.signOut().pipe(tap({
99
- next: () => {
100
- patchState(store, initialState);
101
- void router.navigateByUrl(redirect);
102
- },
103
- }), catchError(() => EMPTY));
104
- },
105
- })));
106
-
107
- // noinspection JSUnusedGlobalSymbols
108
- function utils() {
109
- return "Hello World";
169
+ /**
170
+ * Validates a form and returns clean data if valid, or null if invalid
171
+ *
172
+ * This utility function combines form validation with data cleaning in a single operation.
173
+ * It first marks all invalid controls as dirty (to show validation errors), then checks
174
+ * if the form is valid. If valid, it returns the form data with null values removed.
175
+ * If invalid, it returns null.
176
+ *
177
+ * This is particularly useful for form submission handlers where you want to:
178
+ * 1. Show all validation errors if the form is invalid
179
+ * 2. Get clean, validated data if the form is valid
180
+ * 3. Handle both cases with a simple null check
181
+ *
182
+ * The function uses the DataFormGroup type to ensure type safety between the form
183
+ * structure and the returned data type.
184
+ *
185
+ * @template T - The type of the data structure represented by the form
186
+ * @param form - The DataFormGroup to validate and extract data from
187
+ * @returns The validated and cleaned form data, or null if the form is invalid
188
+ *
189
+ * @example
190
+ * ```typescript
191
+ * // Basic form validation and submission
192
+ * export class UserFormComponent {
193
+ * userForm: DataFormGroup<UserData> = this.fb.group({
194
+ * name: ['', Validators.required],
195
+ * email: ['', [Validators.required, Validators.email]],
196
+ * phone: [null], // Optional field
197
+ * age: [null, Validators.min(18)]
198
+ * });
199
+ *
200
+ * onSubmit() {
201
+ * const validData = validatedFormData(this.userForm);
202
+ * if (validData) {
203
+ * // Form is valid, submit clean data
204
+ * this.userService.createUser(validData);
205
+ * } else {
206
+ * // Form is invalid, errors are now visible
207
+ * console.log('Please fix form errors');
208
+ * }
209
+ * }
210
+ * }
211
+ * ```
212
+ *
213
+ * @example
214
+ * ```typescript
215
+ * // Using with async operations
216
+ * export class ProfileComponent {
217
+ * profileForm: DataFormGroup<ProfileUpdate> = this.fb.group({
218
+ * firstName: ['', Validators.required],
219
+ * lastName: ['', Validators.required],
220
+ * bio: [null], // Optional
221
+ * website: [null, Validators.pattern(/^https?:\/\/.+/)]
222
+ * });
223
+ *
224
+ * async updateProfile() {
225
+ * const updateData = validatedFormData(this.profileForm);
226
+ * if (!updateData) {
227
+ * this.showErrorMessage('Please fix the form errors');
228
+ * return;
229
+ * }
230
+ *
231
+ * try {
232
+ * await this.profileService.update(updateData);
233
+ * this.showSuccessMessage('Profile updated successfully');
234
+ * } catch (error) {
235
+ * this.showErrorMessage('Failed to update profile');
236
+ * }
237
+ * }
238
+ * }
239
+ * ```
240
+ *
241
+ * @example
242
+ * ```typescript
243
+ * // Type-safe form data extraction
244
+ * interface ContactForm {
245
+ * name: string;
246
+ * email: string;
247
+ * message: string;
248
+ * newsletter?: boolean;
249
+ * }
250
+ *
251
+ * const contactForm: DataFormGroup<ContactForm> = this.fb.group({
252
+ * name: ['', Validators.required],
253
+ * email: ['', [Validators.required, Validators.email]],
254
+ * message: ['', [Validators.required, Validators.minLength(10)]],
255
+ * newsletter: [null]
256
+ * });
257
+ *
258
+ * const formData = validatedFormData(contactForm);
259
+ * if (formData) {
260
+ * // TypeScript knows formData is ContactForm with null values removed
261
+ * console.log(formData.name); // string
262
+ * console.log(formData.email); // string
263
+ * console.log(formData.newsletter); // boolean | undefined (null was removed)
264
+ * }
265
+ * ```
266
+ *
267
+ * @see {@link DataFormGroup} Type-safe form group interface
268
+ * @see {@link markFormDirty} Function used internally to mark invalid controls
269
+ * @see {@link replaceNulls} Function used internally to clean the data
270
+ */
271
+ function validatedFormData(form) {
272
+ markFormDirty(form);
273
+ if (form.invalid)
274
+ return null;
275
+ return replaceNulls(form.value);
276
+ }
277
+ /**
278
+ * Creates a FormData object from a plain JavaScript object
279
+ *
280
+ * This utility function converts a plain object into a FormData object, which is
281
+ * required for multipart/form-data HTTP requests, particularly when uploading files
282
+ * or sending form data that includes binary content. The function handles different
283
+ * data types appropriately, preserving file names for File objects and converting
284
+ * other values to strings.
285
+ *
286
+ * The function is particularly useful when working with Angular forms that need to
287
+ * submit both regular form fields and file uploads in a single request. It automatically
288
+ * handles the conversion of various data types to the format expected by FormData.
289
+ *
290
+ * Key features:
291
+ * - Preserves original file names for File objects
292
+ * - Converts primitive values to strings
293
+ * - Maintains type safety with generic constraints
294
+ * - Handles Blob objects correctly
295
+ * - Creates multipart/form-data compatible output
296
+ *
297
+ * @template T - Object type with string keys and values that can be converted to FormData
298
+ * @param data - Object containing the data to convert to FormData
299
+ * @returns A FormData object ready for HTTP submission
300
+ *
301
+ * @example
302
+ * ```typescript
303
+ * // Basic usage with mixed data types
304
+ * const formData = createFormData({
305
+ * name: 'John Doe',
306
+ * age: 30,
307
+ * isActive: true,
308
+ * avatar: fileInput.files[0] // File object
309
+ * });
310
+ *
311
+ * // Submit via HTTP
312
+ * this.http.post('/api/users', formData).subscribe();
313
+ * ```
314
+ *
315
+ * @example
316
+ * ```typescript
317
+ * // File upload with metadata
318
+ * export class FileUploadComponent {
319
+ * onFileUpload(file: File, description: string, isPublic: boolean) {
320
+ * const uploadData = createFormData({
321
+ * file: file,
322
+ * description: description,
323
+ * isPublic: isPublic,
324
+ * uploadedAt: new Date().toISOString()
325
+ * });
326
+ *
327
+ * this.fileService.upload(uploadData).subscribe({
328
+ * next: (response) => console.log('Upload successful'),
329
+ * error: (error) => console.error('Upload failed', error)
330
+ * });
331
+ * }
332
+ * }
333
+ * ```
334
+ *
335
+ * @example
336
+ * ```typescript
337
+ * // Using with form validation
338
+ * export class ProfileFormComponent {
339
+ * profileForm = this.fb.group({
340
+ * name: ['', Validators.required],
341
+ * bio: [''],
342
+ * profilePicture: [null]
343
+ * });
344
+ *
345
+ * onSubmit() {
346
+ * const formValue = validatedFormData(this.profileForm);
347
+ * if (!formValue) return;
348
+ *
349
+ * // Convert to FormData for file upload
350
+ * const formData = createFormData({
351
+ * name: formValue.name,
352
+ * bio: formValue.bio || '',
353
+ * profilePicture: formValue.profilePicture,
354
+ * timestamp: Date.now()
355
+ * });
356
+ *
357
+ * this.profileService.updateProfile(formData);
358
+ * }
359
+ * }
360
+ * ```
361
+ *
362
+ * @example
363
+ * ```typescript
364
+ * // Multiple file upload
365
+ * interface UploadRequest {
366
+ * title: string;
367
+ * category: string;
368
+ * document: File;
369
+ * thumbnail: File;
370
+ * isPrivate: boolean;
371
+ * }
372
+ *
373
+ * const uploadRequest: UploadRequest = {
374
+ * title: 'My Document',
375
+ * category: 'reports',
376
+ * document: documentFile,
377
+ * thumbnail: thumbnailFile,
378
+ * isPrivate: false
379
+ * };
380
+ *
381
+ * const formData = createFormData(uploadRequest);
382
+ * // FormData will contain:
383
+ * // - title: "My Document"
384
+ * // - category: "reports"
385
+ * // - document: [File object with original name]
386
+ * // - thumbnail: [File object with original name]
387
+ * // - isPrivate: "false"
388
+ * ```
389
+ *
390
+ * @see {@link FormData} Web API interface for form data
391
+ * @see {@link File} Web API interface for file objects
392
+ * @see {@link Blob} Web API interface for binary data
393
+ * @see {@link validatedFormData} Function for getting validated form data to use with this utility
394
+ */
395
+ function createFormData(data) {
396
+ const formData = new FormData();
397
+ Object.entries(data).forEach(([key, value]) => {
398
+ if (value instanceof File) {
399
+ formData.append(key, value, value.name);
400
+ }
401
+ else {
402
+ formData.append(key, String(value));
403
+ }
404
+ });
405
+ return formData;
110
406
  }
111
407
 
112
408
  // noinspection JSUnusedGlobalSymbols
409
+ /**
410
+ * Creates an HTTP interceptor that automatically prepends a base API URL to relative requests
411
+ *
412
+ * This interceptor factory function creates an HTTP interceptor that automatically adds a base API URL
413
+ * to requests that don't already have a complete URL. It's designed to simplify API calls by allowing
414
+ * developers to use relative URLs throughout their application while ensuring all requests are properly
415
+ * routed to the correct API base URL.
416
+ *
417
+ * The interceptor intelligently handles different URL formats:
418
+ * - Requests that already start with the provided API base URL are passed through unchanged
419
+ * - Requests that start with "http" (absolute URLs) are passed through unchanged
420
+ * - All other requests (relative URLs) have the API base URL prepended
421
+ *
422
+ * This is particularly useful in Angular applications where you want to centralize API URL management
423
+ * and avoid repeating the base URL in every HTTP service call.
424
+ *
425
+ * @param apiBase - The base API URL to prepend to relative requests (without trailing slash)
426
+ * @returns An HttpInterceptorFn that can be used in Angular HTTP interceptor configuration
427
+ *
428
+ * @example
429
+ * ```typescript
430
+ * // Basic usage in app configuration
431
+ * export const appConfig: ApplicationConfig = {
432
+ * providers: [
433
+ * provideHttpClient(
434
+ * withInterceptors([
435
+ * apiUrlInterceptor('https://api.example.com')
436
+ * ])
437
+ * )
438
+ * ]
439
+ * };
440
+ * ```
441
+ *
442
+ * @example
443
+ * ```typescript
444
+ * // Using with environment configuration
445
+ * import { environment } from '../environments/environment';
446
+ *
447
+ * export const appConfig: ApplicationConfig = {
448
+ * providers: [
449
+ * provideHttpClient(
450
+ * withInterceptors([
451
+ * apiUrlInterceptor(environment.apiUrl)
452
+ * ])
453
+ * )
454
+ * ]
455
+ * };
456
+ * ```
457
+ *
458
+ * @example
459
+ * ```typescript
460
+ * // In a service, you can now use relative URLs
461
+ * @Injectable()
462
+ * export class UserService {
463
+ * constructor(private http: HttpClient) {}
464
+ *
465
+ * getUsers() {
466
+ * // This will become: https://api.example.com/users
467
+ * return this.http.get('users');
468
+ * }
469
+ *
470
+ * getUserById(id: string) {
471
+ * // This will become: https://api.example.com/users/123
472
+ * return this.http.get(`users/${id}`);
473
+ * }
474
+ *
475
+ * // Absolute URLs are not modified
476
+ * getExternalData() {
477
+ * // This remains: https://external-api.com/data
478
+ * return this.http.get('https://external-api.com/data');
479
+ * }
480
+ * }
481
+ * ```
482
+ *
483
+ * @example
484
+ * ```typescript
485
+ * // In a module-based application
486
+ * @NgModule({
487
+ * providers: [
488
+ * {
489
+ * provide: HTTP_INTERCEPTORS,
490
+ * useValue: apiUrlInterceptor('https://api.myapp.com/v1'),
491
+ * multi: true
492
+ * }
493
+ * ]
494
+ * })
495
+ * export class AppModule {}
496
+ * ```
497
+ *
498
+ * @see {@link HttpInterceptorFn} Angular HTTP interceptor function type
499
+ * @see {@link HttpRequest} Angular HTTP request interface
500
+ */
113
501
  function apiUrlInterceptor(apiBase) {
114
502
  return (req, next) => {
115
503
  if (req.url.startsWith(apiBase) || req.url.startsWith("http")) {
@@ -120,86 +508,18 @@ function apiUrlInterceptor(apiBase) {
120
508
  };
121
509
  }
122
510
 
123
- const SKIPPED_ERRORS = [
124
- AuthErrorResponseCode.AUTH_401_EXPIRED_TOKEN,
125
- AuthErrorResponseCode.AUTH_401_INVALID_TOKEN,
126
- AuthErrorResponseCode.AUTH_401_NOT_LOGGED_IN,
127
- ];
128
- let refreshingInProgress = false;
129
- const isRefreshTokenReq = (req) => req.url.includes(`${Endpoint.AUTH}/${AuthEndpoint.REFRESH_TOKEN}`);
130
- let tokenSubject = new ReplaySubject(1);
131
- function authInterceptor(redirect, onRedirect) {
132
- return (req, next) => {
133
- const authState = inject(AuthState);
134
- const authService = inject(AuthService);
135
- const router = inject(Router);
136
- const setAccessToken = (req, accessToken) => {
137
- return req.clone({
138
- headers: req.headers.set("Authorization", "Bearer " + accessToken),
139
- });
140
- };
141
- const gotoSignIn = () => {
142
- onRedirect?.();
143
- authState.reset();
144
- // eslint-disable-next-line no-void
145
- void router.navigateByUrl(redirect);
146
- };
147
- const refreshToken = (req, next) => {
148
- if (!refreshingInProgress) {
149
- refreshingInProgress = true;
150
- tokenSubject.next(null);
151
- const refreshToken = authState.refreshToken();
152
- if (!refreshToken) {
153
- refreshingInProgress = false;
154
- gotoSignIn();
155
- return throwError(() => new Error("Refresh token not found."));
156
- }
157
- return authService.refreshToken(refreshToken).pipe(switchMap((tokenResponse) => {
158
- authState.setTokens(tokenResponse);
159
- tokenSubject.next(tokenResponse.accessToken);
160
- tokenSubject.complete();
161
- tokenSubject = new ReplaySubject(1);
162
- refreshingInProgress = false;
163
- return next(setAccessToken(req, tokenResponse.accessToken));
164
- }), catchError((error) => {
165
- refreshingInProgress = false;
166
- tokenSubject.error(error);
167
- tokenSubject.complete();
168
- tokenSubject = new ReplaySubject(1);
169
- gotoSignIn();
170
- return throwError(() => error);
171
- }));
172
- }
173
- return tokenSubject.pipe(filter(result => result !== null), take(1), switchMap(token => {
174
- return next(setAccessToken(req, token));
175
- }));
176
- };
177
- const handleRequest = (req, next) => {
178
- return next(req).pipe(catchError((error) => {
179
- if (error.status === HttpClientErrorStatus.UNAUTHORIZED &&
180
- error.error?.code &&
181
- SKIPPED_ERRORS.includes(error.error?.code) &&
182
- !isRefreshTokenReq(req)) {
183
- if (authState.signedIn()) {
184
- return refreshToken(req, next);
185
- }
186
- }
187
- return throwError(() => error);
188
- }));
189
- };
190
- if (authState.accessToken()) {
191
- const tokenizedRequest = req.clone({
192
- headers: req.headers.set("Authorization", "Bearer " + authState.accessToken()),
193
- });
194
- return handleRequest(tokenizedRequest, next);
195
- }
196
- return handleRequest(req, next);
197
- };
511
+ // export * from "./response.interceptor";
512
+
513
+ class HichchiHttpService {
514
+ http;
515
+ constructor(http) {
516
+ this.http = http;
517
+ }
198
518
  }
199
519
 
200
520
  /**
201
521
  * Generated bundle index. Do not edit.
202
522
  */
203
523
 
204
- export { AuthService, AuthState, SKIPPED_ERRORS, apiUrlInterceptor, authInterceptor, utils };
524
+ export { HichchiHttpService, apiUrlInterceptor, createFormData, markFormDirty, replaceNulls, validatedFormData };
205
525
  //# sourceMappingURL=hichchi-ngx-utils.mjs.map