http-request-manager 18.16.25 → 18.16.28

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.
@@ -6610,16 +6610,19 @@ class DatabaseManagerService extends DbService {
6610
6610
  }
6611
6611
  updateTableRecord(table, record) {
6612
6612
  const tableName = this.cleanTableName(table);
6613
+ console.log(`🔵 updateTableRecord: INPUT table='${table}' CLEANED='${tableName}'`);
6613
6614
  return this.updateTableRecords(tableName, [record])
6614
6615
  .pipe(map(item => item.length > 0 ? item[0] : null));
6615
6616
  }
6616
6617
  updateTableRecords(table, records) {
6617
6618
  const tableName = this.cleanTableName(table);
6619
+ console.log(`🔵 updateTableRecords: INPUT table='${table}' CLEANED='${tableName}' recordCount=${records.length}`);
6618
6620
  return this.getDatabaseTable(tableName).pipe(switchMap((tableData) => {
6619
6621
  if (!tableData) {
6620
- console.warn(`updateTableRecords: Table '${tableName}' not found`);
6622
+ console.warn(`❌ updateTableRecords: Table '${tableName}' not found`);
6621
6623
  return EMPTY;
6622
6624
  }
6625
+ console.log(`✅ updateTableRecords: Table '${tableName}' FOUND, executing bulkPut with ${records.length} records`);
6623
6626
  const insertRecords = records.map((record) => {
6624
6627
  const payload = { ...(record || {}) };
6625
6628
  if (payload.id === undefined || payload.id === null || payload.id === '') {
@@ -7228,19 +7231,16 @@ class HTTPManagerStateService extends ComponentStore {
7228
7231
  }
7229
7232
  return this.httpManagerService.getRequest(requestOptions, effectiveParams).pipe(tap((data) => {
7230
7233
  // Extract array from paginated response if needed
7234
+ // Data is already adapted by RequestService.request() pipe - no need to adapt again
7231
7235
  const arrayData = (data?.results && Array.isArray(data.results)) ? data.results : data;
7232
- // Apply adapter to response data
7233
- let adaptedData = this.applyAdapter(arrayData);
7234
- adaptedData = (!adaptedData) ? (this.dataType === DataType.ARRAY) ? [] : {} : adaptedData;
7235
- this.setData$(adaptedData);
7236
+ this.setData$(arrayData);
7236
7237
  }), concatMap((data) => {
7237
7238
  // Extract array from paginated response for database storage
7239
+ // Data is already adapted by RequestService.request() pipe - no need to adapt again
7238
7240
  const dbData = (data?.results && Array.isArray(data.results)) ? data.results : data;
7239
- // Apply adapter before database storage
7240
- const adaptedDbData = this.applyAdapter(dbData);
7241
- if (this.hasDatabase && this.databaseOptions?.table && Array.isArray(adaptedDbData) && adaptedDbData.length > 0) {
7241
+ if (this.hasDatabase && this.databaseOptions?.table && Array.isArray(dbData) && dbData.length > 0) {
7242
7242
  const tableName = this.databaseOptions.table;
7243
- const schema = this.buildSchemaFromSample(adaptedDbData[0]);
7243
+ const schema = this.buildSchemaFromSample(dbData[0]);
7244
7244
  const tableDef = TableSchemaDef.adapt({ table: tableName, schema });
7245
7245
  const schemaSignature = this.buildSchemaSignature(schema);
7246
7246
  // Always ensure table exists immediately before writing to avoid stale schema/store races.
@@ -7255,7 +7255,7 @@ class HTTPManagerStateService extends ComponentStore {
7255
7255
  console.warn('[DB STORAGE] Table create/open not ready, skipping DB write for this payload:', { table: tableName });
7256
7256
  return of(data);
7257
7257
  }
7258
- return this.dbManagerService.createTableRecords(tableName, adaptedDbData).pipe(tap(() => this.saveRequestCacheMetadata(tableName, 'GET', requestSignature, schemaSignature, options)));
7258
+ return this.dbManagerService.createTableRecords(tableName, dbData).pipe(tap(() => this.saveRequestCacheMetadata(tableName, 'GET', requestSignature, schemaSignature, options)));
7259
7259
  }));
7260
7260
  }), catchError((error) => {
7261
7261
  console.error('[DB STORAGE] Failed to ensure table and write records:', { table: tableName, schema, error });
@@ -7368,26 +7368,37 @@ class HTTPManagerStateService extends ComponentStore {
7368
7368
  return this.httpManagerService.getRequest(requestOptions, effectiveParams)
7369
7369
  .pipe(tap((data) => {
7370
7370
  console.log('📦 fetchRecord received data:', data);
7371
- // Apply adapter if provided
7372
- let adaptedData = this.applyAdapter(data);
7373
- adaptedData = (!adaptedData) ? (this.dataType === DataType.ARRAY) ? [] : {} : adaptedData;
7371
+ // Data is already adapted by RequestService.request() pipe - no need to adapt again
7372
+ const arrayData = (data?.results && Array.isArray(data.results)) ? data.results : data;
7373
+ const finalData = (!arrayData) ? (this.dataType === DataType.ARRAY) ? [] : {} : arrayData;
7374
7374
  const id = options.path?.length ? options.path[options.path.length - 1] : null;
7375
+ // For single-record operations (CREATE, UPDATE, DELETE), extract from array if needed
7376
+ let singleRecord = finalData;
7377
+ if (Array.isArray(finalData) && finalData.length > 0) {
7378
+ singleRecord = finalData[0];
7379
+ }
7375
7380
  if (method === 'DELETE') {
7376
7381
  console.log('🗑️ Deleting record with id:', id);
7377
7382
  this.deleteData$({ id });
7378
7383
  }
7379
7384
  if (method === 'UPDATE') {
7380
- console.log('✏️ Updating record:', adaptedData);
7381
- this.updateData$(adaptedData);
7385
+ console.log('✏️ Updating record:', singleRecord);
7386
+ this.updateData$(singleRecord);
7382
7387
  }
7383
7388
  if (method === 'CREATE') {
7384
- console.log('➕ Adding record:', adaptedData);
7385
- this.addData$(adaptedData);
7389
+ console.log('➕ Adding record:', finalData);
7390
+ this.addData$(finalData);
7386
7391
  }
7387
7392
  }), concatMap((data) => {
7388
- const adaptedData = this.applyAdapter(data);
7393
+ // Data is already adapted by RequestService.request() pipe - no need to adapt again
7394
+ const dbData = (data?.results && Array.isArray(data.results)) ? data.results : data;
7389
7395
  const tableName = this.databaseOptions?.table;
7390
7396
  const idFromPath = options.path?.length ? options.path[options.path.length - 1] : null;
7397
+ // For single-record operations, extract from array if needed
7398
+ let singleRecord = dbData;
7399
+ if (Array.isArray(dbData) && dbData.length > 0) {
7400
+ singleRecord = dbData[0];
7401
+ }
7391
7402
  if (this.hasDatabase && tableName) {
7392
7403
  switch (method) {
7393
7404
  case 'DELETE':
@@ -7398,18 +7409,18 @@ class HTTPManagerStateService extends ComponentStore {
7398
7409
  this.logger.warn('fetchRecord', 'DELETE method called but id is missing from path', { options });
7399
7410
  break;
7400
7411
  case 'UPDATE':
7401
- if (adaptedData && adaptedData.id != null) {
7402
- this.logger.debug('fetchRecord', 'Updating database record', { table: tableName, id: adaptedData.id, data: adaptedData });
7403
- return this.dbManagerService.updateTableRecord(tableName, adaptedData);
7412
+ if (singleRecord && singleRecord.id != null) {
7413
+ this.logger.debug('fetchRecord', 'Updating database record', { table: tableName, id: singleRecord.id, data: singleRecord });
7414
+ return this.dbManagerService.updateTableRecord(tableName, singleRecord);
7404
7415
  }
7405
- this.logger.warn('fetchRecord', 'UPDATE method called but adaptedData or id is missing', { adaptedData, hasData: !!adaptedData, hasId: !!adaptedData?.id });
7416
+ this.logger.warn('fetchRecord', 'UPDATE method called but singleRecord or id is missing', { singleRecord, hasData: !!singleRecord, hasId: !!singleRecord?.id });
7406
7417
  break;
7407
7418
  case 'CREATE':
7408
- if (adaptedData && adaptedData.id != null && adaptedData.id !== '') {
7409
- this.logger.debug('fetchRecord', 'Creating database record', { table: tableName, id: adaptedData.id, data: adaptedData });
7410
- return this.dbManagerService.createTableRecord(tableName, adaptedData);
7419
+ if (dbData && dbData.id != null && dbData.id !== '') {
7420
+ this.logger.debug('fetchRecord', 'Creating database record', { table: tableName, id: dbData.id, data: dbData });
7421
+ return this.dbManagerService.createTableRecord(tableName, dbData);
7411
7422
  }
7412
- this.logger.warn('fetchRecord', 'CREATE method called but data.id is invalid', { adaptedData });
7423
+ this.logger.warn('fetchRecord', 'CREATE method called but data.id is invalid', { dbData });
7413
7424
  break;
7414
7425
  default:
7415
7426
  this.logger.debug('fetchRecord', 'Method does not require database operation', { method });
@@ -7421,7 +7432,7 @@ class HTTPManagerStateService extends ComponentStore {
7421
7432
  hasTable: !!tableName
7422
7433
  });
7423
7434
  }
7424
- return of(adaptedData);
7435
+ return of(dbData);
7425
7436
  }));
7426
7437
  })));
7427
7438
  // CREATE RECORD
@@ -7430,17 +7441,13 @@ class HTTPManagerStateService extends ComponentStore {
7430
7441
  const requestOptions = this.updateRequestOptions(options?.headers);
7431
7442
  const effectiveParams = this.getEffectiveParams(options?.path);
7432
7443
  return this.httpManagerService.postRequest(data, requestOptions, effectiveParams)
7433
- .pipe(tap((data) => {
7434
- // Apply adapter to response data
7435
- let adaptedData = this.applyAdapter(data);
7436
- adaptedData = (!adaptedData) ? (this.dataType === DataType.ARRAY) ? [] : {} : adaptedData;
7437
- this.addData$(adaptedData);
7444
+ .pipe(tap((adaptedData) => {
7445
+ // Data is already adapted by RequestService
7446
+ const safeData = (!adaptedData) ? (this.dataType === DataType.ARRAY ? [] : {}) : adaptedData;
7447
+ this.addData$(safeData);
7438
7448
  this.operationSuccess.next(OperationResultModel.adapt({ success: true, operation: 'CREATE' }));
7439
- // Always call wsCommunication - it will queue if not connected
7440
- this.wsCommunication('CREATE', [...options?.path || [], adaptedData.id]);
7441
- }), concatMap((data) => {
7442
- // Apply adapter before database operations
7443
- const adaptedData = this.applyAdapter(data);
7449
+ this.wsCommunication('CREATE', [...options?.path || [], safeData.id]);
7450
+ }), concatMap((adaptedData) => {
7444
7451
  if (this.hasDatabase && this.databaseOptions?.table && adaptedData?.id) {
7445
7452
  return this.dbManagerService.createTableRecord(this.databaseOptions.table, adaptedData);
7446
7453
  }
@@ -7453,17 +7460,13 @@ class HTTPManagerStateService extends ComponentStore {
7453
7460
  const requestOptions = this.updateRequestOptions(options?.headers);
7454
7461
  const effectiveParams = this.getEffectiveParams(options?.path);
7455
7462
  return this.httpManagerService.putRequest(data, requestOptions, effectiveParams)
7456
- .pipe(tap((data) => {
7457
- // Apply adapter to response data
7458
- let adaptedData = this.applyAdapter(data);
7459
- adaptedData = (!adaptedData) ? (this.dataType === DataType.ARRAY) ? [] : {} : adaptedData;
7460
- this.updateData$(adaptedData);
7463
+ .pipe(tap((adaptedData) => {
7464
+ // Data is already adapted by RequestService
7465
+ const safeData = (!adaptedData) ? (this.dataType === DataType.ARRAY ? [] : {}) : adaptedData;
7466
+ this.updateData$(safeData);
7461
7467
  this.operationSuccess.next(OperationResultModel.adapt({ success: true, operation: 'UPDATE' }));
7462
- // Always call wsCommunication - it will queue if not connected
7463
7468
  this.wsCommunication('UPDATE', [...options?.path || []]);
7464
- }), concatMap((data) => {
7465
- // Apply adapter before database operations
7466
- const adaptedData = this.applyAdapter(data);
7469
+ }), concatMap((adaptedData) => {
7467
7470
  if (this.hasDatabase && this.databaseOptions?.table && adaptedData?.id) {
7468
7471
  return this.dbManagerService.updateTableRecord(this.databaseOptions.table, adaptedData);
7469
7472
  }
@@ -7476,17 +7479,13 @@ class HTTPManagerStateService extends ComponentStore {
7476
7479
  const requestOptions = this.updateRequestOptions(options?.headers);
7477
7480
  const effectiveParams = this.getEffectiveParams(options?.path);
7478
7481
  return this.httpManagerService.deleteRequest(requestOptions, effectiveParams)
7479
- .pipe(tap((data) => {
7480
- // Apply adapter to response data
7481
- let adaptedData = this.applyAdapter(data);
7482
- adaptedData = (!adaptedData) ? (this.dataType === DataType.ARRAY) ? [] : {} : adaptedData;
7483
- this.deleteData$(adaptedData);
7482
+ .pipe(tap((adaptedData) => {
7483
+ // Data is already adapted by RequestService
7484
+ const safeData = (!adaptedData) ? (this.dataType === DataType.ARRAY ? [] : {}) : adaptedData;
7485
+ this.deleteData$(safeData);
7484
7486
  this.operationSuccess.next(OperationResultModel.adapt({ success: true, operation: 'DELETE' }));
7485
- // Always call wsCommunication - it will queue if not connected
7486
7487
  this.wsCommunication('DELETE', [...options?.path || []]);
7487
- }), concatMap((data) => {
7488
- // Apply adapter before database operations
7489
- const adaptedData = this.applyAdapter(data);
7488
+ }), concatMap((adaptedData) => {
7490
7489
  if (this.hasDatabase && this.databaseOptions?.table && adaptedData?.id) {
7491
7490
  return this.dbManagerService.deleteTableRecord(this.databaseOptions.table, adaptedData.id);
7492
7491
  }
@@ -7499,13 +7498,12 @@ class HTTPManagerStateService extends ComponentStore {
7499
7498
  const requestOptions = this.updateRequestOptions(options?.headers);
7500
7499
  const effectiveParams = this.getEffectiveParams(options?.path);
7501
7500
  return this.httpManagerService.postRequest(data, requestOptions, effectiveParams)
7502
- .pipe(tap((res) => {
7503
- // Apply adapter to streaming response
7504
- const adaptedRes = this.applyAdapter(res);
7501
+ .pipe(tap((adaptedRes) => {
7502
+ // Data is already adapted by RequestService
7505
7503
  if (adaptedRes.length > 0)
7506
7504
  this.setData$(adaptedRes);
7507
7505
  this.streamedResponse = adaptedRes;
7508
- }), concatMap((res) => this.persistStreamDataToDb(res, options)), scan((acc, res) => {
7506
+ }), concatMap((adaptedRes) => this.persistStreamDataToDb(adaptedRes, options)), scan((acc, res) => {
7509
7507
  const previous = acc.current;
7510
7508
  const current = res;
7511
7509
  return { previous, current };
@@ -7520,14 +7518,12 @@ class HTTPManagerStateService extends ComponentStore {
7520
7518
  }));
7521
7519
  })));
7522
7520
  this.fetchStream = (options) => this.effect(() => of(options).pipe(tap(() => {
7523
- // console.log('[DEBUG] fetchStream called')
7524
7521
  this.streamedResponse = [];
7525
7522
  this.httpManagerService.isPending.next(true);
7526
7523
  }), switchMap((options) => {
7527
7524
  const requestOptions = this.updateRequestOptions(options?.headers);
7528
7525
  requestOptions.stream = true;
7529
7526
  const effectiveParams = this.getEffectiveParams(options?.path);
7530
- // console.log('[DEBUG] Making streaming request:', requestOptions)
7531
7527
  if (this.hasDatabase && this.databaseOptions?.table) {
7532
7528
  const requestSignature = this.buildRequestSignature('STREAM', requestOptions, effectiveParams);
7533
7529
  const fetchStreamFromAPI = () => {
@@ -7536,9 +7532,7 @@ class HTTPManagerStateService extends ComponentStore {
7536
7532
  if (Array.isArray(currentStateData) && currentStateData.length > 0) {
7537
7533
  return of({ data: currentStateData, fromCache: true });
7538
7534
  }
7539
- if (currentStateData &&
7540
- !Array.isArray(currentStateData) &&
7541
- Object.keys(currentStateData).length > 0) {
7535
+ if (currentStateData && !Array.isArray(currentStateData) && Object.keys(currentStateData).length > 0) {
7542
7536
  return of({ data: currentStateData, fromCache: true });
7543
7537
  }
7544
7538
  return of({ data: this.dataType === DataType.ARRAY ? [] : {}, fromCache: true });
@@ -7573,9 +7567,7 @@ class HTTPManagerStateService extends ComponentStore {
7573
7567
  if (Array.isArray(currentStateData) && currentStateData.length > 0) {
7574
7568
  return of({ data: currentStateData, fromCache: true });
7575
7569
  }
7576
- if (currentStateData &&
7577
- !Array.isArray(currentStateData) &&
7578
- Object.keys(currentStateData).length > 0) {
7570
+ if (currentStateData && !Array.isArray(currentStateData) && Object.keys(currentStateData).length > 0) {
7579
7571
  return of({ data: currentStateData, fromCache: true });
7580
7572
  }
7581
7573
  return fetchStreamFromAPI();
@@ -7585,23 +7577,17 @@ class HTTPManagerStateService extends ComponentStore {
7585
7577
  }));
7586
7578
  })).pipe(tap((packet) => {
7587
7579
  const res = packet?.data;
7588
- // Apply adapter to streaming response
7589
- const adaptedRes = this.applyAdapter(res);
7590
- // console.log('[DEBUG] Streaming response received:', adaptedRes)
7591
- if (adaptedRes && adaptedRes.length > 0) {
7592
- // console.log('[DEBUG] Updating state with streaming data:', adaptedRes)
7593
- this.setData$(adaptedRes);
7594
- this.streamedResponse = [...this.streamedResponse, ...adaptedRes];
7580
+ // Data is already adapted by RequestService
7581
+ if (res && res.length > 0) {
7582
+ this.setData$(res);
7583
+ this.streamedResponse = [...this.streamedResponse, ...res];
7595
7584
  }
7596
7585
  }), concatMap((packet) => {
7597
7586
  if (packet?.fromCache) {
7598
7587
  return of(packet?.data);
7599
7588
  }
7600
7589
  return this.persistStreamDataToDb(packet?.data, options);
7601
- }), map((res) => {
7602
- // console.log('[DEBUG] Returning data to subscribers:', res)
7603
- return res;
7604
- }), catchError((error) => {
7590
+ }), map((res) => res), catchError((error) => {
7605
7591
  console.error('[DEBUG] Streaming error:', error);
7606
7592
  return of([]);
7607
7593
  }), finalize(() => this.httpManagerService.isPending.next(false)));
@@ -7609,23 +7595,12 @@ class HTTPManagerStateService extends ComponentStore {
7609
7595
  // If no database is configured, always call the API (do not check tracker)
7610
7596
  return this.httpManagerService.getRequest(requestOptions, effectiveParams)
7611
7597
  .pipe(tap((res) => {
7612
- // Apply adapter to streaming response
7613
- const adaptedRes = this.applyAdapter(res);
7614
- console.log('[DEBUG] Streaming response received:', adaptedRes);
7615
- // Always update state with streaming data
7616
- if (adaptedRes && adaptedRes.length > 0) {
7617
- // console.log('[DEBUG] Updating state with streaming data:', adaptedRes)
7618
- this.setData$(adaptedRes);
7619
- this.streamedResponse = [...this.streamedResponse, ...adaptedRes];
7620
- }
7621
- else {
7622
- // console.log('[DEBUG] No streaming data or empty array:', adaptedRes)
7598
+ // Data is already adapted by RequestService
7599
+ if (res && res.length > 0) {
7600
+ this.setData$(res);
7601
+ this.streamedResponse = [...this.streamedResponse, ...res];
7623
7602
  }
7624
- }), concatMap((res) => this.persistStreamDataToDb(res, options)), map((res) => {
7625
- // console.log('[DEBUG] Returning data to subscribers:', res)
7626
- return res; // Return the data so subscribers can receive it
7627
- }), catchError((error) => {
7628
- // console.error('[DEBUG] Streaming error:', error)
7603
+ }), concatMap((res) => this.persistStreamDataToDb(res, options)), map((res) => res), catchError((error) => {
7629
7604
  return of([]);
7630
7605
  }), finalize(() => this.httpManagerService.isPending.next(false)));
7631
7606
  })));
@@ -7913,17 +7888,16 @@ class HTTPManagerStateService extends ComponentStore {
7913
7888
  if (!this.hasDatabase || !this.databaseOptions?.table) {
7914
7889
  return of(payload);
7915
7890
  }
7916
- // Apply adapter to payload before processing
7917
- const adaptedPayload = this.applyAdapter(payload);
7918
- const dbData = (adaptedPayload?.results && Array.isArray(adaptedPayload.results))
7919
- ? adaptedPayload.results
7920
- : Array.isArray(adaptedPayload)
7921
- ? adaptedPayload
7922
- : adaptedPayload
7923
- ? [adaptedPayload]
7891
+ // Payload is already adapted by RequestService.requestStreaming() pipe - no need to adapt again
7892
+ const dbData = (payload?.results && Array.isArray(payload.results))
7893
+ ? payload.results
7894
+ : Array.isArray(payload)
7895
+ ? payload
7896
+ : payload
7897
+ ? [payload]
7924
7898
  : [];
7925
7899
  if (dbData.length === 0) {
7926
- return of(adaptedPayload);
7900
+ return of(payload);
7927
7901
  }
7928
7902
  const tableName = this.databaseOptions.table;
7929
7903
  const requestOptions = this.updateRequestOptions(streamOptions?.headers);
@@ -7942,13 +7916,13 @@ class HTTPManagerStateService extends ComponentStore {
7942
7916
  return ensureTable$.pipe(switchMap((created) => {
7943
7917
  if (!created) {
7944
7918
  console.warn('[DB STORAGE] Stream table create/open not ready, skipping DB write for this chunk:', { table: tableName });
7945
- return of(adaptedPayload);
7919
+ return of(payload);
7946
7920
  }
7947
- return this.dbManagerService.createTableRecords(tableName, dbData).pipe(tap(() => this.saveRequestCacheMetadata(tableName, 'STREAM', requestSignature, schemaSignature, streamOptions)), map(() => adaptedPayload));
7921
+ return this.dbManagerService.createTableRecords(tableName, dbData).pipe(tap(() => this.saveRequestCacheMetadata(tableName, 'STREAM', requestSignature, schemaSignature, streamOptions)), map(() => payload));
7948
7922
  }));
7949
- }), map(() => adaptedPayload), catchError((error) => {
7923
+ }), map(() => payload), catchError((error) => {
7950
7924
  console.error('[DB STORAGE] Failed to persist streaming payload:', { table: tableName, schema, error });
7951
- return of(adaptedPayload);
7925
+ return of(payload);
7952
7926
  }));
7953
7927
  }
7954
7928
  // WEBSOCKET COMMUNICATION (STATE MANAGER)
@@ -8270,19 +8244,8 @@ class HTTPManagerStateService extends ComponentStore {
8270
8244
  return Object.keys(obj).length === 0;
8271
8245
  }
8272
8246
  /**
8273
- * Apply adapter to data if adapter is provided
8274
- * Handles both array and single object responses
8275
- * Only applies adapter when it exists - returns data as-is otherwise
8247
+ * Update request options with provided headers
8276
8248
  */
8277
- applyAdapter(data) {
8278
- if (!data || !this.apiOptions?.adapter) {
8279
- return data;
8280
- }
8281
- if (Array.isArray(data)) {
8282
- return data.map((item) => this.apiOptions.adapter(item));
8283
- }
8284
- return this.apiOptions.adapter(data);
8285
- }
8286
8249
  updateRequestOptions(headers) {
8287
8250
  const options = ApiRequest.adapt({ ...this.apiOptions });
8288
8251
  options.headers = (headers)
@@ -8406,6 +8369,58 @@ class HTTPManagerStateService extends ComponentStore {
8406
8369
  const currentQueryParams = { ...(currentEntry.queryParams || {}) };
8407
8370
  const currentQueryCombinations = [...(currentEntry.queryCombinations || [])];
8408
8371
  const currentQueryParamsExpires = currentEntry.queryParamsExpires ?? null;
8372
+ // Extract query params from options?.path and build combination string
8373
+ const resolvedPath = this.resolvePath(options?.path);
8374
+ const extractedParams = {};
8375
+ const ignoreQueryParams = Array.isArray(options?.ignoreQueryParams) ? options.ignoreQueryParams : [];
8376
+ if (Array.isArray(resolvedPath)) {
8377
+ const normalizedIgnore = ignoreQueryParams.map(p => this.trackerNormalizeParamKey(p));
8378
+ resolvedPath.forEach((pathPart) => {
8379
+ // Extract query params from objects in the path array
8380
+ if (pathPart && typeof pathPart === 'object' && !Array.isArray(pathPart)) {
8381
+ Object.keys(pathPart).forEach((key) => {
8382
+ const normalizedKey = this.trackerNormalizeParamKey(key);
8383
+ const value = String(pathPart[key]);
8384
+ // Only add to queryParams if NOT in ignoreQueryParams
8385
+ if (!normalizedIgnore.includes(normalizedKey)) {
8386
+ if (!currentQueryParams[key]) {
8387
+ currentQueryParams[key] = [];
8388
+ }
8389
+ if (!currentQueryParams[key].includes(value)) {
8390
+ currentQueryParams[key].push(value);
8391
+ }
8392
+ // Track extracted param for combination string
8393
+ extractedParams[normalizedKey] = value;
8394
+ }
8395
+ });
8396
+ }
8397
+ else if (typeof pathPart === 'string') {
8398
+ // Parse URL query strings like 'items?active=true&location=6'
8399
+ const normalized = this.trackerNormalizePath([pathPart]);
8400
+ if (normalized.hasQuery) {
8401
+ const filtered = this.trackerFilterQuery(normalized.query, ignoreQueryParams);
8402
+ Object.assign(extractedParams, filtered);
8403
+ // Add filtered params to queryParams
8404
+ Object.keys(filtered).forEach((key) => {
8405
+ if (!currentQueryParams[key]) {
8406
+ currentQueryParams[key] = [];
8407
+ }
8408
+ if (!currentQueryParams[key].includes(filtered[key])) {
8409
+ currentQueryParams[key].push(filtered[key]);
8410
+ }
8411
+ });
8412
+ }
8413
+ }
8414
+ });
8415
+ }
8416
+ // Build combination string if we have extracted params
8417
+ if (Object.keys(extractedParams).length > 0) {
8418
+ const keys = Object.keys(extractedParams).sort();
8419
+ const combinationString = keys.map((k) => `${k}=${extractedParams[k]}`).join('&');
8420
+ if (!currentQueryCombinations.includes(combinationString)) {
8421
+ currentQueryCombinations.push(combinationString);
8422
+ }
8423
+ }
8409
8424
  this.localStorageManagerService.updateStore({
8410
8425
  name: tableName,
8411
8426
  data: {
@@ -8416,7 +8431,7 @@ class HTTPManagerStateService extends ComponentStore {
8416
8431
  ...currentEntry,
8417
8432
  signature,
8418
8433
  savedAt: Date.now(),
8419
- path: this.resolvePath(options?.path),
8434
+ path: resolvedPath,
8420
8435
  headers: this.filterHeaders(options?.headers),
8421
8436
  queryCombinations: currentQueryCombinations,
8422
8437
  queryParams: currentQueryParams,
@@ -8543,22 +8558,6 @@ class HTTPManagerStateService extends ComponentStore {
8543
8558
  });
8544
8559
  return result;
8545
8560
  }
8546
- trackerBuildExpiryEpoch(expireIn) {
8547
- if (typeof expireIn === 'undefined' || expireIn === null || expireIn === '')
8548
- return null;
8549
- if (typeof expireIn === 'number' && Number.isFinite(expireIn) && expireIn > 0) {
8550
- return Math.floor(Date.now() / 1000) + Math.floor(expireIn);
8551
- }
8552
- const raw = String(expireIn).trim().toLowerCase().replace(/\s+/g, '');
8553
- const parsed = raw.match(/^(\d+)(y|w|d|hr|h|mn|min|m|s)$/);
8554
- if (!parsed)
8555
- return null;
8556
- const toSeconds = { y: 31556926, w: 604800, d: 86400, hr: 3600, h: 3600, mn: 60, min: 60, m: 60, s: 1 };
8557
- const seconds = toSeconds[parsed[2]];
8558
- if (!seconds)
8559
- return null;
8560
- return Math.floor(Date.now() / 1000) + Number(parsed[1]) * seconds;
8561
- }
8562
8561
  checkTrackerAllowsRequest(tableName, type, path, options, storeData) {
8563
8562
  const normalized = this.trackerNormalizePath(path);
8564
8563
  const ignoreQueryParams = Array.isArray(options?.ignoreQueryParams) ? options.ignoreQueryParams : [];
@@ -8577,58 +8576,47 @@ class HTTPManagerStateService extends ComponentStore {
8577
8576
  const combinationString = keys.sort().map((k) => `${k}=${filtered[k]}`).join('&');
8578
8577
  // Legacy per-key queryParams for backward compatibility (read-only)
8579
8578
  const queryParams = { ...(meta.queryParams || {}) };
8580
- let queryParamsExpires = meta.queryParamsExpires ?? null;
8579
+ const queryParamsExpires = meta.queryParamsExpires ?? null;
8581
8580
  // New combination-based tracking
8582
- let queryCombinations = [...(meta.queryCombinations || [])];
8581
+ const queryCombinations = [...(meta.queryCombinations || [])];
8583
8582
  // Reset combinations if the request path has changed (different endpoint)
8584
8583
  // Use trackerNormalizePath so inline query strings (e.g. 'items?a=1') are stripped
8585
8584
  // before comparing, matching the same normalization applied to the current request.
8586
8585
  const storedPathKey = meta.path
8587
8586
  ? this.trackerNormalizePath(meta.path.filter((p) => typeof p === 'string' || typeof p === 'number').map(String)).pathKey
8588
8587
  : null;
8589
- if (storedPathKey && storedPathKey !== normalized.pathKey) {
8590
- queryCombinations = [];
8591
- // Also clear legacy per-key tracking so old data from a different path doesn't block
8592
- Object.keys(queryParams).forEach((k) => delete queryParams[k]);
8593
- queryParamsExpires = null;
8594
- }
8595
- if (queryParamsExpires !== null && queryParamsExpires <= now) {
8596
- queryCombinations = [];
8597
- queryParamsExpires = null;
8598
- Object.keys(queryParams).forEach((k) => delete queryParams[k]);
8599
- }
8588
+ const pathChanged = storedPathKey && storedPathKey !== normalized.pathKey;
8589
+ const isExpired = queryParamsExpires !== null && queryParamsExpires <= now;
8590
+ const shouldReset = pathChanged || isExpired;
8600
8591
  // Determine if request is accepted (not yet tracked)
8601
8592
  // Use combination-based tracking when available; fall back to legacy per-key tracking
8602
- let accepted;
8603
- if (queryCombinations.length > 0) {
8604
- accepted = !queryCombinations.includes(combinationString);
8605
- }
8606
- else if (Object.keys(queryParams).length > 0) {
8607
- // Legacy per-key backward compatibility
8608
- accepted = !keys.every((key) => {
8609
- const consumed = queryParams[key] || [];
8610
- return consumed.includes(filtered[key]);
8611
- });
8612
- }
8613
- else {
8614
- accepted = true;
8615
- }
8616
- if (accepted) {
8617
- queryCombinations = [...queryCombinations, combinationString];
8618
- // Also update legacy queryParams so existing consumers still work
8619
- keys.forEach(key => {
8593
+ const accepted = shouldReset
8594
+ ? true
8595
+ : queryCombinations.length > 0
8596
+ ? !queryCombinations.includes(combinationString)
8597
+ : Object.keys(queryParams).length > 0
8598
+ ? !keys.every((key) => (queryParams[key] || []).includes(filtered[key]))
8599
+ : true;
8600
+ // Compute updated values immutably
8601
+ const updatedQueryCombinations = accepted
8602
+ ? [...queryCombinations, combinationString]
8603
+ : queryCombinations;
8604
+ const updatedQueryParams = accepted
8605
+ ? keys.reduce((acc, key) => {
8620
8606
  const value = filtered[key];
8621
- const consumed = queryParams[key] || [];
8607
+ const consumed = acc[key] || [];
8622
8608
  if (!consumed.includes(value)) {
8623
- queryParams[key] = [...consumed, value];
8609
+ acc[key] = [...consumed, value];
8624
8610
  }
8625
- });
8626
- }
8627
- const newExpiry = this.trackerBuildExpiryEpoch(options?.queryParamsExpiresIn);
8628
- if (newExpiry !== null) {
8629
- queryParamsExpires = newExpiry;
8630
- }
8631
- if (accepted || newExpiry !== null) {
8611
+ return acc;
8612
+ }, { ...queryParams })
8613
+ : { ...queryParams };
8614
+ const updatedQueryParamsExpires = this.utils.expires(options?.queryParamsExpiresIn) ?? queryParamsExpires;
8615
+ // Apply reset if path changed or expired
8616
+ const finalQueryCombinations = shouldReset ? updatedQueryCombinations : queryCombinations;
8617
+ const finalQueryParams = shouldReset ? updatedQueryParams : queryParams;
8618
+ const finalQueryParamsExpires = shouldReset ? updatedQueryParamsExpires : updatedQueryParamsExpires;
8619
+ if (accepted || updatedQueryParamsExpires !== queryParamsExpires) {
8632
8620
  this.localStorageManagerService.store$(tableName).pipe(take(1), tap((latestStoreData) => {
8633
8621
  const currentCache = latestStoreData?.requestCache || {};
8634
8622
  const currentEntry = currentCache[type] || {};
@@ -8640,9 +8628,9 @@ class HTTPManagerStateService extends ComponentStore {
8640
8628
  ...currentCache,
8641
8629
  [type]: {
8642
8630
  ...currentEntry,
8643
- queryCombinations,
8644
- queryParams,
8645
- queryParamsExpires,
8631
+ queryCombinations: finalQueryCombinations,
8632
+ queryParams: finalQueryParams,
8633
+ queryParamsExpires: finalQueryParamsExpires,
8646
8634
  }
8647
8635
  }
8648
8636
  }