http-request-manager 18.15.15 → 18.15.17
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.
|
@@ -6126,6 +6126,19 @@ class DbService extends Dexie {
|
|
|
6126
6126
|
});
|
|
6127
6127
|
return schema;
|
|
6128
6128
|
}
|
|
6129
|
+
deleteAndReinitialize() {
|
|
6130
|
+
return from(Dexie.delete(this.storageDB).then(async () => {
|
|
6131
|
+
if (this.isOpen()) {
|
|
6132
|
+
this.close();
|
|
6133
|
+
}
|
|
6134
|
+
this.dbReady = this.init();
|
|
6135
|
+
await this.dbReady;
|
|
6136
|
+
return this.isOpen();
|
|
6137
|
+
})).pipe(catchError((err) => {
|
|
6138
|
+
console.error('[DB] deleteAndReinitialize failed:', err);
|
|
6139
|
+
return of(false);
|
|
6140
|
+
}));
|
|
6141
|
+
}
|
|
6129
6142
|
cleanTableName(str) {
|
|
6130
6143
|
return str
|
|
6131
6144
|
.replace(/[^a-zA-Z0-9\s_]/g, '')
|
|
@@ -6273,10 +6286,26 @@ class DatabaseManagerService extends DbService {
|
|
|
6273
6286
|
if (!this.isMissingObjectStoreError(error)) {
|
|
6274
6287
|
throw error;
|
|
6275
6288
|
}
|
|
6276
|
-
// console.warn(`createTableRecords: Missing object store for '${tableName}'. Recreating table and retrying once...`, error);
|
|
6277
6289
|
return recreateMissingTableAndRetry().pipe(catchError((retryError) => {
|
|
6278
|
-
|
|
6279
|
-
|
|
6290
|
+
if (!this.isMissingObjectStoreError(retryError)) {
|
|
6291
|
+
console.error(`createTableRecords: Retry failed for '${tableName}'`, retryError);
|
|
6292
|
+
throw retryError;
|
|
6293
|
+
}
|
|
6294
|
+
console.warn(`createTableRecords: Table '${tableName}' still missing after retry. Deleting DB and reinitializing...`);
|
|
6295
|
+
return this.deleteAndReinitialize().pipe(switchMap((reinitialized) => {
|
|
6296
|
+
if (!reinitialized) {
|
|
6297
|
+
throw retryError;
|
|
6298
|
+
}
|
|
6299
|
+
const inferredSchema = this.inferSchemaFromRecords(insertRecords);
|
|
6300
|
+
if (!inferredSchema) {
|
|
6301
|
+
throw retryError;
|
|
6302
|
+
}
|
|
6303
|
+
const tableDef = TableSchemaDef.adapt({ table: tableName, schema: inferredSchema });
|
|
6304
|
+
return this.createDatabaseTable(tableDef).pipe(switchMap(() => writeRecords()));
|
|
6305
|
+
}), catchError((finalError) => {
|
|
6306
|
+
console.error(`createTableRecords: All retries exhausted for '${tableName}'`, finalError);
|
|
6307
|
+
throw finalError;
|
|
6308
|
+
}));
|
|
6280
6309
|
}));
|
|
6281
6310
|
}));
|
|
6282
6311
|
}
|
|
@@ -6369,6 +6398,9 @@ class DatabaseManagerService extends DbService {
|
|
|
6369
6398
|
return of(false);
|
|
6370
6399
|
})).subscribe();
|
|
6371
6400
|
}
|
|
6401
|
+
resetDatabase() {
|
|
6402
|
+
return this.deleteAndReinitialize();
|
|
6403
|
+
}
|
|
6372
6404
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DatabaseManagerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
6373
6405
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DatabaseManagerService, providedIn: 'root' }); }
|
|
6374
6406
|
}
|
|
@@ -6434,25 +6466,28 @@ class QueryParamsTrackerService {
|
|
|
6434
6466
|
}
|
|
6435
6467
|
checkRequestOptions(requestOptions = [], options = {}) {
|
|
6436
6468
|
this.ensureStateRestored();
|
|
6437
|
-
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
|
|
6442
|
-
|
|
6443
|
-
|
|
6444
|
-
|
|
6445
|
-
|
|
6446
|
-
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
return this.checkExact(normalized, options);
|
|
6469
|
+
if (!this.ready$.value) {
|
|
6470
|
+
return true;
|
|
6471
|
+
}
|
|
6472
|
+
const normalized = this.normalizeRequestOptions(requestOptions);
|
|
6473
|
+
if (!normalized.pathKey)
|
|
6474
|
+
return false;
|
|
6475
|
+
this.cleanupExpiredEntries();
|
|
6476
|
+
if (!normalized.hasQuery) {
|
|
6477
|
+
const pathState = this.ensurePathState(normalized.pathKey);
|
|
6478
|
+
// Check if we've seen this path before by checking for a special marker
|
|
6479
|
+
const pathSeenBefore = pathState.consumedValuesByKey.hasOwnProperty('__path_seen__');
|
|
6480
|
+
if (!pathSeenBefore) {
|
|
6481
|
+
// Mark this path as seen
|
|
6482
|
+
pathState.consumedValuesByKey['__path_seen__'] = ['true'];
|
|
6483
|
+
this.persistState();
|
|
6453
6484
|
}
|
|
6454
|
-
return
|
|
6455
|
-
}
|
|
6485
|
+
return !pathSeenBefore;
|
|
6486
|
+
}
|
|
6487
|
+
if (options.mode === 'exact') {
|
|
6488
|
+
return this.checkExact(normalized, options);
|
|
6489
|
+
}
|
|
6490
|
+
return this.checkVariation(normalized, options);
|
|
6456
6491
|
}
|
|
6457
6492
|
matchesPath(requestOptions = [], expectedPathOptions = []) {
|
|
6458
6493
|
this.ensureStateRestored();
|
|
@@ -7268,7 +7303,99 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
7268
7303
|
table: this.databaseOptions?.table,
|
|
7269
7304
|
databaseOptions: this.databaseOptions
|
|
7270
7305
|
});
|
|
7271
|
-
|
|
7306
|
+
if (this.hasDatabase && this.databaseOptions?.table) {
|
|
7307
|
+
return this.dbManagerService.databaseExists().pipe(switchMap((dbExists) => {
|
|
7308
|
+
if (!dbExists) {
|
|
7309
|
+
const initObs = this.initDBStorageAsync();
|
|
7310
|
+
return initObs.pipe(switchMap(() => fetchFromAPI()), catchError((error) => {
|
|
7311
|
+
console.warn('[DB STORAGE] initDBStorageAsync failed when DB did not exist, continuing with API:', error);
|
|
7312
|
+
return fetchFromAPI();
|
|
7313
|
+
}));
|
|
7314
|
+
}
|
|
7315
|
+
return this.dbManagerService.hasDatabaseTable(this.databaseOptions.table).pipe(switchMap((tableExists) => {
|
|
7316
|
+
if (!tableExists) {
|
|
7317
|
+
const initObs = this.initDBStorageAsync();
|
|
7318
|
+
return initObs.pipe(switchMap(() => fetchFromAPI()), catchError((error) => {
|
|
7319
|
+
console.warn('[DB STORAGE] initDBStorageAsync failed when table missing, continuing with API:', error);
|
|
7320
|
+
return fetchFromAPI();
|
|
7321
|
+
}));
|
|
7322
|
+
}
|
|
7323
|
+
return this.localStorageManagerService.store$(this.databaseOptions.table).pipe(take(1), switchMap((storeData) => {
|
|
7324
|
+
console.log('[CacheDebug] storeData for table:', this.databaseOptions.table, { storeData, requestCache: storeData?.requestCache, expires: storeData?.expires });
|
|
7325
|
+
const forceRefresh = !!options?.forceRefresh;
|
|
7326
|
+
const storedSchemaSignature = this.getStoredSchemaSignature(storeData);
|
|
7327
|
+
const expires = storeData?.expires || 0;
|
|
7328
|
+
const hasExpired = expires > 0 && this.utils.hasExpired(expires);
|
|
7329
|
+
if (forceRefresh) {
|
|
7330
|
+
return fetchFromAPI();
|
|
7331
|
+
}
|
|
7332
|
+
if (hasExpired) {
|
|
7333
|
+
return this.dbManagerService.clearTable(this.databaseOptions.table).pipe(switchMap(() => fetchFromAPI()));
|
|
7334
|
+
}
|
|
7335
|
+
const expectedSchema = this.buildSchemaFromAdapter();
|
|
7336
|
+
const expectedSchemaSignature = this.buildSchemaSignature(expectedSchema);
|
|
7337
|
+
console.log('[CacheDebug] schema check:', { tableName: this.databaseOptions.table, storedSchemaSignature, expectedSchemaSignature, mismatch: storedSchemaSignature && storedSchemaSignature !== expectedSchemaSignature });
|
|
7338
|
+
if (storedSchemaSignature && storedSchemaSignature !== expectedSchemaSignature) {
|
|
7339
|
+
const tableDef = TableSchemaDef.adapt({ table: this.databaseOptions.table, schema: expectedSchema });
|
|
7340
|
+
return this.dbManagerService.clearTable(this.databaseOptions.table).pipe(switchMap(() => this.dbManagerService.createDatabaseTable(tableDef)), switchMap(() => fetchFromAPI()));
|
|
7341
|
+
}
|
|
7342
|
+
const trackerAllowsRequest = this.checkTrackerAllowsRequest(this.databaseOptions.table, this.resolvePath(effectiveParams), options, storeData);
|
|
7343
|
+
if (trackerAllowsRequest) {
|
|
7344
|
+
const normalizedPath = this.trackerNormalizePath(this.resolvePath(effectiveParams));
|
|
7345
|
+
if (!normalizedPath.hasQuery) {
|
|
7346
|
+
return this.dbManagerService.getTableRecords(this.databaseOptions.table).pipe(switchMap((dbData) => {
|
|
7347
|
+
if (Array.isArray(dbData) && dbData.length > 0) {
|
|
7348
|
+
this.setData$(dbData);
|
|
7349
|
+
// Save cache metadata for both GET and STREAM request types so
|
|
7350
|
+
// tracker/check logic can detect cached responses regardless
|
|
7351
|
+
// of whether a subsequent call is a normal GET or a streaming GET.
|
|
7352
|
+
const getSignature = requestSignature;
|
|
7353
|
+
const streamRequestOptions = { ...(requestOptions || {}), stream: true };
|
|
7354
|
+
const streamSignature = this.buildRequestSignature('STREAM', streamRequestOptions, effectiveParams);
|
|
7355
|
+
this.saveRequestCacheMetadata(this.databaseOptions.table, 'GET', getSignature, storedSchemaSignature ?? expectedSchemaSignature ?? undefined, options);
|
|
7356
|
+
this.saveRequestCacheMetadata(this.databaseOptions.table, 'STREAM', streamSignature, storedSchemaSignature ?? expectedSchemaSignature ?? undefined, options);
|
|
7357
|
+
return of({ data: dbData, fromCache: true });
|
|
7358
|
+
}
|
|
7359
|
+
return fetchFromAPI();
|
|
7360
|
+
}), catchError((error) => {
|
|
7361
|
+
const tableName = this.databaseOptions.table;
|
|
7362
|
+
console.warn('[DB STORAGE] fallback cache read failed, falling back to API:', { table: tableName, error });
|
|
7363
|
+
return fetchFromAPI();
|
|
7364
|
+
}));
|
|
7365
|
+
}
|
|
7366
|
+
return fetchFromAPI();
|
|
7367
|
+
}
|
|
7368
|
+
return this.dbManagerService.getTableRecords(this.databaseOptions.table).pipe(switchMap((dbData) => {
|
|
7369
|
+
if (Array.isArray(dbData) && dbData.length > 0) {
|
|
7370
|
+
this.setData$(dbData);
|
|
7371
|
+
this.saveRequestCacheMetadata(this.databaseOptions.table, 'GET', requestSignature, storedSchemaSignature ?? expectedSchemaSignature ?? undefined, options);
|
|
7372
|
+
return of(dbData);
|
|
7373
|
+
}
|
|
7374
|
+
const currentStateData = this.get()?.data;
|
|
7375
|
+
if (Array.isArray(currentStateData) && currentStateData.length > 0) {
|
|
7376
|
+
return of(currentStateData);
|
|
7377
|
+
}
|
|
7378
|
+
if (currentStateData &&
|
|
7379
|
+
!Array.isArray(currentStateData) &&
|
|
7380
|
+
Object.keys(currentStateData).length > 0) {
|
|
7381
|
+
return of(currentStateData);
|
|
7382
|
+
}
|
|
7383
|
+
return of(this.dataType === DataType.ARRAY ? [] : {});
|
|
7384
|
+
}), catchError((error) => {
|
|
7385
|
+
const tableName = this.databaseOptions.table;
|
|
7386
|
+
console.warn('[DB STORAGE] getTableRecords failed, recreating table and falling back to API:', { table: tableName, error });
|
|
7387
|
+
const schema = this.buildSchemaFromAdapter();
|
|
7388
|
+
const tableDef = TableSchemaDef.adapt({ table: tableName, schema });
|
|
7389
|
+
return this.dbManagerService.createDatabaseTable(tableDef).pipe(switchMap(() => fetchFromAPI()), catchError((recreateError) => {
|
|
7390
|
+
console.error('[DB STORAGE] Failed to recreate table after read error, continuing with API only:', recreateError);
|
|
7391
|
+
return fetchFromAPI();
|
|
7392
|
+
}));
|
|
7393
|
+
}));
|
|
7394
|
+
}));
|
|
7395
|
+
}));
|
|
7396
|
+
}));
|
|
7397
|
+
}
|
|
7398
|
+
return fetchFromAPI();
|
|
7272
7399
|
})));
|
|
7273
7400
|
// FETCH RECORD
|
|
7274
7401
|
this.fetchRecord = (options, method) => this.effect(() => of(RequestOptions.adapt(options)).pipe(tap(() => console.log('🔄 fetchRecord effect triggered with path:', options?.path, 'method:', method)), switchMap((options) => {
|
|
@@ -7408,29 +7535,62 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
7408
7535
|
const requestOptions = this.updateRequestOptions(options?.headers);
|
|
7409
7536
|
requestOptions.stream = true;
|
|
7410
7537
|
const effectiveParams = this.getEffectiveParams(options?.path);
|
|
7411
|
-
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
if (
|
|
7416
|
-
|
|
7417
|
-
|
|
7418
|
-
|
|
7419
|
-
|
|
7420
|
-
|
|
7421
|
-
|
|
7538
|
+
// console.log('[DEBUG] Making streaming request:', requestOptions)
|
|
7539
|
+
if (this.hasDatabase && this.databaseOptions?.table) {
|
|
7540
|
+
const requestSignature = this.buildRequestSignature('STREAM', requestOptions, effectiveParams);
|
|
7541
|
+
const fetchStreamFromAPI = () => {
|
|
7542
|
+
if (!this.tryBeginInFlightRequest(requestSignature)) {
|
|
7543
|
+
const currentStateData = this.get()?.data;
|
|
7544
|
+
if (Array.isArray(currentStateData) && currentStateData.length > 0) {
|
|
7545
|
+
return of({ data: currentStateData, fromCache: true });
|
|
7546
|
+
}
|
|
7547
|
+
if (currentStateData &&
|
|
7548
|
+
!Array.isArray(currentStateData) &&
|
|
7549
|
+
Object.keys(currentStateData).length > 0) {
|
|
7550
|
+
return of({ data: currentStateData, fromCache: true });
|
|
7551
|
+
}
|
|
7552
|
+
return of({ data: this.dataType === DataType.ARRAY ? [] : {}, fromCache: true });
|
|
7422
7553
|
}
|
|
7423
|
-
return of({ data: this.dataType === DataType.ARRAY ? [] : {}, fromCache: true });
|
|
7424
|
-
}
|
|
7425
|
-
if (this.hasDatabase && this.databaseOptions?.table) {
|
|
7426
7554
|
this.setCachedRequestSignature(this.databaseOptions.table, 'STREAM', requestSignature);
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7433
|
-
|
|
7555
|
+
return this.httpManagerService.getRequest(requestOptions, effectiveParams).pipe(map((apiData) => ({ data: apiData, fromCache: false })), finalize(() => this.endInFlightRequest(requestSignature)));
|
|
7556
|
+
};
|
|
7557
|
+
return this.localStorageManagerService.store$(this.databaseOptions.table).pipe(take(1), switchMap((storeData) => {
|
|
7558
|
+
const forceRefresh = !!options?.forceRefresh;
|
|
7559
|
+
const expires = storeData?.expires || 0;
|
|
7560
|
+
const hasExpired = expires > 0 && this.utils.hasExpired(expires);
|
|
7561
|
+
if (forceRefresh) {
|
|
7562
|
+
return fetchStreamFromAPI();
|
|
7563
|
+
}
|
|
7564
|
+
if (hasExpired) {
|
|
7565
|
+
return this.dbManagerService.clearTable(this.databaseOptions.table).pipe(switchMap(() => fetchStreamFromAPI()));
|
|
7566
|
+
}
|
|
7567
|
+
const storedSchemaSignature = this.getStoredSchemaSignature(storeData);
|
|
7568
|
+
const expectedSchema = this.buildSchemaFromAdapter();
|
|
7569
|
+
const expectedSchemaSignature = this.buildSchemaSignature(expectedSchema);
|
|
7570
|
+
if (storedSchemaSignature && storedSchemaSignature !== expectedSchemaSignature) {
|
|
7571
|
+
const tableDef = TableSchemaDef.adapt({ table: this.databaseOptions.table, schema: expectedSchema });
|
|
7572
|
+
return this.dbManagerService.clearTable(this.databaseOptions.table).pipe(switchMap(() => this.dbManagerService.createDatabaseTable(tableDef)), switchMap(() => fetchStreamFromAPI()));
|
|
7573
|
+
}
|
|
7574
|
+
const trackerAllowsRequest = this.checkTrackerAllowsRequest(this.databaseOptions.table, this.resolvePath(effectiveParams), options, storeData);
|
|
7575
|
+
if (!trackerAllowsRequest) {
|
|
7576
|
+
return this.dbManagerService.getTableRecords(this.databaseOptions.table).pipe(switchMap((dbData) => {
|
|
7577
|
+
if (Array.isArray(dbData) && dbData.length > 0) {
|
|
7578
|
+
return of({ data: dbData, fromCache: true });
|
|
7579
|
+
}
|
|
7580
|
+
const currentStateData = this.get()?.data;
|
|
7581
|
+
if (Array.isArray(currentStateData) && currentStateData.length > 0) {
|
|
7582
|
+
return of({ data: currentStateData, fromCache: true });
|
|
7583
|
+
}
|
|
7584
|
+
if (currentStateData &&
|
|
7585
|
+
!Array.isArray(currentStateData) &&
|
|
7586
|
+
Object.keys(currentStateData).length > 0) {
|
|
7587
|
+
return of({ data: currentStateData, fromCache: true });
|
|
7588
|
+
}
|
|
7589
|
+
return of({ data: this.dataType === DataType.ARRAY ? [] : {}, fromCache: true });
|
|
7590
|
+
}));
|
|
7591
|
+
}
|
|
7592
|
+
return fetchStreamFromAPI();
|
|
7593
|
+
})).pipe(tap((packet) => {
|
|
7434
7594
|
const res = packet?.data;
|
|
7435
7595
|
// console.log('[DEBUG] Streaming response received:', res)
|
|
7436
7596
|
if (res && res.length > 0) {
|
|
@@ -7697,130 +7857,6 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
7697
7857
|
});
|
|
7698
7858
|
return [...updatedData, ...addedData];
|
|
7699
7859
|
}
|
|
7700
|
-
// --------------------------------------------------------------------------------------------------
|
|
7701
|
-
// SHARED CACHE GATING DECISION
|
|
7702
|
-
// --------------------------------------------------------------------------------------------------
|
|
7703
|
-
/**
|
|
7704
|
-
* Resolves whether a request should use cached/DB data or call the API.
|
|
7705
|
-
* Shared by both fetchRecords (GET) and fetchStream (STREAM) to ensure parity.
|
|
7706
|
-
*
|
|
7707
|
-
* Decision order:
|
|
7708
|
-
* 1. forceRefresh → API
|
|
7709
|
-
* 2. cache expired → clear + API
|
|
7710
|
-
* 3. schema mismatch → clear + rebuild + API
|
|
7711
|
-
* 4. tracker blocks request → DB/state fallback
|
|
7712
|
-
* 5. tracker allows request → API (with optional no-query DB shortcut)
|
|
7713
|
-
*
|
|
7714
|
-
* Returns an observable of the result data.
|
|
7715
|
-
*/
|
|
7716
|
-
resolveCacheDecision(requestType, requestOptions, effectiveParams, options, fetchFromAPI) {
|
|
7717
|
-
if (!this.hasDatabase || !this.databaseOptions?.table) {
|
|
7718
|
-
return fetchFromAPI();
|
|
7719
|
-
}
|
|
7720
|
-
const requestSignature = this.buildRequestSignature(requestType, requestOptions, effectiveParams);
|
|
7721
|
-
return this.dbManagerService.databaseExists().pipe(switchMap((dbExists) => {
|
|
7722
|
-
if (!dbExists) {
|
|
7723
|
-
return this.initDBStorageAsync().pipe(switchMap(() => fetchFromAPI()), catchError((error) => {
|
|
7724
|
-
console.warn('[DB STORAGE] initDBStorageAsync failed when DB did not exist, continuing with API:', error);
|
|
7725
|
-
return fetchFromAPI();
|
|
7726
|
-
}));
|
|
7727
|
-
}
|
|
7728
|
-
return this.dbManagerService.hasDatabaseTable(this.databaseOptions.table).pipe(switchMap((tableExists) => {
|
|
7729
|
-
if (!tableExists) {
|
|
7730
|
-
return this.initDBStorageAsync().pipe(switchMap(() => fetchFromAPI()), catchError((error) => {
|
|
7731
|
-
console.warn('[DB STORAGE] initDBStorageAsync failed when table missing, continuing with API:', error);
|
|
7732
|
-
return fetchFromAPI();
|
|
7733
|
-
}));
|
|
7734
|
-
}
|
|
7735
|
-
return this.localStorageManagerService.store$(this.databaseOptions.table).pipe(take(1), switchMap((storeData) => {
|
|
7736
|
-
console.log('[CacheDebug] storeData for table:', this.databaseOptions.table, { storeData, requestCache: storeData?.requestCache, expires: storeData?.expires });
|
|
7737
|
-
// 1. forceRefresh → API
|
|
7738
|
-
const forceRefresh = !!options?.forceRefresh;
|
|
7739
|
-
if (forceRefresh) {
|
|
7740
|
-
return fetchFromAPI();
|
|
7741
|
-
}
|
|
7742
|
-
// 2. cache expired → clear + API
|
|
7743
|
-
const expires = storeData?.expires || 0;
|
|
7744
|
-
const hasExpired = expires > 0 && this.utils.hasExpired(expires);
|
|
7745
|
-
if (hasExpired) {
|
|
7746
|
-
return this.dbManagerService.clearTable(this.databaseOptions.table).pipe(switchMap(() => fetchFromAPI()));
|
|
7747
|
-
}
|
|
7748
|
-
// 3. schema mismatch → clear + rebuild + API
|
|
7749
|
-
const storedSchemaSignature = this.getStoredSchemaSignature(storeData);
|
|
7750
|
-
const expectedSchema = this.buildSchemaFromAdapter();
|
|
7751
|
-
const expectedSchemaSignature = this.buildSchemaSignature(expectedSchema);
|
|
7752
|
-
console.log('[CacheDebug] schema check:', { tableName: this.databaseOptions.table, storedSchemaSignature, expectedSchemaSignature, mismatch: storedSchemaSignature && storedSchemaSignature !== expectedSchemaSignature });
|
|
7753
|
-
if (storedSchemaSignature && storedSchemaSignature !== expectedSchemaSignature) {
|
|
7754
|
-
const tableDef = TableSchemaDef.adapt({ table: this.databaseOptions.table, schema: expectedSchema });
|
|
7755
|
-
return this.dbManagerService.clearTable(this.databaseOptions.table).pipe(switchMap(() => this.dbManagerService.createDatabaseTable(tableDef)), switchMap(() => fetchFromAPI()));
|
|
7756
|
-
}
|
|
7757
|
-
// 4 & 5. tracker decision (async — awaits tracker readiness)
|
|
7758
|
-
return this.checkTrackerAllowsRequest(this.databaseOptions.table, this.resolvePath(effectiveParams), options, storeData).pipe(switchMap((trackerAllowsRequest) => {
|
|
7759
|
-
if (trackerAllowsRequest) {
|
|
7760
|
-
// For no-query paths, try DB first before API
|
|
7761
|
-
const normalizedPath = this.trackerNormalizePath(this.resolvePath(effectiveParams));
|
|
7762
|
-
if (!normalizedPath.hasQuery) {
|
|
7763
|
-
return this.dbManagerService.getTableRecords(this.databaseOptions.table).pipe(switchMap((dbData) => {
|
|
7764
|
-
if (Array.isArray(dbData) && dbData.length > 0) {
|
|
7765
|
-
this.setData$(dbData);
|
|
7766
|
-
// Save cache metadata for both GET and STREAM request types so
|
|
7767
|
-
// tracker/check logic can detect cached responses regardless
|
|
7768
|
-
// of whether a subsequent call is a normal GET or a streaming GET.
|
|
7769
|
-
const getSignature = this.buildRequestSignature('GET', requestOptions, effectiveParams);
|
|
7770
|
-
const streamRequestOptions = { ...(requestOptions || {}), stream: true };
|
|
7771
|
-
const streamSignature = this.buildRequestSignature('STREAM', streamRequestOptions, effectiveParams);
|
|
7772
|
-
this.saveRequestCacheMetadata(this.databaseOptions.table, 'GET', getSignature, storedSchemaSignature ?? expectedSchemaSignature ?? undefined, options);
|
|
7773
|
-
this.saveRequestCacheMetadata(this.databaseOptions.table, 'STREAM', streamSignature, storedSchemaSignature ?? expectedSchemaSignature ?? undefined, options);
|
|
7774
|
-
return of({ data: dbData, fromCache: true });
|
|
7775
|
-
}
|
|
7776
|
-
return fetchFromAPI();
|
|
7777
|
-
}), catchError((error) => {
|
|
7778
|
-
const tableName = this.databaseOptions.table;
|
|
7779
|
-
console.warn('[DB STORAGE] fallback cache read failed, falling back to API:', { table: tableName, error });
|
|
7780
|
-
return fetchFromAPI();
|
|
7781
|
-
}));
|
|
7782
|
-
}
|
|
7783
|
-
return fetchFromAPI();
|
|
7784
|
-
}
|
|
7785
|
-
// tracker blocks request → DB/state fallback
|
|
7786
|
-
return this.dbManagerService.getTableRecords(this.databaseOptions.table).pipe(switchMap((dbData) => {
|
|
7787
|
-
if (Array.isArray(dbData) && dbData.length > 0) {
|
|
7788
|
-
this.setData$(dbData);
|
|
7789
|
-
// Save cache metadata for both GET and STREAM request types so
|
|
7790
|
-
// tracker/check logic can detect cached responses regardless
|
|
7791
|
-
// of whether a subsequent call is a normal GET or a streaming GET.
|
|
7792
|
-
const getSignature = this.buildRequestSignature('GET', requestOptions, effectiveParams);
|
|
7793
|
-
const streamRequestOptions = { ...(requestOptions || {}), stream: true };
|
|
7794
|
-
const streamSignature = this.buildRequestSignature('STREAM', streamRequestOptions, effectiveParams);
|
|
7795
|
-
this.saveRequestCacheMetadata(this.databaseOptions.table, 'GET', getSignature, storedSchemaSignature ?? expectedSchemaSignature ?? undefined, options);
|
|
7796
|
-
this.saveRequestCacheMetadata(this.databaseOptions.table, 'STREAM', streamSignature, storedSchemaSignature ?? expectedSchemaSignature ?? undefined, options);
|
|
7797
|
-
return of(dbData);
|
|
7798
|
-
}
|
|
7799
|
-
const currentStateData = this.get()?.data;
|
|
7800
|
-
if (Array.isArray(currentStateData) && currentStateData.length > 0) {
|
|
7801
|
-
return of(currentStateData);
|
|
7802
|
-
}
|
|
7803
|
-
if (currentStateData &&
|
|
7804
|
-
!Array.isArray(currentStateData) &&
|
|
7805
|
-
Object.keys(currentStateData).length > 0) {
|
|
7806
|
-
return of(currentStateData);
|
|
7807
|
-
}
|
|
7808
|
-
return of(this.dataType === DataType.ARRAY ? [] : {});
|
|
7809
|
-
}), catchError((error) => {
|
|
7810
|
-
const tableName = this.databaseOptions.table;
|
|
7811
|
-
console.warn('[DB STORAGE] getTableRecords failed, recreating table and falling back to API:', { table: tableName, error });
|
|
7812
|
-
const schema = this.buildSchemaFromAdapter();
|
|
7813
|
-
const tableDef = TableSchemaDef.adapt({ table: tableName, schema });
|
|
7814
|
-
return this.dbManagerService.createDatabaseTable(tableDef).pipe(switchMap(() => fetchFromAPI()), catchError((recreateError) => {
|
|
7815
|
-
console.error('[DB STORAGE] Failed to recreate table after read error, continuing with API only:', recreateError);
|
|
7816
|
-
return fetchFromAPI();
|
|
7817
|
-
}));
|
|
7818
|
-
}));
|
|
7819
|
-
}));
|
|
7820
|
-
}));
|
|
7821
|
-
}));
|
|
7822
|
-
}));
|
|
7823
|
-
}
|
|
7824
7860
|
initDBStorageAsync() {
|
|
7825
7861
|
console.log('[initDBStorageAsync] Starting initialization:', {
|
|
7826
7862
|
dataType: this.dataType,
|
|
@@ -8492,7 +8528,7 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
8492
8528
|
return Math.floor(Date.now() / 1000) + Number(parsed[1]) * seconds;
|
|
8493
8529
|
}
|
|
8494
8530
|
checkTrackerAllowsRequest(tableName, path, options, storeData) {
|
|
8495
|
-
if (options &&
|
|
8531
|
+
if (options && 'watchParams' in options) {
|
|
8496
8532
|
return this.queryParamsTrackerService.checkRequestOptions(path, {
|
|
8497
8533
|
watchParams: options.watchParams,
|
|
8498
8534
|
watchExpiresAt: options?.watchExpiresAt,
|
|
@@ -8503,12 +8539,12 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
8503
8539
|
if (!normalized.hasQuery || ignoreQueryParams.length === 0) {
|
|
8504
8540
|
const meta = this.getRequestCacheMetadata(storeData, 'GET');
|
|
8505
8541
|
console.log('[CacheDebug] checkTrackerAllowsRequest: no query params path', { tableName, requestCacheMeta: meta, allowsRequest: !meta });
|
|
8506
|
-
return
|
|
8542
|
+
return !meta;
|
|
8507
8543
|
}
|
|
8508
8544
|
const filtered = this.trackerFilterQuery(normalized.query, ignoreQueryParams);
|
|
8509
8545
|
const keys = Object.keys(filtered);
|
|
8510
8546
|
if (keys.length === 0) {
|
|
8511
|
-
return
|
|
8547
|
+
return !this.getRequestCacheMetadata(storeData, 'GET');
|
|
8512
8548
|
}
|
|
8513
8549
|
const tracker = this.getTrackerState(storeData);
|
|
8514
8550
|
const now = Math.floor(Date.now() / 1000);
|
|
@@ -8532,7 +8568,7 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
8532
8568
|
}
|
|
8533
8569
|
this.saveTrackerState(tableName, tracker.consumedValuesByKey, tracker.trackingExpires);
|
|
8534
8570
|
}
|
|
8535
|
-
return
|
|
8571
|
+
return accepted;
|
|
8536
8572
|
}
|
|
8537
8573
|
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 }); }
|
|
8538
8574
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: HTTPManagerStateService }); }
|