@flusys/ng-core 0.1.0-alpha.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/fesm2022/flusys-ng-core.mjs +253 -0
- package/fesm2022/flusys-ng-core.mjs.map +1 -0
- package/package.json +25 -0
- package/types/flusys-ng-core.d.ts +194 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { signal, computed, Injectable, inject, Component, PLATFORM_ID, InjectionToken } from '@angular/core';
|
|
3
|
+
import * as i2 from 'primeng/toast';
|
|
4
|
+
import { ToastModule } from 'primeng/toast';
|
|
5
|
+
import { ConfirmDialog } from 'primeng/confirmdialog';
|
|
6
|
+
import * as i1 from 'primeng/progressbar';
|
|
7
|
+
import { ProgressBarModule } from 'primeng/progressbar';
|
|
8
|
+
import { finalize } from 'rxjs/operators';
|
|
9
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
10
|
+
import { MessageService } from 'primeng/api';
|
|
11
|
+
import { catchError, throwError } from 'rxjs';
|
|
12
|
+
import { HttpClient } from '@angular/common/http';
|
|
13
|
+
|
|
14
|
+
class ApiLoaderService {
|
|
15
|
+
loaders = signal({}, ...(ngDevMode ? [{ debugName: "loaders" }] : [])); // 👈 reactive store
|
|
16
|
+
DEFAULT_TAG = 'default';
|
|
17
|
+
// Global loading state
|
|
18
|
+
show = computed(() => {
|
|
19
|
+
const loaders = this.loaders();
|
|
20
|
+
return Object.values(loaders).some((count) => count > 0);
|
|
21
|
+
}, ...(ngDevMode ? [{ debugName: "show" }] : []));
|
|
22
|
+
// Get specific loader as a signal
|
|
23
|
+
getLoader(name) {
|
|
24
|
+
return computed(() => (this.loaders()[name] ?? 0) > 0);
|
|
25
|
+
}
|
|
26
|
+
increase(name = this.DEFAULT_TAG) {
|
|
27
|
+
this.loaders.update((loaders) => ({
|
|
28
|
+
...loaders,
|
|
29
|
+
[name]: (loaders[name] ?? 0) + 1,
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
decrease(name = this.DEFAULT_TAG) {
|
|
33
|
+
this.loaders.update((loaders) => {
|
|
34
|
+
const current = loaders[name] ?? 0;
|
|
35
|
+
return { ...loaders, [name]: Math.max(0, current - 1) };
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: ApiLoaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
39
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: ApiLoaderService, providedIn: 'root' });
|
|
40
|
+
}
|
|
41
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: ApiLoaderService, decorators: [{
|
|
42
|
+
type: Injectable,
|
|
43
|
+
args: [{ providedIn: 'root' }]
|
|
44
|
+
}] });
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Root configuration component providing global UI elements.
|
|
48
|
+
* Include once at app root for global toast, confirm dialog, and loader.
|
|
49
|
+
*/
|
|
50
|
+
class LibAppConfigComponent {
|
|
51
|
+
apiLoaderService = inject(ApiLoaderService);
|
|
52
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: LibAppConfigComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
53
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: LibAppConfigComponent, isStandalone: true, selector: "lib-app-config", ngImport: i0, template: "@if (apiLoaderService.show()) {\n<p-progressBar mode=\"indeterminate\" />\n}\n<p-toast />\n<p-confirmdialog />\n", styles: [":host ::ng-deep .p-progressbar{position:fixed;height:4px;z-index:998;left:0;right:0}\n"], dependencies: [{ kind: "component", type: ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "modal", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "ngmodule", type: ProgressBarModule }, { kind: "component", type: i1.ProgressBar, selector: "p-progressBar, p-progressbar, p-progress-bar", inputs: ["value", "showValue", "styleClass", "valueStyleClass", "unit", "mode", "color"] }, { kind: "ngmodule", type: ToastModule }, { kind: "component", type: i2.Toast, selector: "p-toast", inputs: ["key", "autoZIndex", "baseZIndex", "life", "styleClass", "position", "preventOpenDuplicates", "preventDuplicates", "showTransformOptions", "hideTransformOptions", "showTransitionOptions", "hideTransitionOptions", "motionOptions", "breakpoints"], outputs: ["onClose"] }] });
|
|
54
|
+
}
|
|
55
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: LibAppConfigComponent, decorators: [{
|
|
56
|
+
type: Component,
|
|
57
|
+
args: [{ selector: 'lib-app-config', standalone: true, imports: [ConfirmDialog, ProgressBarModule, ToastModule], template: "@if (apiLoaderService.show()) {\n<p-progressBar mode=\"indeterminate\" />\n}\n<p-toast />\n<p-confirmdialog />\n", styles: [":host ::ng-deep .p-progressbar{position:fixed;height:4px;z-index:998;left:0;right:0}\n"] }]
|
|
58
|
+
}] });
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Interceptor that tracks loading state for HTTP requests.
|
|
62
|
+
* Uses 'x-loader-tag' header to group related requests.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* http.get('/api/users', {
|
|
67
|
+
* headers: new HttpHeaders({ 'x-loader-tag': 'users-list' })
|
|
68
|
+
* });
|
|
69
|
+
* // In template: apiLoaderService.getLoader('users-list')
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
function apiLoaderInterceptor(req, next) {
|
|
73
|
+
const loaderService = inject(ApiLoaderService);
|
|
74
|
+
const loaderTag = req.headers.get('x-loader-tag') ?? loaderService.DEFAULT_TAG;
|
|
75
|
+
loaderService.increase(loaderTag);
|
|
76
|
+
const cleanReq = req.clone({
|
|
77
|
+
headers: req.headers.delete('x-loader-tag'),
|
|
78
|
+
});
|
|
79
|
+
return next(cleanReq).pipe(finalize(() => loaderService.decrease(loaderTag)));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Error Catching Interceptor
|
|
84
|
+
* Displays error messages for failed HTTP requests.
|
|
85
|
+
*
|
|
86
|
+
* NOTE: This interceptor only handles error display.
|
|
87
|
+
* For 401 handling and token refresh, use tokenRefreshInterceptor from @flusys/ng-auth.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* // In app.config.ts
|
|
92
|
+
* provideHttpClient(
|
|
93
|
+
* withFetch(),
|
|
94
|
+
* withInterceptors([
|
|
95
|
+
* authInterceptor, // from @flusys/ng-auth
|
|
96
|
+
* tokenRefreshInterceptor, // from @flusys/ng-auth
|
|
97
|
+
* errorCatchingInterceptor, // from @flusys/ng-core
|
|
98
|
+
* apiLoaderInterceptor, // from @flusys/ng-core
|
|
99
|
+
* ])
|
|
100
|
+
* )
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
function errorCatchingInterceptor(req, next) {
|
|
104
|
+
const messageService = inject(MessageService);
|
|
105
|
+
const platformId = inject(PLATFORM_ID);
|
|
106
|
+
const isBrowser = isPlatformBrowser(platformId);
|
|
107
|
+
// Skip error display for check-login (expected to fail when not logged in)
|
|
108
|
+
const isCheckLogin = req.url.includes('/check-login');
|
|
109
|
+
return next(req).pipe(catchError((error) => {
|
|
110
|
+
// Skip 401 errors - handled by tokenRefreshInterceptor in ng-auth
|
|
111
|
+
// Skip check-login errors - expected behavior
|
|
112
|
+
if (error.status === 401 || isCheckLogin) {
|
|
113
|
+
return throwError(() => error);
|
|
114
|
+
}
|
|
115
|
+
// Display error message for other errors
|
|
116
|
+
if (isBrowser) {
|
|
117
|
+
const message = extractErrorMessage(error);
|
|
118
|
+
messageService.add({
|
|
119
|
+
severity: 'error',
|
|
120
|
+
summary: 'Sorry, an error occurred',
|
|
121
|
+
detail: message,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return throwError(() => error);
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Extract error message from HTTP error response
|
|
129
|
+
*/
|
|
130
|
+
function extractErrorMessage(error) {
|
|
131
|
+
if (typeof error.error?.message === 'string') {
|
|
132
|
+
return error.error.message;
|
|
133
|
+
}
|
|
134
|
+
if (Array.isArray(error.error?.message)) {
|
|
135
|
+
return error.error.message[0];
|
|
136
|
+
}
|
|
137
|
+
if (error.message) {
|
|
138
|
+
return error.message;
|
|
139
|
+
}
|
|
140
|
+
return 'An unexpected error occurred.';
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* App Configuration Token
|
|
145
|
+
* Use this to inject app config in services/components
|
|
146
|
+
*/
|
|
147
|
+
const APP_CONFIG = new InjectionToken('APP_CONFIG');
|
|
148
|
+
/**
|
|
149
|
+
* Get database mode from config
|
|
150
|
+
* Derived from multiTenant.enabled
|
|
151
|
+
*/
|
|
152
|
+
function getDatabaseMode(config) {
|
|
153
|
+
return config.multiTenant.enabled ? 'multi-tenant' : 'single';
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Check if a feature is enabled
|
|
157
|
+
* Features are enabled if their corresponding service exists and is enabled
|
|
158
|
+
*/
|
|
159
|
+
function isFeatureEnabled(config, feature) {
|
|
160
|
+
const service = config.services[feature];
|
|
161
|
+
return service?.enabled ?? false;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Helper function to get service base URL
|
|
165
|
+
* Returns service-specific URL or falls back to default apiBaseUrl
|
|
166
|
+
*/
|
|
167
|
+
function getServiceUrl(config, serviceName) {
|
|
168
|
+
const service = config.services[serviceName];
|
|
169
|
+
if (service?.enabled) {
|
|
170
|
+
return service.baseUrl;
|
|
171
|
+
}
|
|
172
|
+
// Fallback to default API base URL
|
|
173
|
+
return config.apiBaseUrl;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Helper function to check if a service is enabled
|
|
177
|
+
*/
|
|
178
|
+
function isServiceEnabled(config, serviceName) {
|
|
179
|
+
const service = config.services[serviceName];
|
|
180
|
+
return service?.enabled ?? false;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Check if company feature is enabled (backward compatible)
|
|
184
|
+
* Company feature is enabled if auth service is enabled
|
|
185
|
+
*/
|
|
186
|
+
function isCompanyFeatureEnabled(config) {
|
|
187
|
+
return config.enableCompanyFeature ?? false;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Check if storage feature is enabled (backward compatible)
|
|
191
|
+
* Storage feature is enabled if storage service is enabled
|
|
192
|
+
*/
|
|
193
|
+
function isStorageFeatureEnabled(config) {
|
|
194
|
+
return config.services.storage?.enabled ?? false;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Get permission mode from config
|
|
198
|
+
* Defaults to 'full' if not specified
|
|
199
|
+
*/
|
|
200
|
+
function getPermissionMode(config) {
|
|
201
|
+
return config.permissionMode ?? 'full';
|
|
202
|
+
}
|
|
203
|
+
const DEFAULT_APP_NAME = 'FLUSYS';
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Base API Service
|
|
207
|
+
* Provides service-specific base URL resolution
|
|
208
|
+
*
|
|
209
|
+
* Usage:
|
|
210
|
+
* ```typescript
|
|
211
|
+
* @Injectable({ providedIn: 'root' })
|
|
212
|
+
* export class MyService extends BaseApiService {
|
|
213
|
+
* constructor() {
|
|
214
|
+
* super('my-service'); // Service name from config
|
|
215
|
+
* }
|
|
216
|
+
*
|
|
217
|
+
* getData() {
|
|
218
|
+
* return this.http.get(`${this.baseUrl}/data`);
|
|
219
|
+
* }
|
|
220
|
+
* }
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
class BaseApiService {
|
|
224
|
+
http = inject(HttpClient);
|
|
225
|
+
appConfig = inject(APP_CONFIG);
|
|
226
|
+
baseUrl;
|
|
227
|
+
/**
|
|
228
|
+
* @param serviceName - Service name from config (e.g., 'auth', 'iam', 'storage')
|
|
229
|
+
*/
|
|
230
|
+
constructor(serviceName) {
|
|
231
|
+
this.baseUrl = getServiceUrl(this.appConfig, serviceName);
|
|
232
|
+
console.log(`[${serviceName}] Base URL:`, this.baseUrl);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Get full URL for an endpoint
|
|
236
|
+
* @param endpoint - API endpoint (e.g., '/users/get-all')
|
|
237
|
+
* @returns Full URL (e.g., 'http://localhost:2002/users/get-all')
|
|
238
|
+
*/
|
|
239
|
+
getUrl(endpoint) {
|
|
240
|
+
// Remove leading slash if present to avoid double slashes
|
|
241
|
+
const cleanEndpoint = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint;
|
|
242
|
+
return `${this.baseUrl}/${cleanEndpoint}`;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Components
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Generated bundle index. Do not edit.
|
|
250
|
+
*/
|
|
251
|
+
|
|
252
|
+
export { APP_CONFIG, ApiLoaderService, BaseApiService, DEFAULT_APP_NAME, LibAppConfigComponent, apiLoaderInterceptor, errorCatchingInterceptor, getDatabaseMode, getPermissionMode, getServiceUrl, isCompanyFeatureEnabled, isFeatureEnabled, isServiceEnabled, isStorageFeatureEnabled };
|
|
253
|
+
//# sourceMappingURL=flusys-ng-core.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flusys-ng-core.mjs","sources":["../../../projects/ng-core/services/api-loader.service.ts","../../../projects/ng-core/components/lib-app-config/lib-app-config.component.ts","../../../projects/ng-core/components/lib-app-config/lib-app-config.component.html","../../../projects/ng-core/interceptors/api-loader.interceptor.ts","../../../projects/ng-core/interceptors/error-catching.interceptor.ts","../../../projects/ng-core/interfaces/app-config.interface.ts","../../../projects/ng-core/services/base-api.service.ts","../../../projects/ng-core/public-api.ts","../../../projects/ng-core/flusys-ng-core.ts"],"sourcesContent":["import { computed, Injectable, Signal, signal } from '@angular/core';\n\n@Injectable({ providedIn: 'root' })\nexport class ApiLoaderService {\n private loaders = signal<Record<string, number>>({}); // 👈 reactive store\n public readonly DEFAULT_TAG = 'default';\n\n // Global loading state\n readonly show: Signal<boolean> = computed(() => {\n const loaders = this.loaders();\n return Object.values(loaders).some((count) => count > 0);\n });\n\n // Get specific loader as a signal\n getLoader(name: string): Signal<boolean> {\n return computed(() => (this.loaders()[name] ?? 0) > 0);\n }\n\n increase(name: string = this.DEFAULT_TAG): void {\n this.loaders.update((loaders) => ({\n ...loaders,\n [name]: (loaders[name] ?? 0) + 1,\n }));\n }\n\n decrease(name: string = this.DEFAULT_TAG): void {\n this.loaders.update((loaders) => {\n const current = loaders[name] ?? 0;\n return { ...loaders, [name]: Math.max(0, current - 1) };\n });\n }\n}\n","import { Component, inject } from '@angular/core';\nimport { ToastModule } from 'primeng/toast';\nimport { ConfirmDialog } from 'primeng/confirmdialog';\nimport { ApiLoaderService } from '../../services/api-loader.service';\nimport { ProgressBarModule } from 'primeng/progressbar';\n\n/**\n * Root configuration component providing global UI elements.\n * Include once at app root for global toast, confirm dialog, and loader.\n */\n@Component({\n selector: 'lib-app-config',\n standalone: true,\n imports: [ConfirmDialog, ProgressBarModule, ToastModule],\n templateUrl: './lib-app-config.component.html',\n styleUrl: './lib-app-config.component.scss',\n})\nexport class LibAppConfigComponent {\n readonly apiLoaderService = inject(ApiLoaderService);\n}\n","@if (apiLoaderService.show()) {\n<p-progressBar mode=\"indeterminate\" />\n}\n<p-toast />\n<p-confirmdialog />\n","import { HttpEvent, HttpHandlerFn, HttpRequest } from '@angular/common/http';\nimport { inject } from '@angular/core';\nimport { ApiLoaderService } from '../services/api-loader.service';\nimport { Observable } from 'rxjs';\nimport { finalize } from 'rxjs/operators';\n\n/**\n * Interceptor that tracks loading state for HTTP requests.\n * Uses 'x-loader-tag' header to group related requests.\n *\n * @example\n * ```typescript\n * http.get('/api/users', {\n * headers: new HttpHeaders({ 'x-loader-tag': 'users-list' })\n * });\n * // In template: apiLoaderService.getLoader('users-list')\n * ```\n */\nexport function apiLoaderInterceptor(\n req: HttpRequest<unknown>,\n next: HttpHandlerFn\n): Observable<HttpEvent<unknown>> {\n const loaderService = inject(ApiLoaderService);\n const loaderTag = req.headers.get('x-loader-tag') ?? loaderService.DEFAULT_TAG;\n\n loaderService.increase(loaderTag);\n\n const cleanReq = req.clone({\n headers: req.headers.delete('x-loader-tag'),\n });\n\n return next(cleanReq).pipe(\n finalize(() => loaderService.decrease(loaderTag))\n );\n}\n","import {\n HttpErrorResponse,\n HttpEvent,\n HttpHandlerFn,\n HttpRequest,\n} from '@angular/common/http';\nimport { inject, PLATFORM_ID } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { MessageService } from 'primeng/api';\nimport { catchError, Observable, throwError } from 'rxjs';\n\n/**\n * Error Catching Interceptor\n * Displays error messages for failed HTTP requests.\n *\n * NOTE: This interceptor only handles error display.\n * For 401 handling and token refresh, use tokenRefreshInterceptor from @flusys/ng-auth.\n *\n * @example\n * ```typescript\n * // In app.config.ts\n * provideHttpClient(\n * withFetch(),\n * withInterceptors([\n * authInterceptor, // from @flusys/ng-auth\n * tokenRefreshInterceptor, // from @flusys/ng-auth\n * errorCatchingInterceptor, // from @flusys/ng-core\n * apiLoaderInterceptor, // from @flusys/ng-core\n * ])\n * )\n * ```\n */\nexport function errorCatchingInterceptor(\n req: HttpRequest<unknown>,\n next: HttpHandlerFn\n): Observable<HttpEvent<unknown>> {\n const messageService = inject(MessageService);\n const platformId = inject(PLATFORM_ID);\n const isBrowser = isPlatformBrowser(platformId);\n\n // Skip error display for check-login (expected to fail when not logged in)\n const isCheckLogin = req.url.includes('/check-login');\n\n return next(req).pipe(\n catchError((error: HttpErrorResponse) => {\n // Skip 401 errors - handled by tokenRefreshInterceptor in ng-auth\n // Skip check-login errors - expected behavior\n if (error.status === 401 || isCheckLogin) {\n return throwError(() => error);\n }\n\n // Display error message for other errors\n if (isBrowser) {\n const message = extractErrorMessage(error);\n messageService.add({\n severity: 'error',\n summary: 'Sorry, an error occurred',\n detail: message,\n });\n }\n\n return throwError(() => error);\n })\n );\n}\n\n/**\n * Extract error message from HTTP error response\n */\nfunction extractErrorMessage(error: HttpErrorResponse): string {\n if (typeof error.error?.message === 'string') {\n return error.error.message;\n }\n\n if (Array.isArray(error.error?.message)) {\n return error.error.message[0];\n }\n\n if (error.message) {\n return error.message;\n }\n\n return 'An unexpected error occurred.';\n}\n","import { InjectionToken } from '@angular/core';\n\n/**\n * IAM Permission Mode - controls permission system behavior\n */\nexport type PermissionMode = 'rbac' | 'direct' | 'full';\n\n/**\n * Service Configuration Interface\n */\nexport interface IServiceConfig {\n baseUrl: string;\n enabled: boolean;\n}\n\n/**\n * App Configuration Interface\n * Centralized configuration for feature toggles and behavior control\n */\nexport interface IAppConfig {\n /** Application name */\n appName: string;\n\n /** Default API base URL (fallback) */\n apiBaseUrl: string; \n \n /**\n * enableCompanyFeature in across the app\n */\n enableCompanyFeature: boolean,\n\n /**\n * Service-specific base URLs\n * If a service exists in this object, its feature is enabled\n * Database mode is determined by multiTenant.enabled\n */\n services: {\n auth: IServiceConfig;\n iam: IServiceConfig;\n storage: IServiceConfig;\n [key: string]: IServiceConfig;\n };\n\n /**\n * Multi-tenant configuration\n * enabled: true → Database mode = multi-tenant\n * enabled: false → Database mode = single\n */\n multiTenant: {\n enabled: boolean;\n tenantHeader: string;\n tenantId?: string;\n };\n\n /**\n * IAM Permission Mode - controls permission system behavior\n * - 'rbac': Role-Based Access Control only (users get permissions via roles)\n * - 'direct': Direct action assignments only (actions assigned directly to users)\n * - 'full': Both RBAC and direct permissions (most flexible, default)\n */\n permissionMode?: PermissionMode;\n}\n\n/**\n * App Configuration Token\n * Use this to inject app config in services/components\n */\nexport const APP_CONFIG = new InjectionToken<IAppConfig>('APP_CONFIG');\n\n/**\n * Get database mode from config\n * Derived from multiTenant.enabled\n */\nexport function getDatabaseMode(config: IAppConfig): 'single' | 'multi-tenant' {\n return config.multiTenant.enabled ? 'multi-tenant' : 'single';\n}\n\n/**\n * Check if a feature is enabled\n * Features are enabled if their corresponding service exists and is enabled\n */\nexport function isFeatureEnabled(\n config: IAppConfig,\n feature: 'auth' | 'iam' | 'storage',\n): boolean {\n const service = config.services[feature];\n return service?.enabled ?? false;\n}\n\n/**\n * Helper function to get service base URL\n * Returns service-specific URL or falls back to default apiBaseUrl\n */\nexport function getServiceUrl(\n config: IAppConfig,\n serviceName: keyof IAppConfig['services'],\n): string {\n const service = config.services[serviceName];\n if (service?.enabled) {\n return service.baseUrl;\n }\n // Fallback to default API base URL\n return config.apiBaseUrl;\n}\n\n/**\n * Helper function to check if a service is enabled\n */\nexport function isServiceEnabled(\n config: IAppConfig,\n serviceName: keyof IAppConfig['services'],\n): boolean {\n const service = config.services[serviceName];\n return service?.enabled ?? false;\n}\n\n/**\n * Check if company feature is enabled (backward compatible)\n * Company feature is enabled if auth service is enabled\n */\nexport function isCompanyFeatureEnabled(config: IAppConfig): boolean {\n return config.enableCompanyFeature ?? false;\n}\n\n/**\n * Check if storage feature is enabled (backward compatible)\n * Storage feature is enabled if storage service is enabled\n */\nexport function isStorageFeatureEnabled(config: IAppConfig): boolean {\n return config.services.storage?.enabled ?? false;\n}\n\n/**\n * Get permission mode from config\n * Defaults to 'full' if not specified\n */\nexport function getPermissionMode(config: IAppConfig): PermissionMode {\n return config.permissionMode ?? 'full';\n}\nexport const DEFAULT_APP_NAME = 'FLUSYS';\n","import { inject } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport { APP_CONFIG, getServiceUrl } from '../interfaces/app-config.interface';\n\n/**\n * Base API Service\n * Provides service-specific base URL resolution\n *\n * Usage:\n * ```typescript\n * @Injectable({ providedIn: 'root' })\n * export class MyService extends BaseApiService {\n * constructor() {\n * super('my-service'); // Service name from config\n * }\n *\n * getData() {\n * return this.http.get(`${this.baseUrl}/data`);\n * }\n * }\n * ```\n */\nexport abstract class BaseApiService {\n protected readonly http = inject(HttpClient);\n protected readonly appConfig = inject(APP_CONFIG);\n protected readonly baseUrl: string;\n\n /**\n * @param serviceName - Service name from config (e.g., 'auth', 'iam', 'storage')\n */\n constructor(serviceName: string) {\n this.baseUrl = getServiceUrl(this.appConfig, serviceName);\n console.log(`[${serviceName}] Base URL:`, this.baseUrl);\n }\n\n /**\n * Get full URL for an endpoint\n * @param endpoint - API endpoint (e.g., '/users/get-all')\n * @returns Full URL (e.g., 'http://localhost:2002/users/get-all')\n */\n protected getUrl(endpoint: string): string {\n // Remove leading slash if present to avoid double slashes\n const cleanEndpoint = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint;\n return `${this.baseUrl}/${cleanEndpoint}`;\n }\n}\n","// Components\nexport * from './components/lib-app-config/lib-app-config.component';\n\n// Interceptors\nexport * from './interceptors/api-loader.interceptor';\nexport * from './interceptors/error-catching.interceptor';\n\n// Interfaces\nexport * from './interfaces/app-config.interface';\n\n// Services\nexport * from './services/api-loader.service';\nexport * from './services/base-api.service';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@flusys/ng-core",
|
|
3
|
+
"version": "0.1.0-alpha.1",
|
|
4
|
+
"description": "Core utilities and services for FLUSYS Angular packages",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"peerDependencies": {
|
|
7
|
+
"@angular/common": "^21.0.0",
|
|
8
|
+
"@angular/core": "^21.0.0"
|
|
9
|
+
},
|
|
10
|
+
"sideEffects": false,
|
|
11
|
+
"module": "fesm2022/flusys-ng-core.mjs",
|
|
12
|
+
"typings": "types/flusys-ng-core.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
"./package.json": {
|
|
15
|
+
"default": "./package.json"
|
|
16
|
+
},
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./types/flusys-ng-core.d.ts",
|
|
19
|
+
"default": "./fesm2022/flusys-ng-core.mjs"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"tslib": "^2.3.0"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { Signal, InjectionToken } from '@angular/core';
|
|
3
|
+
import { HttpRequest, HttpHandlerFn, HttpEvent, HttpClient } from '@angular/common/http';
|
|
4
|
+
import { Observable } from 'rxjs';
|
|
5
|
+
import * as _flusys_ng_core from '@flusys/ng-core';
|
|
6
|
+
|
|
7
|
+
declare class ApiLoaderService {
|
|
8
|
+
private loaders;
|
|
9
|
+
readonly DEFAULT_TAG = "default";
|
|
10
|
+
readonly show: Signal<boolean>;
|
|
11
|
+
getLoader(name: string): Signal<boolean>;
|
|
12
|
+
increase(name?: string): void;
|
|
13
|
+
decrease(name?: string): void;
|
|
14
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ApiLoaderService, never>;
|
|
15
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<ApiLoaderService>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Root configuration component providing global UI elements.
|
|
20
|
+
* Include once at app root for global toast, confirm dialog, and loader.
|
|
21
|
+
*/
|
|
22
|
+
declare class LibAppConfigComponent {
|
|
23
|
+
readonly apiLoaderService: ApiLoaderService;
|
|
24
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<LibAppConfigComponent, never>;
|
|
25
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<LibAppConfigComponent, "lib-app-config", never, {}, {}, never, never, true, never>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Interceptor that tracks loading state for HTTP requests.
|
|
30
|
+
* Uses 'x-loader-tag' header to group related requests.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* http.get('/api/users', {
|
|
35
|
+
* headers: new HttpHeaders({ 'x-loader-tag': 'users-list' })
|
|
36
|
+
* });
|
|
37
|
+
* // In template: apiLoaderService.getLoader('users-list')
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
declare function apiLoaderInterceptor(req: HttpRequest<unknown>, next: HttpHandlerFn): Observable<HttpEvent<unknown>>;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Error Catching Interceptor
|
|
44
|
+
* Displays error messages for failed HTTP requests.
|
|
45
|
+
*
|
|
46
|
+
* NOTE: This interceptor only handles error display.
|
|
47
|
+
* For 401 handling and token refresh, use tokenRefreshInterceptor from @flusys/ng-auth.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* // In app.config.ts
|
|
52
|
+
* provideHttpClient(
|
|
53
|
+
* withFetch(),
|
|
54
|
+
* withInterceptors([
|
|
55
|
+
* authInterceptor, // from @flusys/ng-auth
|
|
56
|
+
* tokenRefreshInterceptor, // from @flusys/ng-auth
|
|
57
|
+
* errorCatchingInterceptor, // from @flusys/ng-core
|
|
58
|
+
* apiLoaderInterceptor, // from @flusys/ng-core
|
|
59
|
+
* ])
|
|
60
|
+
* )
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
declare function errorCatchingInterceptor(req: HttpRequest<unknown>, next: HttpHandlerFn): Observable<HttpEvent<unknown>>;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* IAM Permission Mode - controls permission system behavior
|
|
67
|
+
*/
|
|
68
|
+
type PermissionMode = 'rbac' | 'direct' | 'full';
|
|
69
|
+
/**
|
|
70
|
+
* Service Configuration Interface
|
|
71
|
+
*/
|
|
72
|
+
interface IServiceConfig {
|
|
73
|
+
baseUrl: string;
|
|
74
|
+
enabled: boolean;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* App Configuration Interface
|
|
78
|
+
* Centralized configuration for feature toggles and behavior control
|
|
79
|
+
*/
|
|
80
|
+
interface IAppConfig {
|
|
81
|
+
/** Application name */
|
|
82
|
+
appName: string;
|
|
83
|
+
/** Default API base URL (fallback) */
|
|
84
|
+
apiBaseUrl: string;
|
|
85
|
+
/**
|
|
86
|
+
* enableCompanyFeature in across the app
|
|
87
|
+
*/
|
|
88
|
+
enableCompanyFeature: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Service-specific base URLs
|
|
91
|
+
* If a service exists in this object, its feature is enabled
|
|
92
|
+
* Database mode is determined by multiTenant.enabled
|
|
93
|
+
*/
|
|
94
|
+
services: {
|
|
95
|
+
auth: IServiceConfig;
|
|
96
|
+
iam: IServiceConfig;
|
|
97
|
+
storage: IServiceConfig;
|
|
98
|
+
[key: string]: IServiceConfig;
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Multi-tenant configuration
|
|
102
|
+
* enabled: true → Database mode = multi-tenant
|
|
103
|
+
* enabled: false → Database mode = single
|
|
104
|
+
*/
|
|
105
|
+
multiTenant: {
|
|
106
|
+
enabled: boolean;
|
|
107
|
+
tenantHeader: string;
|
|
108
|
+
tenantId?: string;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* IAM Permission Mode - controls permission system behavior
|
|
112
|
+
* - 'rbac': Role-Based Access Control only (users get permissions via roles)
|
|
113
|
+
* - 'direct': Direct action assignments only (actions assigned directly to users)
|
|
114
|
+
* - 'full': Both RBAC and direct permissions (most flexible, default)
|
|
115
|
+
*/
|
|
116
|
+
permissionMode?: PermissionMode;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* App Configuration Token
|
|
120
|
+
* Use this to inject app config in services/components
|
|
121
|
+
*/
|
|
122
|
+
declare const APP_CONFIG: InjectionToken<IAppConfig>;
|
|
123
|
+
/**
|
|
124
|
+
* Get database mode from config
|
|
125
|
+
* Derived from multiTenant.enabled
|
|
126
|
+
*/
|
|
127
|
+
declare function getDatabaseMode(config: IAppConfig): 'single' | 'multi-tenant';
|
|
128
|
+
/**
|
|
129
|
+
* Check if a feature is enabled
|
|
130
|
+
* Features are enabled if their corresponding service exists and is enabled
|
|
131
|
+
*/
|
|
132
|
+
declare function isFeatureEnabled(config: IAppConfig, feature: 'auth' | 'iam' | 'storage'): boolean;
|
|
133
|
+
/**
|
|
134
|
+
* Helper function to get service base URL
|
|
135
|
+
* Returns service-specific URL or falls back to default apiBaseUrl
|
|
136
|
+
*/
|
|
137
|
+
declare function getServiceUrl(config: IAppConfig, serviceName: keyof IAppConfig['services']): string;
|
|
138
|
+
/**
|
|
139
|
+
* Helper function to check if a service is enabled
|
|
140
|
+
*/
|
|
141
|
+
declare function isServiceEnabled(config: IAppConfig, serviceName: keyof IAppConfig['services']): boolean;
|
|
142
|
+
/**
|
|
143
|
+
* Check if company feature is enabled (backward compatible)
|
|
144
|
+
* Company feature is enabled if auth service is enabled
|
|
145
|
+
*/
|
|
146
|
+
declare function isCompanyFeatureEnabled(config: IAppConfig): boolean;
|
|
147
|
+
/**
|
|
148
|
+
* Check if storage feature is enabled (backward compatible)
|
|
149
|
+
* Storage feature is enabled if storage service is enabled
|
|
150
|
+
*/
|
|
151
|
+
declare function isStorageFeatureEnabled(config: IAppConfig): boolean;
|
|
152
|
+
/**
|
|
153
|
+
* Get permission mode from config
|
|
154
|
+
* Defaults to 'full' if not specified
|
|
155
|
+
*/
|
|
156
|
+
declare function getPermissionMode(config: IAppConfig): PermissionMode;
|
|
157
|
+
declare const DEFAULT_APP_NAME = "FLUSYS";
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Base API Service
|
|
161
|
+
* Provides service-specific base URL resolution
|
|
162
|
+
*
|
|
163
|
+
* Usage:
|
|
164
|
+
* ```typescript
|
|
165
|
+
* @Injectable({ providedIn: 'root' })
|
|
166
|
+
* export class MyService extends BaseApiService {
|
|
167
|
+
* constructor() {
|
|
168
|
+
* super('my-service'); // Service name from config
|
|
169
|
+
* }
|
|
170
|
+
*
|
|
171
|
+
* getData() {
|
|
172
|
+
* return this.http.get(`${this.baseUrl}/data`);
|
|
173
|
+
* }
|
|
174
|
+
* }
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
declare abstract class BaseApiService {
|
|
178
|
+
protected readonly http: HttpClient;
|
|
179
|
+
protected readonly appConfig: _flusys_ng_core.IAppConfig;
|
|
180
|
+
protected readonly baseUrl: string;
|
|
181
|
+
/**
|
|
182
|
+
* @param serviceName - Service name from config (e.g., 'auth', 'iam', 'storage')
|
|
183
|
+
*/
|
|
184
|
+
constructor(serviceName: string);
|
|
185
|
+
/**
|
|
186
|
+
* Get full URL for an endpoint
|
|
187
|
+
* @param endpoint - API endpoint (e.g., '/users/get-all')
|
|
188
|
+
* @returns Full URL (e.g., 'http://localhost:2002/users/get-all')
|
|
189
|
+
*/
|
|
190
|
+
protected getUrl(endpoint: string): string;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export { APP_CONFIG, ApiLoaderService, BaseApiService, DEFAULT_APP_NAME, LibAppConfigComponent, apiLoaderInterceptor, errorCatchingInterceptor, getDatabaseMode, getPermissionMode, getServiceUrl, isCompanyFeatureEnabled, isFeatureEnabled, isServiceEnabled, isStorageFeatureEnabled };
|
|
194
|
+
export type { IAppConfig, IServiceConfig, PermissionMode };
|