@inweb/client 25.3.17 → 25.3.18

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.
Files changed (43) hide show
  1. package/dist/client.js +698 -527
  2. package/dist/client.js.map +1 -1
  3. package/dist/client.min.js +1 -1
  4. package/dist/client.module.js +473 -484
  5. package/dist/client.module.js.map +1 -1
  6. package/lib/Api/Assembly.d.ts +32 -8
  7. package/lib/Api/ClashTest.d.ts +1 -1
  8. package/lib/Api/Client.d.ts +2 -3
  9. package/lib/Api/Fetch.d.ts +6 -0
  10. package/lib/Api/{impl/FetchError.d.ts → FetchError.d.ts} +2 -0
  11. package/lib/Api/File.d.ts +34 -10
  12. package/lib/Api/HttpClient.d.ts +9 -3
  13. package/lib/Api/IHttpClient.d.ts +10 -4
  14. package/lib/Api/Job.d.ts +1 -1
  15. package/lib/Api/Model.d.ts +33 -9
  16. package/lib/Api/Project.d.ts +3 -3
  17. package/lib/Api/User.d.ts +1 -1
  18. package/lib/Api/Utils.d.ts +11 -0
  19. package/lib/Api/XMLHttp.d.ts +7 -0
  20. package/lib/index.d.ts +1 -1
  21. package/package.json +1 -1
  22. package/src/Api/Assembly.ts +76 -70
  23. package/src/Api/ClashTest.ts +10 -19
  24. package/src/Api/Client.ts +92 -56
  25. package/src/Api/Fetch.ts +84 -0
  26. package/src/Api/{impl/http.ts → FetchError.ts} +33 -1
  27. package/src/Api/File.ts +112 -117
  28. package/src/Api/HttpClient.ts +107 -20
  29. package/src/Api/IHttpClient.ts +17 -12
  30. package/src/Api/Job.ts +7 -5
  31. package/src/Api/Member.ts +7 -5
  32. package/src/Api/Model.ts +61 -14
  33. package/src/Api/Permission.ts +6 -5
  34. package/src/Api/Project.ts +93 -88
  35. package/src/Api/Role.ts +6 -5
  36. package/src/Api/User.ts +28 -17
  37. package/src/Api/Utils.ts +104 -0
  38. package/src/Api/XMLHttp.ts +72 -0
  39. package/src/index.ts +1 -1
  40. package/lib/Api/impl/Utils.d.ts +0 -32
  41. package/lib/Api/impl/http.d.ts +0 -66
  42. package/src/Api/impl/FetchError.ts +0 -48
  43. package/src/Api/impl/Utils.ts +0 -367
package/src/Api/File.ts CHANGED
@@ -27,16 +27,7 @@ import { IShortUserDescription } from "./IUser";
27
27
  import { Model } from "./Model";
28
28
  import { Permission } from "./Permission";
29
29
  import { Job } from "./Job";
30
- import {
31
- json,
32
- text,
33
- downloadProgress,
34
- downloadPartOfFile,
35
- waitFor,
36
- parseArgs,
37
- userFullName,
38
- userInitials,
39
- } from "./impl/Utils";
30
+ import { waitFor, parseArgs, userFullName, userInitials } from "./Utils";
40
31
 
41
32
  /**
42
33
  * The class representing a `file` entity.
@@ -59,7 +50,6 @@ export class File {
59
50
 
60
51
  private appendVersionParam(relativePath: string): string {
61
52
  if (this._useVersion === undefined) return relativePath;
62
-
63
53
  const delimiter = relativePath.includes("?") ? "&" : "?";
64
54
  return `${relativePath}${delimiter}version=${this._useVersion}`;
65
55
  }
@@ -69,18 +59,12 @@ export class File {
69
59
  return this.httpClient.get(`${this.path}${relativePath}`, signal);
70
60
  }
71
61
 
72
- private internalPost(
73
- relativePath: string,
74
- body?: ArrayBuffer | Blob | globalThis.File | FormData | object | string | null
75
- ) {
62
+ private internalPost(relativePath: string, body?: BodyInit | object) {
76
63
  relativePath = this.appendVersionParam(relativePath);
77
64
  return this.httpClient.post(`${this.path}${relativePath}`, body);
78
65
  }
79
66
 
80
- private internalPut(
81
- relativePath: string,
82
- body?: ArrayBuffer | Blob | globalThis.File | FormData | object | string | null
83
- ) {
67
+ private internalPut(relativePath: string, body?: BodyInit | object) {
84
68
  relativePath = this.appendVersionParam(relativePath);
85
69
  return this.httpClient.put(`${this.path}${relativePath}`, body);
86
70
  }
@@ -90,52 +74,6 @@ export class File {
90
74
  return this.httpClient.delete(`${this.path}${relativePath}`);
91
75
  }
92
76
 
93
- async partialDownloadResource(
94
- dataId: string,
95
- onProgress?: (progress: number, downloaded: Uint8Array) => void,
96
- signal?: AbortSignal
97
- ) {
98
- let pathname = `${this.path}/downloads/${dataId}`;
99
- pathname = this.appendVersionParam(pathname);
100
-
101
- // TODO: replace with $get to handle fetch errors
102
- const response = await fetch(`${this.httpClient.serverUrl}${pathname}`, {
103
- headers: this.httpClient.headers,
104
- signal,
105
- });
106
-
107
- // TODO: use ReadableStream pipeTo()
108
- const contentLength = response.headers.get("Content-Length") ?? "";
109
- const total = parseInt(contentLength, 10);
110
- const reader = response.body.getReader();
111
- let loaded = 0;
112
- while (true) {
113
- const { done, value } = await reader.read();
114
- if (done) break;
115
- loaded += value.byteLength;
116
- if (typeof onProgress === "function") onProgress(loaded / total, value);
117
- }
118
- }
119
-
120
- downloadFileRange(
121
- requestId: number,
122
- records: any | null,
123
- dataId: string,
124
- onProgress?: (progress: number, downloaded: Uint8Array, requestId: number) => void,
125
- signal?: AbortSignal
126
- ) {
127
- let pathname = `${this.path}/downloads/${dataId}?requestId=${requestId}`;
128
- pathname = this.appendVersionParam(pathname);
129
- return downloadPartOfFile(
130
- requestId,
131
- records,
132
- `${this.httpClient.serverUrl}${pathname}`,
133
- this.httpClient.headers,
134
- onProgress,
135
- signal
136
- );
137
- }
138
-
139
77
  /**
140
78
  * Active version number of the file.
141
79
  *
@@ -201,8 +139,8 @@ export class File {
201
139
  }
202
140
 
203
141
  /**
204
- * Returns a list of formats in which the active version of the file was exported. To export
205
- * file to one of the supported formats create File Converter job using
142
+ * Returns a list of files in different formats in which the active version of the file was
143
+ * exported. To export file to one of the supported formats create File Converter job using
206
144
  * {@link File.createJob()}. To download exported file use {@link File.downloadResource()}.
207
145
  *
208
146
  * @readonly
@@ -377,7 +315,8 @@ export class File {
377
315
  * @async
378
316
  */
379
317
  async checkout(): Promise<File> {
380
- this.data = await json(this.internalGet(""));
318
+ const response = await this.internalGet("");
319
+ this.data = await response.json();
381
320
  return this;
382
321
  }
383
322
 
@@ -388,7 +327,8 @@ export class File {
388
327
  * @param data - Raw file data.
389
328
  */
390
329
  async update(data: any): Promise<File> {
391
- this.data = await json(this.internalPut("", data));
330
+ const response = await this.internalPut("", data);
331
+ this.data = await response.json();
392
332
  return this;
393
333
  }
394
334
 
@@ -399,7 +339,7 @@ export class File {
399
339
  * @returns Returns the raw data of a deleted file.
400
340
  */
401
341
  delete(): Promise<any> {
402
- return json(this.internalDelete(""));
342
+ return this.internalDelete("").then((response) => response.json());
403
343
  }
404
344
 
405
345
  /**
@@ -425,12 +365,9 @@ export class File {
425
365
  * Web API <a href="https://developer.mozilla.org/docs/Web/API/File"
426
366
  * target="_blank">File</a> object. Setting the `image` to `null` will remove the preview.
427
367
  */
428
- async setPreview(image?: ArrayBuffer | Blob | globalThis.File | FormData | string | null): Promise<File> {
429
- if (image) {
430
- this.data = await json(this.internalPost("/preview", image));
431
- } else {
432
- this.data = await json(this.internalDelete("/preview"));
433
- }
368
+ async setPreview(image: BodyInit | null): Promise<File> {
369
+ const response = await (image ? this.internalPost("/preview", image) : this.internalDelete("/preview"));
370
+ this.data = await response.json();
434
371
  return this;
435
372
  }
436
373
 
@@ -440,7 +377,9 @@ export class File {
440
377
  * @async
441
378
  */
442
379
  getModels(): Promise<Model[]> {
443
- return json(this.internalGet("/geometry")).then((array) => array.map((data) => new Model(data, this)));
380
+ return this.internalGet("/geometry")
381
+ .then((response) => response.json())
382
+ .then((array) => array.map((data) => new Model(data, this)));
444
383
  }
445
384
 
446
385
  // File does not support model transformation.
@@ -470,7 +409,8 @@ export class File {
470
409
  * to get properties for all objects in the file.
471
410
  */
472
411
  getProperties(handles?: string | string[]): Promise<any[]> {
473
- return json(this.internalGet(handles !== undefined ? `/properties?handles=${handles}` : "/properties"));
412
+ const relativePath = handles !== undefined ? `/properties?handles=${handles}` : "/properties";
413
+ return this.internalGet(relativePath).then((response) => response.json());
474
414
  }
475
415
 
476
416
  /**
@@ -519,7 +459,7 @@ export class File {
519
459
  */
520
460
 
521
461
  searchProperties(searchPattern: any): Promise<any[]> {
522
- return json(this.internalPost("/properties/search", searchPattern));
462
+ return this.internalPost("/properties/search", searchPattern).then((response) => response.json());
523
463
  }
524
464
 
525
465
  /**
@@ -528,7 +468,7 @@ export class File {
528
468
  * @async
529
469
  */
530
470
  getCdaTree(): Promise<any[]> {
531
- return json(this.internalGet(`/properties/tree`));
471
+ return this.internalGet(`/properties/tree`).then((response) => response.json());
532
472
  }
533
473
 
534
474
  /**
@@ -537,7 +477,9 @@ export class File {
537
477
  * @async
538
478
  */
539
479
  getViewpoints(): Promise<any[]> {
540
- return json(this.internalGet("/viewpoints")).then((viewpoints) => viewpoints.result);
480
+ return this.internalGet("/viewpoints")
481
+ .then((response) => response.json())
482
+ .then((viewpoints) => viewpoints.result);
541
483
  }
542
484
 
543
485
  /**
@@ -548,7 +490,7 @@ export class File {
548
490
  * @param viewpoint - Viewpoint.
549
491
  */
550
492
  saveViewpoint(viewpoint: any): Promise<any> {
551
- return json(this.internalPost("/viewpoints", viewpoint));
493
+ return this.internalPost("/viewpoints", viewpoint).then((response) => response.json());
552
494
  }
553
495
 
554
496
  /**
@@ -559,7 +501,7 @@ export class File {
559
501
  * @returns Returns the raw data of a deleted viewpoint.
560
502
  */
561
503
  deleteViewpoint(guid: string): Promise<any> {
562
- return json(this.internalDelete(`/viewpoints/${guid}`));
504
+ return this.internalDelete(`/viewpoints/${guid}`).then((response) => response.json());
563
505
  }
564
506
 
565
507
  /**
@@ -571,7 +513,7 @@ export class File {
571
513
  * @param guid - Viewpoint GUID.
572
514
  */
573
515
  getSnapshot(guid: string): Promise<string> {
574
- return text(this.internalGet(`/viewpoints/${guid}/snapshot`));
516
+ return this.internalGet(`/viewpoints/${guid}/snapshot`).then((response) => response.text());
575
517
  }
576
518
 
577
519
  /**
@@ -582,7 +524,7 @@ export class File {
582
524
  * @param bitmapGuid - Bitmap GUID.
583
525
  */
584
526
  getSnapshotData(guid: string, bitmapGuid: string): Promise<string> {
585
- return text(this.internalGet(`/viewpoints/${guid}/bitmaps/${bitmapGuid}`));
527
+ return this.internalGet(`/viewpoints/${guid}/bitmaps/${bitmapGuid}`).then((response) => response.text());
586
528
  }
587
529
 
588
530
  /**
@@ -595,24 +537,26 @@ export class File {
595
537
  * and abort it if desired.
596
538
  */
597
539
  download(onProgress?: (progress: number) => void, signal?: AbortSignal): Promise<ArrayBuffer> {
598
- return this.internalGet(`/downloads`, signal)
599
- .then((response) => downloadProgress(response, onProgress))
540
+ const relativePath = this.appendVersionParam("/downloads");
541
+ return this.httpClient
542
+ .downloadFile(`${this.path}${relativePath}`, onProgress, signal)
600
543
  .then((response) => response.arrayBuffer());
601
544
  }
602
545
 
603
546
  /**
604
- * Download file resource data of the active version of the file, such as exported file.
547
+ * Download a resource file of the active version of the file. Resource files are files that
548
+ * contain model scene descriptions, or geometry data, or exported files.
605
549
  *
606
550
  * @example <caption>Export file to DWG.</caption>
607
551
  * const job = await file.crateJob("dwg");
608
552
  * await job.waitForDone();
609
- * const resourceId = file.exports.find((x) => x.endsWith(".dwg"));
610
- * const arrayBuffer = await file.downloadResource(resourceId);
553
+ * const dwgFileName = file.exports.find((x) => x.endsWith(".dwg"));
554
+ * const arrayBuffer = await file.downloadResource(dwgFileName);
611
555
  * const blob = new Blob([arrayBuffer]);
612
556
  * const fileName = file.name.replace(/\.[^.]+$/, "") + ".dwg";
613
557
  * FileSaver.saveAs(blob, fileName);
614
558
  *
615
- * @param dataId - Resource ID.
559
+ * @param dataId - Resource file name.
616
560
  * @param onProgress - Download progress callback.
617
561
  * @param signal - An <a href="https://developer.mozilla.org/docs/Web/API/AbortSignal" target
618
562
  * ="_blank">AbortSignal</a> object instance. Allows to communicate with a fetch request
@@ -620,14 +564,67 @@ export class File {
620
564
  */
621
565
  downloadResource(
622
566
  dataId: string,
623
- onProgress?: (progress: number) => void,
567
+ onProgress?: (progress: number, chunk: Uint8Array) => void,
568
+ signal?: AbortSignal
569
+ ): Promise<ArrayBuffer> {
570
+ const relativePath = this.appendVersionParam(`/downloads/${dataId}`);
571
+ return this.httpClient
572
+ .downloadFile(`${this.path}${relativePath}`, onProgress, signal)
573
+ .then((response) => response.arrayBuffer());
574
+ }
575
+
576
+ /**
577
+ * Download a part of resource file of the active version of the file. Resource files are
578
+ * files that contain model scene descriptions, or geometry data, or exported files.
579
+ *
580
+ * @param dataId - Resource file name.
581
+ * @param ranges - A range of resource file contents to download.
582
+ * @param requestId - Request ID for download progress callback.
583
+ * @param onProgress - Download progress callback.
584
+ * @param signal - An <a href="https://developer.mozilla.org/docs/Web/API/AbortSignal" target
585
+ * ="_blank">AbortSignal</a> object instance. Allows to communicate with a fetch request
586
+ * and abort it if desired.
587
+ */
588
+ downloadResourceRange(
589
+ dataId: string,
590
+ ranges: Array<{ begin: number; end: number; requestId: number }>,
591
+ requestId: number,
592
+ onProgress?: (progress: number, chunk: Uint8Array, requestId: number) => void,
624
593
  signal?: AbortSignal
625
594
  ): Promise<ArrayBuffer> {
626
- return this.internalGet(`/downloads/${dataId}`, signal)
627
- .then((response) => downloadProgress(response, onProgress))
595
+ const relativePath = this.appendVersionParam(`/downloads/${dataId}?requestId=${requestId}`);
596
+ return this.httpClient
597
+ .downloadFileRange(`${this.path}${relativePath}`, ranges, onProgress, signal)
628
598
  .then((response) => response.arrayBuffer());
629
599
  }
630
600
 
601
+ /**
602
+ * Deprecated since `25.3`. Use {@link File.downloadResource()} instead.
603
+ */
604
+ partialDownloadResource(
605
+ dataId: string,
606
+ onProgress?: (progress: number, downloaded: Uint8Array) => void,
607
+ signal?: AbortSignal
608
+ ): Promise<ArrayBuffer> {
609
+ console.warn(
610
+ "File.partialDownloadResource() has been deprecated since 25.3 and will be removed in a future release, use File.downloadResource() instead."
611
+ );
612
+ return this.downloadResource(dataId, onProgress, signal);
613
+ }
614
+
615
+ /**
616
+ * Deprecated since `25.3`. Use {@link File.downloadResourceRange()} instead.
617
+ */
618
+ async downloadFileRange(
619
+ requestId: number,
620
+ records: any | null,
621
+ dataId: string,
622
+ onProgress?: (progress: number, downloaded: Uint8Array, requestId: number) => void,
623
+ signal?: AbortSignal
624
+ ): Promise<void> {
625
+ await this.downloadResourceRange(dataId, records, requestId, onProgress, signal);
626
+ }
627
+
631
628
  /**
632
629
  * Returns a list of references to files used to correct rendering of the current file.
633
630
  *
@@ -637,7 +634,7 @@ export class File {
637
634
  * signal object instance, which can be used to abort waiting as desired.
638
635
  */
639
636
  getReferences(signal?: AbortSignal): Promise<IFileReferences> {
640
- return json(this.internalGet("/references", signal));
637
+ return this.internalGet("/references", signal).then((response) => response.json());
641
638
  }
642
639
 
643
640
  /**
@@ -647,7 +644,7 @@ export class File {
647
644
  * @param references - File references.
648
645
  */
649
646
  setReferences(references: IFileReferences): Promise<IFileReferences> {
650
- return json(this.internalPut("/references", references));
647
+ return this.internalPut("/references", references).then((response) => response.json());
651
648
  }
652
649
 
653
650
  /**
@@ -671,9 +668,9 @@ export class File {
671
668
  * for the File Converter tool in form "--arg=value".
672
669
  */
673
670
  createJob(outputFormat: string, parameters?: string | object): Promise<Job> {
674
- const pathname = this.appendVersionParam("/jobs");
671
+ const relativePath = this.appendVersionParam("/jobs");
675
672
  return this.httpClient
676
- .post(pathname, {
673
+ .post(relativePath, {
677
674
  fileId: this.id,
678
675
  outputFormat,
679
676
  parameters: parseArgs(parameters),
@@ -779,9 +776,9 @@ export class File {
779
776
  * @async
780
777
  */
781
778
  getPermissions(): Promise<Permission[]> {
782
- return json(this.internalGet("/permissions")).then((array) =>
783
- array.map((data) => new Permission(data, this.id, this.httpClient))
784
- );
779
+ return this.internalGet("/permissions")
780
+ .then((response) => response.json())
781
+ .then((array) => array.map((data) => new Permission(data, this.id, this.httpClient)));
785
782
  }
786
783
 
787
784
  /**
@@ -791,9 +788,9 @@ export class File {
791
788
  * @param permissionId - Permission ID.
792
789
  */
793
790
  getPermission(permissionId: string): Promise<Permission> {
794
- return json(this.internalGet(`/permissions/${permissionId}`)).then(
795
- (data) => new Permission(data, this.id, this.httpClient)
796
- );
791
+ return this.internalGet(`/permissions/${permissionId}`)
792
+ .then((response) => response.json())
793
+ .then((data) => new Permission(data, this.id, this.httpClient));
797
794
  }
798
795
 
799
796
  /**
@@ -806,13 +803,13 @@ export class File {
806
803
  * @param public = false - Specifies whether all users have access to the file or not.
807
804
  */
808
805
  createPermission(actions: string | string[], grantedTo: any[], _public: boolean): Promise<Permission> {
809
- return json(
810
- this.internalPost("/permissions", {
811
- actions: typeof actions === "string" ? [actions] : actions,
812
- grantedTo,
813
- public: _public,
814
- })
815
- ).then((data) => new Permission(data, this.id, this.httpClient));
806
+ return this.internalPost("/permissions", {
807
+ actions: Array.isArray(actions) ? actions : [actions],
808
+ grantedTo,
809
+ public: _public,
810
+ })
811
+ .then((response) => response.json())
812
+ .then((data) => new Permission(data, this.id, this.httpClient));
816
813
  }
817
814
 
818
815
  /**
@@ -823,7 +820,7 @@ export class File {
823
820
  * @returns Returns the raw data of a deleted permission.
824
821
  */
825
822
  deletePermission(permissionId: string): Promise<any> {
826
- return json(this.internalDelete(`/permissions/${permissionId}`));
823
+ return this.internalDelete(`/permissions/${permissionId}`).then((response) => response.json());
827
824
  }
828
825
 
829
826
  /**
@@ -864,7 +861,7 @@ export class File {
864
861
  }
865
862
  ): Promise<File> {
866
863
  const result = await this.httpClient
867
- .postFile(`${this.path}/versions`, file, (progress) => params.onProgress?.(progress, file))
864
+ .uploadFile(`${this.path}/versions`, file, (progress) => params.onProgress?.(progress, file))
868
865
  .then((xhr: XMLHttpRequest) => JSON.parse(xhr.responseText))
869
866
  .then((data) => new File(data, this.httpClient));
870
867
 
@@ -914,11 +911,9 @@ export class File {
914
911
  */
915
912
  async deleteVersion(version: number): Promise<any> {
916
913
  const response = await this.internalDelete(`/versions/${version}`);
917
- const result = await response.json();
918
-
914
+ const data = await response.json();
919
915
  await this.checkout();
920
-
921
- return result;
916
+ return data;
922
917
  }
923
918
 
924
919
  /**
@@ -22,7 +22,8 @@
22
22
  ///////////////////////////////////////////////////////////////////////////////
23
23
 
24
24
  import { IHttpClient } from "./IHttpClient";
25
- import { $get, $delete, $post, $put, $XMLHttp } from "./impl/Utils";
25
+ import { $fetch } from "./Fetch";
26
+ import { $xmlhttp } from "./XMLHttp";
26
27
 
27
28
  export class HttpClient implements IHttpClient {
28
29
  serverUrl: string;
@@ -34,40 +35,126 @@ export class HttpClient implements IHttpClient {
34
35
  }
35
36
 
36
37
  get(relativePath: string, signal?: AbortSignal): Promise<Response> {
37
- return $get(`${this.serverUrl}${relativePath}`, this.headers, signal);
38
+ return $fetch(`${this.serverUrl}${relativePath}`, { method: "GET", headers: this.headers, signal });
38
39
  }
39
40
 
40
- post(
41
- relativePath: string,
42
- body?: string | object | ArrayBuffer | Blob | globalThis.File | FormData
43
- ): Promise<Response> {
44
- return $post(`${this.serverUrl}${relativePath}`, this.headers, body);
41
+ post(relativePath: string, body?: BodyInit | object): Promise<Response> {
42
+ return $fetch(`${this.serverUrl}${relativePath}`, { method: "POST", headers: this.headers, body });
45
43
  }
46
44
 
47
- put(
48
- relativePath: string,
49
- body?: string | object | ArrayBuffer | Blob | globalThis.File | FormData
50
- ): Promise<Response> {
51
- return $put(`${this.serverUrl}${relativePath}`, this.headers, body);
45
+ put(relativePath: string, body?: BodyInit | object): Promise<Response> {
46
+ return $fetch(`${this.serverUrl}${relativePath}`, { method: "PUT", headers: this.headers, body });
52
47
  }
53
48
 
54
49
  delete(relativePath: string): Promise<Response> {
55
- return $delete(`${this.serverUrl}${relativePath}`, this.headers);
50
+ return $fetch(`${this.serverUrl}${relativePath}`, { method: "DELETE", headers: this.headers });
56
51
  }
57
52
 
58
- postFile(
59
- relativePath: string,
60
- file: globalThis.File,
61
- onProgress?: (progress: number) => void
62
- ): Promise<XMLHttpRequest> {
53
+ uploadFile(relativePath: string, file: File, onProgress?: (progress: number) => void): Promise<XMLHttpRequest> {
63
54
  const data = new FormData();
64
55
  data.append("file", file);
65
-
66
- return $XMLHttp(`${this.serverUrl}${relativePath}`, {
56
+ return $xmlhttp(`${this.serverUrl}${relativePath}`, {
67
57
  method: "POST",
68
58
  headers: this.headers,
69
59
  body: data,
70
60
  uploadProgress: onProgress,
71
61
  });
72
62
  }
63
+
64
+ // async downloadFile(
65
+ // relativePath: string,
66
+ // onProgress?: (progress: number, chunk: Uint8Array) => void,
67
+ // signal?: AbortSignal
68
+ // ): Promise<Response> {
69
+ // const response = await this.get(relativePath, signal);
70
+ // const teedOff = response.body.tee();
71
+ // if (onProgress) {
72
+ // const contentLength = response.headers.get("Content-Length");
73
+ // const total = parseInt(contentLength, 10) || 1;
74
+ // let loaded = 0;
75
+ // const reader = teedOff[0].getReader();
76
+ // reader.read().then(function processChunk({ done, value }) {
77
+ // if (done) return;
78
+ // loaded += value.length;
79
+ // onProgress(loaded / total, value);
80
+ // reader.read().then(processChunk);
81
+ // });
82
+ // }
83
+ // return new Response(teedOff[1]);
84
+ // }
85
+
86
+ async downloadFile(
87
+ relativePath: string,
88
+ onProgress?: (progress: number, chunk: Uint8Array) => void,
89
+ signal?: AbortSignal
90
+ ): Promise<Response> {
91
+ const response = await this.get(relativePath, signal);
92
+ const contentLength = response.headers.get("Content-Length");
93
+ const total = parseInt(contentLength, 10) || 1;
94
+ return new Response(
95
+ new ReadableStream({
96
+ async start(controller) {
97
+ const reader = response.body.getReader();
98
+ let loaded = 0;
99
+ while (true) {
100
+ const { done, value } = await reader.read();
101
+ if (done) break;
102
+ controller.enqueue(value);
103
+ loaded += value.length;
104
+ if (onProgress) onProgress(loaded / total, value);
105
+ }
106
+ controller.close();
107
+ },
108
+ })
109
+ );
110
+ }
111
+
112
+ async downloadFileRange(
113
+ relativePath: string,
114
+ ranges: Array<{ begin: number; end: number; requestId: number }>,
115
+ onProgress?: (progress: number, chunk: Uint8Array, requestId: number) => void,
116
+ signal?: AbortSignal
117
+ ): Promise<Response> {
118
+ const headers = { ...this.headers };
119
+ headers["Range"] = "bytes=" + ranges.map((x) => `${x.begin}-${x.end}`).join(",");
120
+ const response = await $fetch(`${this.serverUrl}${relativePath}`, { method: "GET", headers, signal });
121
+ const contentLength = response.headers.get("content-length");
122
+ const total = parseInt(contentLength, 10) || 1;
123
+ return new Response(
124
+ new ReadableStream({
125
+ async start(controller) {
126
+ const reader = response.body.getReader();
127
+ let loaded = 0;
128
+ let rangedIndex = 0;
129
+ let rangePos = 0;
130
+ while (true) {
131
+ const { done, value } = await reader.read();
132
+ if (done) break;
133
+ controller.enqueue(value);
134
+ loaded += value.length;
135
+ let chunkLeft = value.length;
136
+ let chunkPos = 0;
137
+ while (chunkLeft > 0) {
138
+ const range = ranges[rangedIndex];
139
+ const rangeLeft = range.end - range.begin - rangePos;
140
+ if (chunkLeft < rangeLeft) {
141
+ const chunk = value.subarray(chunkPos, chunkPos + chunkLeft);
142
+ if (onProgress) onProgress(loaded / total, chunk, range.requestId);
143
+ rangePos += chunkLeft;
144
+ chunkLeft = 0;
145
+ } else {
146
+ const chunk = value.subarray(chunkPos, chunkPos + rangeLeft);
147
+ if (onProgress) onProgress(loaded / total, chunk, range.requestId);
148
+ chunkPos += rangeLeft;
149
+ chunkLeft -= rangeLeft;
150
+ rangedIndex++;
151
+ rangePos = 0;
152
+ }
153
+ }
154
+ }
155
+ controller.close();
156
+ },
157
+ })
158
+ );
159
+ }
73
160
  }
@@ -23,28 +23,33 @@
23
23
 
24
24
  export interface IHttpClient {
25
25
  serverUrl: string;
26
-
27
26
  headers: HeadersInit;
28
-
29
27
  signInUserId: string;
30
28
 
31
- get(relativePath, signal?: AbortSignal): Promise<Response>;
29
+ get(relativePath: string, signal?: AbortSignal): Promise<Response>;
32
30
 
33
- post(
34
- relativePath: string,
35
- body?: ArrayBuffer | Blob | globalThis.File | FormData | object | string | null
36
- ): Promise<Response>;
31
+ post(relativePath: string, body?: BodyInit | object): Promise<Response>;
37
32
 
38
- put(
39
- relativePath: string,
40
- body?: ArrayBuffer | Blob | globalThis.File | FormData | object | string | null
41
- ): Promise<Response>;
33
+ put(relativePath: string, body?: BodyInit | object): Promise<Response>;
42
34
 
43
35
  delete(relativePath: string): Promise<Response>;
44
36
 
45
- postFile(
37
+ uploadFile(
46
38
  relativePath: string,
47
39
  file: globalThis.File,
48
40
  onProgress?: (progress: number) => void
49
41
  ): Promise<XMLHttpRequest>;
42
+
43
+ downloadFile(
44
+ relativePath: string,
45
+ onProgress?: (progress: number, chunk: Uint8Array) => void,
46
+ signal?: AbortSignal
47
+ ): Promise<Response>;
48
+
49
+ downloadFileRange(
50
+ relativePath: string,
51
+ ranges: Array<{ begin: number; end: number; requestId: number }>,
52
+ onProgress?: (progress: number, chunk: Uint8Array, requestId: number) => void,
53
+ signal?: AbortSignal
54
+ ): Promise<Response>;
50
55
  }