@@ -5,77 +5,7 @@ import './App.css';
55import { type Chunker , type Source , OpenTDF } from '@opentdf/sdk' ;
66import { type SessionInformation , OidcClient } from './session.js' ;
77import { c } from './config.js' ;
8-
9- /**
10- * Downloads a ReadableStream as a file by collecting its data and triggering a browser download.
11- * Supports aborting via AbortSignal in options.
12- *
13- * @param stream - The ReadableStream of Uint8Array data to download as a file.
14- * @param filename - The name for the downloaded file (default: 'download.tdf').
15- * @param options - Optional StreamPipeOptions, supports AbortSignal for cancellation.
16- * @returns Promise that resolves when the download is triggered or rejects if aborted.
17- */
18- export async function toFile (
19- stream : ReadableStream < Uint8Array > ,
20- filename = 'download.tdf' ,
21- options ?: StreamPipeOptions
22- ) : Promise < void > {
23- // Get a reader for the stream
24- const reader = stream . getReader ( ) ;
25- const chunks : Uint8Array [ ] = [ ] ;
26- let done = false ;
27- let aborted = false ;
28- const signal = options ?. signal ;
29- let abortHandler : ( ( ) => void ) | undefined ;
30-
31- // Setup abort handling if a signal is provided
32- if ( signal ) {
33- if ( signal . aborted ) {
34- throw new DOMException ( 'Aborted' , 'AbortError' ) ;
35- }
36- abortHandler = ( ) => {
37- aborted = true ;
38- reader . cancel ( ) ;
39- } ;
40- signal . addEventListener ( 'abort' , abortHandler ) ;
41- }
42- try {
43- // Read the stream chunk by chunk
44- while ( ! done ) {
45- if ( aborted ) {
46- throw new DOMException ( 'Aborted' , 'AbortError' ) ;
47- }
48- const { value, done : streamDone } = await reader . read ( ) ;
49- if ( value ) {
50- chunks . push ( value ) ; // Collect each chunk
51- }
52- done = streamDone ;
53- }
54- } finally {
55- // Clean up abort event listener
56- if ( signal && abortHandler ) {
57- signal . removeEventListener ( 'abort' , abortHandler ) ;
58- }
59- }
60- if ( aborted ) {
61- throw new DOMException ( 'Aborted' , 'AbortError' ) ;
62- }
63- // Create a Blob from the collected chunks
64- const blob = new Blob ( chunks ) ;
65- // Create a temporary object URL for the Blob
66- const url = URL . createObjectURL ( blob ) ;
67- // Create an anchor element and trigger the download
68- const a = document . createElement ( 'a' ) ;
69- a . href = url ;
70- a . download = filename ;
71- document . body . appendChild ( a ) ;
72- a . click ( ) ;
73- // Clean up the anchor and object URL after download is triggered
74- setTimeout ( ( ) => {
75- document . body . removeChild ( a ) ;
76- URL . revokeObjectURL ( url ) ;
77- } , 0 ) ;
78- }
8+ import { downloadReadableStream } from './utils/download-readable-stream' ;
799
8010function decryptedFileName ( encryptedFileName : string ) : string {
8111 // Groups: 1 file 'name' bit
@@ -450,7 +380,7 @@ function App() {
450380 try {
451381 switch ( sinkType ) {
452382 case 'file' :
453- await toFile ( cipherTextWithProgress , downloadName , { signal : sc . signal } ) ;
383+ await downloadReadableStream ( cipherTextWithProgress , downloadName , { signal : sc . signal } ) ;
454384 break ;
455385 case 'fsapi' :
456386 if ( ! f ) {
@@ -525,7 +455,7 @@ function App() {
525455 . pipeThrough ( progressTransformers . writer ) ;
526456 switch ( sinkType ) {
527457 case 'file' :
528- await toFile ( plainTextStream , dfn , { signal : sc . signal } ) ;
458+ await downloadReadableStream ( plainTextStream , dfn , { signal : sc . signal } ) ;
529459 break ;
530460 case 'fsapi' :
531461 if ( ! f ) {
0 commit comments