uni-manager 0.0.79 → 0.1.1

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.
@@ -0,0 +1,677 @@
1
+ import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
2
+ import { map } from 'rxjs/internal/operators/map';
3
+ import { tap } from 'rxjs/internal/operators/tap';
4
+ import { UniToastManager } from 'uni-manager/toast';
5
+ import isEqual from 'lodash-es/isEqual';
6
+ import { defer } from 'rxjs/internal/observable/defer';
7
+ import { from } from 'rxjs/internal/observable/from';
8
+ import { timer } from 'rxjs/internal/observable/timer';
9
+ import { catchError } from 'rxjs/internal/operators/catchError';
10
+ import { distinctUntilChanged } from 'rxjs/internal/operators/distinctUntilChanged';
11
+ import { finalize } from 'rxjs/internal/operators/finalize';
12
+ import { UniErrorManager } from 'uni-manager/error';
13
+ import { EMPTY } from 'rxjs/internal/observable/empty';
14
+ import { of } from 'rxjs/internal/observable/of';
15
+ import { throwError } from 'rxjs/internal/observable/throwError';
16
+ import { concatMap } from 'rxjs/internal/operators/concatMap';
17
+ import { exhaustMap } from 'rxjs/internal/operators/exhaustMap';
18
+ import { mergeMap } from 'rxjs/internal/operators/mergeMap';
19
+ import { switchMap } from 'rxjs/internal/operators/switchMap';
20
+ import { UniHttpError, isHttpErrorBody } from 'uni-error/http';
21
+ import { UniTypeDateManager } from 'uni-manager/type';
22
+
23
+ var MapOperator;
24
+ (function (MapOperator) {
25
+ /** Cancella la precedente richiesta, mantiene solo l’ultima */
26
+ MapOperator[MapOperator["SWITCH_MAP"] = 0] = "SWITCH_MAP";
27
+ /** Ignora nuovi valori finché la corrente non finisce */
28
+ MapOperator[MapOperator["EXHAUST_MAP"] = 1] = "EXHAUST_MAP";
29
+ /** Mette le richieste in coda, le esegue una alla volta */
30
+ MapOperator[MapOperator["CONCAT_MAP"] = 2] = "CONCAT_MAP";
31
+ /** Esegue tutte le richieste in parallelo, ordine non garantito */
32
+ MapOperator[MapOperator["MERGE_MAP"] = 3] = "MERGE_MAP";
33
+ })(MapOperator || (MapOperator = {}));
34
+ var PollingErrorMode;
35
+ (function (PollingErrorMode) {
36
+ /** Salta questa iterazione emettendo un undefined. Il polling continua al tick successivo. */
37
+ PollingErrorMode[PollingErrorMode["IGNORE"] = 0] = "IGNORE";
38
+ /** Salta questa iterazione senza emettere valori. Il polling continua al tick successivo. */
39
+ PollingErrorMode[PollingErrorMode["SKIP"] = 1] = "SKIP";
40
+ /** Interrompe il polling propagando l'errore. */
41
+ PollingErrorMode[PollingErrorMode["STOP"] = 2] = "STOP";
42
+ /** Ignora l'errore, lo salva (es. per UI), e continua il polling. Emette `undefined`. */
43
+ PollingErrorMode[PollingErrorMode["IGNORE_WITH_ERROR"] = 3] = "IGNORE_WITH_ERROR";
44
+ })(PollingErrorMode || (PollingErrorMode = {}));
45
+ var EmitValueMode;
46
+ (function (EmitValueMode) {
47
+ /** Aggiorna lo stato solo se arrivano dati nuovi (distinct) */
48
+ EmitValueMode[EmitValueMode["ON_NEW_DATA"] = 0] = "ON_NEW_DATA";
49
+ /** Aggiorna lo stato ad ogni chiamata, anche se i dati sono uguali */
50
+ EmitValueMode[EmitValueMode["EVERY_TIME"] = 1] = "EVERY_TIME";
51
+ })(EmitValueMode || (EmitValueMode = {}));
52
+
53
+ function operatorHandler(operator) {
54
+ // Gestione della concorrenza in base al parametro
55
+ switch (operator) {
56
+ case MapOperator.EXHAUST_MAP: {
57
+ return (project) => exhaustMap(project);
58
+ }
59
+ case MapOperator.CONCAT_MAP: {
60
+ return (project) => concatMap(project);
61
+ }
62
+ case MapOperator.MERGE_MAP: {
63
+ return (project) => mergeMap(project);
64
+ }
65
+ case MapOperator.SWITCH_MAP: {
66
+ return (project) => switchMap(project);
67
+ }
68
+ }
69
+ }
70
+ function errorHandler(err, errorMode, ref) {
71
+ // Controllo: sia effettivamente un errore di tipo 'UniHttpError'
72
+ if (err instanceof UniHttpError) {
73
+ switch (errorMode) {
74
+ case PollingErrorMode.IGNORE: {
75
+ return of();
76
+ }
77
+ case PollingErrorMode.SKIP: {
78
+ return EMPTY;
79
+ }
80
+ case PollingErrorMode.IGNORE_WITH_ERROR: {
81
+ UniErrorManager.add(ref, err);
82
+ return of();
83
+ }
84
+ case PollingErrorMode.STOP: {
85
+ UniErrorManager.add(ref, err);
86
+ return throwError(() => err);
87
+ }
88
+ }
89
+ }
90
+ else {
91
+ return throwError(() => err);
92
+ }
93
+ }
94
+
95
+ /* ------------------------------------------------------------------------------- */
96
+ /* -------------------------------- Funzioni Core RxJS -------------------------- */
97
+ /* ------------------------------------------------------------------------------- */
98
+ /**
99
+ * Gestisce l'esecuzione e il ciclo di vita di una singola richiesta HTTP.
100
+ * Si occupa della registrazione della reference, della gestione dei loader, dei toast di successo e dell'intercettazione degli errori.
101
+ */
102
+ function http$(url, refType, config, promiseFactory) {
103
+ /* Recupero configurazione */
104
+ const { ref, toast, hasLoader } = config;
105
+ return defer(() => {
106
+ const http$ = from(promiseFactory());
107
+ return http$.pipe(tap({
108
+ subscribe: () => {
109
+ /* Creazione reference */
110
+ add(ref, url, refType);
111
+ /* Incrementa per il loader */
112
+ if (hasLoader !== false) {
113
+ updateIsLoading(ref, 1);
114
+ }
115
+ },
116
+ unsubscribe: () => {
117
+ /* Rimozione reference */
118
+ remove(ref);
119
+ },
120
+ next: (res) => {
121
+ /* Mostra toast (se presente) */
122
+ if (toast) {
123
+ UniToastManager.showHttp(toast, res);
124
+ }
125
+ },
126
+ }), catchError((err) => {
127
+ // Aggiorna la ref nella map
128
+ updateHasError(ref, true);
129
+ /* Gestione errore */
130
+ return errorHandler(err, PollingErrorMode.STOP, ref);
131
+ }), finalize(() => {
132
+ /* Decrementa per il loader */
133
+ if (hasLoader !== false) {
134
+ updateIsLoading(ref, -1);
135
+ }
136
+ }));
137
+ });
138
+ }
139
+ /**
140
+ * Avvia e coordina un ciclo di polling a intervalli regolari.
141
+ * Gestisce la concorrenza tramite operatori RxJS configurabili, la rimozione dei popup, di errore nelle iterazioni successive e i comportamenti custom al primo avvio.
142
+ */
143
+ function httpPolling$(url, config, promiseFactory) {
144
+ /* Recupero configurazione */
145
+ const { interval, ref, operator = MapOperator.SWITCH_MAP, errorMode = PollingErrorMode.STOP, emitValueMode = EmitValueMode.ON_NEW_DATA, firstIteration, } = config;
146
+ const timer$ = timer(0, interval);
147
+ const source$ = timer$.pipe(tap({
148
+ subscribe: () => {
149
+ /* Creazione reference */
150
+ add(ref, url, 'polling');
151
+ },
152
+ unsubscribe: () => {
153
+ /* Rimozione reference */
154
+ remove(ref);
155
+ },
156
+ }), operatorHandler(operator)((index) => {
157
+ /* Incrementa per il loader */
158
+ if (index === 0 && firstIteration?.hasLoader !== false) {
159
+ updateIsLoading(ref, 1);
160
+ }
161
+ return defer(() => {
162
+ const http$ = from(promiseFactory());
163
+ return http$.pipe(tap((res) => {
164
+ /* Meccanismo di ripristino automatico: se il polling torna in salute, cancella l'errore dallo store e nasconde i relativi messaggi a schermo */
165
+ if (errorMode === PollingErrorMode.IGNORE_WITH_ERROR) {
166
+ updateHasError(ref, false);
167
+ UniErrorManager.remove(ref);
168
+ }
169
+ /* Prima risposta */
170
+ if (index === 0 && firstIteration?.toast) {
171
+ UniToastManager.showHttp(firstIteration.toast, res);
172
+ }
173
+ }), catchError((err) => {
174
+ // Aggiorna la ref nella map
175
+ updateHasError(ref, true);
176
+ /* Gestione errore */
177
+ return errorHandler(err, errorMode, ref);
178
+ }), finalize(() => {
179
+ /* Decrementa per il loader */
180
+ if (index === 0 && firstIteration?.hasLoader !== false) {
181
+ updateIsLoading(ref, -1);
182
+ }
183
+ }));
184
+ });
185
+ }));
186
+ return emitValueMode === EmitValueMode.ON_NEW_DATA
187
+ ? source$.pipe(distinctUntilChanged((prev, cur) => isEqual(prev, cur)))
188
+ : source$;
189
+ }
190
+ /* ------------------------------------------------------------------------------- */
191
+ /* ------------------------------------ Utils ------------------------------------ */
192
+ /* ------------------------------------------------------------------------------- */
193
+ /**
194
+ * Aggiunge una nuova ref nello store solo se non è già presente.
195
+ * Se l'ID esiste già, l'operazione viene interrotta per preservare il dato originale.
196
+ */
197
+ function add(id, url, type) {
198
+ // Recupera l'ultimo stato (Map)
199
+ const oldMap = UniHttpManager.currentValue;
200
+ // Controllo: se è presente l'item allora termina
201
+ if (oldMap.get(id))
202
+ return;
203
+ // Crea il nuovo oggetto
204
+ const newItemMap = {
205
+ type,
206
+ lineId: undefined,
207
+ url,
208
+ hasError: false,
209
+ pendingCount: 0,
210
+ };
211
+ // Crea una nuova istanza della Map
212
+ const newMap = new Map(oldMap);
213
+ newMap.set(id, newItemMap);
214
+ // Aggiorna il nuovo stato notificando l'observer
215
+ UniHttpManager.store.next(newMap);
216
+ }
217
+ /**
218
+ * Rimuove un http ref tramite ID
219
+ */
220
+ function remove(id) {
221
+ // Recupera l'ultimo stato (Map)
222
+ const oldMap = UniHttpManager.currentValue;
223
+ // Controllo: se non è presente l'item allora termina
224
+ if (!oldMap.has(id))
225
+ return;
226
+ // Aggiorna store
227
+ const newMap = new Map(oldMap);
228
+ newMap.delete(id);
229
+ UniHttpManager.store.next(newMap);
230
+ }
231
+ /**
232
+ * Aggiorna il contatore delle chiamate pendenti per una specifica ref.
233
+ * Incrementa o decrementa 'pendingCount' garantendo che non scenda mai sotto lo zero.
234
+ * Se la ref non esiste, l'operazione viene ignorata.
235
+ */
236
+ function updateIsLoading(id, delta) {
237
+ // Recupera l'ultimo stato (Map)
238
+ const oldMap = UniHttpManager.currentValue;
239
+ // Controllo: se non è presente l'item allora termina
240
+ const oldItem = oldMap.get(id);
241
+ if (!oldItem)
242
+ return;
243
+ // Aggiorna l'oggetto
244
+ const newItemMap = {
245
+ ...oldItem,
246
+ pendingCount: Math.max(0, oldItem.pendingCount + delta),
247
+ };
248
+ // Crea una nuova istanza della Map
249
+ const newMap = new Map(oldMap);
250
+ newMap.set(id, newItemMap);
251
+ // Aggiorna il nuovo stato notificando l'observer
252
+ UniHttpManager.store.next(newMap);
253
+ }
254
+ /**
255
+ * Aggiorna lo stato di errore per una specifica ref.
256
+ * Se il valore di 'hasError' è identico a quello attuale o se la ref non esiste,
257
+ * l'operazione viene interrotta per evitare aggiornamenti inutili.
258
+ */
259
+ function updateHasError(id, hasError) {
260
+ // Recupera l'ultimo stato (Map)
261
+ const oldMap = UniHttpManager.currentValue;
262
+ // Controllo: se non è presente l'item allora termina
263
+ const oldItem = oldMap.get(id);
264
+ if (!oldItem)
265
+ return;
266
+ // Controllo: se con lo stesso valore, salta
267
+ if (oldItem.hasError === hasError)
268
+ return;
269
+ // Aggiorna l'oggetto
270
+ const newItemMap = { ...oldItem, hasError };
271
+ // Crea una nuova istanza della Map
272
+ const newMap = new Map(oldMap);
273
+ newMap.set(id, newItemMap);
274
+ // Aggiorna il nuovo stato notificando l'observer
275
+ UniHttpManager.store.next(newMap);
276
+ }
277
+
278
+ async function execute(url, init) {
279
+ try {
280
+ /* Esegue chiamata http */
281
+ const res = await fetch(url, init);
282
+ /* Nessun contenuto cons status 204 */
283
+ if (res.status === 204) {
284
+ return undefined;
285
+ }
286
+ /* Risposta ok */
287
+ if (res.ok) {
288
+ return res;
289
+ }
290
+ /* Errore HTTP (quindi risposta ricevuta ma non ok) */
291
+ let errorBody;
292
+ try {
293
+ /* Clona risposta per leggerla senza consumare la originale */
294
+ const resClone = res.clone();
295
+ /* Recupero se è un json */
296
+ const contentType = res.headers.get('content-type') ?? '';
297
+ const isJson = contentType.startsWith('application/json');
298
+ /* Aggiorna body con struttura errore */
299
+ errorBody = isJson ? await resClone.json() : await resClone.text();
300
+ }
301
+ catch {
302
+ // Se il clone o il parsing falliscono, si usa una stringa di fallback sicura
303
+ errorBody = `Failed to parse error response body (Status: ${res.status})`;
304
+ }
305
+ if (isHttpErrorBody(errorBody)) {
306
+ const type = errorBody.exceptionType.includes('HttpRequestException') ? 'be' : 'ice';
307
+ throw new UniHttpError(type, res.status, url, errorBody);
308
+ }
309
+ else {
310
+ const error = new Error(`HTTP ${res.statusText}`);
311
+ throw new UniHttpError('base', res.status, url, {
312
+ exceptionMessage: error.message,
313
+ exceptionType: 'ErrorBase',
314
+ message: error.message,
315
+ stackTrace: error.stack ?? '',
316
+ });
317
+ }
318
+ }
319
+ catch (error) {
320
+ // Se l'errore è già un UniHttpError (lanciato sopra) bypassa tutto il resto
321
+ if (error instanceof UniHttpError) {
322
+ throw error;
323
+ }
324
+ if (error instanceof TypeError) {
325
+ throw new UniHttpError('network', -1, url, {
326
+ exceptionMessage: `${error.name}: ${error.message}\n${error.stack}`,
327
+ exceptionType: error.name,
328
+ message: error.message,
329
+ stackTrace: error.stack ?? '',
330
+ });
331
+ }
332
+ // Fallback per qualsiasi altro tipo di errore sconosciuto
333
+ throw error;
334
+ }
335
+ }
336
+ async function executeHttp(url, init) {
337
+ /* Esegue la chiamata HTTP e restituisce il corpo decodificato come JSON */
338
+ const res = await execute(url, init);
339
+ if (!res)
340
+ return undefined;
341
+ /* Estrae il contenuto come testo */
342
+ const text = await res.text();
343
+ /* Controllo: se il testo è vuoto (''), ritorna undefined */
344
+ if (!text || text.trim().length === 0) {
345
+ return undefined;
346
+ }
347
+ /* Parsa manualmente il testo, dato che lo stream è stato già letto */
348
+ return JSON.parse(text);
349
+ }
350
+ async function executeBlob(url, init) {
351
+ /* Esegue la chiamata HTTP */
352
+ const res = await execute(url, init);
353
+ if (!res)
354
+ return undefined;
355
+ /* Estrae il contenuto come Blob direttamente */
356
+ const blob = await res.blob();
357
+ /* Controllo: se il blob è vuoto (0 byte), ritorna undefined */
358
+ if (blob.size === 0) {
359
+ return undefined;
360
+ }
361
+ /* Estrae il nome del file dall'header */
362
+ const disposition = res.headers.get('Content-Disposition');
363
+ let fileName = 'download.pdf'; // Fallback di default
364
+ if (disposition) {
365
+ const matches = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec(disposition);
366
+ if (!!matches && matches[1]) {
367
+ fileName = matches[1].replaceAll(/['"]/g, '');
368
+ }
369
+ }
370
+ /* Genera l'URL temporaneo dal blob */
371
+ const fileUrl = URL.createObjectURL(blob);
372
+ return { url: fileUrl, name: fileName };
373
+ }
374
+
375
+ /**
376
+ * Costruisce un URL completo per l'API partendo dai parametri di configurazione.
377
+ */
378
+ function getUrl(hostname, port, config) {
379
+ const { pathParams, path, hasApiPrefix } = config;
380
+ // Costruzione url
381
+ const prefix = hasApiPrefix === false ? '' : 'api';
382
+ const cleanPath = path.startsWith('/') ? path.slice(1) : path;
383
+ const pathFixed = prefix ? `${prefix}/${cleanPath}` : cleanPath;
384
+ const url = new URL(pathFixed, `http://${hostname}:${port}`);
385
+ if (pathParams) {
386
+ // Regex per intercettare stringhe in formato ISO string
387
+ const isoDateRegex = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?)?$/;
388
+ for (const [key, rawValue] of Object.entries(pathParams)) {
389
+ if (rawValue === undefined || rawValue === null) {
390
+ continue;
391
+ }
392
+ // Conversione in array per usare un solo ciclo
393
+ const valuesArray = Array.isArray(rawValue) ? rawValue : [rawValue];
394
+ for (const item of valuesArray) {
395
+ if (item === undefined || item === null) {
396
+ continue;
397
+ }
398
+ let formattedValue;
399
+ // Caso: Date nativo
400
+ if (item instanceof Date) {
401
+ formattedValue = UniTypeDateManager.toYYYYMMDD(item);
402
+ }
403
+ // Caso: Date formato ISO string
404
+ else if (typeof item === 'string' && isoDateRegex.test(item)) {
405
+ const parsedDate = new Date(item);
406
+ formattedValue = Number.isNaN(parsedDate.getTime())
407
+ ? item
408
+ : UniTypeDateManager.toYYYYMMDD(parsedDate);
409
+ }
410
+ // Default
411
+ else {
412
+ formattedValue = String(item);
413
+ }
414
+ url.searchParams.append(key, formattedValue);
415
+ }
416
+ }
417
+ }
418
+ return url;
419
+ }
420
+ /**
421
+ * Normalizza i valori del body cosi da sistemare le incongruenze tra ui e db
422
+ */
423
+ function normalizeHttpBody(body, isRoot = true) {
424
+ // PRIMITIVI GENERICI
425
+ // Tipi gestiti: null, undefined, number, boolean, symbol, bigint, string
426
+ if (body === null || typeof body !== 'object') {
427
+ // Sotto-gestione specifica per il tipo: string
428
+ if (typeof body === 'string') {
429
+ return body.trim();
430
+ }
431
+ return body;
432
+ }
433
+ // DATE
434
+ // Tipi gestiti: Date
435
+ // Formattazione esplicita manuale in YYYY-MM-DD
436
+ if (body instanceof Date) {
437
+ const year = body.getFullYear();
438
+ const month = String(body.getMonth() + 1).padStart(2, '0');
439
+ const day = String(body.getDate()).padStart(2, '0');
440
+ return `${year}-${month}-${day}`;
441
+ }
442
+ // STRUTTURE DATI ITERABILI
443
+ // Tipi gestiti: Array (qualsiasi array, es. string[], number[], Object[])
444
+ // Se è un array, viene mappato ricorsivamente ogni singolo elemento al suo interno (passando isRoot = false perché gli elementi dell'array non sono l'oggetto root principale)
445
+ if (Array.isArray(body)) {
446
+ return body.map((item) => normalizeHttpBody(item, false));
447
+ }
448
+ // OGGETTI
449
+ // Tipi gestiti: Record<string, any>, generici oggetti JavaScript ({ })
450
+ // Rimuove chiave 'id' al primo livello e prosegue ricorsivamente
451
+ const entries = Object.entries(body)
452
+ .filter(([key]) => !(isRoot && key.toLowerCase() === 'id'))
453
+ .map(([key, value]) => [key, normalizeHttpBody(value, false)]);
454
+ // Ricostruisce l'oggetto normalizzato
455
+ return Object.fromEntries(entries);
456
+ }
457
+
458
+ const CONFIG_TOAST_DEFAULT = {
459
+ type: 'success',
460
+ label: 'OperationCompleted',
461
+ };
462
+ class UniHttpManager {
463
+ /* ------------------------------------------------------------------------------- */
464
+ /* --------------------------------- Metodi: get --------------------------------- */
465
+ /* ------------------------------------------------------------------------------- */
466
+ /** Restituisce se lo store ha chiamate in attesa di risposta o meno */
467
+ static get hasWaitingRequests$() {
468
+ return this.store$.pipe(map((x) => [...x.values()].some((y) => y.pendingCount > 0)));
469
+ }
470
+ /* ------------------------------------------------------------------------------- */
471
+ /* ------------------------------------ Store ------------------------------------ */
472
+ /* ------------------------------------------------------------------------------- */
473
+ /** Store privato (Subject) */
474
+ static { this.store = new BehaviorSubject(new Map()); }
475
+ /** Store pubblico (Observable) */
476
+ static { this.store$ = this.store.asObservable(); }
477
+ /** Ottiene lo stato attuale della Map senza dover sottoscrivere l'observable */
478
+ static get currentValue() {
479
+ return this.store.getValue();
480
+ }
481
+ /* ------------------------------------------------------------------------------- */
482
+ /* -------------------------------- Metodi: setup -------------------------------- */
483
+ /* ------------------------------------------------------------------------------- */
484
+ /**
485
+ * Inizializza la configurazione di rete del manager.
486
+ * Deve essere chiamato prima di effettuare qualsiasi richiesta HTTP.
487
+ */
488
+ static setup(hostname, port) {
489
+ this.hostname = hostname;
490
+ this.port = port;
491
+ }
492
+ /* ------------------------------------------------------------------------------- */
493
+ /* -------------------------------- Metodi: CRUD --------------------------------- */
494
+ /* ------------------------------------------------------------------------------- */
495
+ /*
496
+ * Esegue una singola richiesta HTTP GET.
497
+ * Utilizza il path configurato per costruire l'URL completo e restituisce un Observable del risultato.
498
+ */
499
+ static read$(config) {
500
+ /* Config */
501
+ const initCustom = {
502
+ ...config.init,
503
+ method: 'GET',
504
+ };
505
+ /* API */
506
+ const url = getUrl(this.hostname, this.port, config);
507
+ return http$(url, 'one', config, () => executeHttp(url, initCustom)).pipe(tap((res) => {
508
+ if (Array.isArray(res) && config.toast === undefined) {
509
+ UniToastManager.show({
510
+ label: 'ItemsFound',
511
+ params: { count: res.length },
512
+ });
513
+ }
514
+ }));
515
+ }
516
+ /**
517
+ * Esegue una richiesta HTTP POST inviando un payload JSON nel corpo della richiesta.
518
+ * Imposta automaticamente l'header 'Content-Type' come 'application/json'.
519
+ */
520
+ static create$(config, body) {
521
+ /* Config */
522
+ const initCustom = {
523
+ ...config.init,
524
+ method: 'POST',
525
+ headers: {
526
+ 'Content-Type': 'application/json',
527
+ ...config.init?.headers,
528
+ },
529
+ body: JSON.stringify(normalizeHttpBody(body)),
530
+ };
531
+ /* Config custom (toast di default) */
532
+ const configCustom = {
533
+ ...config,
534
+ toast: config.hasToast === false ? undefined : (config.toast ?? CONFIG_TOAST_DEFAULT),
535
+ };
536
+ /* API */
537
+ const url = getUrl(this.hostname, this.port, config);
538
+ return http$(url, 'one', configCustom, () => executeHttp(url, initCustom));
539
+ }
540
+ /**
541
+ * Esegue una singola richiesta HTTP PUT per aggiornare una risorsa esistente.
542
+ */
543
+ static update$(config, body) {
544
+ /* Config */
545
+ const initCustom = { ...config.init, method: 'PUT' };
546
+ if (body !== undefined) {
547
+ initCustom.headers = {
548
+ 'Content-Type': 'application/json',
549
+ ...config.init?.headers,
550
+ };
551
+ initCustom.body = JSON.stringify(normalizeHttpBody(body));
552
+ }
553
+ /* Config custom (toast di default) */
554
+ const configCustom = {
555
+ ...config,
556
+ toast: config.hasToast === false ? undefined : (config.toast ?? CONFIG_TOAST_DEFAULT),
557
+ };
558
+ /* API */
559
+ const url = getUrl(this.hostname, this.port, config);
560
+ return http$(url, 'one', configCustom, () => executeHttp(url, initCustom));
561
+ }
562
+ /**
563
+ * Esegue una richiesta HTTP DELETE per rimuovere una risorsa.
564
+ * Utilizza il path configurato per costruire l'URL completo e restituisce un Observable del risultato.
565
+ */
566
+ static delete$(config) {
567
+ /* Config */
568
+ const initCustom = {
569
+ ...config.init,
570
+ method: 'DELETE',
571
+ };
572
+ /* Config custom (toast di default) */
573
+ const configCustom = {
574
+ ...config,
575
+ toast: config.hasToast === false ? undefined : (config.toast ?? CONFIG_TOAST_DEFAULT),
576
+ };
577
+ /* API */
578
+ const url = getUrl(this.hostname, this.port, config);
579
+ return http$(url, 'one', configCustom, () => executeHttp(url, initCustom));
580
+ }
581
+ /* ------------------------------------------------------------------------------- */
582
+ /* -------------------------- Metodi: CRUD file/image ---------------------------- */
583
+ /* ------------------------------------------------------------------------------- */
584
+ /**
585
+ * Recupera un'immagine tramite una richiesta GET e la trasforma in un formato gestibile (es. Blob o Base64).
586
+ * Delega la logica di conversione alla funzione executeImage.
587
+ */
588
+ static readImage$(config) {
589
+ /* Config */
590
+ const initCustom = {
591
+ ...config.init,
592
+ method: 'GET',
593
+ };
594
+ /* API */
595
+ const url = getUrl(this.hostname, this.port, config);
596
+ return http$(url, 'image', config, () => executeBlob(url, initCustom));
597
+ }
598
+ /**
599
+ * Recupera un file (es. PDF) tramite una richiesta GET e restituisce un Object URL temporaneo.
600
+ * Delega la logica di conversione alla funzione executeFile.
601
+ */
602
+ static readFile$(config) {
603
+ /* Config */
604
+ const initCustom = {
605
+ ...config.init,
606
+ method: 'GET',
607
+ };
608
+ /* Config custom (toast di default) */
609
+ const configCustom = {
610
+ ...config,
611
+ toast: config.hasToast === false ? undefined : (config.toast ?? CONFIG_TOAST_DEFAULT),
612
+ };
613
+ /* API */
614
+ const url = getUrl(this.hostname, this.port, config);
615
+ return http$(url, 'file', configCustom, () => executeBlob(url, initCustom));
616
+ }
617
+ /* ------------------------------------------------------------------------------- */
618
+ /* ---------------------------- Metodi: CRUD polling ----------------------------- */
619
+ /* ------------------------------------------------------------------------------- */
620
+ /**
621
+ * Avvia un ciclo di polling basato su richieste GET.
622
+ * Continua a emettere valori in base alla configurazione di intervallo definita in HttpConfigPolling.
623
+ */
624
+ static readPolling$(config) {
625
+ /* Config */
626
+ const initCustom = {
627
+ ...config.init,
628
+ method: 'GET',
629
+ };
630
+ /* API */
631
+ const url = getUrl(this.hostname, this.port, config);
632
+ return httpPolling$(url, config, () => executeHttp(url, initCustom));
633
+ }
634
+ /**
635
+ * Avvia un ciclo di polling basato su richieste POST.
636
+ * Invia il body specificato a ogni iterazione del ciclo.
637
+ */
638
+ static createPolling$(config, body) {
639
+ /* Config */
640
+ const initCustom = {
641
+ ...config.init,
642
+ method: 'POST',
643
+ headers: { 'Content-Type': 'application/json' },
644
+ body: JSON.stringify(body),
645
+ };
646
+ /* API */
647
+ const url = getUrl(this.hostname, this.port, config);
648
+ return httpPolling$(url, config, () => executeHttp(url, initCustom));
649
+ }
650
+ /**
651
+ * Avvia un ciclo di polling basato su richieste PUT.
652
+ */
653
+ static updatePolling$(config, body) {
654
+ /* Config */
655
+ const initCustom = {
656
+ ...config.init,
657
+ method: 'PUT',
658
+ };
659
+ if (body !== undefined) {
660
+ initCustom.headers = {
661
+ ...initCustom.headers,
662
+ 'Content-Type': 'application/json',
663
+ };
664
+ initCustom.body = JSON.stringify(body);
665
+ }
666
+ /* API */
667
+ const url = getUrl(this.hostname, this.port, config);
668
+ return httpPolling$(url, config, () => executeHttp(url, initCustom));
669
+ }
670
+ }
671
+
672
+ /**
673
+ * Generated bundle index. Do not edit.
674
+ */
675
+
676
+ export { EmitValueMode, MapOperator, PollingErrorMode, UniHttpManager };
677
+ //# sourceMappingURL=uni-manager-http.mjs.map