http-request-manager 18.12.3 → 18.12.5

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.
@@ -883,28 +883,66 @@ class StreamingProcessor {
883
883
  this.buffer = '';
884
884
  this.contentType = '';
885
885
  this.maxBufferSize = 10 * 1024 * 1024; // 10MB limit
886
+ this.lastParsedLength = 0; // Track parsed position to avoid duplicates
886
887
  this.streamConfig = config || { streamType: StreamType.AI_STREAMING };
887
888
  }
888
889
  /**
889
- * Process HTTP events and extract streaming data
890
+ * Process HTTP events and extract streaming data with progress
890
891
  */
891
892
  process(event) {
892
893
  switch (event.type) {
893
894
  case HttpEventType.ResponseHeader:
894
895
  this.contentType = event.headers?.get('content-type') || '';
896
+ // Read total from response header if configured
897
+ if (this.streamConfig.totalHeader && event.headers) {
898
+ const totalVal = event.headers.get(this.streamConfig.totalHeader);
899
+ if (totalVal !== undefined && totalVal !== null) {
900
+ const parsed = parseInt(totalVal, 10);
901
+ if (!isNaN(parsed)) {
902
+ this.totalFromHeader = parsed;
903
+ }
904
+ }
905
+ }
895
906
  return null;
896
907
  case HttpEventType.DownloadProgress:
897
908
  if (event.partialText) {
898
909
  this.appendToBuffer(event.partialText);
899
910
  const parsedData = this.parseBuffer();
900
- return parsedData.length > 0 ? [parsedData[0]] : null;
911
+ // Only return NEW items since last parse (progressive updates)
912
+ const newItems = parsedData.slice(this.lastParsedLength);
913
+ this.lastParsedLength = parsedData.length;
914
+ // Calculate progress
915
+ const progress = {
916
+ received: this.lastParsedLength,
917
+ total: this.totalFromHeader,
918
+ percent: this.totalFromHeader
919
+ ? Math.round((this.lastParsedLength / this.totalFromHeader) * 100)
920
+ : 0,
921
+ stage: 'streaming'
922
+ };
923
+ return {
924
+ data: newItems.length > 0 ? newItems : [],
925
+ progress
926
+ };
901
927
  }
902
928
  return null;
903
929
  case HttpEventType.Response:
904
930
  if (event.body) {
905
931
  this.appendToBuffer(event.body);
906
932
  const parsedData = this.parseBuffer();
907
- return parsedData.length > 0 ? parsedData : null;
933
+ // Calculate final progress
934
+ const progress = {
935
+ received: parsedData.length,
936
+ total: this.totalFromHeader,
937
+ percent: this.totalFromHeader
938
+ ? Math.round((parsedData.length / this.totalFromHeader) * 100)
939
+ : 100,
940
+ stage: 'complete'
941
+ };
942
+ return {
943
+ data: parsedData.length > 0 ? parsedData : [],
944
+ progress
945
+ };
908
946
  }
909
947
  return null;
910
948
  default:
@@ -943,6 +981,8 @@ class StreamingProcessor {
943
981
  reset() {
944
982
  this.buffer = '';
945
983
  this.contentType = '';
984
+ this.lastParsedLength = 0;
985
+ this.totalFromHeader = undefined;
946
986
  }
947
987
  /**
948
988
  * Update configuration
@@ -2793,19 +2833,6 @@ class UploadValidationErrorModel {
2793
2833
  }
2794
2834
  }
2795
2835
 
2796
- class UserData {
2797
- constructor(ldap = '', name = '', email = '', color = RandomPaletteColor()) {
2798
- this.ldap = ldap;
2799
- this.name = name;
2800
- this.email = email;
2801
- this.color = color;
2802
- }
2803
- static adapt(item) {
2804
- const userName = `${item?.first_name} ${item?.last_name}`;
2805
- return new UserData(item?.ldap, userName, item?.email, item?.color);
2806
- }
2807
- }
2808
-
2809
2836
  class RequestService extends WebsocketService {
2810
2837
  constructor() {
2811
2838
  super(...arguments);
@@ -2816,6 +2843,13 @@ class RequestService extends WebsocketService {
2816
2843
  this.isPending$ = this.isPending.asObservable();
2817
2844
  this.progress = new BehaviorSubject(0);
2818
2845
  this.progress$ = this.progress.asObservable();
2846
+ this.streamProgress = new BehaviorSubject({
2847
+ received: 0,
2848
+ total: undefined,
2849
+ percent: 0,
2850
+ stage: 'connecting'
2851
+ });
2852
+ this.streamProgress$ = this.streamProgress.asObservable();
2819
2853
  }
2820
2854
  // Implementation
2821
2855
  getRecordRequest(options) {
@@ -2884,7 +2918,12 @@ class RequestService extends WebsocketService {
2884
2918
  }
2885
2919
  requestStreaming(options) {
2886
2920
  return (source$) => {
2887
- return source$.pipe(map(data => {
2921
+ return source$.pipe(tap(output => {
2922
+ // Update progress from stream output
2923
+ this.progress.next(output.progress.received);
2924
+ this.streamProgress.next(output.progress);
2925
+ }), map(output => {
2926
+ const data = output.data;
2888
2927
  if (!data || (Array.isArray(data) && data.length === 0)) {
2889
2928
  return data;
2890
2929
  }
@@ -3586,6 +3625,7 @@ class HTTPManagerService extends RequestService {
3586
3625
  this.data$ = this.data.asObservable();
3587
3626
  this.polling$ = new Subject();
3588
3627
  this.config = ApiRequest.adapt();
3628
+ this.streamProgress$ = this.streamProgress.asObservable();
3589
3629
  this.config = (configOptions) ? ApiRequest.adapt(configOptions.httpRequestOptions) : this.config;
3590
3630
  }
3591
3631
  // ═══════════════════════════════════════════════════════════════════════════
@@ -3722,6 +3762,12 @@ class HTTPManagerService extends RequestService {
3722
3762
  getRequest(options, params) {
3723
3763
  this.isPending.next(true);
3724
3764
  this.data.next(null);
3765
+ this.streamProgress.next({
3766
+ received: 0,
3767
+ total: undefined,
3768
+ percent: 0,
3769
+ stage: 'connecting'
3770
+ });
3725
3771
  const updatedOptions = this.defineReqOptions(options, params);
3726
3772
  const func = this.getRecordRequest;
3727
3773
  const requests = this.createRequest(func, updatedOptions);
@@ -3730,9 +3776,19 @@ class HTTPManagerService extends RequestService {
3730
3776
  this.data.next(data);
3731
3777
  if (updatedOptions.displaySuccess)
3732
3778
  this.handleSuccessWithSnackBar(updatedOptions.successMessage);
3733
- })).pipe(finalize(() => this.isPending.next(false)), catchError((err) => {
3779
+ }), finalize(() => {
3780
+ this.streamProgress.next({
3781
+ ...this.streamProgress.value,
3782
+ stage: 'complete'
3783
+ });
3784
+ this.isPending.next(false);
3785
+ }), catchError((err) => {
3734
3786
  if (updatedOptions.displayError)
3735
3787
  this.handleErrorWithSnackBar(err, updatedOptions.errorMessage || err?.message);
3788
+ this.streamProgress.next({
3789
+ ...this.streamProgress.value,
3790
+ stage: 'error'
3791
+ });
3736
3792
  this.isPending.next(false);
3737
3793
  return this.handleError(err);
3738
3794
  }));
@@ -4154,7 +4210,8 @@ class RequestSignalsService extends WebsocketService {
4154
4210
  }
4155
4211
  requestStreamingOperator(options) {
4156
4212
  return (source$) => {
4157
- return source$.pipe(map(data => {
4213
+ return source$.pipe(map(output => {
4214
+ const data = output.data;
4158
4215
  if (!data || (Array.isArray(data) && data.length === 0)) {
4159
4216
  return data;
4160
4217
  }
@@ -4891,12 +4948,13 @@ class ApiRequest {
4891
4948
  }
4892
4949
 
4893
4950
  class RequestOptions {
4894
- constructor(path = [], headers = {}) {
4951
+ constructor(path = [], headers = {}, forceRefresh) {
4895
4952
  this.path = path;
4896
4953
  this.headers = headers;
4954
+ this.forceRefresh = forceRefresh;
4897
4955
  }
4898
4956
  static adapt(item) {
4899
- return new RequestOptions(item?.path, item?.headers);
4957
+ return new RequestOptions(item?.path, item?.headers, item?.forceRefresh);
4900
4958
  }
4901
4959
  }
4902
4960
 
@@ -5772,9 +5830,12 @@ class DbService extends Dexie {
5772
5830
  await this.dbReady;
5773
5831
  const safeTableName = this.cleanTableName(tableName);
5774
5832
  const safeSchema = schema.trim();
5775
- if (this.tableExists(safeTableName))
5776
- return;
5777
5833
  const currentSchema = this.getCurrentSchema();
5834
+ const existingSchema = currentSchema[safeTableName]?.trim();
5835
+ // No-op only when table already exists and schema is identical.
5836
+ if (this.tableExists(safeTableName) && existingSchema === safeSchema) {
5837
+ return;
5838
+ }
5778
5839
  console.log('Current Schema before update:', currentSchema);
5779
5840
  currentSchema[safeTableName] = safeSchema;
5780
5841
  const nextVersion = this.verno + 1;
@@ -5788,6 +5849,7 @@ class DbService extends Dexie {
5788
5849
  const created = this.tables.some(t => t.name === safeTableName);
5789
5850
  if (!created) {
5790
5851
  console.error(`CRITICAL: Table ${safeTableName} was NOT created after upgrade! Tables found:`, this.tables.map(t => t.name));
5852
+ throw new Error(`Table '${safeTableName}' was not created after schema upgrade`);
5791
5853
  }
5792
5854
  else {
5793
5855
  console.log(`Database opened successfully version ${this.verno}. Table ${safeTableName} verified.`);
@@ -5795,15 +5857,24 @@ class DbService extends Dexie {
5795
5857
  }
5796
5858
  catch (err) {
5797
5859
  console.error('Error opening database after schema update:', err);
5860
+ throw err;
5798
5861
  }
5799
5862
  }
5800
5863
  async DBOpened() {
5864
+ try {
5865
+ await this.dbReady;
5866
+ }
5867
+ catch (err) {
5868
+ console.error('DBOpened: init failed', err);
5869
+ return false;
5870
+ }
5801
5871
  if (!this.isOpen()) {
5802
5872
  try {
5803
5873
  await this.open();
5804
5874
  return true;
5805
5875
  }
5806
5876
  catch (err) {
5877
+ console.error('DBOpened: open failed', err);
5807
5878
  return false;
5808
5879
  }
5809
5880
  }
@@ -5898,7 +5969,11 @@ class DatabaseManagerService extends DbService {
5898
5969
  }));
5899
5970
  }
5900
5971
  createDatabaseTable(tableDef) {
5901
- return from(this.createTable(tableDef.table, tableDef.schema)).pipe(switchMap(() => this.DBOpened()));
5972
+ const tableName = this.cleanTableName(tableDef.table);
5973
+ return from(this.createTable(tableDef.table, tableDef.schema)).pipe(switchMap(() => from(this.DBOpened())), map((opened) => opened && this.tableExists(tableName)), catchError((error) => {
5974
+ console.error(`createDatabaseTable: failed for table '${tableName}'`, error);
5975
+ return of(false);
5976
+ }));
5902
5977
  }
5903
5978
  updateDatabaseTableSchema(tableDef) {
5904
5979
  return from(this.createTable(tableDef.table, tableDef.schema)).pipe(switchMap(() => this.getDatabaseTable(tableDef.table)));
@@ -5945,26 +6020,23 @@ class DatabaseManagerService extends DbService {
5945
6020
  }
5946
6021
  createTableRecords(table, records) {
5947
6022
  const tableName = this.cleanTableName(table);
5948
- return from(this.DBOpened()).pipe(switchMap(() => {
6023
+ return from(this.DBOpened()).pipe(switchMap((opened) => {
6024
+ if (!opened) {
6025
+ console.error(`createTableRecords: DB not open. Cannot write to '${tableName}'.`);
6026
+ return EMPTY;
6027
+ }
5949
6028
  if (!this.tables.some(t => t.name === tableName)) {
5950
6029
  console.error(`createTableRecords: Table '${tableName}' does not exist in DB version ${this.verno}. Available:`, this.tables.map(t => t.name));
5951
6030
  return EMPTY;
5952
6031
  }
5953
6032
  const tableInstance = this.table(tableName);
5954
- // Extract schema fields directly from the table instance
5955
- const schema = tableInstance.schema;
5956
- const validFields = [
5957
- schema.primKey.name,
5958
- ...schema.indexes.map(idx => idx.name)
5959
- ];
6033
+ // Keep full object payload; Dexie stores non-indexed properties as well.
5960
6034
  const insertRecords = records.map((record) => {
5961
- const objectFromSchema = {};
5962
- validFields.forEach((field) => {
5963
- if (field) {
5964
- objectFromSchema[field] = record[field] ?? null;
5965
- }
5966
- });
5967
- return objectFromSchema;
6035
+ const payload = { ...(record || {}) };
6036
+ if (payload.id === undefined || payload.id === null || payload.id === '') {
6037
+ delete payload.id;
6038
+ }
6039
+ return payload;
5968
6040
  });
5969
6041
  console.log(`createTableRecords: Bulk putting ${insertRecords.length} records into ${tableName}`);
5970
6042
  return from(tableInstance.bulkPut(insertRecords)).pipe(map(() => insertRecords));
@@ -5978,17 +6050,14 @@ class DatabaseManagerService extends DbService {
5978
6050
  updateTableRecords(table, records) {
5979
6051
  const tableName = this.cleanTableName(table);
5980
6052
  return this.getDatabaseTable(tableName).pipe(switchMap((tableData) => {
5981
- return this.getDatabaseTableSchema(tableName).pipe(switchMap((schema) => {
5982
- const insertRecords = records.map((record) => {
5983
- const objectFromSchema = {};
5984
- schema.forEach((field) => {
5985
- const data = record[field] ?? null;
5986
- objectFromSchema[field] = data;
5987
- });
5988
- return objectFromSchema;
5989
- });
5990
- return from(tableData.bulkPut(insertRecords)).pipe(map(() => insertRecords));
5991
- }));
6053
+ const insertRecords = records.map((record) => {
6054
+ const payload = { ...(record || {}) };
6055
+ if (payload.id === undefined || payload.id === null || payload.id === '') {
6056
+ delete payload.id;
6057
+ }
6058
+ return payload;
6059
+ });
6060
+ return from(tableData.bulkPut(insertRecords)).pipe(map(() => insertRecords));
5992
6061
  }));
5993
6062
  }
5994
6063
  deleteTableRecord(table, id) {
@@ -6106,6 +6175,15 @@ class HTTPManagerStateService extends ComponentStore {
6106
6175
  this.hasDatabase = false;
6107
6176
  this.streamedResponse = [];
6108
6177
  this.shouldRetry = true;
6178
+ this.volatileHeaders = new Set([
6179
+ 'authorization',
6180
+ 'x-request-id',
6181
+ 'x-correlation-id',
6182
+ 'x-trace-id',
6183
+ 'x-amzn-trace-id',
6184
+ 'date',
6185
+ 'if-none-match'
6186
+ ]);
6109
6187
  this.wsRetryAttempts = new BehaviorSubject(0);
6110
6188
  this.wsRetryAttempts$ = this.wsRetryAttempts.asObservable();
6111
6189
  this.messages = new BehaviorSubject([]);
@@ -6375,22 +6453,25 @@ class HTTPManagerStateService extends ComponentStore {
6375
6453
  }
6376
6454
  }))))));
6377
6455
  this.initDBStorage = this.effect((trigger$) => trigger$.pipe(tap(() => {
6456
+ console.log('[initDBStorage effect] Triggered, checking conditions:', {
6457
+ dataType: this.dataType,
6458
+ isARRAY: this.dataType === DataType.ARRAY,
6459
+ hasAdapter: !!this.apiOptions?.adapter,
6460
+ hasTable: !!this.databaseOptions?.table,
6461
+ tableValue: this.databaseOptions?.table
6462
+ });
6378
6463
  if (this.dataType !== DataType.ARRAY)
6379
6464
  console.warn('Database storage requires dataType to be ARRAY');
6380
6465
  if (!this.apiOptions.adapter)
6381
- console.warn('Database storage requires an adapter to define the data shape');
6466
+ console.warn('Database storage adapter missing, using minimal or inferred schema');
6382
6467
  if (this.databaseOptions && this.databaseOptions?.table === '')
6383
6468
  console.warn('Database storage requires a table name');
6384
- }), filter(() => this.dataType === DataType.ARRAY && !!this.apiOptions.adapter && !!this.databaseOptions?.table), switchMap(() => {
6385
- const sampleData = this.apiOptions.adapter?.({}) || {};
6386
- const schemaKeys = Object.keys(sampleData).filter(key => sampleData[key] !== undefined);
6387
- let schema = '++id';
6388
- if (schemaKeys.length > 0) {
6389
- const otherKeys = schemaKeys.filter(k => k !== 'id');
6390
- if (otherKeys.length > 0) {
6391
- schema += ', ' + otherKeys.join(', ');
6392
- }
6393
- }
6469
+ }), filter(() => {
6470
+ const shouldProceed = this.dataType === DataType.ARRAY && !!this.databaseOptions?.table;
6471
+ console.log('[initDBStorage effect] Filter result:', shouldProceed);
6472
+ return shouldProceed;
6473
+ }), switchMap(() => {
6474
+ const schema = this.buildSchemaFromAdapter();
6394
6475
  const tableDef = TableSchemaDef.adapt({
6395
6476
  table: this.databaseOptions?.table,
6396
6477
  schema: schema
@@ -6479,6 +6560,7 @@ class HTTPManagerStateService extends ComponentStore {
6479
6560
  }
6480
6561
  }), concatMap(() => {
6481
6562
  if (this.hasDatabase && this.databaseOptions?.table) {
6563
+ this.clearRequestCacheMetadata(this.databaseOptions.table);
6482
6564
  const currentData = this.get()?.data;
6483
6565
  const idsToDelete = Array.isArray(currentData) ? currentData.map((r) => r.id) : [];
6484
6566
  if (idsToDelete.length > 0) {
@@ -6493,35 +6575,86 @@ class HTTPManagerStateService extends ComponentStore {
6493
6575
  this.fetchRecords = (options) => this.effect(() => of(RequestOptions.adapt(options)).pipe(switchMap(() => {
6494
6576
  this.streamedResponse = [];
6495
6577
  const requestOptions = this.updateRequestOptions(options?.headers);
6578
+ const effectiveParams = this.getEffectiveParams(options?.path);
6579
+ const requestSignature = this.buildRequestSignature('GET', requestOptions, effectiveParams);
6496
6580
  const fetchFromAPI = () => {
6497
- return this.httpManagerService.getRequest(requestOptions, options?.path).pipe(tap((data) => {
6498
- data = (!data) ? (this.dataType === DataType.ARRAY) ? [] : {} : data;
6581
+ return this.httpManagerService.getRequest(requestOptions, effectiveParams).pipe(tap((data) => {
6582
+ // Extract array from paginated response if needed
6583
+ const arrayData = (data?.results && Array.isArray(data.results)) ? data.results : data;
6584
+ data = (!arrayData) ? (this.dataType === DataType.ARRAY) ? [] : {} : arrayData;
6499
6585
  this.setData$(data);
6500
6586
  }), concatMap((data) => {
6501
- if (this.hasDatabase && this.databaseOptions?.table && Array.isArray(data) && data.length > 0) {
6587
+ // Extract array from paginated response for database storage
6588
+ const dbData = (data?.results && Array.isArray(data.results)) ? data.results : data;
6589
+ if (this.hasDatabase && this.databaseOptions?.table && Array.isArray(dbData) && dbData.length > 0) {
6590
+ const tableName = this.databaseOptions.table;
6502
6591
  this.localStorageManagerService.updateStore({
6503
- name: this.databaseOptions.table,
6592
+ name: tableName,
6504
6593
  data: { ...this.databaseOptions, ...{ expires: this.utils.expires(this.databaseOptions.expiresIn) } }
6505
6594
  });
6506
- return this.dbManagerService.createTableRecords(this.databaseOptions.table, data);
6595
+ const schema = this.buildSchemaFromSample(dbData[0]);
6596
+ const tableDef = TableSchemaDef.adapt({ table: tableName, schema });
6597
+ const schemaSignature = this.buildSchemaSignature(schema);
6598
+ // Always ensure table exists immediately before writing to avoid stale schema/store races.
6599
+ return this.localStorageManagerService.store$(tableName).pipe(take(1), switchMap((storeData) => {
6600
+ const storedSchemaSignature = this.getStoredSchemaSignature(storeData);
6601
+ const schemaChanged = !!storedSchemaSignature && storedSchemaSignature !== schemaSignature;
6602
+ const ensureTable$ = schemaChanged
6603
+ ? this.dbManagerService.clearTable(tableName).pipe(switchMap(() => this.dbManagerService.createDatabaseTable(tableDef)))
6604
+ : this.dbManagerService.createDatabaseTable(tableDef);
6605
+ return ensureTable$.pipe(switchMap((created) => {
6606
+ if (!created) {
6607
+ console.warn('[DB STORAGE] Table create/open not ready, skipping DB write for this payload:', { table: tableName });
6608
+ return of(data);
6609
+ }
6610
+ return this.dbManagerService.createTableRecords(tableName, dbData).pipe(tap(() => this.saveRequestCacheMetadata(tableName, 'GET', requestSignature, schemaSignature, options)));
6611
+ }));
6612
+ }), catchError((error) => {
6613
+ console.error('[DB STORAGE] Failed to ensure table and write records:', { table: tableName, schema, error });
6614
+ return of(data);
6615
+ }));
6507
6616
  }
6508
6617
  return of(data);
6509
6618
  }));
6510
6619
  };
6620
+ console.log('[DB STORAGE] Checking database storage:', {
6621
+ hasDatabase: this.hasDatabase,
6622
+ table: this.databaseOptions?.table,
6623
+ databaseOptions: this.databaseOptions
6624
+ });
6511
6625
  if (this.hasDatabase && this.databaseOptions?.table) {
6512
6626
  return this.dbManagerService.databaseExists().pipe(switchMap((dbExists) => {
6513
6627
  if (!dbExists) {
6514
6628
  const initObs = this.initDBStorageAsync();
6515
- return initObs.pipe(switchMap(() => fetchFromAPI()));
6629
+ return initObs.pipe(switchMap(() => fetchFromAPI()), catchError((error) => {
6630
+ console.warn('[DB STORAGE] initDBStorageAsync failed when DB did not exist, continuing with API:', error);
6631
+ return fetchFromAPI();
6632
+ }));
6516
6633
  }
6517
6634
  return this.dbManagerService.hasDatabaseTable(this.databaseOptions.table).pipe(switchMap((tableExists) => {
6518
6635
  if (!tableExists) {
6519
6636
  const initObs = this.initDBStorageAsync();
6520
- return initObs.pipe(switchMap(() => fetchFromAPI()));
6637
+ return initObs.pipe(switchMap(() => fetchFromAPI()), catchError((error) => {
6638
+ console.warn('[DB STORAGE] initDBStorageAsync failed when table missing, continuing with API:', error);
6639
+ return fetchFromAPI();
6640
+ }));
6521
6641
  }
6522
6642
  return this.localStorageManagerService.store$(this.databaseOptions.table).pipe(take(1), switchMap((storeData) => {
6643
+ const cached = this.getRequestCacheMetadata(storeData, 'GET');
6644
+ const sameSignature = !!cached?.signature && cached.signature === requestSignature;
6645
+ const forceRefresh = !!options?.forceRefresh;
6646
+ const storedSchemaSignature = this.getStoredSchemaSignature(storeData);
6523
6647
  const expires = storeData?.expires || 0;
6524
6648
  const hasExpired = expires > 0 && this.utils.hasExpired(expires);
6649
+ if (!forceRefresh && sameSignature && !hasExpired) {
6650
+ return this.dbManagerService.getTableRecords(this.databaseOptions.table).pipe(switchMap((dbData) => {
6651
+ if (Array.isArray(dbData) && dbData.length > 0) {
6652
+ this.setData$(dbData);
6653
+ return of(dbData);
6654
+ }
6655
+ return fetchFromAPI();
6656
+ }));
6657
+ }
6525
6658
  if (hasExpired) {
6526
6659
  return this.dbManagerService.clearTable(this.databaseOptions.table).pipe(switchMap(() => fetchFromAPI()), tap(() => {
6527
6660
  this.localStorageManagerService.updateStore({
@@ -6530,12 +6663,27 @@ class HTTPManagerStateService extends ComponentStore {
6530
6663
  });
6531
6664
  }));
6532
6665
  }
6666
+ const expectedSchema = this.buildSchemaFromAdapter();
6667
+ const expectedSchemaSignature = this.buildSchemaSignature(expectedSchema);
6668
+ if (storedSchemaSignature && storedSchemaSignature !== expectedSchemaSignature) {
6669
+ const tableDef = TableSchemaDef.adapt({ table: this.databaseOptions.table, schema: expectedSchema });
6670
+ return this.dbManagerService.clearTable(this.databaseOptions.table).pipe(switchMap(() => this.dbManagerService.createDatabaseTable(tableDef)), switchMap(() => fetchFromAPI()));
6671
+ }
6533
6672
  return this.dbManagerService.getTableRecords(this.databaseOptions.table).pipe(switchMap((dbData) => {
6534
6673
  if (Array.isArray(dbData) && dbData.length > 0) {
6535
6674
  this.setData$(dbData);
6536
6675
  return of(dbData);
6537
6676
  }
6538
6677
  return fetchFromAPI();
6678
+ }), catchError((error) => {
6679
+ const tableName = this.databaseOptions.table;
6680
+ console.warn('[DB STORAGE] getTableRecords failed, recreating table and falling back to API:', { table: tableName, error });
6681
+ const schema = this.buildSchemaFromAdapter();
6682
+ const tableDef = TableSchemaDef.adapt({ table: tableName, schema });
6683
+ return this.dbManagerService.createDatabaseTable(tableDef).pipe(switchMap(() => fetchFromAPI()), catchError((recreateError) => {
6684
+ console.error('[DB STORAGE] Failed to recreate table after read error, continuing with API only:', recreateError);
6685
+ return fetchFromAPI();
6686
+ }));
6539
6687
  }));
6540
6688
  }));
6541
6689
  }));
@@ -6659,7 +6807,7 @@ class HTTPManagerStateService extends ComponentStore {
6659
6807
  if (res.length > 0)
6660
6808
  this.setData$(res);
6661
6809
  this.streamedResponse = res;
6662
- }), scan((acc, res) => {
6810
+ }), concatMap((res) => this.persistStreamDataToDb(res, options)), scan((acc, res) => {
6663
6811
  const previous = acc.current;
6664
6812
  const current = res;
6665
6813
  return { previous, current };
@@ -6679,8 +6827,52 @@ class HTTPManagerStateService extends ComponentStore {
6679
6827
  }), switchMap((options) => {
6680
6828
  const requestOptions = this.updateRequestOptions(options?.headers);
6681
6829
  requestOptions.stream = true;
6830
+ const effectiveParams = this.getEffectiveParams(options?.path);
6831
+ const requestSignature = this.buildRequestSignature('STREAM', requestOptions, effectiveParams);
6682
6832
  console.log('[DEBUG] Making streaming request:', requestOptions);
6683
- return this.httpManagerService.getRequest(requestOptions, options?.path)
6833
+ if (this.hasDatabase && this.databaseOptions?.table && !options?.forceRefresh) {
6834
+ return this.localStorageManagerService.store$(this.databaseOptions.table).pipe(take(1), switchMap((storeData) => {
6835
+ const cached = this.getRequestCacheMetadata(storeData, 'STREAM');
6836
+ const sameSignature = !!cached?.signature && cached.signature === requestSignature;
6837
+ const expires = storeData?.expires || 0;
6838
+ const hasExpired = expires > 0 && this.utils.hasExpired(expires);
6839
+ if (sameSignature && !hasExpired) {
6840
+ return this.dbManagerService.getTableRecords(this.databaseOptions.table).pipe(switchMap((dbData) => {
6841
+ if (Array.isArray(dbData) && dbData.length > 0) {
6842
+ return of({ data: dbData, fromCache: true });
6843
+ }
6844
+ return this.httpManagerService.getRequest(requestOptions, effectiveParams).pipe(map((apiData) => ({ data: apiData, fromCache: false })));
6845
+ }));
6846
+ }
6847
+ return this.httpManagerService.getRequest(requestOptions, effectiveParams).pipe(map((apiData) => ({ data: apiData, fromCache: false })));
6848
+ })).pipe(tap((packet) => {
6849
+ const res = packet?.data;
6850
+ console.log('[DEBUG] Streaming response received:', res);
6851
+ if (res && res.length > 0) {
6852
+ console.log('[DEBUG] Updating state with streaming data:', res);
6853
+ this.setData$(res);
6854
+ this.streamedResponse = res;
6855
+ }
6856
+ else {
6857
+ console.log('[DEBUG] No streaming data or empty array:', res);
6858
+ }
6859
+ // Reset pending once we have a response packet (cache or network)
6860
+ this.httpManagerService.isPending.next(false);
6861
+ }), concatMap((packet) => {
6862
+ if (packet?.fromCache) {
6863
+ return of(packet?.data);
6864
+ }
6865
+ return this.persistStreamDataToDb(packet?.data, options);
6866
+ }), map((res) => {
6867
+ console.log('[DEBUG] Returning data to subscribers:', res);
6868
+ return res;
6869
+ }), catchError((error) => {
6870
+ console.error('[DEBUG] Streaming error:', error);
6871
+ this.httpManagerService.isPending.next(false);
6872
+ return of([]);
6873
+ }));
6874
+ }
6875
+ return this.httpManagerService.getRequest(requestOptions, effectiveParams)
6684
6876
  .pipe(tap((res) => {
6685
6877
  console.log('[DEBUG] Streaming response received:', res);
6686
6878
  // Always update state with streaming data
@@ -6692,7 +6884,9 @@ class HTTPManagerStateService extends ComponentStore {
6692
6884
  else {
6693
6885
  console.log('[DEBUG] No streaming data or empty array:', res);
6694
6886
  }
6695
- }), map((res) => {
6887
+ // Reset pending once we have a response packet
6888
+ this.httpManagerService.isPending.next(false);
6889
+ }), concatMap((res) => this.persistStreamDataToDb(res, options)), map((res) => {
6696
6890
  console.log('[DEBUG] Returning data to subscribers:', res);
6697
6891
  return res; // Return the data so subscribers can receive it
6698
6892
  }), catchError((error) => {
@@ -6719,7 +6913,11 @@ class HTTPManagerStateService extends ComponentStore {
6719
6913
  encrypted: false,
6720
6914
  })
6721
6915
  });
6722
- this.initDBStorage();
6916
+ // Use initDBStorageAsync directly - the effect initDBStorage requires subscription
6917
+ this.initDBStorageAsync().subscribe({
6918
+ next: () => console.log('[Constructor] Database storage initialized'),
6919
+ error: (err) => console.error('[Constructor] Database storage initialization failed:', err)
6920
+ });
6723
6921
  }
6724
6922
  }
6725
6923
  catch (error) {
@@ -6773,8 +6971,24 @@ class HTTPManagerStateService extends ComponentStore {
6773
6971
  this.dataType = (dataType) ? dataType : DataType.ARRAY;
6774
6972
  // Only update database options if a database parameter is explicitly provided
6775
6973
  if (database !== undefined) {
6974
+ console.log('[setApiRequestOptions] Database config:', {
6975
+ database,
6976
+ hasTable: !!database?.table,
6977
+ tableValue: database?.table
6978
+ });
6776
6979
  this.hasDatabase = (database?.table) ? true : false;
6777
- this.databaseOptions = (this.hasDatabase) ? DatabaseStorage.adapt(database) : undefined;
6980
+ const adapted = DatabaseStorage.adapt(database);
6981
+ console.log('[setApiRequestOptions] DatabaseStorage.adapt result:', adapted);
6982
+ this.databaseOptions = (this.hasDatabase) ? adapted : undefined;
6983
+ // Trigger database table creation if table is configured
6984
+ if (this.hasDatabase && this.databaseOptions?.table) {
6985
+ console.log('[setApiRequestOptions] Initializing database storage for table:', this.databaseOptions.table);
6986
+ // Use initDBStorageAsync directly instead of the effect - effects need subscription to run
6987
+ this.initDBStorageAsync().subscribe({
6988
+ next: () => console.log('[setApiRequestOptions] Database storage initialized successfully'),
6989
+ error: (err) => console.error('[setApiRequestOptions] Database storage initialization failed:', err)
6990
+ });
6991
+ }
6778
6992
  }
6779
6993
  if (this.apiOptions.ws && this.apiOptions.ws.id !== '') {
6780
6994
  // Auto-prefix channel ID for private state manager channels
@@ -6896,11 +7110,20 @@ class HTTPManagerStateService extends ComponentStore {
6896
7110
  this.setData$(data);
6897
7111
  }
6898
7112
  updateArrayState(currentData, newData) {
7113
+ // For non-streaming requests (GET), REPLACE data entirely
7114
+ // For streaming requests, MERGE with existing data incrementally
7115
+ if (this.streamedResponse.length === 0) {
7116
+ // GET request: return new data as-is (replace)
7117
+ return newData;
7118
+ }
7119
+ // Streaming: merge with existing data
6899
7120
  const filterCurrentData = () => {
6900
7121
  const ids = this.streamedResponse.map((obj) => obj.id);
6901
7122
  return currentData.filter(obj => (obj.id) ? ids.includes(obj.id) : obj);
6902
7123
  };
6903
- const filteredCurrentData = (this.httpManagerService.isPending.value) ? currentData : filterCurrentData();
7124
+ const filteredCurrentData = (this.httpManagerService.isPending.value)
7125
+ ? currentData
7126
+ : filterCurrentData();
6904
7127
  const updatedData = filteredCurrentData.map(item => {
6905
7128
  const newItem = newData.find(newItem => {
6906
7129
  const hasId = (newItem?.id && item?.id) ? true : false;
@@ -6917,32 +7140,92 @@ class HTTPManagerStateService extends ComponentStore {
6917
7140
  return [...updatedData, ...addedData];
6918
7141
  }
6919
7142
  initDBStorageAsync() {
7143
+ console.log('[initDBStorageAsync] Starting initialization:', {
7144
+ dataType: this.dataType,
7145
+ hasAdapter: !!this.apiOptions?.adapter,
7146
+ table: this.databaseOptions?.table,
7147
+ databaseOptions: this.databaseOptions
7148
+ });
6920
7149
  if (this.dataType !== DataType.ARRAY) {
6921
7150
  console.warn('Database storage requires dataType to be ARRAY');
6922
7151
  return of(null);
6923
7152
  }
6924
7153
  if (!this.apiOptions.adapter) {
6925
- console.warn('Database storage requires an adapter to define the data shape');
6926
- return of(null);
7154
+ console.warn('Database storage adapter missing, using minimal or inferred schema');
6927
7155
  }
6928
7156
  if (!this.databaseOptions?.table) {
6929
7157
  console.warn('Database storage requires a table name');
6930
7158
  return of(null);
6931
7159
  }
7160
+ const schema = this.buildSchemaFromAdapter();
7161
+ const tableDef = TableSchemaDef.adapt({
7162
+ table: this.databaseOptions?.table,
7163
+ schema: schema
7164
+ });
7165
+ return this.dbManagerService.createDatabaseTable(tableDef).pipe(tap((created) => {
7166
+ if (created && this.databaseOptions?.table) {
7167
+ this.saveSchemaSignature(this.databaseOptions.table, this.buildSchemaSignature(schema));
7168
+ }
7169
+ }));
7170
+ }
7171
+ buildSchemaFromAdapter() {
6932
7172
  const sampleData = this.apiOptions.adapter?.({}) || {};
6933
- const schemaKeys = Object.keys(sampleData).filter(key => sampleData[key] !== undefined);
7173
+ return this.buildSchemaFromSample(sampleData);
7174
+ }
7175
+ buildSchemaFromSample(sampleData) {
7176
+ const schemaKeys = Object.keys(sampleData || {}).filter(key => sampleData[key] !== undefined);
6934
7177
  let schema = '++id';
6935
7178
  if (schemaKeys.length > 0) {
6936
- const otherKeys = schemaKeys.filter(k => k !== 'id');
7179
+ const otherKeys = schemaKeys.filter((k) => k !== 'id');
6937
7180
  if (otherKeys.length > 0) {
6938
7181
  schema += ', ' + otherKeys.join(', ');
6939
7182
  }
6940
7183
  }
6941
- const tableDef = TableSchemaDef.adapt({
6942
- table: this.databaseOptions?.table,
6943
- schema: schema
6944
- });
6945
- return this.dbManagerService.createDatabaseTable(tableDef);
7184
+ return schema;
7185
+ }
7186
+ persistStreamDataToDb(payload, streamOptions) {
7187
+ if (!this.hasDatabase || !this.databaseOptions?.table) {
7188
+ return of(payload);
7189
+ }
7190
+ const dbData = (payload?.results && Array.isArray(payload.results))
7191
+ ? payload.results
7192
+ : Array.isArray(payload)
7193
+ ? payload
7194
+ : payload
7195
+ ? [payload]
7196
+ : [];
7197
+ if (dbData.length === 0) {
7198
+ return of(payload);
7199
+ }
7200
+ const tableName = this.databaseOptions.table;
7201
+ const requestOptions = this.updateRequestOptions(streamOptions?.headers);
7202
+ requestOptions.stream = true;
7203
+ const effectiveParams = this.getEffectiveParams(streamOptions?.path);
7204
+ const requestSignature = this.buildRequestSignature('STREAM', requestOptions, effectiveParams);
7205
+ this.localStorageManagerService.updateStore({
7206
+ name: tableName,
7207
+ data: { ...this.databaseOptions, ...{ expires: this.utils.expires(this.databaseOptions.expiresIn) } }
7208
+ });
7209
+ const schema = this.buildSchemaFromSample(dbData[0]);
7210
+ const schemaSignature = this.buildSchemaSignature(schema);
7211
+ const tableDef = TableSchemaDef.adapt({ table: tableName, schema });
7212
+ return this.localStorageManagerService.store$(tableName).pipe(take(1), switchMap((storeData) => {
7213
+ const storedSchemaSignature = this.getStoredSchemaSignature(storeData);
7214
+ const schemaChanged = !!storedSchemaSignature && storedSchemaSignature !== schemaSignature;
7215
+ const ensureTable$ = schemaChanged
7216
+ ? this.dbManagerService.clearTable(tableName).pipe(switchMap(() => this.dbManagerService.createDatabaseTable(tableDef)))
7217
+ : this.dbManagerService.createDatabaseTable(tableDef);
7218
+ return ensureTable$.pipe(switchMap((created) => {
7219
+ if (!created) {
7220
+ console.warn('[DB STORAGE] Stream table create/open not ready, skipping DB write for this chunk:', { table: tableName });
7221
+ return of(payload);
7222
+ }
7223
+ return this.dbManagerService.createTableRecords(tableName, dbData).pipe(tap(() => this.saveRequestCacheMetadata(tableName, 'STREAM', requestSignature, schemaSignature, streamOptions)), map(() => payload));
7224
+ }));
7225
+ }), map(() => payload), catchError((error) => {
7226
+ console.error('[DB STORAGE] Failed to persist streaming payload:', { table: tableName, schema, error });
7227
+ return of(payload);
7228
+ }));
6946
7229
  }
6947
7230
  // WEBSOCKET COMMUNICATION (STATE MANAGER)
6948
7231
  wsCommunication(method, path) {
@@ -7238,6 +7521,7 @@ class HTTPManagerStateService extends ComponentStore {
7238
7521
  const tableName = this.databaseOptions.table;
7239
7522
  this.dbManagerService.clearTable(tableName).subscribe({
7240
7523
  next: () => {
7524
+ this.clearRequestCacheMetadata(tableName);
7241
7525
  if (this.dataType === DataType.ARRAY) {
7242
7526
  this.setData$([]);
7243
7527
  }
@@ -7260,6 +7544,115 @@ class HTTPManagerStateService extends ComponentStore {
7260
7544
  : { ...options.headers };
7261
7545
  return options;
7262
7546
  }
7547
+ normalizeObject(value) {
7548
+ if (Array.isArray(value)) {
7549
+ return value.map((item) => this.normalizeObject(item));
7550
+ }
7551
+ if (value && typeof value === 'object') {
7552
+ return Object.keys(value)
7553
+ .sort()
7554
+ .reduce((acc, key) => {
7555
+ acc[key] = this.normalizeObject(value[key]);
7556
+ return acc;
7557
+ }, {});
7558
+ }
7559
+ return value;
7560
+ }
7561
+ filterHeaders(headers) {
7562
+ const source = headers || {};
7563
+ return Object.keys(source).reduce((acc, key) => {
7564
+ if (!this.volatileHeaders.has(key.toLowerCase())) {
7565
+ acc[key] = source[key];
7566
+ }
7567
+ return acc;
7568
+ }, {});
7569
+ }
7570
+ resolvePath(params) {
7571
+ const basePath = Array.isArray(this.apiOptions.path) ? this.apiOptions.path : [];
7572
+ const effective = this.getEffectiveParams(params);
7573
+ return effective ? [...basePath, ...effective] : [...basePath];
7574
+ }
7575
+ getEffectiveParams(params) {
7576
+ if (!Array.isArray(params) || params.length === 0) {
7577
+ return undefined;
7578
+ }
7579
+ const basePath = Array.isArray(this.apiOptions.path) ? this.apiOptions.path : [];
7580
+ if (basePath.length !== params.length) {
7581
+ return params;
7582
+ }
7583
+ const normalizePart = (value) => {
7584
+ if (value && typeof value === 'object') {
7585
+ return JSON.stringify(this.normalizeObject(value));
7586
+ }
7587
+ return String(value);
7588
+ };
7589
+ const samePath = params.every((part, index) => normalizePart(part) === normalizePart(basePath[index]));
7590
+ return samePath ? undefined : params;
7591
+ }
7592
+ buildRequestSignature(method, requestOptions, params) {
7593
+ const signaturePayload = {
7594
+ method,
7595
+ server: requestOptions.server,
7596
+ path: this.resolvePath(params),
7597
+ headers: this.filterHeaders(requestOptions.headers),
7598
+ stream: !!requestOptions.stream,
7599
+ streamType: requestOptions.streamType || null
7600
+ };
7601
+ return JSON.stringify(this.normalizeObject(signaturePayload));
7602
+ }
7603
+ buildSchemaSignature(schema) {
7604
+ return JSON.stringify(this.normalizeObject(schema.split(',').map((part) => part.trim()).filter(Boolean)));
7605
+ }
7606
+ getRequestCacheMetadata(storeData, type) {
7607
+ return storeData?.requestCache?.[type] || null;
7608
+ }
7609
+ getStoredSchemaSignature(storeData) {
7610
+ return storeData?.schemaSignature || null;
7611
+ }
7612
+ saveSchemaSignature(tableName, schemaSignature) {
7613
+ this.localStorageManagerService.store$(tableName).pipe(take(1), tap((storeData) => {
7614
+ this.localStorageManagerService.updateStore({
7615
+ name: tableName,
7616
+ data: {
7617
+ ...(storeData || {}),
7618
+ schemaSignature,
7619
+ }
7620
+ });
7621
+ })).subscribe();
7622
+ }
7623
+ saveRequestCacheMetadata(tableName, type, signature, schemaSignature, options) {
7624
+ this.localStorageManagerService.store$(tableName).pipe(take(1), tap((storeData) => {
7625
+ const currentCache = storeData?.requestCache || {};
7626
+ this.localStorageManagerService.updateStore({
7627
+ name: tableName,
7628
+ data: {
7629
+ ...(storeData || {}),
7630
+ schemaSignature: schemaSignature || storeData?.schemaSignature || null,
7631
+ requestCache: {
7632
+ ...currentCache,
7633
+ [type]: {
7634
+ signature,
7635
+ savedAt: Date.now(),
7636
+ path: this.resolvePath(options?.path),
7637
+ headers: this.filterHeaders(options?.headers)
7638
+ }
7639
+ }
7640
+ }
7641
+ });
7642
+ })).subscribe();
7643
+ }
7644
+ clearRequestCacheMetadata(tableName) {
7645
+ this.localStorageManagerService.store$(tableName).pipe(take(1), tap((storeData) => {
7646
+ if (!storeData)
7647
+ return;
7648
+ const updated = { ...(storeData || {}) };
7649
+ delete updated.requestCache;
7650
+ this.localStorageManagerService.updateStore({
7651
+ name: tableName,
7652
+ data: updated
7653
+ });
7654
+ })).subscribe();
7655
+ }
7263
7656
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: HTTPManagerStateService, deps: [{ token: API_OPTS }, { token: "dataType" }, { token: DatabaseStorage }], target: i0.ɵɵFactoryTarget.Injectable }); }
7264
7657
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: HTTPManagerStateService }); }
7265
7658
  }
@@ -8596,13 +8989,13 @@ class StateManagerDemoService extends HTTPManagerStateService {
8596
8989
  const sampleOptions = RequestOptions.adapt({ path: [data.id] });
8597
8990
  this.deleteRecord(sampleOptions);
8598
8991
  }
8599
- streamRequest() {
8992
+ streamRequest(options) {
8600
8993
  console.log('[DEMO SERVICE] streamRequest called');
8601
8994
  const headers = {
8602
8995
  auth: "sample-auth-token"
8603
8996
  };
8604
8997
  console.log('[DEMO SERVICE] Calling fetchStream with headers:', headers);
8605
- this.fetchStream();
8998
+ this.fetchStream(options);
8606
8999
  }
8607
9000
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: StateManagerDemoService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
8608
9001
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: StateManagerDemoService }); }
@@ -8849,11 +9242,23 @@ class RequestManagerStateDemoComponent {
8849
9242
  return { apiOptions: apiOptions, path: pathReq };
8850
9243
  }
8851
9244
  onSetStateOptions() {
8852
- if (!this.isValid)
9245
+ const dbValue = this.database;
9246
+ console.log('[onSetStateOptions] Called, checking form values:', {
9247
+ isValid: this.isValid,
9248
+ database: dbValue,
9249
+ hasTable: !!dbValue?.table,
9250
+ tableValue: dbValue?.table,
9251
+ dataType: this.dataType
9252
+ });
9253
+ if (!this.isValid) {
9254
+ console.log('[onSetStateOptions] Form invalid, aborting');
8853
9255
  return;
9256
+ }
8854
9257
  const reqParams = this.compileRequest();
8855
- const db = DatabaseStorage.adapt(this.database);
9258
+ const db = DatabaseStorage.adapt(dbValue);
9259
+ console.log('[onSetStateOptions] DatabaseStorage.adapt result:', db);
8856
9260
  const type = this.dataType === "ARRAY" ? DataType.ARRAY : DataType.OBJECT;
9261
+ console.log('[onSetStateOptions] Calling setAPIOptions with:', { db, type, hasTable: !!db?.table });
8857
9262
  this.stateManagerDemoService.setAPIOptions(reqParams.apiOptions, type, db);
8858
9263
  this.requestForm.markAsPristine();
8859
9264
  }
@@ -8888,8 +9293,13 @@ class RequestManagerStateDemoComponent {
8888
9293
  reqParams.apiOptions.stream = true;
8889
9294
  reqParams.apiOptions.streamType = this.streamType;
8890
9295
  this.requestType = 'STREAM';
9296
+ const streamOptions = RequestOptions.adapt({
9297
+ path: reqParams.path,
9298
+ headers: reqParams.apiOptions.headers,
9299
+ forceRefresh: false,
9300
+ });
8891
9301
  console.log('[COMPONENT] Calling streamRequest...');
8892
- this.stateManagerDemoService.streamRequest();
9302
+ this.stateManagerDemoService.streamRequest(streamOptions);
8893
9303
  }
8894
9304
  errorHandling(err, type) {
8895
9305
  console.log(err, type);
@@ -9934,6 +10344,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
9934
10344
  }]
9935
10345
  }] });
9936
10346
 
10347
+ class UserData {
10348
+ constructor(ldap = '', name = '', email = '', color = RandomPaletteColor()) {
10349
+ this.ldap = ldap;
10350
+ this.name = name;
10351
+ this.email = email;
10352
+ this.color = color;
10353
+ }
10354
+ static adapt(item) {
10355
+ const userName = `${item?.first_name} ${item?.last_name}`;
10356
+ return new UserData(item?.ldap, userName, item?.email, item?.color);
10357
+ }
10358
+ }
10359
+
9937
10360
  class StateDataRequestService extends HTTPManagerStateService {
9938
10361
  constructor() {
9939
10362
  super(ApiRequest.adapt({