@aakash58/chatbot 1.1.34 → 1.1.35

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,9 +1,9 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { isDevMode, InjectionToken, signal, Optional, Inject, Injectable, inject, effect, EventEmitter, Output, Input, Component, Pipe, ViewChild, HostListener, Directive, computed, ChangeDetectionStrategy, ElementRef, ViewEncapsulation, makeEnvironmentProviders } from '@angular/core';
3
- import { delay, retry, map, catchError, of, BehaviorSubject, firstValueFrom, throwError, tap, Observable, Subject, lastValueFrom, switchMap, filter, take } from 'rxjs';
3
+ import { BehaviorSubject, delay, retry, map, catchError, of, firstValueFrom, throwError, tap, Observable, Subject, lastValueFrom, switchMap, filter, take } from 'rxjs';
4
4
  import { JwtHelperService } from '@auth0/angular-jwt';
5
5
  import * as i1 from '@angular/common/http';
6
- import { HttpHeaders, HttpEventType, HttpClient, HttpErrorResponse, HTTP_INTERCEPTORS } from '@angular/common/http';
6
+ import { HttpHeaders, HttpEventType, HttpErrorResponse, HTTP_INTERCEPTORS } from '@angular/common/http';
7
7
  import * as CryptoJS from 'crypto-js';
8
8
  import * as i4 from '@angular/router';
9
9
  import * as i1$1 from '@angular/cdk/overlay';
@@ -178,13 +178,12 @@ const DEFAULT_DOOHBOT_CONFIG = {
178
178
  retryAttempts: 2,
179
179
  retryDelay: 1000,
180
180
  apiSegment: 'api/',
181
- secretKey: '',
181
+ secretKey: undefined,
182
182
  storageKey: 'doohbot_storage',
183
- authToken: '',
184
- companyCode: '',
185
- tenancyName: '',
186
- licenseKey: '',
187
- licenseFilePath: '',
183
+ authToken: 'doohbot_storage',
184
+ companyCode: 'doohbot_storage',
185
+ tenancyName: 'doohbot_storage',
186
+ licenseKey: 'doohbot_storage',
188
187
  rememberMe: false,
189
188
  useStandardApi: false,
190
189
  enableDrag: false,
@@ -198,58 +197,72 @@ const DEFAULT_DOOHBOT_CONFIG = {
198
197
  */
199
198
  const DOOHBOT_CONFIG = new InjectionToken('DOOHBOT_CONFIG');
200
199
 
201
- // TODO: remove
202
- class CoreConfigService {
200
+ /**
201
+ * Centralized service for managing Doohbot configuration.
202
+ * Provides reactive access and runtime updates.
203
+ * Singleton via providedIn: 'root'.
204
+ */
205
+ class DoohbotConfigService {
206
+ /** Current configuration snapshot */
207
+ get config() {
208
+ return this.configSignal();
209
+ }
203
210
  constructor(injectedConfig = {}) {
204
- // Use DoohbotConfig for type-safe signal
205
- this.configSignal = signal({
206
- ...DEFAULT_DOOHBOT_CONFIG,
207
- }, ...(ngDevMode ? [{ debugName: "configSignal" }] : []));
208
- this.config$ = this.configSignal.asReadonly();
209
211
  // Merge injected config with defaults
210
- this.config = {
212
+ const mergedConfig = {
211
213
  ...DEFAULT_DOOHBOT_CONFIG,
212
214
  ...injectedConfig,
213
215
  };
214
- // Initialize signal with merged config
215
- this.configSignal.set(this.config);
216
+ this.validateConfig(mergedConfig);
217
+ // Initialize state
218
+ this.configSignal = signal(mergedConfig, ...(ngDevMode ? [{ debugName: "configSignal" }] : []));
219
+ this.configSubject = new BehaviorSubject(mergedConfig);
220
+ this.config$ = this.configSubject.asObservable();
216
221
  }
217
222
  /**
218
- * Updates the global library configuration
223
+ * Updates the global library configuration from dynamic runtime fields
219
224
  */
220
- updateConfig(input) {
225
+ updateRuntimeInput(input) {
221
226
  if (!input)
222
227
  return;
223
- // Map only the dynamic runtime fields
228
+ const current = this.configSignal();
224
229
  const updatedConfig = {
225
- ...this.configSignal(),
226
- authToken: input.authToken ?? this.configSignal().authToken,
230
+ ...current,
231
+ authToken: input.authToken ?? current.authToken,
232
+ licenseKey: input.licenseKey ?? current.licenseKey,
233
+ licenseFilePath: input.licenseFilePath ?? current.licenseFilePath,
227
234
  };
228
- this.configSignal.set(updatedConfig);
235
+ this.updateConfig(updatedConfig);
229
236
  }
230
237
  /**
231
238
  * Update configuration at runtime.
232
239
  * @param updates Partial config updates
233
240
  */
234
- updateRuntimeConfig(updates) {
241
+ updateConfig(updates) {
235
242
  const newConfig = { ...this.configSignal(), ...updates };
243
+ this.validateConfig(newConfig);
236
244
  this.configSignal.set(newConfig);
245
+ this.configSubject.next(newConfig);
246
+ }
247
+ validateConfig(config) {
248
+ if (config.timeout < 0)
249
+ throw new Error('timeout must be >= 0');
250
+ if (config.maxHistoryMessages < 0)
251
+ throw new Error('maxHistoryMessages must be >= 0');
252
+ if (config.retryAttempts < 0)
253
+ throw new Error('retryAttempts must be >= 0');
254
+ if (config.retryDelay < 0)
255
+ throw new Error('retryDelay must be >= 0');
237
256
  }
238
257
  /**
239
258
  * Dynamic getters for common config properties
240
259
  */
241
260
  get apiUrl() {
242
261
  const config = this.configSignal();
243
- if (config.apiBaseUrl) {
244
- return `${config.apiBaseUrl}${config.apiSegment || ''}`;
245
- }
246
- // Fallback to AppConst
247
- const appBase = this.config?.apiBaseUrl || '';
248
- const appSegment = this.config?.apiSegment || '';
249
- return `${appBase}${appSegment}`;
262
+ return `${config.apiBaseUrl}${config.apiSegment || ''}`;
250
263
  }
251
264
  get storageKey() {
252
- return this.configSignal().storageKey || '';
265
+ return this.configSignal().storageKey || 'doohbot_storage';
253
266
  }
254
267
  get secretKey() {
255
268
  return this.configSignal().secretKey || '';
@@ -267,7 +280,7 @@ class CoreConfigService {
267
280
  return this.configSignal().licenseFilePath || '';
268
281
  }
269
282
  get rememberMe() {
270
- return this.configSignal().rememberMe !== undefined ? this.configSignal().rememberMe : false;
283
+ return !!this.configSignal().rememberMe;
271
284
  }
272
285
  get useStandardApi() {
273
286
  return !!this.configSignal().useStandardApi;
@@ -279,20 +292,21 @@ class CoreConfigService {
279
292
  return !!this.configSignal().enableResize;
280
293
  }
281
294
  get apiConfig() {
282
- // Use specialized type if needed
283
295
  return this.configSignal().apiConfig;
284
296
  }
285
297
  get themeConfig() {
286
- // Use specialized type if needed
287
298
  return this.configSignal().themeConfig;
288
299
  }
289
300
  get buttonStyle() {
290
301
  return this.configSignal().buttonStyle || 'fab';
291
302
  }
292
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: CoreConfigService, deps: [{ token: DOOHBOT_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
293
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: CoreConfigService, providedIn: 'root' }); }
303
+ ngOnDestroy() {
304
+ this.configSubject.complete();
305
+ }
306
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DoohbotConfigService, deps: [{ token: DOOHBOT_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
307
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DoohbotConfigService, providedIn: 'root' }); }
294
308
  }
295
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: CoreConfigService, decorators: [{
309
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DoohbotConfigService, decorators: [{
296
310
  type: Injectable,
297
311
  args: [{
298
312
  providedIn: 'root',
@@ -306,13 +320,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
306
320
 
307
321
  class StorageService {
308
322
  get storageKey() {
309
- return this.coreConfig.storageKey;
323
+ return this.configService.storageKey;
310
324
  }
311
325
  get secretKey() {
312
- return this.coreConfig.secretKey;
326
+ return this.configService.secretKey;
313
327
  }
314
- constructor(coreConfig) {
315
- this.coreConfig = coreConfig;
328
+ constructor(configService) {
329
+ this.configService = configService;
316
330
  // Determine initial storage
317
331
  // If session storage has data, use it (implies remember me was false)
318
332
  // Otherwise default/fallback to local storage
@@ -399,7 +413,7 @@ class StorageService {
399
413
  return null;
400
414
  }
401
415
  }
402
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: StorageService, deps: [{ token: CoreConfigService }], target: i0.ɵɵFactoryTarget.Injectable }); }
416
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: StorageService, deps: [{ token: DoohbotConfigService }], target: i0.ɵɵFactoryTarget.Injectable }); }
403
417
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: StorageService, providedIn: 'root' }); }
404
418
  }
405
419
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: StorageService, decorators: [{
@@ -407,17 +421,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
407
421
  args: [{
408
422
  providedIn: 'root',
409
423
  }]
410
- }], ctorParameters: () => [{ type: CoreConfigService }] });
424
+ }], ctorParameters: () => [{ type: DoohbotConfigService }] });
411
425
 
412
426
  class HttpService {
413
427
  // @BlockUI() blockUI!: NgBlockUI;
414
428
  get apiUrl() {
415
- return this.coreConfig.apiUrl;
429
+ return this.configService.apiUrl;
416
430
  }
417
- constructor(http, tokenStorage, coreConfig) {
431
+ constructor(http, tokenStorage, configService) {
418
432
  this.http = http;
419
433
  this.tokenStorage = tokenStorage;
420
- this.coreConfig = coreConfig;
434
+ this.configService = configService;
421
435
  Logger.log('HttpService: Initialized');
422
436
  }
423
437
  get(url, param, nestedParam = false, showLoader = false, refresh = true, headers) {
@@ -495,7 +509,7 @@ class HttpService {
495
509
  // }
496
510
  return value;
497
511
  }
498
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: HttpService, deps: [{ token: i1.HttpClient }, { token: StorageService }, { token: CoreConfigService }], target: i0.ɵɵFactoryTarget.Injectable }); }
512
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: HttpService, deps: [{ token: i1.HttpClient }, { token: StorageService }, { token: DoohbotConfigService }], target: i0.ɵɵFactoryTarget.Injectable }); }
499
513
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: HttpService, providedIn: 'root' }); }
500
514
  }
501
515
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: HttpService, decorators: [{
@@ -503,7 +517,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
503
517
  args: [{
504
518
  providedIn: 'root',
505
519
  }]
506
- }], ctorParameters: () => [{ type: i1.HttpClient }, { type: StorageService }, { type: CoreConfigService }] });
520
+ }], ctorParameters: () => [{ type: i1.HttpClient }, { type: StorageService }, { type: DoohbotConfigService }] });
507
521
 
508
522
  class AccountService {
509
523
  constructor(http, tokenStorage) {
@@ -592,23 +606,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
592
606
 
593
607
  class AuthService {
594
608
  get apiUrl() {
595
- return this.coreConfig.apiUrl;
609
+ return this.configService.apiUrl;
596
610
  }
597
611
  get storageKey() {
598
- return this.coreConfig.storageKey;
612
+ return this.configService.storageKey;
599
613
  }
600
614
  get secretKey() {
601
- return this.coreConfig.secretKey;
615
+ return this.configService.secretKey;
602
616
  }
603
617
  get companyCode() {
604
- return this.coreConfig.companyCode;
618
+ return this.configService.companyCode;
605
619
  }
606
- constructor(accountService, cryptoHelper, tokenStorage, router, coreConfig) {
620
+ constructor(accountService, cryptoHelper, tokenStorage, router, configService) {
607
621
  this.accountService = accountService;
608
622
  this.cryptoHelper = cryptoHelper;
609
623
  this.tokenStorage = tokenStorage;
610
624
  this.router = router;
611
- this.coreConfig = coreConfig;
625
+ this.configService = configService;
612
626
  this.jwtHelper = new JwtHelperService();
613
627
  this.advancedConfig = inject(DOOHBOT_ADVANCED_CONFIG, { optional: true });
614
628
  // Reactive Authentication State
@@ -624,7 +638,7 @@ class AuthService {
624
638
  * Updates the service configuration from the component input
625
639
  */
626
640
  updateConfig(config) {
627
- this.coreConfig.updateConfig(config);
641
+ this.configService.updateRuntimeInput(config);
628
642
  }
629
643
  getLoggedInUserName() {
630
644
  const username = this.tokenStorage.get('username');
@@ -649,7 +663,7 @@ class AuthService {
649
663
  * Resolves a federated token from browser storage
650
664
  */
651
665
  resolveSilentToken() {
652
- const config = this.coreConfig.config$();
666
+ const config = this.configService.config;
653
667
  const commonKeys = ['access_token', 'id_token', 'token', 'authToken'];
654
668
  // 1. Try explicit authToken from config (Highest Priority)
655
669
  if (config.authToken) {
@@ -916,7 +930,7 @@ class AuthService {
916
930
  };
917
931
  }
918
932
  get licenseKey() {
919
- return this.tokenStorage.get('license_key') || this.coreConfig.licenseKey || '';
933
+ return this.tokenStorage.get('license_key') || this.configService.licenseKey || '';
920
934
  }
921
935
  get isFederated() {
922
936
  return this.licenseKey.startsWith('doohbot_lic_');
@@ -955,7 +969,7 @@ class AuthService {
955
969
  clearCache() {
956
970
  // this.cacheService.clear();
957
971
  }
958
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: AuthService, deps: [{ token: AccountService }, { token: CryptoHelperService }, { token: StorageService }, { token: i4.Router }, { token: CoreConfigService }], target: i0.ɵɵFactoryTarget.Injectable }); }
972
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: AuthService, deps: [{ token: AccountService }, { token: CryptoHelperService }, { token: StorageService }, { token: i4.Router }, { token: DoohbotConfigService }], target: i0.ɵɵFactoryTarget.Injectable }); }
959
973
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: AuthService, providedIn: 'root' }); }
960
974
  }
961
975
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: AuthService, decorators: [{
@@ -963,7 +977,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
963
977
  args: [{
964
978
  providedIn: 'root',
965
979
  }]
966
- }], ctorParameters: () => [{ type: AccountService }, { type: CryptoHelperService }, { type: StorageService }, { type: i4.Router }, { type: CoreConfigService }] });
980
+ }], ctorParameters: () => [{ type: AccountService }, { type: CryptoHelperService }, { type: StorageService }, { type: i4.Router }, { type: DoohbotConfigService }] });
967
981
 
968
982
  const BASE_STORAGE_KEY = 'app.personalization.v1';
969
983
  const DEFAULT_SETTINGS = {
@@ -2877,7 +2891,7 @@ class ChatService {
2877
2891
  // Dependencies
2878
2892
  this.apiService = inject(ChatApiService);
2879
2893
  this.authService = inject(AuthService);
2880
- this.customConfig = inject(CoreConfigService);
2894
+ this.configService = inject(DoohbotConfigService);
2881
2895
  this.audioService = inject(ChatAudioService);
2882
2896
  this.config = inject(DOOHBOT_ADVANCED_CONFIG, { optional: true });
2883
2897
  this.chatHistoryService = inject(ChatHistoryService);
@@ -2904,7 +2918,7 @@ class ChatService {
2904
2918
  this.isBotTyping = signal(false, ...(ngDevMode ? [{ debugName: "isBotTyping" }] : []));
2905
2919
  this.promptMode = signal('markdown', ...(ngDevMode ? [{ debugName: "promptMode" }] : []));
2906
2920
  //! Controls whether to use Streaming API (default) or Standard API
2907
- this.isStreaming = computed(() => !this.customConfig.useStandardApi, ...(ngDevMode ? [{ debugName: "isStreaming" }] : []));
2921
+ this.isStreaming = computed(() => !this.configService.useStandardApi, ...(ngDevMode ? [{ debugName: "isStreaming" }] : []));
2908
2922
  this.messagesStream = [];
2909
2923
  this.currentResponse = '';
2910
2924
  this.cancelSubject = new Subject();
@@ -4429,68 +4443,136 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
4429
4443
  }] } });
4430
4444
 
4431
4445
  class LicenseService {
4432
- constructor() {
4433
- this.coreConfig = inject(CoreConfigService);
4434
- this.http = inject(HttpClient);
4435
- // Registry for flat map: { "tenantName": "licenseKey" }
4436
- this.registry = signal(new Map(), ...(ngDevMode ? [{ debugName: "registry" }] : []));
4446
+ constructor(http) {
4447
+ this.http = http;
4448
+ // private http = inject(HttpClient);
4449
+ this.configService = inject(DoohbotConfigService);
4450
+ this.registry = signal(null, ...(ngDevMode ? [{ debugName: "registry" }] : []));
4437
4451
  }
4438
4452
  /**
4439
4453
  * Load the license configuration from a JSON file.
4440
- * Expected format: { "tenantName": "licenseKey" }
4454
+ * Supports both Hierarchical (entitlements) and Flat-map (package:key) formats.
4455
+ * @param filePath Path to the license JSON file
4441
4456
  */
4442
4457
  async loadLicenseFile(filePath) {
4443
4458
  try {
4444
- const finalPath = filePath || this.coreConfig.licenseFilePath;
4445
- if (!finalPath) {
4446
- Logger.debug('[LicenseService] No license file path provided.');
4447
- return;
4448
- }
4449
- Logger.log(`[LicenseService] Loading flat-map license file: ${finalPath}`);
4459
+ const finalPath = filePath || this.configService.licenseFilePath;
4450
4460
  const data = await firstValueFrom(this.http.get(finalPath));
4451
- if (data) {
4452
- const newRegistry = new Map(Object.entries(data));
4453
- this.registry.set(newRegistry);
4454
- Logger.log(`[LicenseService] License registry loaded with ${newRegistry.size} entries.`);
4461
+ if (!data) {
4462
+ throw new Error('Empty license file');
4463
+ }
4464
+ // Detection: Hierarchical Format (subjectId/licenses array)
4465
+ if (data.licenses && Array.isArray(data.licenses)) {
4466
+ this.processHierarchicalLicense(data);
4467
+ }
4468
+ // Detection: Flat Map Format (packageId: key)
4469
+ else {
4470
+ this.processFlatMapLicense(data);
4455
4471
  }
4456
4472
  }
4457
4473
  catch (error) {
4458
- Logger.info('[LicenseService] Optional license file not found or failed to load.');
4459
- this.registry.set(new Map());
4474
+ // Industry pattern: Silent loading for optional registry files
4475
+ Logger.log('[LicenseService] No external license file found or failed to load. Falling back to AppConst.');
4476
+ this.registry.set(null);
4460
4477
  }
4461
4478
  }
4479
+ processHierarchicalLicense(data) {
4480
+ const subjectMap = new Map();
4481
+ data.licenses.forEach((license) => {
4482
+ const key = `${license.subjectType}:${license.subjectId}`;
4483
+ subjectMap.set(key, license.packages);
4484
+ });
4485
+ this.registry.set({
4486
+ accountId: data.accountId,
4487
+ subjectLicenses: subjectMap,
4488
+ });
4489
+ Logger.log(`[LicenseService] Hierarchical Registry loaded for account: ${data.accountId}`);
4490
+ }
4491
+ processFlatMapLicense(data) {
4492
+ // Flat-map format: { "tenantName": "license_key" }
4493
+ // Convert each entry to: tenant:tenantName -> { doohbot: license_key }
4494
+ const subjectMap = new Map();
4495
+ Object.entries(data).forEach(([tenantName, licenseKey]) => {
4496
+ const tenantKey = `tenant:${tenantName}`;
4497
+ subjectMap.set(tenantKey, {
4498
+ doohbot: licenseKey,
4499
+ });
4500
+ });
4501
+ this.registry.set({
4502
+ accountId: 'FLAT_MAP_REGISTRY',
4503
+ subjectLicenses: subjectMap,
4504
+ });
4505
+ Logger.log(`[LicenseService] Flat-map registry loaded with ${subjectMap.size} tenant(s)`);
4506
+ }
4462
4507
  /**
4463
- * Resolves the license key for the current tenant.
4464
- * @param tenancyName Optional override for tenancy name
4508
+ * Resolve the correct license key based on context and requested package
4509
+ * @param context The current licensing context (tenant, user, roles)
4510
+ * @param packageId The ID of the package requesting a license
4511
+ * @returns The resolved license key, or null if unauthorized
4465
4512
  */
4466
- resolveTenantLicenseKey(tenancyName) {
4467
- const name = tenancyName || this.coreConfig.tenancyName;
4468
- if (!name) {
4469
- Logger.warn('[LicenseService] Cannot resolve license: No tenancy name provided.');
4513
+ resolveLicenseKey(context, packageId) {
4514
+ // Hierarchical Registry (Most Specific)
4515
+ const keyFromRegistry = this.resolveFromRegistry(context, packageId);
4516
+ if (keyFromRegistry)
4517
+ return keyFromRegistry;
4518
+ Logger.warn(`[LicenseService] No license found for package: ${packageId} and user: ${context.principalId}`);
4519
+ return null;
4520
+ }
4521
+ resolveFromRegistry(context, packageId) {
4522
+ const reg = this.registry();
4523
+ if (!reg)
4524
+ return null;
4525
+ // Strict Account Check
4526
+ if (reg.accountId !== 'EXTERNAL_OVERRIDE' && reg.accountId !== context.tenantId) {
4527
+ Logger.error(`[LicenseService] Account mismatch! Registry: ${reg.accountId}, Context: ${context.tenantId}`);
4470
4528
  return null;
4471
4529
  }
4472
- const key = this.registry().get(name);
4473
- if (key) {
4474
- Logger.debug(`[LicenseService] Resolved license key for tenant: ${name}`);
4475
- return key;
4530
+ const subjectsToSearch = [
4531
+ `user:${context.principalId}`,
4532
+ ...(context.roles?.map((r) => `role:${r}`) || []),
4533
+ `tenant:${context.tenantId}`,
4534
+ 'tenant:default', // Fallback for flat-map external files
4535
+ ];
4536
+ for (const subjectKey of subjectsToSearch) {
4537
+ const packages = reg.subjectLicenses.get(subjectKey);
4538
+ if (packages && packages[packageId]) {
4539
+ Logger.debug(`[LicenseService] Resolved key for ${packageId} via Registry (${subjectKey})`);
4540
+ return packages[packageId];
4541
+ }
4476
4542
  }
4477
- Logger.warn(`[LicenseService] No license key found in registry for tenant: ${name}`);
4478
4543
  return null;
4479
4544
  }
4480
4545
  /**
4481
- * Resolve key using context (for interceptors)
4546
+ * Resolves the license key for the current tenant.
4482
4547
  */
4483
- resolveLicenseKey(context, packageId = 'doohbot') {
4484
- // In flat-map mode, we treat context.tenantId as the tenancy name
4485
- return this.resolveTenantLicenseKey(context.tenantId);
4548
+ resolveTenantLicenseKey(tenancyName) {
4549
+ const activeTenancy = tenancyName || this.configService.tenancyName;
4550
+ if (!activeTenancy) {
4551
+ Logger.warn('[LicenseService] No tenancy name found.');
4552
+ return null;
4553
+ }
4554
+ const reg = this.registry();
4555
+ if (!reg) {
4556
+ Logger.error('[LicenseService] License registry not loaded.');
4557
+ return null;
4558
+ }
4559
+ const tenantLicenses = reg.subjectLicenses.get(`tenant:${activeTenancy}`);
4560
+ const licenseKey = tenantLicenses?.['doohbot'] || null;
4561
+ if (licenseKey) {
4562
+ Logger.info(`[LicenseService] Resolved Doohbot license for: ${activeTenancy}`);
4563
+ }
4564
+ else {
4565
+ Logger.warn(`[LicenseService] No license key found for tenant: ${activeTenancy}`);
4566
+ }
4567
+ return licenseKey;
4486
4568
  }
4487
4569
  /**
4488
4570
  * Check if a registry is currently loaded
4489
4571
  */
4490
4572
  isRegistryLoaded() {
4491
- return this.registry().size > 0;
4573
+ return this.registry() !== null;
4492
4574
  }
4493
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: LicenseService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4575
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: LicenseService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); }
4494
4576
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: LicenseService, providedIn: 'root' }); }
4495
4577
  }
4496
4578
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: LicenseService, decorators: [{
@@ -4498,7 +4580,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
4498
4580
  args: [{
4499
4581
  providedIn: 'root',
4500
4582
  }]
4501
- }] });
4583
+ }], ctorParameters: () => [{ type: i1.HttpClient }] });
4502
4584
 
4503
4585
  /**
4504
4586
  * Doohbot Main Component
@@ -4507,10 +4589,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
4507
4589
  class DoohbotComponent {
4508
4590
  // Configuration exposure for template
4509
4591
  get enableDrag() {
4510
- return this.coreConfig?.enableDrag ?? false;
4592
+ return this.configService?.enableDrag ?? false;
4511
4593
  }
4512
4594
  get enableResize() {
4513
- return this.coreConfig?.enableResize ?? false;
4595
+ return this.configService?.enableResize ?? false;
4514
4596
  }
4515
4597
  //! ======================= CONSTRUCTOR ========================
4516
4598
  constructor(elementRef, renderer, dialogService, snackbarService) {
@@ -4531,7 +4613,7 @@ class DoohbotComponent {
4531
4613
  // private snackbarService = inject(SnackbarService);
4532
4614
  this.personalization = inject(PersonalizationService);
4533
4615
  this.licenseService = inject(LicenseService);
4534
- this.coreConfig = inject(CoreConfigService);
4616
+ this.configService = inject(DoohbotConfigService);
4535
4617
  //! ========================= EXPOSED STATE FROM SERVICES ============================
4536
4618
  // UI State signals
4537
4619
  this.isChatOpen = this.uiState.isChatOpen;
@@ -4576,7 +4658,7 @@ class DoohbotComponent {
4576
4658
  this.renderer.removeClass(host, 'dark-theme');
4577
4659
  this.renderer.addClass(host, activeTheme);
4578
4660
  // Apply theme configuration from global config
4579
- const themeConfig = this.coreConfig?.themeConfig;
4661
+ const themeConfig = this.configService?.themeConfig;
4580
4662
  if (themeConfig) {
4581
4663
  this.themeService.setThemeConfig(themeConfig, host);
4582
4664
  if (themeConfig.primaryColor) {
@@ -4589,11 +4671,7 @@ class DoohbotComponent {
4589
4671
  // Corrected structural integrity.
4590
4672
  async ngOnInit() {
4591
4673
  Logger.log('Initializing Doohbot component...');
4592
- const path = this.coreConfig.licenseFilePath;
4593
- const licenseKey = this.coreConfig.licenseKey;
4594
- if (licenseKey) {
4595
- this.authService.setLicenseKey(licenseKey);
4596
- }
4674
+ const path = this.configService.licenseFilePath;
4597
4675
  // Load license registry from file and wait for it to complete
4598
4676
  if (path) {
4599
4677
  await this.licenseService.loadLicenseFile(path);
@@ -4630,14 +4708,14 @@ class DoohbotComponent {
4630
4708
  }
4631
4709
  canAttemptFederatedLogin() {
4632
4710
  const hasAuthToken = !!this.config?.authToken;
4633
- const hasDirectLicenseKey = !!this.coreConfig?.licenseKey;
4634
- const hasTenantLicenseLookup = !!this.coreConfig?.tenancyName && !!this.coreConfig?.licenseFilePath;
4711
+ const hasDirectLicenseKey = !!this.configService?.licenseKey;
4712
+ const hasTenantLicenseLookup = !!this.configService?.tenancyName && !!this.configService?.licenseFilePath;
4635
4713
  const hasValidLicenseContext = hasDirectLicenseKey || hasTenantLicenseLookup;
4636
4714
  return hasAuthToken && hasValidLicenseContext;
4637
4715
  }
4638
4716
  initializeUI() {
4639
4717
  // Apply theme from global configuration
4640
- const themeConfig = this.coreConfig?.themeConfig;
4718
+ const themeConfig = this.configService?.themeConfig;
4641
4719
  if (themeConfig) {
4642
4720
  this.themeService.setThemeConfig(themeConfig, this.elementRef.nativeElement);
4643
4721
  }
@@ -4665,13 +4743,13 @@ class DoohbotComponent {
4665
4743
  this.authService.updateConfig(this.config);
4666
4744
  this.userAvatarUrl();
4667
4745
  this.updateUserName();
4668
- if (this.coreConfig?.licenseKey) {
4669
- this.authService.setLicenseKey(this.coreConfig.licenseKey);
4746
+ if (this.configService?.licenseKey) {
4747
+ this.authService.setLicenseKey(this.configService.licenseKey);
4670
4748
  }
4671
4749
  // Sync button style from global config to personalization
4672
- if (this.coreConfig?.buttonStyle) {
4750
+ if (this.configService?.buttonStyle) {
4673
4751
  this.personalization.setDeveloperDefaults({
4674
- buttonStyle: this.coreConfig.buttonStyle,
4752
+ buttonStyle: this.configService.buttonStyle,
4675
4753
  });
4676
4754
  }
4677
4755
  // Handle dynamic config updates for authentication
@@ -4688,7 +4766,7 @@ class DoohbotComponent {
4688
4766
  // Logic moved to ChatFacadeService.initialize()
4689
4767
  onNormalLogin(credentials) {
4690
4768
  // Use Tenancy Name from Global Config
4691
- let tenancy = this.coreConfig?.tenancyName;
4769
+ let tenancy = this.configService?.tenancyName;
4692
4770
  //! fallback: Try to resolve from global utility (Auto-detect)
4693
4771
  // if (!tenancy) {
4694
4772
  // tenancy = window.AppPreBootstrap?.resolveTenancyName(window.AppConsts?.appBaseUrl);
@@ -4708,14 +4786,14 @@ class DoohbotComponent {
4708
4786
  let autoKey = this.licenseService.resolveTenantLicenseKey();
4709
4787
  // Fallback to Global Config
4710
4788
  if (!autoKey) {
4711
- autoKey = this.coreConfig?.licenseKey || '';
4789
+ autoKey = this.configService?.licenseKey || '';
4712
4790
  }
4713
4791
  if (autoKey) {
4714
4792
  this.authService.setLicenseKey(autoKey);
4715
4793
  }
4716
4794
  const request = {
4717
4795
  accessToken: token,
4718
- rememberMe: this.coreConfig?.rememberMe,
4796
+ rememberMe: this.configService?.rememberMe,
4719
4797
  license: autoKey || '',
4720
4798
  };
4721
4799
  // Await the federated login result
@@ -4851,7 +4929,7 @@ class DoohbotComponent {
4851
4929
  }
4852
4930
  const loggedInName = this.authService.getLoggedInUserName();
4853
4931
  // const contextName = this.userContext?.userName;
4854
- const configName = this.coreConfig?.config$().authToken ? 'User' : ''; // simplified username logic
4932
+ const configName = this.configService?.config.authToken ? 'User' : ''; // simplified username logic
4855
4933
  if (configName) {
4856
4934
  this.userName = configName;
4857
4935
  }
@@ -5082,7 +5160,6 @@ function provideDoohbot(config = {}) {
5082
5160
  useClass: LicenseInterceptor,
5083
5161
  multi: true,
5084
5162
  },
5085
- CoreConfigService,
5086
5163
  DoohbotConfigService,
5087
5164
  ]);
5088
5165
  }
@@ -5124,72 +5201,6 @@ function provideDoohbotMinimal(config = {}) {
5124
5201
  ]);
5125
5202
  }
5126
5203
 
5127
- /**
5128
- * Centralized service for managing Doohbot configuration.
5129
- * Provides reactive access and runtime updates.
5130
- * Singleton via providedIn: 'root'.
5131
- */
5132
- class DoohbotConfigService {
5133
- /** Current configuration snapshot */
5134
- get config() {
5135
- return this.configSubject.value;
5136
- }
5137
- constructor(userConfig) {
5138
- const mergedConfig = {
5139
- ...DEFAULT_DOOHBOT_CONFIG,
5140
- ...userConfig,
5141
- };
5142
- this.validateConfig(mergedConfig);
5143
- this.configSubject = new BehaviorSubject(mergedConfig);
5144
- this.config$ = this.configSubject.asObservable();
5145
- }
5146
- /**
5147
- * Update configuration at runtime.
5148
- * @param updates Partial config updates
5149
- */
5150
- updateConfig(updates) {
5151
- const newConfig = { ...this.config, ...updates };
5152
- this.validateConfig(newConfig);
5153
- this.configSubject.next(newConfig);
5154
- }
5155
- validateConfig(config) {
5156
- if (config.timeout < 0)
5157
- throw new Error('timeout must be >= 0');
5158
- if (config.maxHistoryMessages < 0)
5159
- throw new Error('maxHistoryMessages must be >= 0');
5160
- if (config.retryAttempts < 0)
5161
- throw new Error('retryAttempts must be >= 0');
5162
- if (config.retryDelay < 0)
5163
- throw new Error('retryDelay must be >= 0');
5164
- if (config.environment === 'production' && !this.isValidUrl(config.apiBaseUrl)) {
5165
- console.warn('DoohbotConfig: apiBaseUrl may be invalid in production');
5166
- }
5167
- }
5168
- isValidUrl(url) {
5169
- try {
5170
- new URL(url);
5171
- return true;
5172
- }
5173
- catch {
5174
- return false;
5175
- }
5176
- }
5177
- ngOnDestroy() {
5178
- this.configSubject.complete();
5179
- }
5180
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DoohbotConfigService, deps: [{ token: DOOHBOT_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
5181
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DoohbotConfigService, providedIn: 'root' }); }
5182
- }
5183
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: DoohbotConfigService, decorators: [{
5184
- type: Injectable,
5185
- args: [{ providedIn: 'root' }]
5186
- }], ctorParameters: () => [{ type: undefined, decorators: [{
5187
- type: Optional
5188
- }, {
5189
- type: Inject,
5190
- args: [DOOHBOT_CONFIG]
5191
- }] }] });
5192
-
5193
5204
  /**
5194
5205
  * public-api.ts
5195
5206
  * Main public API surface of the Doohbot library.