@flusys/ng-core 9.1.2 → 9.2.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.
|
@@ -3,6 +3,9 @@ import { Component, InjectionToken, Service, computed, inject, signal } from "@a
|
|
|
3
3
|
import { ConfirmDialog, ProgressbarComponent, ToastComponent } from "@flusys/ng-ui";
|
|
4
4
|
import { finalize } from "rxjs/operators";
|
|
5
5
|
import { HttpClient } from "@angular/common/http";
|
|
6
|
+
function countOf(loaders, name) {
|
|
7
|
+
return Object.hasOwn(loaders, name) ? loaders[name] : 0;
|
|
8
|
+
}
|
|
6
9
|
var ApiLoaderService = class ApiLoaderService {
|
|
7
10
|
loaders = signal({}, ...ngDevMode ? [{ debugName: "loaders" }] : /* istanbul ignore next */ []);
|
|
8
11
|
DEFAULT_TAG = "default";
|
|
@@ -11,22 +14,19 @@ var ApiLoaderService = class ApiLoaderService {
|
|
|
11
14
|
return Object.values(loaders).some((count) => count > 0);
|
|
12
15
|
}, ...ngDevMode ? [{ debugName: "show" }] : /* istanbul ignore next */ []);
|
|
13
16
|
getLoader(name) {
|
|
14
|
-
return computed(() => (this.loaders()
|
|
17
|
+
return computed(() => countOf(this.loaders(), name) > 0);
|
|
15
18
|
}
|
|
16
19
|
increase(name = this.DEFAULT_TAG) {
|
|
17
20
|
this.loaders.update((loaders) => ({
|
|
18
21
|
...loaders,
|
|
19
|
-
[name]: (loaders
|
|
22
|
+
[name]: countOf(loaders, name) + 1
|
|
20
23
|
}));
|
|
21
24
|
}
|
|
22
25
|
decrease(name = this.DEFAULT_TAG) {
|
|
23
|
-
this.loaders.update((loaders) => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
[name]: Math.max(0, current - 1)
|
|
28
|
-
};
|
|
29
|
-
});
|
|
26
|
+
this.loaders.update((loaders) => ({
|
|
27
|
+
...loaders,
|
|
28
|
+
[name]: Math.max(0, countOf(loaders, name) - 1)
|
|
29
|
+
}));
|
|
30
30
|
}
|
|
31
31
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
32
32
|
minVersion: "12.0.0",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flusys-ng-core.mjs","names":[],"sources":["../../../projects/ng-core/services/api-loader.service.ts","../../../projects/ng-core/components/lib-app-config/lib-app-config.component.ts","../../../projects/ng-core/interceptors/api-loader.interceptor.ts","../../../projects/ng-core/interfaces/app-config.interface.ts","../../../projects/ng-core/interfaces/translate-adapter.interface.ts","../../../projects/ng-core/services/base-api.service.ts"],"sourcesContent":["import { computed, Signal, signal, Service } from '@angular/core';\n\n@Service()\nexport class ApiLoaderService {\n private readonly loaders = signal<Record<string, number>>({});\n 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 { ConfirmDialog, ProgressbarComponent, ToastComponent } from '@flusys/ng-ui';\nimport { ApiLoaderService } from '../../services/api-loader.service';\n\n@Component({\n selector: 'lib-app-config',\n imports: [ConfirmDialog, ProgressbarComponent, ToastComponent],\n template: `\n @if (apiLoaderService.show()) {\n <f-progressbar mode=\"indeterminate\" />\n }\n <f-toast />\n <f-confirmdialog />\n `,\n styles: [\n `\n f-progressbar {\n position: fixed;\n }\n `,\n ],\n})\nexport class LibAppConfigComponent {\n readonly apiLoaderService = inject(ApiLoaderService);\n}\n","import { HttpEvent, HttpHandlerFn, HttpRequest } from '@angular/common/http';\nimport { inject } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { finalize } from 'rxjs/operators';\nimport { ApiLoaderService } from '../services/api-loader.service';\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 =\n 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(finalize(() => loaderService.decrease(loaderTag)));\n}\n","import { InjectionToken } from '@angular/core';\n\nexport type PermissionMode = 'rbac' | 'direct' | 'full';\n\nexport type ServiceName =\n | 'auth'\n | 'administration'\n | 'iam'\n | 'storage'\n | 'formBuilder'\n | 'email'\n | 'eventManager'\n | 'notification'\n | 'localization'\n | 'taskManager'\n | 'aiAssistant'\n | 'entityBuilder';\n\nexport interface IServiceConfig {\n baseUrl: string;\n enabled: boolean;\n}\n\nexport interface IStorageServiceConfig extends IServiceConfig {\n /** Default storage config ID (falls back to company/branch default if not set) */\n defaultStorageConfigId?: string;\n}\n\nexport interface INotificationServiceConfig extends IServiceConfig {\n /** WebSocket URL (defaults to baseUrl if not set) */\n socketUrl?: string;\n}\n\nexport interface IAuthorConfig {\n name: string;\n url: string;\n}\n\nexport interface IRegistrationDefaults {\n companySlug?: string;\n branchSlug?: string;\n}\n\n/** Layout skin — shared services and components, different shell markup and styling. */\nexport type LayoutTheme = 'classic' | 'modern';\n\nexport interface LayoutConfig {\n preset?: string;\n primary?: string;\n surface?: string | null;\n darkTheme?: boolean;\n menuMode?: 'static' | 'overlay' | 'topbar';\n /** @default 'classic' */\n layoutTheme?: LayoutTheme;\n isMemorable?: boolean;\n}\n\nexport interface IAppConfig {\n appName: string;\n appLogo: string;\n author?: IAuthorConfig;\n apiBaseUrl: string;\n enableCompanyFeature: boolean;\n /** @default true */\n enableSignUp?: boolean;\n registrationDefaults?: IRegistrationDefaults;\n layoutConfig?: LayoutConfig;\n services: {\n auth: IServiceConfig;\n administration: IServiceConfig;\n iam: IServiceConfig;\n storage: IStorageServiceConfig;\n formBuilder: IServiceConfig;\n email: IServiceConfig;\n eventManager: IServiceConfig;\n notification?: INotificationServiceConfig;\n localization?: IServiceConfig;\n taskManager?: IServiceConfig;\n aiAssistant?: IServiceConfig;\n entityBuilder?: IServiceConfig;\n };\n multiTenant: {\n enabled: boolean;\n tenantHeader: string;\n tenantId?: string;\n };\n /** 'rbac' | 'direct' | 'full' (default: 'full') */\n permissionMode?: PermissionMode;\n}\n\nexport const APP_CONFIG = new InjectionToken<IAppConfig>('APP_CONFIG');\n\nexport function isServiceEnabled(\n config: IAppConfig,\n serviceName: ServiceName,\n): boolean {\n const service = config.services[serviceName as keyof typeof config.services];\n return service?.enabled ?? false;\n}\n\nexport function getServiceUrl(\n config: IAppConfig,\n serviceName: ServiceName,\n): string {\n if (isServiceEnabled(config, serviceName)) {\n const service =\n config.services[serviceName as keyof typeof config.services];\n return service?.baseUrl ?? config.apiBaseUrl;\n }\n return config.apiBaseUrl;\n}\n\nexport function isCompanyFeatureEnabled(config: IAppConfig): boolean {\n return config.enableCompanyFeature ?? false;\n}\n\nexport function getNotificationSocketUrl(config: IAppConfig): string | null {\n const service = config.services.notification;\n if (!service?.enabled) return null;\n return service.socketUrl ?? service.baseUrl;\n}\n\nexport function getPermissionMode(config: IAppConfig): PermissionMode {\n return config.permissionMode ?? 'full';\n}\n\nexport function getDefaultStorageConfigId(\n config: IAppConfig,\n): string | undefined {\n return config.services.storage?.defaultStorageConfigId;\n}\n\nexport function isSignUpEnabled(config: IAppConfig): boolean {\n return config.enableSignUp ?? true;\n}\n\nexport function getDefaultCompanySlug(config: IAppConfig): string | undefined {\n return config.registrationDefaults?.companySlug;\n}\n\nexport function getDefaultBranchSlug(config: IAppConfig): string | undefined {\n return config.registrationDefaults?.branchSlug;\n}\n\nexport const DEFAULT_APP_NAME = 'FLUSYS';\nexport const DEFAULT_AUTHOR: IAuthorConfig = {\n name: 'Flusys',\n url: 'https://flusys.vercel.app',\n};\n","import { InjectionToken, Signal } from '@angular/core';\nimport { Observable } from 'rxjs';\n\nexport interface ITranslateAdapter {\n /** Current language code signal - read this to create reactive dependency */\n translate(key: string, params?: Record<string, unknown>): string;\n}\n\n/** Registry for fallback messages when localization is not active */\nexport const FALLBACK_MESSAGES_REGISTRY = new InjectionToken<\n Record<string, string>\n>('FALLBACK_MESSAGES_REGISTRY');\n// ✅ Provide it once at root as a single shared object\nexport const provideFallbackMessagesRegistry = (\n initialFallbackMessages?: Record<string, string>,\n) => ({\n provide: FALLBACK_MESSAGES_REGISTRY,\n useValue: initialFallbackMessages || {}, // Single object instance shared across all injections\n});\n\n// Injection Token for localization services used in the resolver\nexport interface ILocalizationStateServicesAdapter {\n updateFallbackMessages(messages: Record<string, string>): void;\n currentLanguageCode: Signal<string>;\n isModuleLoaded(module: string): boolean;\n mergeTranslations(translations: Record<string, string>): void;\n markModuleLoaded(module: string): void;\n currentLanguage: Signal<string>;\n translations: Signal<Record<string, string>>;\n fallbackMessages: Signal<Record<string, string>>;\n}\nexport interface ILocalizationApiServicesAdapter {\n getTranslationsByLanguage(\n languageCode: string,\n modules: string[],\n ): Observable<unknown>;\n}\nexport const LOCALIZATION_STATE_SERVICE =\n new InjectionToken<ILocalizationStateServicesAdapter>(\n 'LOCALIZATION_STATE_SERVICE',\n );\nexport const LOCALIZATION_API_SERVICE =\n new InjectionToken<ILocalizationApiServicesAdapter>(\n 'LOCALIZATION_API_SERVICE',\n );\n","import { HttpClient } from '@angular/common/http';\nimport { inject } from '@angular/core';\nimport {\n APP_CONFIG,\n getServiceUrl,\n ServiceName,\n} from '../interfaces/app-config.interface';\n\n/**\n * Base API Service\n * Provides service-specific base URL resolution\n *\n * Note: This project uses POST-only RPC - all endpoints use POST, not REST verbs.\n *\n * Usage:\n * ```typescript\n * @Service()\n * export class MyService extends BaseApiService {\n * constructor() {\n * super('my-service'); // Service name from config\n * }\n *\n * getData() {\n * return this.http.post(`${this.baseUrl}/data/get`, {});\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: ServiceName) {\n this.baseUrl = getServiceUrl(this.appConfig, serviceName);\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('/')\n ? endpoint.substring(1)\n : endpoint;\n return `${this.baseUrl}/${cleanEndpoint}`;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"flusys-ng-core.mjs","names":[],"sources":["../../../projects/ng-core/services/api-loader.service.ts","../../../projects/ng-core/components/lib-app-config/lib-app-config.component.ts","../../../projects/ng-core/interceptors/api-loader.interceptor.ts","../../../projects/ng-core/interfaces/app-config.interface.ts","../../../projects/ng-core/interfaces/translate-adapter.interface.ts","../../../projects/ng-core/services/base-api.service.ts"],"sourcesContent":["import { computed, Signal, signal, Service } from '@angular/core';\n\nfunction countOf(loaders: Record<string, number>, name: string): number {\n return Object.hasOwn(loaders, name) ? loaders[name] : 0;\n}\n\n@Service()\nexport class ApiLoaderService {\n private readonly loaders = signal<Record<string, number>>({});\n readonly DEFAULT_TAG = 'default';\n\n readonly show: Signal<boolean> = computed(() => {\n const loaders = this.loaders();\n return Object.values(loaders).some((count) => count > 0);\n });\n\n getLoader(name: string): Signal<boolean> {\n return computed(() => countOf(this.loaders(), name) > 0);\n }\n\n increase(name: string = this.DEFAULT_TAG): void {\n this.loaders.update((loaders) => ({\n ...loaders,\n [name]: countOf(loaders, name) + 1,\n }));\n }\n\n decrease(name: string = this.DEFAULT_TAG): void {\n this.loaders.update((loaders) => ({\n ...loaders,\n [name]: Math.max(0, countOf(loaders, name) - 1),\n }));\n }\n}\n","import { Component, inject } from '@angular/core';\nimport { ConfirmDialog, ProgressbarComponent, ToastComponent } from '@flusys/ng-ui';\nimport { ApiLoaderService } from '../../services/api-loader.service';\n\n@Component({\n selector: 'lib-app-config',\n imports: [ConfirmDialog, ProgressbarComponent, ToastComponent],\n template: `\n @if (apiLoaderService.show()) {\n <f-progressbar mode=\"indeterminate\" />\n }\n <f-toast />\n <f-confirmdialog />\n `,\n styles: [\n `\n f-progressbar {\n position: fixed;\n }\n `,\n ],\n})\nexport class LibAppConfigComponent {\n readonly apiLoaderService = inject(ApiLoaderService);\n}\n","import { HttpEvent, HttpHandlerFn, HttpRequest } from '@angular/common/http';\nimport { inject } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { finalize } from 'rxjs/operators';\nimport { ApiLoaderService } from '../services/api-loader.service';\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 =\n 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(finalize(() => loaderService.decrease(loaderTag)));\n}\n","import { InjectionToken } from '@angular/core';\n\nexport type PermissionMode = 'rbac' | 'direct' | 'full';\n\nexport type ServiceName =\n | 'auth'\n | 'administration'\n | 'iam'\n | 'storage'\n | 'formBuilder'\n | 'email'\n | 'eventManager'\n | 'notification'\n | 'localization'\n | 'taskManager'\n | 'aiAssistant'\n | 'entityBuilder';\n\nexport interface IServiceConfig {\n baseUrl: string;\n enabled: boolean;\n}\n\nexport interface IStorageServiceConfig extends IServiceConfig {\n /** Default storage config ID (falls back to company/branch default if not set) */\n defaultStorageConfigId?: string;\n}\n\nexport interface INotificationServiceConfig extends IServiceConfig {\n /** WebSocket URL (defaults to baseUrl if not set) */\n socketUrl?: string;\n}\n\nexport interface IAuthorConfig {\n name: string;\n url: string;\n}\n\nexport interface IRegistrationDefaults {\n companySlug?: string;\n branchSlug?: string;\n}\n\n/** Layout skin — shared services and components, different shell markup and styling. */\nexport type LayoutTheme = 'classic' | 'modern';\n\nexport interface LayoutConfig {\n preset?: string;\n primary?: string;\n surface?: string | null;\n darkTheme?: boolean;\n menuMode?: 'static' | 'overlay' | 'topbar';\n /** @default 'classic' */\n layoutTheme?: LayoutTheme;\n isMemorable?: boolean;\n}\n\nexport interface IAppConfig {\n appName: string;\n appLogo: string;\n author?: IAuthorConfig;\n apiBaseUrl: string;\n enableCompanyFeature: boolean;\n /** @default true */\n enableSignUp?: boolean;\n registrationDefaults?: IRegistrationDefaults;\n layoutConfig?: LayoutConfig;\n services: {\n auth: IServiceConfig;\n administration: IServiceConfig;\n iam: IServiceConfig;\n storage: IStorageServiceConfig;\n formBuilder: IServiceConfig;\n email: IServiceConfig;\n eventManager: IServiceConfig;\n notification?: INotificationServiceConfig;\n localization?: IServiceConfig;\n taskManager?: IServiceConfig;\n aiAssistant?: IServiceConfig;\n entityBuilder?: IServiceConfig;\n };\n multiTenant: {\n enabled: boolean;\n tenantHeader: string;\n tenantId?: string;\n };\n /** 'rbac' | 'direct' | 'full' (default: 'full') */\n permissionMode?: PermissionMode;\n}\n\nexport const APP_CONFIG = new InjectionToken<IAppConfig>('APP_CONFIG');\n\nexport function isServiceEnabled(\n config: IAppConfig,\n serviceName: ServiceName,\n): boolean {\n const service = config.services[serviceName as keyof typeof config.services];\n return service?.enabled ?? false;\n}\n\nexport function getServiceUrl(\n config: IAppConfig,\n serviceName: ServiceName,\n): string {\n if (isServiceEnabled(config, serviceName)) {\n const service =\n config.services[serviceName as keyof typeof config.services];\n return service?.baseUrl ?? config.apiBaseUrl;\n }\n return config.apiBaseUrl;\n}\n\nexport function isCompanyFeatureEnabled(config: IAppConfig): boolean {\n return config.enableCompanyFeature ?? false;\n}\n\nexport function getNotificationSocketUrl(config: IAppConfig): string | null {\n const service = config.services.notification;\n if (!service?.enabled) return null;\n return service.socketUrl ?? service.baseUrl;\n}\n\nexport function getPermissionMode(config: IAppConfig): PermissionMode {\n return config.permissionMode ?? 'full';\n}\n\nexport function getDefaultStorageConfigId(\n config: IAppConfig,\n): string | undefined {\n return config.services.storage?.defaultStorageConfigId;\n}\n\nexport function isSignUpEnabled(config: IAppConfig): boolean {\n return config.enableSignUp ?? true;\n}\n\nexport function getDefaultCompanySlug(config: IAppConfig): string | undefined {\n return config.registrationDefaults?.companySlug;\n}\n\nexport function getDefaultBranchSlug(config: IAppConfig): string | undefined {\n return config.registrationDefaults?.branchSlug;\n}\n\nexport const DEFAULT_APP_NAME = 'FLUSYS';\nexport const DEFAULT_AUTHOR: IAuthorConfig = {\n name: 'Flusys',\n url: 'https://flusys.vercel.app',\n};\n","import { InjectionToken, Signal } from '@angular/core';\nimport { Observable } from 'rxjs';\n\nexport interface ITranslateAdapter {\n /** Current language code signal - read this to create reactive dependency */\n translate(key: string, params?: Record<string, unknown>): string;\n}\n\n/** Registry for fallback messages when localization is not active */\nexport const FALLBACK_MESSAGES_REGISTRY = new InjectionToken<\n Record<string, string>\n>('FALLBACK_MESSAGES_REGISTRY');\n// ✅ Provide it once at root as a single shared object\nexport const provideFallbackMessagesRegistry = (\n initialFallbackMessages?: Record<string, string>,\n) => ({\n provide: FALLBACK_MESSAGES_REGISTRY,\n useValue: initialFallbackMessages || {}, // Single object instance shared across all injections\n});\n\n// Injection Token for localization services used in the resolver\nexport interface ILocalizationStateServicesAdapter {\n updateFallbackMessages(messages: Record<string, string>): void;\n currentLanguageCode: Signal<string>;\n isModuleLoaded(module: string): boolean;\n mergeTranslations(translations: Record<string, string>): void;\n markModuleLoaded(module: string): void;\n currentLanguage: Signal<string>;\n translations: Signal<Record<string, string>>;\n fallbackMessages: Signal<Record<string, string>>;\n}\nexport interface ILocalizationApiServicesAdapter {\n getTranslationsByLanguage(\n languageCode: string,\n modules: string[],\n ): Observable<unknown>;\n}\nexport const LOCALIZATION_STATE_SERVICE =\n new InjectionToken<ILocalizationStateServicesAdapter>(\n 'LOCALIZATION_STATE_SERVICE',\n );\nexport const LOCALIZATION_API_SERVICE =\n new InjectionToken<ILocalizationApiServicesAdapter>(\n 'LOCALIZATION_API_SERVICE',\n );\n","import { HttpClient } from '@angular/common/http';\nimport { inject } from '@angular/core';\nimport {\n APP_CONFIG,\n getServiceUrl,\n ServiceName,\n} from '../interfaces/app-config.interface';\n\n/**\n * Base API Service\n * Provides service-specific base URL resolution\n *\n * Note: This project uses POST-only RPC - all endpoints use POST, not REST verbs.\n *\n * Usage:\n * ```typescript\n * @Service()\n * export class MyService extends BaseApiService {\n * constructor() {\n * super('my-service'); // Service name from config\n * }\n *\n * getData() {\n * return this.http.post(`${this.baseUrl}/data/get`, {});\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: ServiceName) {\n this.baseUrl = getServiceUrl(this.appConfig, serviceName);\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('/')\n ? endpoint.substring(1)\n : endpoint;\n return `${this.baseUrl}/${cleanEndpoint}`;\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flusys/ng-core",
|
|
3
|
-
"version": "9.1
|
|
3
|
+
"version": "9.2.1",
|
|
4
4
|
"description": "Core utilities and services for FLUSYS Angular packages",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"peerDependencies": {
|
|
7
7
|
"@angular/common": ">=22.0.0",
|
|
8
8
|
"@angular/core": ">=22.0.0",
|
|
9
|
-
"@flusys/ng-ui": ">=9.1
|
|
9
|
+
"@flusys/ng-ui": ">=9.2.1",
|
|
10
10
|
"rxjs": "^7.8.0"
|
|
11
11
|
},
|
|
12
12
|
"sideEffects": false,
|