http-request-manager 18.16.26 → 18.16.29

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.
@@ -4259,10 +4259,8 @@ class HTTPManagerService extends RequestService {
4259
4259
  handleSuccessWithSnackBar(message) {
4260
4260
  const displaySuccess = ToastDisplay.adapt({
4261
4261
  message: message || 'Success',
4262
- action: 'OK',
4263
4262
  color: ToastColors.SUCCESS,
4264
4263
  icon: 'check_circle',
4265
- duration: 3 * 1000, //3 seconds
4266
4264
  });
4267
4265
  this.toastMessage.toastMessage(displaySuccess);
4268
4266
  }
@@ -5059,10 +5057,8 @@ class HTTPManagerSignalsService extends RequestSignalsService {
5059
5057
  handleSuccessWithSnackBar(message) {
5060
5058
  const displaySuccess = ToastDisplay.adapt({
5061
5059
  message: message || 'Success',
5062
- action: 'OK',
5063
5060
  color: ToastColors.SUCCESS,
5064
5061
  icon: 'check_circle',
5065
- duration: 3 * 1000,
5066
5062
  });
5067
5063
  this.toastMessage.toastMessage(displaySuccess);
5068
5064
  }
@@ -7231,19 +7227,16 @@ class HTTPManagerStateService extends ComponentStore {
7231
7227
  }
7232
7228
  return this.httpManagerService.getRequest(requestOptions, effectiveParams).pipe(tap((data) => {
7233
7229
  // Extract array from paginated response if needed
7230
+ // Data is already adapted by RequestService.request() pipe - no need to adapt again
7234
7231
  const arrayData = (data?.results && Array.isArray(data.results)) ? data.results : data;
7235
- // Apply adapter to response data
7236
- let adaptedData = this.applyAdapter(arrayData);
7237
- adaptedData = (!adaptedData) ? (this.dataType === DataType.ARRAY) ? [] : {} : adaptedData;
7238
- this.setData$(adaptedData);
7232
+ this.setData$(arrayData);
7239
7233
  }), concatMap((data) => {
7240
7234
  // Extract array from paginated response for database storage
7235
+ // Data is already adapted by RequestService.request() pipe - no need to adapt again
7241
7236
  const dbData = (data?.results && Array.isArray(data.results)) ? data.results : data;
7242
- // Apply adapter before database storage
7243
- const adaptedDbData = this.applyAdapter(dbData);
7244
- if (this.hasDatabase && this.databaseOptions?.table && Array.isArray(adaptedDbData) && adaptedDbData.length > 0) {
7237
+ if (this.hasDatabase && this.databaseOptions?.table && Array.isArray(dbData) && dbData.length > 0) {
7245
7238
  const tableName = this.databaseOptions.table;
7246
- const schema = this.buildSchemaFromSample(adaptedDbData[0]);
7239
+ const schema = this.buildSchemaFromSample(dbData[0]);
7247
7240
  const tableDef = TableSchemaDef.adapt({ table: tableName, schema });
7248
7241
  const schemaSignature = this.buildSchemaSignature(schema);
7249
7242
  // Always ensure table exists immediately before writing to avoid stale schema/store races.
@@ -7258,7 +7251,7 @@ class HTTPManagerStateService extends ComponentStore {
7258
7251
  console.warn('[DB STORAGE] Table create/open not ready, skipping DB write for this payload:', { table: tableName });
7259
7252
  return of(data);
7260
7253
  }
7261
- return this.dbManagerService.createTableRecords(tableName, adaptedDbData).pipe(tap(() => this.saveRequestCacheMetadata(tableName, 'GET', requestSignature, schemaSignature, options)));
7254
+ return this.dbManagerService.createTableRecords(tableName, dbData).pipe(tap(() => this.saveRequestCacheMetadata(tableName, 'GET', requestSignature, schemaSignature, options)));
7262
7255
  }));
7263
7256
  }), catchError((error) => {
7264
7257
  console.error('[DB STORAGE] Failed to ensure table and write records:', { table: tableName, schema, error });
@@ -7371,14 +7364,14 @@ class HTTPManagerStateService extends ComponentStore {
7371
7364
  return this.httpManagerService.getRequest(requestOptions, effectiveParams)
7372
7365
  .pipe(tap((data) => {
7373
7366
  console.log('📦 fetchRecord received data:', data);
7374
- // Apply adapter if provided
7375
- let adaptedData = this.applyAdapter(data);
7376
- adaptedData = (!adaptedData) ? (this.dataType === DataType.ARRAY) ? [] : {} : adaptedData;
7367
+ // Data is already adapted by RequestService.request() pipe - no need to adapt again
7368
+ const arrayData = (data?.results && Array.isArray(data.results)) ? data.results : data;
7369
+ const finalData = (!arrayData) ? (this.dataType === DataType.ARRAY) ? [] : {} : arrayData;
7377
7370
  const id = options.path?.length ? options.path[options.path.length - 1] : null;
7378
7371
  // For single-record operations (CREATE, UPDATE, DELETE), extract from array if needed
7379
- let singleRecord = adaptedData;
7380
- if (Array.isArray(adaptedData) && adaptedData.length > 0) {
7381
- singleRecord = adaptedData[0];
7372
+ let singleRecord = finalData;
7373
+ if (Array.isArray(finalData) && finalData.length > 0) {
7374
+ singleRecord = finalData[0];
7382
7375
  }
7383
7376
  if (method === 'DELETE') {
7384
7377
  console.log('🗑️ Deleting record with id:', id);
@@ -7389,17 +7382,18 @@ class HTTPManagerStateService extends ComponentStore {
7389
7382
  this.updateData$(singleRecord);
7390
7383
  }
7391
7384
  if (method === 'CREATE') {
7392
- console.log('➕ Adding record:', adaptedData);
7393
- this.addData$(adaptedData);
7385
+ console.log('➕ Adding record:', finalData);
7386
+ this.addData$(finalData);
7394
7387
  }
7395
7388
  }), concatMap((data) => {
7396
- const adaptedData = this.applyAdapter(data);
7389
+ // Data is already adapted by RequestService.request() pipe - no need to adapt again
7390
+ const dbData = (data?.results && Array.isArray(data.results)) ? data.results : data;
7397
7391
  const tableName = this.databaseOptions?.table;
7398
7392
  const idFromPath = options.path?.length ? options.path[options.path.length - 1] : null;
7399
7393
  // For single-record operations, extract from array if needed
7400
- let singleRecord = adaptedData;
7401
- if (Array.isArray(adaptedData) && adaptedData.length > 0) {
7402
- singleRecord = adaptedData[0];
7394
+ let singleRecord = dbData;
7395
+ if (Array.isArray(dbData) && dbData.length > 0) {
7396
+ singleRecord = dbData[0];
7403
7397
  }
7404
7398
  if (this.hasDatabase && tableName) {
7405
7399
  switch (method) {
@@ -7418,11 +7412,11 @@ class HTTPManagerStateService extends ComponentStore {
7418
7412
  this.logger.warn('fetchRecord', 'UPDATE method called but singleRecord or id is missing', { singleRecord, hasData: !!singleRecord, hasId: !!singleRecord?.id });
7419
7413
  break;
7420
7414
  case 'CREATE':
7421
- if (adaptedData && adaptedData.id != null && adaptedData.id !== '') {
7422
- this.logger.debug('fetchRecord', 'Creating database record', { table: tableName, id: adaptedData.id, data: adaptedData });
7423
- return this.dbManagerService.createTableRecord(tableName, adaptedData);
7415
+ if (dbData && dbData.id != null && dbData.id !== '') {
7416
+ this.logger.debug('fetchRecord', 'Creating database record', { table: tableName, id: dbData.id, data: dbData });
7417
+ return this.dbManagerService.createTableRecord(tableName, dbData);
7424
7418
  }
7425
- this.logger.warn('fetchRecord', 'CREATE method called but data.id is invalid', { adaptedData });
7419
+ this.logger.warn('fetchRecord', 'CREATE method called but data.id is invalid', { dbData });
7426
7420
  break;
7427
7421
  default:
7428
7422
  this.logger.debug('fetchRecord', 'Method does not require database operation', { method });
@@ -7434,7 +7428,7 @@ class HTTPManagerStateService extends ComponentStore {
7434
7428
  hasTable: !!tableName
7435
7429
  });
7436
7430
  }
7437
- return of(adaptedData);
7431
+ return of(dbData);
7438
7432
  }));
7439
7433
  })));
7440
7434
  // CREATE RECORD
@@ -7443,17 +7437,13 @@ class HTTPManagerStateService extends ComponentStore {
7443
7437
  const requestOptions = this.updateRequestOptions(options?.headers);
7444
7438
  const effectiveParams = this.getEffectiveParams(options?.path);
7445
7439
  return this.httpManagerService.postRequest(data, requestOptions, effectiveParams)
7446
- .pipe(tap((data) => {
7447
- // Apply adapter to response data
7448
- let adaptedData = this.applyAdapter(data);
7449
- adaptedData = (!adaptedData) ? (this.dataType === DataType.ARRAY) ? [] : {} : adaptedData;
7450
- this.addData$(adaptedData);
7440
+ .pipe(tap((adaptedData) => {
7441
+ // Data is already adapted by RequestService
7442
+ const safeData = (!adaptedData) ? (this.dataType === DataType.ARRAY ? [] : {}) : adaptedData;
7443
+ this.addData$(safeData);
7451
7444
  this.operationSuccess.next(OperationResultModel.adapt({ success: true, operation: 'CREATE' }));
7452
- // Always call wsCommunication - it will queue if not connected
7453
- this.wsCommunication('CREATE', [...options?.path || [], adaptedData.id]);
7454
- }), concatMap((data) => {
7455
- // Apply adapter before database operations
7456
- const adaptedData = this.applyAdapter(data);
7445
+ this.wsCommunication('CREATE', [...options?.path || [], safeData.id]);
7446
+ }), concatMap((adaptedData) => {
7457
7447
  if (this.hasDatabase && this.databaseOptions?.table && adaptedData?.id) {
7458
7448
  return this.dbManagerService.createTableRecord(this.databaseOptions.table, adaptedData);
7459
7449
  }
@@ -7466,17 +7456,13 @@ class HTTPManagerStateService extends ComponentStore {
7466
7456
  const requestOptions = this.updateRequestOptions(options?.headers);
7467
7457
  const effectiveParams = this.getEffectiveParams(options?.path);
7468
7458
  return this.httpManagerService.putRequest(data, requestOptions, effectiveParams)
7469
- .pipe(tap((data) => {
7470
- // Apply adapter to response data
7471
- let adaptedData = this.applyAdapter(data);
7472
- adaptedData = (!adaptedData) ? (this.dataType === DataType.ARRAY) ? [] : {} : adaptedData;
7473
- this.updateData$(adaptedData);
7459
+ .pipe(tap((adaptedData) => {
7460
+ // Data is already adapted by RequestService
7461
+ const safeData = (!adaptedData) ? (this.dataType === DataType.ARRAY ? [] : {}) : adaptedData;
7462
+ this.updateData$(safeData);
7474
7463
  this.operationSuccess.next(OperationResultModel.adapt({ success: true, operation: 'UPDATE' }));
7475
- // Always call wsCommunication - it will queue if not connected
7476
7464
  this.wsCommunication('UPDATE', [...options?.path || []]);
7477
- }), concatMap((data) => {
7478
- // Apply adapter before database operations
7479
- const adaptedData = this.applyAdapter(data);
7465
+ }), concatMap((adaptedData) => {
7480
7466
  if (this.hasDatabase && this.databaseOptions?.table && adaptedData?.id) {
7481
7467
  return this.dbManagerService.updateTableRecord(this.databaseOptions.table, adaptedData);
7482
7468
  }
@@ -7489,17 +7475,13 @@ class HTTPManagerStateService extends ComponentStore {
7489
7475
  const requestOptions = this.updateRequestOptions(options?.headers);
7490
7476
  const effectiveParams = this.getEffectiveParams(options?.path);
7491
7477
  return this.httpManagerService.deleteRequest(requestOptions, effectiveParams)
7492
- .pipe(tap((data) => {
7493
- // Apply adapter to response data
7494
- let adaptedData = this.applyAdapter(data);
7495
- adaptedData = (!adaptedData) ? (this.dataType === DataType.ARRAY) ? [] : {} : adaptedData;
7496
- this.deleteData$(adaptedData);
7478
+ .pipe(tap((adaptedData) => {
7479
+ // Data is already adapted by RequestService
7480
+ const safeData = (!adaptedData) ? (this.dataType === DataType.ARRAY ? [] : {}) : adaptedData;
7481
+ this.deleteData$(safeData);
7497
7482
  this.operationSuccess.next(OperationResultModel.adapt({ success: true, operation: 'DELETE' }));
7498
- // Always call wsCommunication - it will queue if not connected
7499
7483
  this.wsCommunication('DELETE', [...options?.path || []]);
7500
- }), concatMap((data) => {
7501
- // Apply adapter before database operations
7502
- const adaptedData = this.applyAdapter(data);
7484
+ }), concatMap((adaptedData) => {
7503
7485
  if (this.hasDatabase && this.databaseOptions?.table && adaptedData?.id) {
7504
7486
  return this.dbManagerService.deleteTableRecord(this.databaseOptions.table, adaptedData.id);
7505
7487
  }
@@ -7512,13 +7494,12 @@ class HTTPManagerStateService extends ComponentStore {
7512
7494
  const requestOptions = this.updateRequestOptions(options?.headers);
7513
7495
  const effectiveParams = this.getEffectiveParams(options?.path);
7514
7496
  return this.httpManagerService.postRequest(data, requestOptions, effectiveParams)
7515
- .pipe(tap((res) => {
7516
- // Apply adapter to streaming response
7517
- const adaptedRes = this.applyAdapter(res);
7497
+ .pipe(tap((adaptedRes) => {
7498
+ // Data is already adapted by RequestService
7518
7499
  if (adaptedRes.length > 0)
7519
7500
  this.setData$(adaptedRes);
7520
7501
  this.streamedResponse = adaptedRes;
7521
- }), concatMap((res) => this.persistStreamDataToDb(res, options)), scan((acc, res) => {
7502
+ }), concatMap((adaptedRes) => this.persistStreamDataToDb(adaptedRes, options)), scan((acc, res) => {
7522
7503
  const previous = acc.current;
7523
7504
  const current = res;
7524
7505
  return { previous, current };
@@ -7533,14 +7514,12 @@ class HTTPManagerStateService extends ComponentStore {
7533
7514
  }));
7534
7515
  })));
7535
7516
  this.fetchStream = (options) => this.effect(() => of(options).pipe(tap(() => {
7536
- // console.log('[DEBUG] fetchStream called')
7537
7517
  this.streamedResponse = [];
7538
7518
  this.httpManagerService.isPending.next(true);
7539
7519
  }), switchMap((options) => {
7540
7520
  const requestOptions = this.updateRequestOptions(options?.headers);
7541
7521
  requestOptions.stream = true;
7542
7522
  const effectiveParams = this.getEffectiveParams(options?.path);
7543
- // console.log('[DEBUG] Making streaming request:', requestOptions)
7544
7523
  if (this.hasDatabase && this.databaseOptions?.table) {
7545
7524
  const requestSignature = this.buildRequestSignature('STREAM', requestOptions, effectiveParams);
7546
7525
  const fetchStreamFromAPI = () => {
@@ -7549,9 +7528,7 @@ class HTTPManagerStateService extends ComponentStore {
7549
7528
  if (Array.isArray(currentStateData) && currentStateData.length > 0) {
7550
7529
  return of({ data: currentStateData, fromCache: true });
7551
7530
  }
7552
- if (currentStateData &&
7553
- !Array.isArray(currentStateData) &&
7554
- Object.keys(currentStateData).length > 0) {
7531
+ if (currentStateData && !Array.isArray(currentStateData) && Object.keys(currentStateData).length > 0) {
7555
7532
  return of({ data: currentStateData, fromCache: true });
7556
7533
  }
7557
7534
  return of({ data: this.dataType === DataType.ARRAY ? [] : {}, fromCache: true });
@@ -7586,9 +7563,7 @@ class HTTPManagerStateService extends ComponentStore {
7586
7563
  if (Array.isArray(currentStateData) && currentStateData.length > 0) {
7587
7564
  return of({ data: currentStateData, fromCache: true });
7588
7565
  }
7589
- if (currentStateData &&
7590
- !Array.isArray(currentStateData) &&
7591
- Object.keys(currentStateData).length > 0) {
7566
+ if (currentStateData && !Array.isArray(currentStateData) && Object.keys(currentStateData).length > 0) {
7592
7567
  return of({ data: currentStateData, fromCache: true });
7593
7568
  }
7594
7569
  return fetchStreamFromAPI();
@@ -7598,23 +7573,17 @@ class HTTPManagerStateService extends ComponentStore {
7598
7573
  }));
7599
7574
  })).pipe(tap((packet) => {
7600
7575
  const res = packet?.data;
7601
- // Apply adapter to streaming response
7602
- const adaptedRes = this.applyAdapter(res);
7603
- // console.log('[DEBUG] Streaming response received:', adaptedRes)
7604
- if (adaptedRes && adaptedRes.length > 0) {
7605
- // console.log('[DEBUG] Updating state with streaming data:', adaptedRes)
7606
- this.setData$(adaptedRes);
7607
- this.streamedResponse = [...this.streamedResponse, ...adaptedRes];
7576
+ // Data is already adapted by RequestService
7577
+ if (res && res.length > 0) {
7578
+ this.setData$(res);
7579
+ this.streamedResponse = [...this.streamedResponse, ...res];
7608
7580
  }
7609
7581
  }), concatMap((packet) => {
7610
7582
  if (packet?.fromCache) {
7611
7583
  return of(packet?.data);
7612
7584
  }
7613
7585
  return this.persistStreamDataToDb(packet?.data, options);
7614
- }), map((res) => {
7615
- // console.log('[DEBUG] Returning data to subscribers:', res)
7616
- return res;
7617
- }), catchError((error) => {
7586
+ }), map((res) => res), catchError((error) => {
7618
7587
  console.error('[DEBUG] Streaming error:', error);
7619
7588
  return of([]);
7620
7589
  }), finalize(() => this.httpManagerService.isPending.next(false)));
@@ -7622,23 +7591,12 @@ class HTTPManagerStateService extends ComponentStore {
7622
7591
  // If no database is configured, always call the API (do not check tracker)
7623
7592
  return this.httpManagerService.getRequest(requestOptions, effectiveParams)
7624
7593
  .pipe(tap((res) => {
7625
- // Apply adapter to streaming response
7626
- const adaptedRes = this.applyAdapter(res);
7627
- console.log('[DEBUG] Streaming response received:', adaptedRes);
7628
- // Always update state with streaming data
7629
- if (adaptedRes && adaptedRes.length > 0) {
7630
- // console.log('[DEBUG] Updating state with streaming data:', adaptedRes)
7631
- this.setData$(adaptedRes);
7632
- this.streamedResponse = [...this.streamedResponse, ...adaptedRes];
7633
- }
7634
- else {
7635
- // console.log('[DEBUG] No streaming data or empty array:', adaptedRes)
7594
+ // Data is already adapted by RequestService
7595
+ if (res && res.length > 0) {
7596
+ this.setData$(res);
7597
+ this.streamedResponse = [...this.streamedResponse, ...res];
7636
7598
  }
7637
- }), concatMap((res) => this.persistStreamDataToDb(res, options)), map((res) => {
7638
- // console.log('[DEBUG] Returning data to subscribers:', res)
7639
- return res; // Return the data so subscribers can receive it
7640
- }), catchError((error) => {
7641
- // console.error('[DEBUG] Streaming error:', error)
7599
+ }), concatMap((res) => this.persistStreamDataToDb(res, options)), map((res) => res), catchError((error) => {
7642
7600
  return of([]);
7643
7601
  }), finalize(() => this.httpManagerService.isPending.next(false)));
7644
7602
  })));
@@ -7926,17 +7884,16 @@ class HTTPManagerStateService extends ComponentStore {
7926
7884
  if (!this.hasDatabase || !this.databaseOptions?.table) {
7927
7885
  return of(payload);
7928
7886
  }
7929
- // Apply adapter to payload before processing
7930
- const adaptedPayload = this.applyAdapter(payload);
7931
- const dbData = (adaptedPayload?.results && Array.isArray(adaptedPayload.results))
7932
- ? adaptedPayload.results
7933
- : Array.isArray(adaptedPayload)
7934
- ? adaptedPayload
7935
- : adaptedPayload
7936
- ? [adaptedPayload]
7887
+ // Payload is already adapted by RequestService.requestStreaming() pipe - no need to adapt again
7888
+ const dbData = (payload?.results && Array.isArray(payload.results))
7889
+ ? payload.results
7890
+ : Array.isArray(payload)
7891
+ ? payload
7892
+ : payload
7893
+ ? [payload]
7937
7894
  : [];
7938
7895
  if (dbData.length === 0) {
7939
- return of(adaptedPayload);
7896
+ return of(payload);
7940
7897
  }
7941
7898
  const tableName = this.databaseOptions.table;
7942
7899
  const requestOptions = this.updateRequestOptions(streamOptions?.headers);
@@ -7955,13 +7912,13 @@ class HTTPManagerStateService extends ComponentStore {
7955
7912
  return ensureTable$.pipe(switchMap((created) => {
7956
7913
  if (!created) {
7957
7914
  console.warn('[DB STORAGE] Stream table create/open not ready, skipping DB write for this chunk:', { table: tableName });
7958
- return of(adaptedPayload);
7915
+ return of(payload);
7959
7916
  }
7960
- return this.dbManagerService.createTableRecords(tableName, dbData).pipe(tap(() => this.saveRequestCacheMetadata(tableName, 'STREAM', requestSignature, schemaSignature, streamOptions)), map(() => adaptedPayload));
7917
+ return this.dbManagerService.createTableRecords(tableName, dbData).pipe(tap(() => this.saveRequestCacheMetadata(tableName, 'STREAM', requestSignature, schemaSignature, streamOptions)), map(() => payload));
7961
7918
  }));
7962
- }), map(() => adaptedPayload), catchError((error) => {
7919
+ }), map(() => payload), catchError((error) => {
7963
7920
  console.error('[DB STORAGE] Failed to persist streaming payload:', { table: tableName, schema, error });
7964
- return of(adaptedPayload);
7921
+ return of(payload);
7965
7922
  }));
7966
7923
  }
7967
7924
  // WEBSOCKET COMMUNICATION (STATE MANAGER)
@@ -8283,19 +8240,8 @@ class HTTPManagerStateService extends ComponentStore {
8283
8240
  return Object.keys(obj).length === 0;
8284
8241
  }
8285
8242
  /**
8286
- * Apply adapter to data if adapter is provided
8287
- * Handles both array and single object responses
8288
- * Only applies adapter when it exists - returns data as-is otherwise
8243
+ * Update request options with provided headers
8289
8244
  */
8290
- applyAdapter(data) {
8291
- if (!data || !this.apiOptions?.adapter) {
8292
- return data;
8293
- }
8294
- if (Array.isArray(data)) {
8295
- return data.map((item) => this.apiOptions.adapter(item));
8296
- }
8297
- return this.apiOptions.adapter(data);
8298
- }
8299
8245
  updateRequestOptions(headers) {
8300
8246
  const options = ApiRequest.adapt({ ...this.apiOptions });
8301
8247
  options.headers = (headers)
@@ -8419,6 +8365,58 @@ class HTTPManagerStateService extends ComponentStore {
8419
8365
  const currentQueryParams = { ...(currentEntry.queryParams || {}) };
8420
8366
  const currentQueryCombinations = [...(currentEntry.queryCombinations || [])];
8421
8367
  const currentQueryParamsExpires = currentEntry.queryParamsExpires ?? null;
8368
+ // Extract query params from options?.path and build combination string
8369
+ const resolvedPath = this.resolvePath(options?.path);
8370
+ const extractedParams = {};
8371
+ const ignoreQueryParams = Array.isArray(options?.ignoreQueryParams) ? options.ignoreQueryParams : [];
8372
+ if (Array.isArray(resolvedPath)) {
8373
+ const normalizedIgnore = ignoreQueryParams.map(p => this.trackerNormalizeParamKey(p));
8374
+ resolvedPath.forEach((pathPart) => {
8375
+ // Extract query params from objects in the path array
8376
+ if (pathPart && typeof pathPart === 'object' && !Array.isArray(pathPart)) {
8377
+ Object.keys(pathPart).forEach((key) => {
8378
+ const normalizedKey = this.trackerNormalizeParamKey(key);
8379
+ const value = String(pathPart[key]);
8380
+ // Only add to queryParams if NOT in ignoreQueryParams
8381
+ if (!normalizedIgnore.includes(normalizedKey)) {
8382
+ if (!currentQueryParams[key]) {
8383
+ currentQueryParams[key] = [];
8384
+ }
8385
+ if (!currentQueryParams[key].includes(value)) {
8386
+ currentQueryParams[key].push(value);
8387
+ }
8388
+ // Track extracted param for combination string
8389
+ extractedParams[normalizedKey] = value;
8390
+ }
8391
+ });
8392
+ }
8393
+ else if (typeof pathPart === 'string') {
8394
+ // Parse URL query strings like 'items?active=true&location=6'
8395
+ const normalized = this.trackerNormalizePath([pathPart]);
8396
+ if (normalized.hasQuery) {
8397
+ const filtered = this.trackerFilterQuery(normalized.query, ignoreQueryParams);
8398
+ Object.assign(extractedParams, filtered);
8399
+ // Add filtered params to queryParams
8400
+ Object.keys(filtered).forEach((key) => {
8401
+ if (!currentQueryParams[key]) {
8402
+ currentQueryParams[key] = [];
8403
+ }
8404
+ if (!currentQueryParams[key].includes(filtered[key])) {
8405
+ currentQueryParams[key].push(filtered[key]);
8406
+ }
8407
+ });
8408
+ }
8409
+ }
8410
+ });
8411
+ }
8412
+ // Build combination string if we have extracted params
8413
+ if (Object.keys(extractedParams).length > 0) {
8414
+ const keys = Object.keys(extractedParams).sort();
8415
+ const combinationString = keys.map((k) => `${k}=${extractedParams[k]}`).join('&');
8416
+ if (!currentQueryCombinations.includes(combinationString)) {
8417
+ currentQueryCombinations.push(combinationString);
8418
+ }
8419
+ }
8422
8420
  this.localStorageManagerService.updateStore({
8423
8421
  name: tableName,
8424
8422
  data: {
@@ -8429,7 +8427,7 @@ class HTTPManagerStateService extends ComponentStore {
8429
8427
  ...currentEntry,
8430
8428
  signature,
8431
8429
  savedAt: Date.now(),
8432
- path: this.resolvePath(options?.path),
8430
+ path: resolvedPath,
8433
8431
  headers: this.filterHeaders(options?.headers),
8434
8432
  queryCombinations: currentQueryCombinations,
8435
8433
  queryParams: currentQueryParams,
@@ -8556,22 +8554,6 @@ class HTTPManagerStateService extends ComponentStore {
8556
8554
  });
8557
8555
  return result;
8558
8556
  }
8559
- trackerBuildExpiryEpoch(expireIn) {
8560
- if (typeof expireIn === 'undefined' || expireIn === null || expireIn === '')
8561
- return null;
8562
- if (typeof expireIn === 'number' && Number.isFinite(expireIn) && expireIn > 0) {
8563
- return Math.floor(Date.now() / 1000) + Math.floor(expireIn);
8564
- }
8565
- const raw = String(expireIn).trim().toLowerCase().replace(/\s+/g, '');
8566
- const parsed = raw.match(/^(\d+)(y|w|d|hr|h|mn|min|m|s)$/);
8567
- if (!parsed)
8568
- return null;
8569
- const toSeconds = { y: 31556926, w: 604800, d: 86400, hr: 3600, h: 3600, mn: 60, min: 60, m: 60, s: 1 };
8570
- const seconds = toSeconds[parsed[2]];
8571
- if (!seconds)
8572
- return null;
8573
- return Math.floor(Date.now() / 1000) + Number(parsed[1]) * seconds;
8574
- }
8575
8557
  checkTrackerAllowsRequest(tableName, type, path, options, storeData) {
8576
8558
  const normalized = this.trackerNormalizePath(path);
8577
8559
  const ignoreQueryParams = Array.isArray(options?.ignoreQueryParams) ? options.ignoreQueryParams : [];
@@ -8590,58 +8572,47 @@ class HTTPManagerStateService extends ComponentStore {
8590
8572
  const combinationString = keys.sort().map((k) => `${k}=${filtered[k]}`).join('&');
8591
8573
  // Legacy per-key queryParams for backward compatibility (read-only)
8592
8574
  const queryParams = { ...(meta.queryParams || {}) };
8593
- let queryParamsExpires = meta.queryParamsExpires ?? null;
8575
+ const queryParamsExpires = meta.queryParamsExpires ?? null;
8594
8576
  // New combination-based tracking
8595
- let queryCombinations = [...(meta.queryCombinations || [])];
8577
+ const queryCombinations = [...(meta.queryCombinations || [])];
8596
8578
  // Reset combinations if the request path has changed (different endpoint)
8597
8579
  // Use trackerNormalizePath so inline query strings (e.g. 'items?a=1') are stripped
8598
8580
  // before comparing, matching the same normalization applied to the current request.
8599
8581
  const storedPathKey = meta.path
8600
8582
  ? this.trackerNormalizePath(meta.path.filter((p) => typeof p === 'string' || typeof p === 'number').map(String)).pathKey
8601
8583
  : null;
8602
- if (storedPathKey && storedPathKey !== normalized.pathKey) {
8603
- queryCombinations = [];
8604
- // Also clear legacy per-key tracking so old data from a different path doesn't block
8605
- Object.keys(queryParams).forEach((k) => delete queryParams[k]);
8606
- queryParamsExpires = null;
8607
- }
8608
- if (queryParamsExpires !== null && queryParamsExpires <= now) {
8609
- queryCombinations = [];
8610
- queryParamsExpires = null;
8611
- Object.keys(queryParams).forEach((k) => delete queryParams[k]);
8612
- }
8584
+ const pathChanged = storedPathKey && storedPathKey !== normalized.pathKey;
8585
+ const isExpired = queryParamsExpires !== null && queryParamsExpires <= now;
8586
+ const shouldReset = pathChanged || isExpired;
8613
8587
  // Determine if request is accepted (not yet tracked)
8614
8588
  // Use combination-based tracking when available; fall back to legacy per-key tracking
8615
- let accepted;
8616
- if (queryCombinations.length > 0) {
8617
- accepted = !queryCombinations.includes(combinationString);
8618
- }
8619
- else if (Object.keys(queryParams).length > 0) {
8620
- // Legacy per-key backward compatibility
8621
- accepted = !keys.every((key) => {
8622
- const consumed = queryParams[key] || [];
8623
- return consumed.includes(filtered[key]);
8624
- });
8625
- }
8626
- else {
8627
- accepted = true;
8628
- }
8629
- if (accepted) {
8630
- queryCombinations = [...queryCombinations, combinationString];
8631
- // Also update legacy queryParams so existing consumers still work
8632
- keys.forEach(key => {
8589
+ const accepted = shouldReset
8590
+ ? true
8591
+ : queryCombinations.length > 0
8592
+ ? !queryCombinations.includes(combinationString)
8593
+ : Object.keys(queryParams).length > 0
8594
+ ? !keys.every((key) => (queryParams[key] || []).includes(filtered[key]))
8595
+ : true;
8596
+ // Compute updated values immutably
8597
+ const updatedQueryCombinations = accepted
8598
+ ? [...queryCombinations, combinationString]
8599
+ : queryCombinations;
8600
+ const updatedQueryParams = accepted
8601
+ ? keys.reduce((acc, key) => {
8633
8602
  const value = filtered[key];
8634
- const consumed = queryParams[key] || [];
8603
+ const consumed = acc[key] || [];
8635
8604
  if (!consumed.includes(value)) {
8636
- queryParams[key] = [...consumed, value];
8605
+ acc[key] = [...consumed, value];
8637
8606
  }
8638
- });
8639
- }
8640
- const newExpiry = this.trackerBuildExpiryEpoch(options?.queryParamsExpiresIn);
8641
- if (newExpiry !== null) {
8642
- queryParamsExpires = newExpiry;
8643
- }
8644
- if (accepted || newExpiry !== null) {
8607
+ return acc;
8608
+ }, { ...queryParams })
8609
+ : { ...queryParams };
8610
+ const updatedQueryParamsExpires = this.utils.expires(options?.queryParamsExpiresIn) ?? queryParamsExpires;
8611
+ // Apply reset if path changed or expired
8612
+ const finalQueryCombinations = shouldReset ? updatedQueryCombinations : queryCombinations;
8613
+ const finalQueryParams = shouldReset ? updatedQueryParams : queryParams;
8614
+ const finalQueryParamsExpires = shouldReset ? updatedQueryParamsExpires : updatedQueryParamsExpires;
8615
+ if (accepted || updatedQueryParamsExpires !== queryParamsExpires) {
8645
8616
  this.localStorageManagerService.store$(tableName).pipe(take(1), tap((latestStoreData) => {
8646
8617
  const currentCache = latestStoreData?.requestCache || {};
8647
8618
  const currentEntry = currentCache[type] || {};
@@ -8653,9 +8624,9 @@ class HTTPManagerStateService extends ComponentStore {
8653
8624
  ...currentCache,
8654
8625
  [type]: {
8655
8626
  ...currentEntry,
8656
- queryCombinations,
8657
- queryParams,
8658
- queryParamsExpires,
8627
+ queryCombinations: finalQueryCombinations,
8628
+ queryParams: finalQueryParams,
8629
+ queryParamsExpires: finalQueryParamsExpires,
8659
8630
  }
8660
8631
  }
8661
8632
  }