http-request-manager 18.12.4 → 18.12.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { inject, Injectable, APP_ID, Inject, InjectionToken, isDevMode, signal, effect, computed, Injector, Optional, EventEmitter, Input, Output, ViewEncapsulation, Component, NgModule, ViewChild } from '@angular/core';
|
|
3
3
|
import { ComponentStore } from '@ngrx/component-store';
|
|
4
|
-
import { map, catchError, filter, tap,
|
|
4
|
+
import { map, catchError, filter, finalize, tap, scan, takeWhile, retry, startWith, mergeMap, takeUntil, concatMap, toArray, withLatestFrom, switchMap, delay, take, distinctUntilChanged } from 'rxjs/operators';
|
|
5
5
|
import { HttpClient, HttpHeaders, HttpEventType, HttpHeaderResponse, HttpErrorResponse, HTTP_INTERCEPTORS } from '@angular/common/http';
|
|
6
6
|
import * as CryptoJS from 'crypto-js';
|
|
7
7
|
import { from, BehaviorSubject, EMPTY, throwError, defer, interval, timer, Subject, of, Observable, merge, Subscription, take as take$1, catchError as catchError$1, map as map$1, tap as tap$1, switchMap as switchMap$1, startWith as startWith$1, distinctUntilChanged as distinctUntilChanged$1, combineLatest, filter as filter$1, takeUntil as takeUntil$1, ReplaySubject } from 'rxjs';
|
|
@@ -884,6 +884,7 @@ class StreamingProcessor {
|
|
|
884
884
|
this.contentType = '';
|
|
885
885
|
this.maxBufferSize = 10 * 1024 * 1024; // 10MB limit
|
|
886
886
|
this.lastParsedLength = 0; // Track parsed position to avoid duplicates
|
|
887
|
+
this.lastParsedLineEnd = 0; // Track end of last-parsed complete line for NDJSON incremental parsing
|
|
887
888
|
this.streamConfig = config || { streamType: StreamType.AI_STREAMING };
|
|
888
889
|
}
|
|
889
890
|
/**
|
|
@@ -906,18 +907,26 @@ class StreamingProcessor {
|
|
|
906
907
|
return null;
|
|
907
908
|
case HttpEventType.DownloadProgress:
|
|
908
909
|
if (event.partialText) {
|
|
909
|
-
|
|
910
|
+
// partialText is cumulative, so replace the buffer instead of appending
|
|
911
|
+
this.buffer = event.partialText;
|
|
910
912
|
const parsedData = this.parseBuffer();
|
|
911
|
-
//
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
const
|
|
915
|
-
|
|
913
|
+
// For NDJSON incremental parsing, parsedData already contains only new items.
|
|
914
|
+
// For other formats, parsedData is cumulative so slice from lastParsedLength.
|
|
915
|
+
const isIncremental = this.streamConfig.streamType === StreamType.NDJSON;
|
|
916
|
+
const newItems = isIncremental ? parsedData : parsedData.slice(this.lastParsedLength);
|
|
917
|
+
// received = cumulative total for progress display
|
|
918
|
+
const received = isIncremental
|
|
919
|
+
? this.lastParsedLength + parsedData.length
|
|
920
|
+
: parsedData.length;
|
|
921
|
+
this.lastParsedLength = received;
|
|
922
|
+
// Return null when no new items — prevents empty array emissions
|
|
923
|
+
if (newItems.length === 0) {
|
|
924
|
+
return null;
|
|
925
|
+
}
|
|
916
926
|
const total = this.totalFromHeader;
|
|
917
927
|
const percent = total
|
|
918
928
|
? Math.min(100, Math.round((received / total) * 100))
|
|
919
929
|
: 0;
|
|
920
|
-
// console.log('[STREAM] progress:', percent, 'received:', received, 'total:', total, 'bufferLen:', this.buffer.length, 'parsedCount:', parsedData.length);
|
|
921
930
|
const progress = {
|
|
922
931
|
received,
|
|
923
932
|
total,
|
|
@@ -925,19 +934,24 @@ class StreamingProcessor {
|
|
|
925
934
|
stage: 'streaming'
|
|
926
935
|
};
|
|
927
936
|
return {
|
|
928
|
-
data: newItems
|
|
937
|
+
data: newItems,
|
|
929
938
|
progress
|
|
930
939
|
};
|
|
931
940
|
}
|
|
932
941
|
return null;
|
|
933
942
|
case HttpEventType.Response:
|
|
934
943
|
if (event.body) {
|
|
935
|
-
|
|
944
|
+
// event.body is the complete response, replace the buffer
|
|
945
|
+
this.buffer = event.body;
|
|
936
946
|
const parsedData = this.parseBuffer();
|
|
937
|
-
//
|
|
938
|
-
|
|
939
|
-
this.
|
|
940
|
-
const
|
|
947
|
+
// For NDJSON incremental parsing, parsedData already contains only new items.
|
|
948
|
+
// For other formats, parsedData is cumulative so slice from lastParsedLength.
|
|
949
|
+
const isIncremental = this.streamConfig.streamType === StreamType.NDJSON;
|
|
950
|
+
const remaining = isIncremental ? parsedData : parsedData.slice(this.lastParsedLength);
|
|
951
|
+
const received = isIncremental
|
|
952
|
+
? this.lastParsedLength + parsedData.length
|
|
953
|
+
: parsedData.length;
|
|
954
|
+
this.lastParsedLength = received;
|
|
941
955
|
const total = this.totalFromHeader;
|
|
942
956
|
const percent = total
|
|
943
957
|
? Math.min(100, Math.round((received / total) * 100))
|
|
@@ -966,6 +980,7 @@ class StreamingProcessor {
|
|
|
966
980
|
// Implement sliding window if buffer gets too large
|
|
967
981
|
if (this.buffer.length > this.maxBufferSize) {
|
|
968
982
|
this.buffer = this.buffer.slice(-this.maxBufferSize / 2);
|
|
983
|
+
this.lastParsedLineEnd = 0;
|
|
969
984
|
}
|
|
970
985
|
}
|
|
971
986
|
/**
|
|
@@ -976,11 +991,25 @@ class StreamingProcessor {
|
|
|
976
991
|
return [];
|
|
977
992
|
}
|
|
978
993
|
try {
|
|
994
|
+
if (this.streamConfig.streamType === StreamType.NDJSON) {
|
|
995
|
+
// For NDJSON, only parse complete lines since the last parse.
|
|
996
|
+
// Find the last newline in the buffer — everything after it is an incomplete line.
|
|
997
|
+
const lastNewlineIndex = this.buffer.lastIndexOf('\n');
|
|
998
|
+
if (lastNewlineIndex === -1) {
|
|
999
|
+
// No complete lines yet
|
|
1000
|
+
return [];
|
|
1001
|
+
}
|
|
1002
|
+
// Parse only the content from lastParsedLineEnd up to (and including) the last newline
|
|
1003
|
+
const bufferToParse = this.buffer.substring(this.lastParsedLineEnd, lastNewlineIndex + 1);
|
|
1004
|
+
this.lastParsedLineEnd = lastNewlineIndex + 1;
|
|
1005
|
+
const result = parseStreamData(bufferToParse, this.contentType, this.streamConfig);
|
|
1006
|
+
return result;
|
|
1007
|
+
}
|
|
979
1008
|
const result = parseStreamData(this.buffer, this.contentType, this.streamConfig);
|
|
980
1009
|
return result;
|
|
981
1010
|
}
|
|
982
1011
|
catch (error) {
|
|
983
|
-
console.warn('Failed to parse streaming data:', error);
|
|
1012
|
+
// console.warn('Failed to parse streaming data:', error);
|
|
984
1013
|
return [];
|
|
985
1014
|
}
|
|
986
1015
|
}
|
|
@@ -991,6 +1020,7 @@ class StreamingProcessor {
|
|
|
991
1020
|
this.buffer = '';
|
|
992
1021
|
this.contentType = '';
|
|
993
1022
|
this.lastParsedLength = 0;
|
|
1023
|
+
this.lastParsedLineEnd = 0;
|
|
994
1024
|
this.totalFromHeader = undefined;
|
|
995
1025
|
}
|
|
996
1026
|
/**
|
|
@@ -2891,7 +2921,9 @@ class RequestService extends WebsocketService {
|
|
|
2891
2921
|
observe: 'events',
|
|
2892
2922
|
responseType: 'text',
|
|
2893
2923
|
reportProgress: true
|
|
2894
|
-
}).pipe(
|
|
2924
|
+
}).pipe(
|
|
2925
|
+
// tap(data => console.log('STREAM DATA', data)),
|
|
2926
|
+
requestStreaming({
|
|
2895
2927
|
streamType: options.streamType || StreamType.AI_STREAMING,
|
|
2896
2928
|
totalHeader: options.totalHeader
|
|
2897
2929
|
}), this.requestStreaming(options), finalize(() => {
|
|
@@ -2981,19 +3013,19 @@ class RequestService extends WebsocketService {
|
|
|
2981
3013
|
requestStreaming(options) {
|
|
2982
3014
|
return (source$) => {
|
|
2983
3015
|
return source$.pipe(tap(output => {
|
|
2984
|
-
// Update progress from stream output
|
|
2985
3016
|
this.progress.next(output.progress.percent);
|
|
2986
3017
|
this.streamProgress.next(output.progress);
|
|
2987
|
-
}),
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
return data;
|
|
2991
|
-
}
|
|
3018
|
+
}), scan((acc, output) => {
|
|
3019
|
+
// Accumulate data from each emission
|
|
3020
|
+
const newData = output.data;
|
|
2992
3021
|
if (options?.adapter) {
|
|
2993
|
-
|
|
3022
|
+
const adaptedData = newData.map((item) => options.adapter(item));
|
|
3023
|
+
return [...acc, ...adaptedData];
|
|
2994
3024
|
}
|
|
2995
|
-
|
|
2996
|
-
|
|
3025
|
+
else {
|
|
3026
|
+
return [...acc, ...newData];
|
|
3027
|
+
}
|
|
3028
|
+
}, []));
|
|
2997
3029
|
};
|
|
2998
3030
|
}
|
|
2999
3031
|
downloadFileRequest(options) {
|
|
@@ -4170,7 +4202,7 @@ class HTTPManagerService extends RequestService {
|
|
|
4170
4202
|
}
|
|
4171
4203
|
handleSequentialError(request, error, index, options) {
|
|
4172
4204
|
if (options.logErrors !== false) {
|
|
4173
|
-
console.error(`Batch request ${index} failed:`, error);
|
|
4205
|
+
// console.error(`Batch request ${index} failed:`, error);
|
|
4174
4206
|
}
|
|
4175
4207
|
if (options.stopOnError) {
|
|
4176
4208
|
return throwError(() => error);
|
|
@@ -4182,7 +4214,7 @@ class HTTPManagerService extends RequestService {
|
|
|
4182
4214
|
}
|
|
4183
4215
|
handleParallelError(request, error, index, options) {
|
|
4184
4216
|
if (options.logErrors !== false) {
|
|
4185
|
-
console.error(`Batch request ${index} failed:`, error);
|
|
4217
|
+
// console.error(`Batch request ${index} failed:`, error);
|
|
4186
4218
|
}
|
|
4187
4219
|
if (options.ignoreErrors) {
|
|
4188
4220
|
return of(undefined);
|
|
@@ -4277,17 +4309,17 @@ class RequestSignalsService extends WebsocketService {
|
|
|
4277
4309
|
* - Streams are protected - non-stream requests wait for active streams
|
|
4278
4310
|
*/
|
|
4279
4311
|
queueRequest(request$, method, isStream = false) {
|
|
4280
|
-
console.log(`[Queue] ${method} queued (isStream=${isStream})`, {
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
});
|
|
4312
|
+
// console.log(`[Queue] ${method} queued (isStream=${isStream})`, {
|
|
4313
|
+
// activeMethod: this.activeMethod,
|
|
4314
|
+
// activeStreamMethod: this.activeStreamMethod,
|
|
4315
|
+
// queueLength: this.requestQueue.length
|
|
4316
|
+
// });
|
|
4285
4317
|
return new Observable((observer) => {
|
|
4286
|
-
console.log(`[Queue] ${method} observer created, checking conditions...`, {
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
});
|
|
4318
|
+
// console.log(`[Queue] ${method} observer created, checking conditions...`, {
|
|
4319
|
+
// activeMethod: this.activeMethod,
|
|
4320
|
+
// activeStreamMethod: this.activeStreamMethod,
|
|
4321
|
+
// isStream
|
|
4322
|
+
// });
|
|
4291
4323
|
const queuedRequest = {
|
|
4292
4324
|
observable: request$,
|
|
4293
4325
|
resolve: (value) => observer.next(value),
|
|
@@ -4297,7 +4329,7 @@ class RequestSignalsService extends WebsocketService {
|
|
|
4297
4329
|
};
|
|
4298
4330
|
// If a stream is currently active, non-stream requests must wait
|
|
4299
4331
|
if (this.activeStreamMethod && !isStream) {
|
|
4300
|
-
console.log(`[Queue] ${method} queued (1), waiting for stream ${this.activeStreamMethod}`);
|
|
4332
|
+
// console.log(`[Queue] ${method} queued (1), waiting for stream ${this.activeStreamMethod}`);
|
|
4301
4333
|
this.requestQueue.push(queuedRequest);
|
|
4302
4334
|
return () => {
|
|
4303
4335
|
const idx = this.requestQueue.findIndex(q => q === queuedRequest);
|
|
@@ -4307,7 +4339,7 @@ class RequestSignalsService extends WebsocketService {
|
|
|
4307
4339
|
}
|
|
4308
4340
|
// If a request is already running, queue this one (FIFO)
|
|
4309
4341
|
if (this.activeMethod) {
|
|
4310
|
-
console.log(`[Queue] ${method} queued (2), waiting for ${this.activeMethod}`);
|
|
4342
|
+
// console.log(`[Queue] ${method} queued (2), waiting for ${this.activeMethod}`);
|
|
4311
4343
|
this.requestQueue.push(queuedRequest);
|
|
4312
4344
|
return () => {
|
|
4313
4345
|
const idx = this.requestQueue.findIndex(q => q === queuedRequest);
|
|
@@ -4316,7 +4348,7 @@ class RequestSignalsService extends WebsocketService {
|
|
|
4316
4348
|
};
|
|
4317
4349
|
}
|
|
4318
4350
|
// No active request - start immediately
|
|
4319
|
-
console.log(`[Queue] ${method} starting immediately`);
|
|
4351
|
+
// console.log(`[Queue] ${method} starting immediately`);
|
|
4320
4352
|
this.startRequest(queuedRequest, observer);
|
|
4321
4353
|
return () => {
|
|
4322
4354
|
const idx = this.requestQueue.findIndex(q => q === queuedRequest);
|
|
@@ -4334,23 +4366,23 @@ class RequestSignalsService extends WebsocketService {
|
|
|
4334
4366
|
this.activeStreamMethod = queuedRequest.method;
|
|
4335
4367
|
}
|
|
4336
4368
|
this._activeRequestCount.update(c => c + 1);
|
|
4337
|
-
console.log(`[Queue] Starting ${queuedRequest.method}${queuedRequest.isStream ? ' (STREAM)' : ''}`, {
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
});
|
|
4369
|
+
// console.log(`[Queue] Starting ${queuedRequest.method}${queuedRequest.isStream ? ' (STREAM)' : ''}`, {
|
|
4370
|
+
// activeMethod: this.activeMethod,
|
|
4371
|
+
// activeStreamMethod: this.activeStreamMethod,
|
|
4372
|
+
// queueLength: this.requestQueue.length
|
|
4373
|
+
// });
|
|
4342
4374
|
const sub = queuedRequest.observable.subscribe({
|
|
4343
4375
|
next: (value) => {
|
|
4344
|
-
console.log(`[Queue] ${queuedRequest.method} received value, isStream=${queuedRequest.isStream}`);
|
|
4376
|
+
// console.log(`[Queue] ${queuedRequest.method} received value, isStream=${queuedRequest.isStream}`);
|
|
4345
4377
|
observer.next(value);
|
|
4346
4378
|
},
|
|
4347
4379
|
error: (error) => {
|
|
4348
|
-
console.log(`[Queue] ${queuedRequest.method} error:`, error);
|
|
4380
|
+
// console.log(`[Queue] ${queuedRequest.method} error:`, error);
|
|
4349
4381
|
observer.error(error);
|
|
4350
4382
|
this.cleanupAndProcessNext(queuedRequest.method, !!queuedRequest.isStream);
|
|
4351
4383
|
},
|
|
4352
4384
|
complete: () => {
|
|
4353
|
-
console.log(`[Queue] ${queuedRequest.method} complete, isStream=${queuedRequest.isStream}`);
|
|
4385
|
+
// console.log(`[Queue] ${queuedRequest.method} complete, isStream=${queuedRequest.isStream}`);
|
|
4354
4386
|
observer.complete();
|
|
4355
4387
|
this.cleanupAndProcessNext(queuedRequest.method, !!queuedRequest.isStream);
|
|
4356
4388
|
}
|
|
@@ -4361,35 +4393,29 @@ class RequestSignalsService extends WebsocketService {
|
|
|
4361
4393
|
* Clean up completed request and process next in queue
|
|
4362
4394
|
*/
|
|
4363
4395
|
cleanupAndProcessNext(method, wasStream) {
|
|
4364
|
-
console.log(`[Queue] cleanupAndProcessNext called: method=${method}, wasStream=${wasStream}`, {
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
});
|
|
4396
|
+
// console.log(`[Queue] cleanupAndProcessNext called: method=${method}, wasStream=${wasStream}`, {
|
|
4397
|
+
// activeMethod: this.activeMethod,
|
|
4398
|
+
// activeStreamMethod: this.activeStreamMethod,
|
|
4399
|
+
// queueLength: this.requestQueue.length
|
|
4400
|
+
// });
|
|
4369
4401
|
this.activeRequests.delete(method);
|
|
4370
4402
|
this.activeMethod = null;
|
|
4371
4403
|
if (wasStream) {
|
|
4372
4404
|
this.activeStreamMethod = null;
|
|
4373
4405
|
}
|
|
4374
|
-
this._activeRequestCount.update(c =>
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
});
|
|
4381
|
-
console.log(`[Queue] After cleanup:`, {
|
|
4382
|
-
activeMethod: this.activeMethod,
|
|
4383
|
-
activeStreamMethod: this.activeStreamMethod,
|
|
4384
|
-
queueLength: this.requestQueue.length
|
|
4385
|
-
});
|
|
4406
|
+
this._activeRequestCount.update(c => Math.max(0, c - 1));
|
|
4407
|
+
// console.log(`[Queue] After cleanup:`, {
|
|
4408
|
+
// activeMethod: this.activeMethod,
|
|
4409
|
+
// activeStreamMethod: this.activeStreamMethod,
|
|
4410
|
+
// queueLength: this.requestQueue.length
|
|
4411
|
+
// });
|
|
4386
4412
|
// Process next request in queue
|
|
4387
4413
|
if (this.requestQueue.length > 0) {
|
|
4388
4414
|
const next = this.requestQueue.shift();
|
|
4389
|
-
console.log(`[Queue] Processing next from queue: ${next.method}`, {
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
});
|
|
4415
|
+
// console.log(`[Queue] Processing next from queue: ${next.method}`, {
|
|
4416
|
+
// isStream: next.isStream,
|
|
4417
|
+
// queueLength: this.requestQueue.length
|
|
4418
|
+
// });
|
|
4393
4419
|
this.startRequest(next, {
|
|
4394
4420
|
next: (value) => next.resolve(value),
|
|
4395
4421
|
error: (error) => next.reject(error),
|
|
@@ -8467,7 +8493,7 @@ class RequestManagerBasicDemoComponent {
|
|
|
8467
8493
|
// Update displayed columns when data changes
|
|
8468
8494
|
updateDisplayedColumns(data) {
|
|
8469
8495
|
this.displayedColumns = this.getColumnsFromData(data);
|
|
8470
|
-
console.log('[DEMO] Updated columns:', this.displayedColumns)
|
|
8496
|
+
// console.log('[DEMO] Updated columns:', this.displayedColumns)
|
|
8471
8497
|
}
|
|
8472
8498
|
// Helper to check if value is an object
|
|
8473
8499
|
isObject(value) {
|
|
@@ -8727,7 +8753,7 @@ class RequestManagerBasicDemoComponent {
|
|
|
8727
8753
|
this.requestParams.GET = reqParams.apiOptions;
|
|
8728
8754
|
this.STREAM$ = this.httpManagerService.getRequest(reqParams.apiOptions, reqParams.path)
|
|
8729
8755
|
.pipe(tap((data) => {
|
|
8730
|
-
console.log("API STREAM response", data)
|
|
8756
|
+
// console.log("API STREAM response", data)
|
|
8731
8757
|
if (data && data.length > 0) {
|
|
8732
8758
|
this.updateDisplayedColumns(data);
|
|
8733
8759
|
}
|
|
@@ -9032,7 +9058,7 @@ class RequestManagerStateDemoComponent {
|
|
|
9032
9058
|
this.stateManagerDemoService.data$.pipe(tap$1((data) => console.log("API STREAM_AI response", data)));
|
|
9033
9059
|
this.error$.pipe(tap$1((data) => {
|
|
9034
9060
|
debugger;
|
|
9035
|
-
console.log("API STREAM response", data)
|
|
9061
|
+
// console.log("API STREAM response", data)
|
|
9036
9062
|
}), catchError$1(error => {
|
|
9037
9063
|
return throwError(() => this.errorHandling(error, 'STREAM'));
|
|
9038
9064
|
}));
|
|
@@ -9208,7 +9234,7 @@ class RequestManagerDemoComponent {
|
|
|
9208
9234
|
// Update displayed columns when data changes
|
|
9209
9235
|
updateDisplayedColumns(data) {
|
|
9210
9236
|
this.displayedColumns = this.getColumnsFromData(data);
|
|
9211
|
-
console.log('[DEMO] Updated columns:', this.displayedColumns)
|
|
9237
|
+
// console.log('[DEMO] Updated columns:', this.displayedColumns)
|
|
9212
9238
|
}
|
|
9213
9239
|
// Helper to check if value is an object
|
|
9214
9240
|
isObject(value) {
|
|
@@ -9492,7 +9518,7 @@ class RequestManagerDemoComponent {
|
|
|
9492
9518
|
this.STREAM_error$.next('');
|
|
9493
9519
|
this.STREAM$ = this.httpManagerService.getRequest(reqParams.apiOptions, reqParams.path)
|
|
9494
9520
|
.pipe(tap((data) => {
|
|
9495
|
-
console.log("API STREAM response", data)
|
|
9521
|
+
// console.log("API STREAM response", data)
|
|
9496
9522
|
if (data && data.length > 0) {
|
|
9497
9523
|
this.updateDisplayedColumns(data);
|
|
9498
9524
|
}
|