🚨 Latest Research:Tanstack npm Packages Compromised in Ongoing Mini Shai-Hulud Supply-Chain Attack.Learn More
Socket
Book a DemoSign in
Socket

@php-wasm/progress

Package Overview
Dependencies
Maintainers
8
Versions
237
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@php-wasm/progress - npm Package Compare versions

Comparing version
3.1.19
to
3.1.20
+1
-1
index.cjs

@@ -1,2 +0,2 @@

"use strict";var T=r=>{throw TypeError(r)};var P=(r,e,s)=>e.has(r)||T("Cannot "+s);var n=(r,e,s)=>(P(r,e,"read from private field"),s?s.call(r):e.get(r)),c=(r,e,s)=>e.has(r)?T("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(r):e.set(r,s),_=(r,e,s,t)=>(P(r,e,"write to private field"),t?t.call(r,s):e.set(r,s),s),v=(r,e,s)=>(P(r,e,"access private method"),s);var b=(r,e,s,t)=>({set _(o){_(r,e,o,s)},get _(){return n(r,e,t)}});Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});require("@php-wasm/node-polyfills");const O=require("@php-wasm/logger"),k=5*1024*1024;var l,g,m,C;class S extends EventTarget{constructor(){super(...arguments);c(this,m);c(this,l,{});c(this,g,{})}expectAssets(s){for(const[t,o]of Object.entries(s)){const i="http://example.com/",a=new URL(t,i).pathname.split("/").pop();a in n(this,l)||(n(this,l)[a]=o),a in n(this,g)||(n(this,g)[a]=0)}}async monitorFetch(s){const t=await s;return M(t,i=>{v(this,m,C).call(this,t.url,i.detail.loaded,i.detail.total)})}}l=new WeakMap,g=new WeakMap,m=new WeakSet,C=function(s,t,o){const i=new URL(s,"http://example.com").pathname.split("/").pop();o?i in n(this,l)||(n(this,l)[i]=o,n(this,g)[i]=t):o=n(this,l)[i],i in n(this,g)||O.logger.warn(`Registered a download #progress of an unregistered file "${i}". This may cause a sudden **decrease** in the #progress percentage as the length number of bytes increases during the download.`),n(this,g)[i]=t,this.dispatchEvent(new CustomEvent("progress",{detail:{loaded:I(n(this,g)),total:I(n(this,l))}}))};function I(r){return Object.values(r).reduce((e,s)=>e+s,0)}function M(r,e){const s=r.headers.get("content-length")||"",t=parseInt(s,10)||k;return new Response(R(r.body,t,e),{status:r.status,statusText:r.statusText,headers:r.headers})}function R(r,e,s){let t=0;function o(i,f,a){const h=performance.now();!a&&h-t<500||(t=h,s(new CustomEvent("progress",{detail:{loaded:i,total:f}})))}return new ReadableStream({async start(i){if(!r){i.close();return}const f=r.getReader();let a=0;for(;;)try{const{done:h,value:E}=await f.read();if(E&&(a+=E.byteLength),h){o(a,a,h),i.close();break}else o(a,e,h),i.enqueue(E)}catch(h){O.logger.error({e:h}),i.error(h);break}}})}var d,u,p,L;class x extends EventTarget{constructor(){super(...arguments);c(this,p);c(this,d);c(this,u);_(this,d,{}),_(this,u,0),this.progress=0,this.mode="REAL_TIME",this.caption=""}partialObserver(s,t=""){const o=++b(this,u)._;return n(this,d)[o]=0,i=>{const{loaded:f,total:a}=(i==null?void 0:i.detail)||{};n(this,d)[o]=f/a*s,v(this,p,L).call(this,this.totalProgress,"REAL_TIME",t)}}slowlyIncrementBy(s){const t=++b(this,u)._;n(this,d)[t]=s,v(this,p,L).call(this,this.totalProgress,"SLOWLY_INCREMENT")}get totalProgress(){return Object.values(n(this,d)).reduce((s,t)=>s+t,0)}}d=new WeakMap,u=new WeakMap,p=new WeakSet,L=function(s,t,o){this.dispatchEvent(new CustomEvent("progress",{detail:{progress:s,mode:t,caption:o}}))};const w=1e-5;class y extends EventTarget{constructor({weight:e=1,caption:s="",fillTime:t=4}={}){super(),this._selfWeight=1,this._selfDone=!1,this._selfProgress=0,this._selfCaption="",this._isFilling=!1,this._subTrackers=[],this._weight=e,this._selfCaption=s,this._fillTime=t}stage(e,s=""){if(e||(e=this._selfWeight),this._selfWeight-e<-w)throw new Error(`Cannot add a stage with weight ${e} as the total weight of registered stages would exceed 1.`);this._selfWeight-=e;const t=new y({caption:s,weight:e,fillTime:this._fillTime});return this._subTrackers.push(t),t.addEventListener("progress",()=>this.notifyProgress()),t.addEventListener("done",()=>{this.done&&this.notifyDone()}),t}fillSlowly({stopBeforeFinishing:e=!0}={}){if(this._isFilling)return;this._isFilling=!0;const t=this._fillTime/100;this._fillInterval=setInterval(()=>{this.set(this._selfProgress+1),e&&this._selfProgress>=99&&clearInterval(this._fillInterval)},t)}set(e){this._selfProgress=Math.min(e,100),this.notifyProgress(),this._selfProgress+w>=100&&this.finish()}finish(){this._fillInterval&&clearInterval(this._fillInterval),this._selfDone=!0,this._selfProgress=100,this._isFilling=!1,this._fillInterval=void 0,this.notifyProgress(),this.notifyDone()}get caption(){for(let e=this._subTrackers.length-1;e>=0;e--)if(!this._subTrackers[e].done){const s=this._subTrackers[e].caption;if(s)return s}return this._selfCaption}setCaption(e){this._selfCaption=e,this.notifyProgress()}get done(){return this.progress+w>=100}get progress(){if(this._selfDone)return 100;const e=this._subTrackers.reduce((s,t)=>s+t.progress*t.weight,this._selfProgress*this._selfWeight);return Math.round(e*1e4)/1e4}get weight(){return this._weight}get observer(){return this._progressObserver||(this._progressObserver=e=>{this.set(e)}),this._progressObserver}get loadingListener(){return this._loadingListener||(this._loadingListener=e=>{this.set(e.detail.loaded/e.detail.total*100)}),this._loadingListener}pipe(e){e.setProgress({progress:this.progress,caption:this.caption}),this.addEventListener("progress",s=>{e.setProgress({progress:s.detail.progress,caption:s.detail.caption})}),this.addEventListener("done",()=>{e.setLoaded()})}addEventListener(e,s){super.addEventListener(e,s)}removeEventListener(e,s){super.removeEventListener(e,s)}notifyProgress(){const e=this;this.dispatchEvent(new CustomEvent("progress",{detail:{get progress(){return e.progress},get caption(){return e.caption}}}))}notifyDone(){this.dispatchEvent(new CustomEvent("done"))}}exports.EmscriptenDownloadMonitor=S;exports.ProgressObserver=x;exports.ProgressTracker=y;exports.cloneResponseMonitorProgress=M;exports.cloneStreamMonitorProgress=R;
"use strict";var T=r=>{throw TypeError(r)};var P=(r,e,s)=>e.has(r)||T("Cannot "+s);var n=(r,e,s)=>(P(r,e,"read from private field"),s?s.call(r):e.get(r)),c=(r,e,s)=>e.has(r)?T("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(r):e.set(r,s),_=(r,e,s,t)=>(P(r,e,"write to private field"),t?t.call(r,s):e.set(r,s),s),v=(r,e,s)=>(P(r,e,"access private method"),s);var b=(r,e,s,t)=>({set _(o){_(r,e,o,s)},get _(){return n(r,e,t)}});Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const O=require("@php-wasm/logger"),k=5*1024*1024;var l,g,m,C;class S extends EventTarget{constructor(){super(...arguments);c(this,m);c(this,l,{});c(this,g,{})}expectAssets(s){for(const[t,o]of Object.entries(s)){const i="http://example.com/",a=new URL(t,i).pathname.split("/").pop();a in n(this,l)||(n(this,l)[a]=o),a in n(this,g)||(n(this,g)[a]=0)}}async monitorFetch(s){const t=await s;return M(t,i=>{v(this,m,C).call(this,t.url,i.detail.loaded,i.detail.total)})}}l=new WeakMap,g=new WeakMap,m=new WeakSet,C=function(s,t,o){const i=new URL(s,"http://example.com").pathname.split("/").pop();o?i in n(this,l)||(n(this,l)[i]=o,n(this,g)[i]=t):o=n(this,l)[i],i in n(this,g)||O.logger.warn(`Registered a download #progress of an unregistered file "${i}". This may cause a sudden **decrease** in the #progress percentage as the length number of bytes increases during the download.`),n(this,g)[i]=t,this.dispatchEvent(new CustomEvent("progress",{detail:{loaded:I(n(this,g)),total:I(n(this,l))}}))};function I(r){return Object.values(r).reduce((e,s)=>e+s,0)}function M(r,e){const s=r.headers.get("content-length")||"",t=parseInt(s,10)||k;return new Response(R(r.body,t,e),{status:r.status,statusText:r.statusText,headers:r.headers})}function R(r,e,s){let t=0;function o(i,f,a){const h=performance.now();!a&&h-t<500||(t=h,s(new CustomEvent("progress",{detail:{loaded:i,total:f}})))}return new ReadableStream({async start(i){if(!r){i.close();return}const f=r.getReader();let a=0;for(;;)try{const{done:h,value:E}=await f.read();if(E&&(a+=E.byteLength),h){o(a,a,h),i.close();break}else o(a,e,h),i.enqueue(E)}catch(h){O.logger.error({e:h}),i.error(h);break}}})}var d,u,p,L;class x extends EventTarget{constructor(){super(...arguments);c(this,p);c(this,d);c(this,u);_(this,d,{}),_(this,u,0),this.progress=0,this.mode="REAL_TIME",this.caption=""}partialObserver(s,t=""){const o=++b(this,u)._;return n(this,d)[o]=0,i=>{const{loaded:f,total:a}=(i==null?void 0:i.detail)||{};n(this,d)[o]=f/a*s,v(this,p,L).call(this,this.totalProgress,"REAL_TIME",t)}}slowlyIncrementBy(s){const t=++b(this,u)._;n(this,d)[t]=s,v(this,p,L).call(this,this.totalProgress,"SLOWLY_INCREMENT")}get totalProgress(){return Object.values(n(this,d)).reduce((s,t)=>s+t,0)}}d=new WeakMap,u=new WeakMap,p=new WeakSet,L=function(s,t,o){this.dispatchEvent(new CustomEvent("progress",{detail:{progress:s,mode:t,caption:o}}))};const w=1e-5;class y extends EventTarget{constructor({weight:e=1,caption:s="",fillTime:t=4}={}){super(),this._selfWeight=1,this._selfDone=!1,this._selfProgress=0,this._selfCaption="",this._isFilling=!1,this._subTrackers=[],this._weight=e,this._selfCaption=s,this._fillTime=t}stage(e,s=""){if(e||(e=this._selfWeight),this._selfWeight-e<-w)throw new Error(`Cannot add a stage with weight ${e} as the total weight of registered stages would exceed 1.`);this._selfWeight-=e;const t=new y({caption:s,weight:e,fillTime:this._fillTime});return this._subTrackers.push(t),t.addEventListener("progress",()=>this.notifyProgress()),t.addEventListener("done",()=>{this.done&&this.notifyDone()}),t}fillSlowly({stopBeforeFinishing:e=!0}={}){if(this._isFilling)return;this._isFilling=!0;const t=this._fillTime/100;this._fillInterval=setInterval(()=>{this.set(this._selfProgress+1),e&&this._selfProgress>=99&&clearInterval(this._fillInterval)},t)}set(e){this._selfProgress=Math.min(e,100),this.notifyProgress(),this._selfProgress+w>=100&&this.finish()}finish(){this._fillInterval&&clearInterval(this._fillInterval),this._selfDone=!0,this._selfProgress=100,this._isFilling=!1,this._fillInterval=void 0,this.notifyProgress(),this.notifyDone()}get caption(){for(let e=this._subTrackers.length-1;e>=0;e--)if(!this._subTrackers[e].done){const s=this._subTrackers[e].caption;if(s)return s}return this._selfCaption}setCaption(e){this._selfCaption=e,this.notifyProgress()}get done(){return this.progress+w>=100}get progress(){if(this._selfDone)return 100;const e=this._subTrackers.reduce((s,t)=>s+t.progress*t.weight,this._selfProgress*this._selfWeight);return Math.round(e*1e4)/1e4}get weight(){return this._weight}get observer(){return this._progressObserver||(this._progressObserver=e=>{this.set(e)}),this._progressObserver}get loadingListener(){return this._loadingListener||(this._loadingListener=e=>{this.set(e.detail.loaded/e.detail.total*100)}),this._loadingListener}pipe(e){e.setProgress({progress:this.progress,caption:this.caption}),this.addEventListener("progress",s=>{e.setProgress({progress:s.detail.progress,caption:s.detail.caption})}),this.addEventListener("done",()=>{e.setLoaded()})}addEventListener(e,s){super.addEventListener(e,s)}removeEventListener(e,s){super.removeEventListener(e,s)}notifyProgress(){const e=this;this.dispatchEvent(new CustomEvent("progress",{detail:{get progress(){return e.progress},get caption(){return e.caption}}}))}notifyDone(){this.dispatchEvent(new CustomEvent("done"))}}exports.EmscriptenDownloadMonitor=S;exports.ProgressObserver=x;exports.ProgressTracker=y;exports.cloneResponseMonitorProgress=M;exports.cloneStreamMonitorProgress=R;
//# sourceMappingURL=index.cjs.map

@@ -1,1 +0,1 @@

{"version":3,"file":"index.cjs","sources":["../../../../packages/php-wasm/progress/src/lib/emscripten-download-monitor.ts","../../../../packages/php-wasm/progress/src/lib/progress-observer.ts","../../../../packages/php-wasm/progress/src/lib/progress-tracker.ts"],"sourcesContent":["import { logger } from '@php-wasm/logger';\n/*\n * An approximate file length to use when the actual\n * length number of bytes is missing.\n *\n * This may happen when the files are compressed before transmission\n * and no content-length header is being sent.\n *\n * The approximation isn't accurate, but it's better than nothing.\n * It's not about being exact but about giving the user a rough sense\n * of #progress.\n */\nconst FALLBACK_FILE_SIZE = 5 * 1024 * 1024;\n\n/**\n * Monitors the download #progress of Emscripten modules\n *\n * Usage:\n *\n * ```js\n * const downloadMonitor = new EmscriptenDownloadMonitor();\n * \t const php = await startPHP(\n * phpLoaderModule,\n * 'web',\n * downloadMonitor.phpArgs\n * );\n * downloadMonitor.addEventListener('#progress', (e) => {\n * console.log( e.detail.#progress);\n * })\n * ```\n */\nexport class EmscriptenDownloadMonitor extends EventTarget {\n\t#assetsSizes: Record<string, number> = {};\n\t#progress: Record<string, number> = {};\n\n\texpectAssets(assets: Record<string, number>) {\n\t\tfor (const [urlLike, size] of Object.entries(assets)) {\n\t\t\tconst dummyBaseUrl = 'http://example.com/';\n\t\t\tconst pathname = new URL(urlLike, dummyBaseUrl).pathname;\n\t\t\tconst filename = pathname.split('/').pop()!;\n\t\t\tif (!(filename in this.#assetsSizes)) {\n\t\t\t\tthis.#assetsSizes[filename] = size;\n\t\t\t}\n\t\t\tif (!(filename in this.#progress)) {\n\t\t\t\tthis.#progress[filename] = 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tasync monitorFetch(fetchPromise: Promise<Response>): Promise<Response> {\n\t\tconst response = await fetchPromise;\n\t\tconst onProgress = (event: CustomEvent<DownloadProgress>) => {\n\t\t\tthis.#notify(response.url, event.detail.loaded, event.detail.total);\n\t\t};\n\t\treturn cloneResponseMonitorProgress(response, onProgress);\n\t}\n\n\t/**\n\t * Notifies about the download #progress of a file.\n\t *\n\t * @param file The file name.\n\t * @param loaded The number of bytes of that file loaded so far.\n\t * @param fileSize The length number of bytes in the loaded file.\n\t */\n\t#notify(file: string, loaded: number, fileSize: number) {\n\t\tconst fileName = new URL(file, 'http://example.com').pathname\n\t\t\t.split('/')\n\t\t\t.pop()!;\n\t\tif (!fileSize) {\n\t\t\tfileSize = this.#assetsSizes[fileName];\n\t\t} else if (!(fileName in this.#assetsSizes)) {\n\t\t\tthis.#assetsSizes[fileName] = fileSize;\n\t\t\tthis.#progress[fileName] = loaded;\n\t\t}\n\t\tif (!(fileName in this.#progress)) {\n\t\t\tlogger.warn(\n\t\t\t\t`Registered a download #progress of an unregistered file \"${fileName}\". ` +\n\t\t\t\t\t`This may cause a sudden **decrease** in the #progress percentage as the ` +\n\t\t\t\t\t`length number of bytes increases during the download.`\n\t\t\t);\n\t\t}\n\n\t\tthis.#progress[fileName] = loaded;\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('progress', {\n\t\t\t\tdetail: {\n\t\t\t\t\tloaded: sumValues(this.#progress),\n\t\t\t\t\ttotal: sumValues(this.#assetsSizes),\n\t\t\t\t},\n\t\t\t})\n\t\t);\n\t}\n}\n\nfunction sumValues(obj: Record<string, number>) {\n\treturn Object.values(obj).reduce((length, value) => length + value, 0);\n}\n\nexport default EmscriptenDownloadMonitor;\n\nexport interface DownloadProgress {\n\t/**\n\t * The number of bytes loaded so far.\n\t */\n\tloaded: number;\n\t/**\n\t * The length number of bytes to load.\n\t */\n\ttotal: number;\n}\n\n/**\n * Clones a fetch Response object and returns a version\n * that calls the `onProgress` callback as the #progress\n * changes.\n *\n * @param response The fetch Response object to clone.\n * @param onProgress The callback to call when the download #progress changes.\n * @returns The cloned response\n */\nexport function cloneResponseMonitorProgress(\n\tresponse: Response,\n\tonProgress: (event: CustomEvent<DownloadProgress>) => void\n): Response {\n\tconst contentLength = response.headers.get('content-length') || '';\n\tconst length = parseInt(contentLength, 10) || FALLBACK_FILE_SIZE;\n\n\treturn new Response(\n\t\tcloneStreamMonitorProgress(response.body, length, onProgress),\n\t\t{\n\t\t\tstatus: response.status,\n\t\t\tstatusText: response.statusText,\n\t\t\theaders: response.headers,\n\t\t}\n\t);\n}\n\n/**\n * Clones a ReadableStream and returns a version\n * that calls the `onProgress` callback as the #progress\n * changes.\n *\n * @param stream The ReadableStream to clone.\n * @param total The total number of bytes to load.\n * @param onProgress The callback to call when the download #progress changes.\n * @returns The cloned ReadableStream\n */\nexport function cloneStreamMonitorProgress(\n\tstream: ReadableStream<Uint8Array> | null,\n\ttotal: number,\n\tonProgress: (event: CustomEvent<DownloadProgress>) => void\n): ReadableStream<Uint8Array> {\n\tlet lastNotifyTime = 0;\n\n\tfunction notify(loaded: number, total: number, done: boolean) {\n\t\tconst now = performance.now();\n\n\t\t/*\n\t\t * This throttling exists to prevent severe UX degradation on mobile browsers,\n\t\t * particularly Safari. In some mobile environments, loading Playground\n\t\t * could take tens of seconds and appear frozen or blank, even though the boot\n\t\t * process eventually completed successfully.\n\t\t *\n\t\t * The issue was an excessive number of progress notifications directly tied\n\t\t * to how often php-wasm was able to read from a download's ReadableStream.\n\t\t * Each time we received a chunk from a readable stream, we sent a corresponding\n\t\t * progress notification. This appeared to work OK in Chrome and other browsers,\n\t\t * but we observed Safari's ReadableStream reading data in such small chunks\n\t\t * that we flooded the message channel with progress notifications.\n\t\t * This caused unnecessary main-thread pressure which impacted performance.\n\t\t *\n\t\t * To avoid this issue, we now throttle these progress notifications.\n\t\t */\n\t\tif (!done && now - lastNotifyTime < 500) return;\n\n\t\tlastNotifyTime = now;\n\n\t\tonProgress(\n\t\t\tnew CustomEvent('progress', {\n\t\t\t\tdetail: {\n\t\t\t\t\tloaded,\n\t\t\t\t\ttotal,\n\t\t\t\t},\n\t\t\t})\n\t\t);\n\t}\n\n\treturn new ReadableStream({\n\t\tasync start(controller) {\n\t\t\tif (!stream) {\n\t\t\t\tcontroller.close();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst reader = stream.getReader();\n\t\t\tlet loaded = 0;\n\t\t\twhile (true) {\n\t\t\t\ttry {\n\t\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\t\tif (value) {\n\t\t\t\t\t\tloaded += value.byteLength;\n\t\t\t\t\t}\n\t\t\t\t\tif (done) {\n\t\t\t\t\t\tnotify(loaded, loaded, done);\n\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnotify(loaded, total, done);\n\t\t\t\t\t\tcontroller.enqueue(value);\n\t\t\t\t\t}\n\t\t\t\t} catch (e) {\n\t\t\t\t\tlogger.error({ e });\n\t\t\t\t\tcontroller.error(e);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t});\n}\n\nexport type DownloadProgressCallback = (progress: DownloadProgress) => void;\n","import type { DownloadProgress } from './emscripten-download-monitor';\n\nexport type ProgressMode =\n\t/**\n\t * Real-time progress is used when we get real-time reports\n\t * about the progress.\n\t */\n\t| 'REAL_TIME'\n\n\t/**\n\t * Slowly increment progress is used when we don't know how long\n\t * an operation will take and just want to keep slowly incrementing\n\t * the progress bar.\n\t */\n\t| 'SLOWLY_INCREMENT';\n\nexport type ProgressObserverEvent = {\n\tprogress: number;\n\tmode: ProgressMode;\n\tcaption: string;\n};\n\nexport class ProgressObserver extends EventTarget {\n\t#observedProgresses: Record<number, number> = {};\n\t#lastObserverId = 0;\n\n\tprogress = 0;\n\tmode: ProgressMode = 'REAL_TIME';\n\tcaption = '';\n\n\tpartialObserver(progressBudget: number, caption = '') {\n\t\tconst id = ++this.#lastObserverId;\n\t\tthis.#observedProgresses[id] = 0;\n\t\treturn (progress: CustomEvent<DownloadProgress>) => {\n\t\t\tconst { loaded, total } = progress?.detail || {};\n\t\t\tthis.#observedProgresses[id] = (loaded / total) * progressBudget;\n\t\t\tthis.#onProgress(this.totalProgress, 'REAL_TIME', caption);\n\t\t};\n\t}\n\n\tslowlyIncrementBy(progress: number) {\n\t\tconst id = ++this.#lastObserverId;\n\t\tthis.#observedProgresses[id] = progress;\n\t\tthis.#onProgress(this.totalProgress, 'SLOWLY_INCREMENT');\n\t}\n\n\tget totalProgress() {\n\t\treturn Object.values(this.#observedProgresses).reduce(\n\t\t\t(total, progress) => total + progress,\n\t\t\t0\n\t\t);\n\t}\n\n\t#onProgress(progress: number, mode: ProgressMode, caption?: string) {\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('progress', {\n\t\t\t\tdetail: {\n\t\t\t\t\tprogress,\n\t\t\t\t\tmode,\n\t\t\t\t\tcaption,\n\t\t\t\t},\n\t\t\t})\n\t\t);\n\t}\n}\n","/**\n * Options for customizing the progress tracker.\n */\nexport interface ProgressTrackerOptions {\n\t/** The weight of the progress, a number between 0 and 1. */\n\tweight?: number;\n\t/** The caption to display during progress, a string. */\n\tcaption?: string;\n\t/** The time in milliseconds to fill the progress, a number. */\n\tfillTime?: number;\n}\n\n/**\n * Custom event providing information about a loading process.\n */\nexport type LoadingEvent = CustomEvent<{\n\t/** The number representing how much was loaded. */\n\tloaded: number;\n\t/** The number representing how much needs to loaded in total. */\n\ttotal: number;\n}>;\n\n/**\n * Custom event providing progress details.\n */\nexport type ProgressTrackerEvent = CustomEvent<ProgressDetails>;\n\n/**\n * Custom event providing progress details when the task is done.\n */\nexport type DoneEvent = CustomEvent<ProgressDetails>;\n\nexport interface ProgressDetails {\n\t/** The progress percentage as a number between 0 and 100. */\n\tprogress: number;\n\t/** The caption to display during progress, a string. */\n\tcaption: string;\n}\n\n/**\n * ProgressObserver A function that receives progress updates.\n *\n * @param progress The progress percentage as a number between 0 and 100.\n */\ntype ProgressObserver = (progress: number) => void;\n\n/**\n * Listener A function for handling specific event types.\n *\n * @param event The event of type T.\n */\nexport type Listener<T> = (event: T) => void;\n\nexport type TSCompatibleListener<T> =\n\t| EventListenerOrEventListenerObject\n\t| null\n\t| Listener<T>;\n\nexport interface ProgressReceiver {\n\tsetProgress(details: ProgressDetails): any;\n\tsetLoaded(): any;\n}\n\n/*\n * Like Number.EPSILON, but better tuned to tracking progress.\n *\n * With Number.EPSILON, progress like 99.99999999999997 is still\n * considered to be below 100 – this is highly undeisrable.\n */\nconst PROGRESS_EPSILON = 0.00001;\n\n/**\n * The ProgressTracker class is a tool for tracking progress in an operation\n * that is divided into multiple stages. It allows you to create sub-trackers\n * for each stage, with individual weights and captions. The main tracker\n * automatically calculates the progress based on the weighted sum of each\n * sub-tracker's progress. This makes it easy to keep track of a complex,\n * multi-stage process and report progress in a user-friendly way.\n *\n * After creating the sub-trackers, you can call the set() method to update the\n * progress of the current stage. You can also call the finish() method to mark\n * the current stage as complete and move on to the next one. Alternatively,\n * you can call the fillSlowly() method to simulate progress filling up slowly\n * to 100% before calling finish().\n *\n * @example\n * ```ts\n * const tracker = new ProgressTracker();\n * tracker.addEventListener('progress', (e) => {\n * \t\tconsole.log(\n * \t\t\t\te.detail.progress,\n * \t\t\t\te.detail.caption\n * \t\t);\n * });\n *\n * const stage1 = tracker.stage(0.5, 'Calculating pi digits');\n * const stage2 = tracker.stage(0.5, 'Downloading data');\n *\n * stage1.fillSlowly();\n * await calc100DigitsOfPi();\n * stage1.finish();\n *\n * await fetchWithProgress(function onProgress(loaded, total) {\n * \t\tstage2.set( loaded / total * 100);\n * });\n * stage2.finish();\n */\nexport class ProgressTracker extends EventTarget {\n\tprivate _selfWeight = 1;\n\tprivate _selfDone = false;\n\tprivate _selfProgress = 0;\n\tprivate _selfCaption = '';\n\tprivate _weight: number;\n\tprivate _progressObserver?: ProgressObserver;\n\tprivate _loadingListener?: Listener<LoadingEvent>;\n\tprivate _isFilling = false;\n\tprivate _fillTime: number;\n\tprivate _fillInterval?: any;\n\tprivate _subTrackers: ProgressTracker[] = [];\n\n\tconstructor({\n\t\tweight = 1,\n\t\tcaption = '',\n\t\tfillTime = 4,\n\t}: ProgressTrackerOptions = {}) {\n\t\tsuper();\n\t\tthis._weight = weight;\n\t\tthis._selfCaption = caption;\n\t\tthis._fillTime = fillTime;\n\t}\n\n\t/**\n\t * Creates a new sub-tracker with a specific weight.\n\t *\n\t * The weight determines what percentage of the overall progress\n\t * the sub-tracker represents. For example, if the main tracker is\n\t * monitoring a process that has two stages, and the first stage\n\t * is expected to take twice as long as the second stage, you could\n\t * create the first sub-tracker with a weight of 0.67 and the second\n\t * sub-tracker with a weight of 0.33.\n\t *\n\t * The caption is an optional string that describes the current stage\n\t * of the operation. If provided, it will be used as the progress caption\n\t * for the sub-tracker. If not provided, the main tracker will look for\n\t * the next sub-tracker with a non-empty caption and use that as the progress\n\t * caption instead.\n\t *\n\t * Returns the newly-created sub-tracker.\n\t *\n\t * @throws {Error} If the weight of the new stage would cause the total weight of all stages to exceed 1.\n\t *\n\t * @param weight The weight of the new stage, as a decimal value between 0 and 1.\n\t * @param caption The caption for the new stage, which will be used as the progress caption for the sub-tracker.\n\t *\n\t * @example\n\t * ```ts\n\t * const tracker = new ProgressTracker();\n\t * const subTracker1 = tracker.stage(0.67, 'Slow stage');\n\t * const subTracker2 = tracker.stage(0.33, 'Fast stage');\n\t *\n\t * subTracker2.set(50);\n\t * subTracker1.set(75);\n\t * subTracker2.set(100);\n\t * subTracker1.set(100);\n\t * ```\n\t */\n\tstage(weight?: number, caption = ''): ProgressTracker {\n\t\tif (!weight) {\n\t\t\tweight = this._selfWeight;\n\t\t}\n\t\tif (this._selfWeight - weight < -PROGRESS_EPSILON) {\n\t\t\tthrow new Error(\n\t\t\t\t`Cannot add a stage with weight ${weight} as the total weight of registered stages would exceed 1.`\n\t\t\t);\n\t\t}\n\t\tthis._selfWeight -= weight;\n\n\t\tconst subTracker = new ProgressTracker({\n\t\t\tcaption,\n\t\t\tweight,\n\t\t\tfillTime: this._fillTime,\n\t\t});\n\t\tthis._subTrackers.push(subTracker);\n\t\tsubTracker.addEventListener('progress', () => this.notifyProgress());\n\t\tsubTracker.addEventListener('done', () => {\n\t\t\tif (this.done) {\n\t\t\t\tthis.notifyDone();\n\t\t\t}\n\t\t});\n\t\treturn subTracker;\n\t}\n\n\t/**\n\t * Fills the progress bar slowly over time, simulating progress.\n\t *\n\t * The progress bar is filled in a 100 steps, and each step, the progress\n\t * is increased by 1. If `stopBeforeFinishing` is true, the progress bar\n\t * will stop filling when it reaches 99% so that you can call `finish()`\n\t * explicitly.\n\t *\n\t * If the progress bar is filling or already filled, this method does nothing.\n\t *\n\t * @example\n\t * ```ts\n\t * const progress = new ProgressTracker({ caption: 'Processing...' });\n\t * progress.fillSlowly();\n\t * ```\n\t *\n\t * @param options Optional options.\n\t */\n\tfillSlowly({ stopBeforeFinishing = true } = {}): void {\n\t\tif (this._isFilling) {\n\t\t\treturn;\n\t\t}\n\t\tthis._isFilling = true;\n\t\tconst steps = 100;\n\t\tconst interval = this._fillTime / steps;\n\t\tthis._fillInterval = setInterval(() => {\n\t\t\tthis.set(this._selfProgress + 1);\n\t\t\tif (stopBeforeFinishing && this._selfProgress >= 99) {\n\t\t\t\tclearInterval(this._fillInterval);\n\t\t\t}\n\t\t}, interval);\n\t}\n\n\tset(value: number): void {\n\t\tthis._selfProgress = Math.min(value, 100);\n\t\tthis.notifyProgress();\n\t\tif (this._selfProgress + PROGRESS_EPSILON >= 100) {\n\t\t\tthis.finish();\n\t\t}\n\t}\n\n\tfinish(): void {\n\t\tif (this._fillInterval) {\n\t\t\tclearInterval(this._fillInterval);\n\t\t}\n\t\tthis._selfDone = true;\n\t\tthis._selfProgress = 100;\n\t\tthis._isFilling = false;\n\t\tthis._fillInterval = undefined;\n\t\tthis.notifyProgress();\n\t\tthis.notifyDone();\n\t}\n\n\tget caption(): string {\n\t\tfor (let i = this._subTrackers.length - 1; i >= 0; i--) {\n\t\t\tif (!this._subTrackers[i].done) {\n\t\t\t\tconst captionMaybe = this._subTrackers[i].caption;\n\t\t\t\tif (captionMaybe) {\n\t\t\t\t\treturn captionMaybe;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn this._selfCaption;\n\t}\n\n\tsetCaption(caption: string) {\n\t\tthis._selfCaption = caption;\n\t\tthis.notifyProgress();\n\t}\n\n\tget done(): boolean {\n\t\treturn this.progress + PROGRESS_EPSILON >= 100;\n\t}\n\n\tget progress(): number {\n\t\tif (this._selfDone) {\n\t\t\treturn 100;\n\t\t}\n\t\tconst sum = this._subTrackers.reduce(\n\t\t\t(sum, tracker) => sum + tracker.progress * tracker.weight,\n\t\t\tthis._selfProgress * this._selfWeight\n\t\t);\n\t\treturn Math.round(sum * 10000) / 10000;\n\t}\n\n\tget weight(): number {\n\t\treturn this._weight;\n\t}\n\n\tget observer() {\n\t\tif (!this._progressObserver) {\n\t\t\tthis._progressObserver = (progress: number) => {\n\t\t\t\tthis.set(progress);\n\t\t\t};\n\t\t}\n\t\treturn this._progressObserver;\n\t}\n\n\tget loadingListener() {\n\t\tif (!this._loadingListener) {\n\t\t\tthis._loadingListener = (event: LoadingEvent) => {\n\t\t\t\tthis.set((event.detail.loaded / event.detail.total) * 100);\n\t\t\t};\n\t\t}\n\t\treturn this._loadingListener;\n\t}\n\n\tpipe(receiver: ProgressReceiver) {\n\t\treceiver.setProgress({\n\t\t\tprogress: this.progress,\n\t\t\tcaption: this.caption,\n\t\t});\n\t\tthis.addEventListener('progress', (event: ProgressTrackerEvent) => {\n\t\t\treceiver.setProgress({\n\t\t\t\tprogress: event.detail.progress,\n\t\t\t\tcaption: event.detail.caption,\n\t\t\t});\n\t\t});\n\t\tthis.addEventListener('done', () => {\n\t\t\treceiver.setLoaded();\n\t\t});\n\t}\n\n\toverride addEventListener(\n\t\ttype: string,\n\t\tlistener: TSCompatibleListener<ProgressTrackerEvent>\n\t) {\n\t\tsuper.addEventListener(type, listener as any);\n\t}\n\n\toverride removeEventListener(\n\t\ttype: string,\n\t\tlistener: TSCompatibleListener<ProgressTrackerEvent>\n\t) {\n\t\tsuper.removeEventListener(type, listener as any);\n\t}\n\n\tprivate notifyProgress() {\n\t\t// eslint-disable-next-line @typescript-eslint/no-this-alias\n\t\tconst self = this;\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('progress', {\n\t\t\t\tdetail: {\n\t\t\t\t\tget progress() {\n\t\t\t\t\t\treturn self.progress;\n\t\t\t\t\t},\n\t\t\t\t\tget caption() {\n\t\t\t\t\t\treturn self.caption;\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t);\n\t}\n\n\tprivate notifyDone() {\n\t\tthis.dispatchEvent(new CustomEvent('done'));\n\t}\n}\n"],"names":["FALLBACK_FILE_SIZE","EmscriptenDownloadMonitor","__privateAdd","_EmscriptenDownloadMonitor_instances","_assetsSizes","_progress","assets","urlLike","size","dummyBaseUrl","filename","__privateGet","fetchPromise","response","cloneResponseMonitorProgress","event","__privateMethod","notify_fn","file","loaded","fileSize","fileName","logger","sumValues","obj","length","value","onProgress","contentLength","cloneStreamMonitorProgress","stream","total","lastNotifyTime","notify","done","now","controller","reader","e","ProgressObserver","_ProgressObserver_instances","_observedProgresses","_lastObserverId","__privateSet","progressBudget","caption","id","__privateWrapper","progress","onProgress_fn","mode","PROGRESS_EPSILON","ProgressTracker","weight","fillTime","subTracker","stopBeforeFinishing","interval","i","captionMaybe","sum","tracker","receiver","type","listener","self"],"mappings":"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"}
{"version":3,"file":"index.cjs","sources":["../../../../packages/php-wasm/progress/src/lib/emscripten-download-monitor.ts","../../../../packages/php-wasm/progress/src/lib/progress-observer.ts","../../../../packages/php-wasm/progress/src/lib/progress-tracker.ts"],"sourcesContent":["import { logger } from '@php-wasm/logger';\n/*\n * An approximate file length to use when the actual\n * length number of bytes is missing.\n *\n * This may happen when the files are compressed before transmission\n * and no content-length header is being sent.\n *\n * The approximation isn't accurate, but it's better than nothing.\n * It's not about being exact but about giving the user a rough sense\n * of #progress.\n */\nconst FALLBACK_FILE_SIZE = 5 * 1024 * 1024;\n\n/**\n * Monitors the download #progress of Emscripten modules\n *\n * Usage:\n *\n * ```js\n * const downloadMonitor = new EmscriptenDownloadMonitor();\n * \t const php = await startPHP(\n * phpLoaderModule,\n * 'web',\n * downloadMonitor.phpArgs\n * );\n * downloadMonitor.addEventListener('#progress', (e) => {\n * console.log( e.detail.#progress);\n * })\n * ```\n */\nexport class EmscriptenDownloadMonitor extends EventTarget {\n\t#assetsSizes: Record<string, number> = {};\n\t#progress: Record<string, number> = {};\n\n\texpectAssets(assets: Record<string, number>) {\n\t\tfor (const [urlLike, size] of Object.entries(assets)) {\n\t\t\tconst dummyBaseUrl = 'http://example.com/';\n\t\t\tconst pathname = new URL(urlLike, dummyBaseUrl).pathname;\n\t\t\tconst filename = pathname.split('/').pop()!;\n\t\t\tif (!(filename in this.#assetsSizes)) {\n\t\t\t\tthis.#assetsSizes[filename] = size;\n\t\t\t}\n\t\t\tif (!(filename in this.#progress)) {\n\t\t\t\tthis.#progress[filename] = 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tasync monitorFetch(fetchPromise: Promise<Response>): Promise<Response> {\n\t\tconst response = await fetchPromise;\n\t\tconst onProgress = (event: CustomEvent<DownloadProgress>) => {\n\t\t\tthis.#notify(response.url, event.detail.loaded, event.detail.total);\n\t\t};\n\t\treturn cloneResponseMonitorProgress(response, onProgress);\n\t}\n\n\t/**\n\t * Notifies about the download #progress of a file.\n\t *\n\t * @param file The file name.\n\t * @param loaded The number of bytes of that file loaded so far.\n\t * @param fileSize The length number of bytes in the loaded file.\n\t */\n\t#notify(file: string, loaded: number, fileSize: number) {\n\t\tconst fileName = new URL(file, 'http://example.com').pathname\n\t\t\t.split('/')\n\t\t\t.pop()!;\n\t\tif (!fileSize) {\n\t\t\tfileSize = this.#assetsSizes[fileName];\n\t\t} else if (!(fileName in this.#assetsSizes)) {\n\t\t\tthis.#assetsSizes[fileName] = fileSize;\n\t\t\tthis.#progress[fileName] = loaded;\n\t\t}\n\t\tif (!(fileName in this.#progress)) {\n\t\t\tlogger.warn(\n\t\t\t\t`Registered a download #progress of an unregistered file \"${fileName}\". ` +\n\t\t\t\t\t`This may cause a sudden **decrease** in the #progress percentage as the ` +\n\t\t\t\t\t`length number of bytes increases during the download.`\n\t\t\t);\n\t\t}\n\n\t\tthis.#progress[fileName] = loaded;\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('progress', {\n\t\t\t\tdetail: {\n\t\t\t\t\tloaded: sumValues(this.#progress),\n\t\t\t\t\ttotal: sumValues(this.#assetsSizes),\n\t\t\t\t},\n\t\t\t})\n\t\t);\n\t}\n}\n\nfunction sumValues(obj: Record<string, number>) {\n\treturn Object.values(obj).reduce((length, value) => length + value, 0);\n}\n\nexport default EmscriptenDownloadMonitor;\n\nexport interface DownloadProgress {\n\t/**\n\t * The number of bytes loaded so far.\n\t */\n\tloaded: number;\n\t/**\n\t * The length number of bytes to load.\n\t */\n\ttotal: number;\n}\n\n/**\n * Clones a fetch Response object and returns a version\n * that calls the `onProgress` callback as the #progress\n * changes.\n *\n * @param response The fetch Response object to clone.\n * @param onProgress The callback to call when the download #progress changes.\n * @returns The cloned response\n */\nexport function cloneResponseMonitorProgress(\n\tresponse: Response,\n\tonProgress: (event: CustomEvent<DownloadProgress>) => void\n): Response {\n\tconst contentLength = response.headers.get('content-length') || '';\n\tconst length = parseInt(contentLength, 10) || FALLBACK_FILE_SIZE;\n\n\treturn new Response(\n\t\tcloneStreamMonitorProgress(response.body, length, onProgress),\n\t\t{\n\t\t\tstatus: response.status,\n\t\t\tstatusText: response.statusText,\n\t\t\theaders: response.headers,\n\t\t}\n\t);\n}\n\n/**\n * Clones a ReadableStream and returns a version\n * that calls the `onProgress` callback as the #progress\n * changes.\n *\n * @param stream The ReadableStream to clone.\n * @param total The total number of bytes to load.\n * @param onProgress The callback to call when the download #progress changes.\n * @returns The cloned ReadableStream\n */\nexport function cloneStreamMonitorProgress(\n\tstream: ReadableStream<Uint8Array> | null,\n\ttotal: number,\n\tonProgress: (event: CustomEvent<DownloadProgress>) => void\n): ReadableStream<Uint8Array> {\n\tlet lastNotifyTime = 0;\n\n\tfunction notify(loaded: number, total: number, done: boolean) {\n\t\tconst now = performance.now();\n\n\t\t/*\n\t\t * This throttling exists to prevent severe UX degradation on mobile browsers,\n\t\t * particularly Safari. In some mobile environments, loading Playground\n\t\t * could take tens of seconds and appear frozen or blank, even though the boot\n\t\t * process eventually completed successfully.\n\t\t *\n\t\t * The issue was an excessive number of progress notifications directly tied\n\t\t * to how often php-wasm was able to read from a download's ReadableStream.\n\t\t * Each time we received a chunk from a readable stream, we sent a corresponding\n\t\t * progress notification. This appeared to work OK in Chrome and other browsers,\n\t\t * but we observed Safari's ReadableStream reading data in such small chunks\n\t\t * that we flooded the message channel with progress notifications.\n\t\t * This caused unnecessary main-thread pressure which impacted performance.\n\t\t *\n\t\t * To avoid this issue, we now throttle these progress notifications.\n\t\t */\n\t\tif (!done && now - lastNotifyTime < 500) return;\n\n\t\tlastNotifyTime = now;\n\n\t\tonProgress(\n\t\t\tnew CustomEvent('progress', {\n\t\t\t\tdetail: {\n\t\t\t\t\tloaded,\n\t\t\t\t\ttotal,\n\t\t\t\t},\n\t\t\t})\n\t\t);\n\t}\n\n\treturn new ReadableStream({\n\t\tasync start(controller) {\n\t\t\tif (!stream) {\n\t\t\t\tcontroller.close();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst reader = stream.getReader();\n\t\t\tlet loaded = 0;\n\t\t\twhile (true) {\n\t\t\t\ttry {\n\t\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\t\tif (value) {\n\t\t\t\t\t\tloaded += value.byteLength;\n\t\t\t\t\t}\n\t\t\t\t\tif (done) {\n\t\t\t\t\t\tnotify(loaded, loaded, done);\n\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnotify(loaded, total, done);\n\t\t\t\t\t\tcontroller.enqueue(value);\n\t\t\t\t\t}\n\t\t\t\t} catch (e) {\n\t\t\t\t\tlogger.error({ e });\n\t\t\t\t\tcontroller.error(e);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t});\n}\n\nexport type DownloadProgressCallback = (progress: DownloadProgress) => void;\n","import type { DownloadProgress } from './emscripten-download-monitor';\n\nexport type ProgressMode =\n\t/**\n\t * Real-time progress is used when we get real-time reports\n\t * about the progress.\n\t */\n\t| 'REAL_TIME'\n\n\t/**\n\t * Slowly increment progress is used when we don't know how long\n\t * an operation will take and just want to keep slowly incrementing\n\t * the progress bar.\n\t */\n\t| 'SLOWLY_INCREMENT';\n\nexport type ProgressObserverEvent = {\n\tprogress: number;\n\tmode: ProgressMode;\n\tcaption: string;\n};\n\nexport class ProgressObserver extends EventTarget {\n\t#observedProgresses: Record<number, number> = {};\n\t#lastObserverId = 0;\n\n\tprogress = 0;\n\tmode: ProgressMode = 'REAL_TIME';\n\tcaption = '';\n\n\tpartialObserver(progressBudget: number, caption = '') {\n\t\tconst id = ++this.#lastObserverId;\n\t\tthis.#observedProgresses[id] = 0;\n\t\treturn (progress: CustomEvent<DownloadProgress>) => {\n\t\t\tconst { loaded, total } = progress?.detail || {};\n\t\t\tthis.#observedProgresses[id] = (loaded / total) * progressBudget;\n\t\t\tthis.#onProgress(this.totalProgress, 'REAL_TIME', caption);\n\t\t};\n\t}\n\n\tslowlyIncrementBy(progress: number) {\n\t\tconst id = ++this.#lastObserverId;\n\t\tthis.#observedProgresses[id] = progress;\n\t\tthis.#onProgress(this.totalProgress, 'SLOWLY_INCREMENT');\n\t}\n\n\tget totalProgress() {\n\t\treturn Object.values(this.#observedProgresses).reduce(\n\t\t\t(total, progress) => total + progress,\n\t\t\t0\n\t\t);\n\t}\n\n\t#onProgress(progress: number, mode: ProgressMode, caption?: string) {\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('progress', {\n\t\t\t\tdetail: {\n\t\t\t\t\tprogress,\n\t\t\t\t\tmode,\n\t\t\t\t\tcaption,\n\t\t\t\t},\n\t\t\t})\n\t\t);\n\t}\n}\n","/**\n * Options for customizing the progress tracker.\n */\nexport interface ProgressTrackerOptions {\n\t/** The weight of the progress, a number between 0 and 1. */\n\tweight?: number;\n\t/** The caption to display during progress, a string. */\n\tcaption?: string;\n\t/** The time in milliseconds to fill the progress, a number. */\n\tfillTime?: number;\n}\n\n/**\n * Custom event providing information about a loading process.\n */\nexport type LoadingEvent = CustomEvent<{\n\t/** The number representing how much was loaded. */\n\tloaded: number;\n\t/** The number representing how much needs to loaded in total. */\n\ttotal: number;\n}>;\n\n/**\n * Custom event providing progress details.\n */\nexport type ProgressTrackerEvent = CustomEvent<ProgressDetails>;\n\n/**\n * Custom event providing progress details when the task is done.\n */\nexport type DoneEvent = CustomEvent<ProgressDetails>;\n\nexport interface ProgressDetails {\n\t/** The progress percentage as a number between 0 and 100. */\n\tprogress: number;\n\t/** The caption to display during progress, a string. */\n\tcaption: string;\n}\n\n/**\n * ProgressObserver A function that receives progress updates.\n *\n * @param progress The progress percentage as a number between 0 and 100.\n */\ntype ProgressObserver = (progress: number) => void;\n\n/**\n * Listener A function for handling specific event types.\n *\n * @param event The event of type T.\n */\nexport type Listener<T> = (event: T) => void;\n\nexport type TSCompatibleListener<T> =\n\t| EventListenerOrEventListenerObject\n\t| null\n\t| Listener<T>;\n\nexport interface ProgressReceiver {\n\tsetProgress(details: ProgressDetails): any;\n\tsetLoaded(): any;\n}\n\n/*\n * Like Number.EPSILON, but better tuned to tracking progress.\n *\n * With Number.EPSILON, progress like 99.99999999999997 is still\n * considered to be below 100 – this is highly undeisrable.\n */\nconst PROGRESS_EPSILON = 0.00001;\n\n/**\n * The ProgressTracker class is a tool for tracking progress in an operation\n * that is divided into multiple stages. It allows you to create sub-trackers\n * for each stage, with individual weights and captions. The main tracker\n * automatically calculates the progress based on the weighted sum of each\n * sub-tracker's progress. This makes it easy to keep track of a complex,\n * multi-stage process and report progress in a user-friendly way.\n *\n * After creating the sub-trackers, you can call the set() method to update the\n * progress of the current stage. You can also call the finish() method to mark\n * the current stage as complete and move on to the next one. Alternatively,\n * you can call the fillSlowly() method to simulate progress filling up slowly\n * to 100% before calling finish().\n *\n * @example\n * ```ts\n * const tracker = new ProgressTracker();\n * tracker.addEventListener('progress', (e) => {\n * \t\tconsole.log(\n * \t\t\t\te.detail.progress,\n * \t\t\t\te.detail.caption\n * \t\t);\n * });\n *\n * const stage1 = tracker.stage(0.5, 'Calculating pi digits');\n * const stage2 = tracker.stage(0.5, 'Downloading data');\n *\n * stage1.fillSlowly();\n * await calc100DigitsOfPi();\n * stage1.finish();\n *\n * await fetchWithProgress(function onProgress(loaded, total) {\n * \t\tstage2.set( loaded / total * 100);\n * });\n * stage2.finish();\n */\nexport class ProgressTracker extends EventTarget {\n\tprivate _selfWeight = 1;\n\tprivate _selfDone = false;\n\tprivate _selfProgress = 0;\n\tprivate _selfCaption = '';\n\tprivate _weight: number;\n\tprivate _progressObserver?: ProgressObserver;\n\tprivate _loadingListener?: Listener<LoadingEvent>;\n\tprivate _isFilling = false;\n\tprivate _fillTime: number;\n\tprivate _fillInterval?: any;\n\tprivate _subTrackers: ProgressTracker[] = [];\n\n\tconstructor({\n\t\tweight = 1,\n\t\tcaption = '',\n\t\tfillTime = 4,\n\t}: ProgressTrackerOptions = {}) {\n\t\tsuper();\n\t\tthis._weight = weight;\n\t\tthis._selfCaption = caption;\n\t\tthis._fillTime = fillTime;\n\t}\n\n\t/**\n\t * Creates a new sub-tracker with a specific weight.\n\t *\n\t * The weight determines what percentage of the overall progress\n\t * the sub-tracker represents. For example, if the main tracker is\n\t * monitoring a process that has two stages, and the first stage\n\t * is expected to take twice as long as the second stage, you could\n\t * create the first sub-tracker with a weight of 0.67 and the second\n\t * sub-tracker with a weight of 0.33.\n\t *\n\t * The caption is an optional string that describes the current stage\n\t * of the operation. If provided, it will be used as the progress caption\n\t * for the sub-tracker. If not provided, the main tracker will look for\n\t * the next sub-tracker with a non-empty caption and use that as the progress\n\t * caption instead.\n\t *\n\t * Returns the newly-created sub-tracker.\n\t *\n\t * @throws {Error} If the weight of the new stage would cause the total weight of all stages to exceed 1.\n\t *\n\t * @param weight The weight of the new stage, as a decimal value between 0 and 1.\n\t * @param caption The caption for the new stage, which will be used as the progress caption for the sub-tracker.\n\t *\n\t * @example\n\t * ```ts\n\t * const tracker = new ProgressTracker();\n\t * const subTracker1 = tracker.stage(0.67, 'Slow stage');\n\t * const subTracker2 = tracker.stage(0.33, 'Fast stage');\n\t *\n\t * subTracker2.set(50);\n\t * subTracker1.set(75);\n\t * subTracker2.set(100);\n\t * subTracker1.set(100);\n\t * ```\n\t */\n\tstage(weight?: number, caption = ''): ProgressTracker {\n\t\tif (!weight) {\n\t\t\tweight = this._selfWeight;\n\t\t}\n\t\tif (this._selfWeight - weight < -PROGRESS_EPSILON) {\n\t\t\tthrow new Error(\n\t\t\t\t`Cannot add a stage with weight ${weight} as the total weight of registered stages would exceed 1.`\n\t\t\t);\n\t\t}\n\t\tthis._selfWeight -= weight;\n\n\t\tconst subTracker = new ProgressTracker({\n\t\t\tcaption,\n\t\t\tweight,\n\t\t\tfillTime: this._fillTime,\n\t\t});\n\t\tthis._subTrackers.push(subTracker);\n\t\tsubTracker.addEventListener('progress', () => this.notifyProgress());\n\t\tsubTracker.addEventListener('done', () => {\n\t\t\tif (this.done) {\n\t\t\t\tthis.notifyDone();\n\t\t\t}\n\t\t});\n\t\treturn subTracker;\n\t}\n\n\t/**\n\t * Fills the progress bar slowly over time, simulating progress.\n\t *\n\t * The progress bar is filled in a 100 steps, and each step, the progress\n\t * is increased by 1. If `stopBeforeFinishing` is true, the progress bar\n\t * will stop filling when it reaches 99% so that you can call `finish()`\n\t * explicitly.\n\t *\n\t * If the progress bar is filling or already filled, this method does nothing.\n\t *\n\t * @example\n\t * ```ts\n\t * const progress = new ProgressTracker({ caption: 'Processing...' });\n\t * progress.fillSlowly();\n\t * ```\n\t *\n\t * @param options Optional options.\n\t */\n\tfillSlowly({ stopBeforeFinishing = true } = {}): void {\n\t\tif (this._isFilling) {\n\t\t\treturn;\n\t\t}\n\t\tthis._isFilling = true;\n\t\tconst steps = 100;\n\t\tconst interval = this._fillTime / steps;\n\t\tthis._fillInterval = setInterval(() => {\n\t\t\tthis.set(this._selfProgress + 1);\n\t\t\tif (stopBeforeFinishing && this._selfProgress >= 99) {\n\t\t\t\tclearInterval(this._fillInterval);\n\t\t\t}\n\t\t}, interval);\n\t}\n\n\tset(value: number): void {\n\t\tthis._selfProgress = Math.min(value, 100);\n\t\tthis.notifyProgress();\n\t\tif (this._selfProgress + PROGRESS_EPSILON >= 100) {\n\t\t\tthis.finish();\n\t\t}\n\t}\n\n\tfinish(): void {\n\t\tif (this._fillInterval) {\n\t\t\tclearInterval(this._fillInterval);\n\t\t}\n\t\tthis._selfDone = true;\n\t\tthis._selfProgress = 100;\n\t\tthis._isFilling = false;\n\t\tthis._fillInterval = undefined;\n\t\tthis.notifyProgress();\n\t\tthis.notifyDone();\n\t}\n\n\tget caption(): string {\n\t\tfor (let i = this._subTrackers.length - 1; i >= 0; i--) {\n\t\t\tif (!this._subTrackers[i].done) {\n\t\t\t\tconst captionMaybe = this._subTrackers[i].caption;\n\t\t\t\tif (captionMaybe) {\n\t\t\t\t\treturn captionMaybe;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn this._selfCaption;\n\t}\n\n\tsetCaption(caption: string) {\n\t\tthis._selfCaption = caption;\n\t\tthis.notifyProgress();\n\t}\n\n\tget done(): boolean {\n\t\treturn this.progress + PROGRESS_EPSILON >= 100;\n\t}\n\n\tget progress(): number {\n\t\tif (this._selfDone) {\n\t\t\treturn 100;\n\t\t}\n\t\tconst sum = this._subTrackers.reduce(\n\t\t\t(sum, tracker) => sum + tracker.progress * tracker.weight,\n\t\t\tthis._selfProgress * this._selfWeight\n\t\t);\n\t\treturn Math.round(sum * 10000) / 10000;\n\t}\n\n\tget weight(): number {\n\t\treturn this._weight;\n\t}\n\n\tget observer() {\n\t\tif (!this._progressObserver) {\n\t\t\tthis._progressObserver = (progress: number) => {\n\t\t\t\tthis.set(progress);\n\t\t\t};\n\t\t}\n\t\treturn this._progressObserver;\n\t}\n\n\tget loadingListener() {\n\t\tif (!this._loadingListener) {\n\t\t\tthis._loadingListener = (event: LoadingEvent) => {\n\t\t\t\tthis.set((event.detail.loaded / event.detail.total) * 100);\n\t\t\t};\n\t\t}\n\t\treturn this._loadingListener;\n\t}\n\n\tpipe(receiver: ProgressReceiver) {\n\t\treceiver.setProgress({\n\t\t\tprogress: this.progress,\n\t\t\tcaption: this.caption,\n\t\t});\n\t\tthis.addEventListener('progress', (event: ProgressTrackerEvent) => {\n\t\t\treceiver.setProgress({\n\t\t\t\tprogress: event.detail.progress,\n\t\t\t\tcaption: event.detail.caption,\n\t\t\t});\n\t\t});\n\t\tthis.addEventListener('done', () => {\n\t\t\treceiver.setLoaded();\n\t\t});\n\t}\n\n\toverride addEventListener(\n\t\ttype: string,\n\t\tlistener: TSCompatibleListener<ProgressTrackerEvent>\n\t) {\n\t\tsuper.addEventListener(type, listener as any);\n\t}\n\n\toverride removeEventListener(\n\t\ttype: string,\n\t\tlistener: TSCompatibleListener<ProgressTrackerEvent>\n\t) {\n\t\tsuper.removeEventListener(type, listener as any);\n\t}\n\n\tprivate notifyProgress() {\n\t\t// eslint-disable-next-line @typescript-eslint/no-this-alias\n\t\tconst self = this;\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('progress', {\n\t\t\t\tdetail: {\n\t\t\t\t\tget progress() {\n\t\t\t\t\t\treturn self.progress;\n\t\t\t\t\t},\n\t\t\t\t\tget caption() {\n\t\t\t\t\t\treturn self.caption;\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t);\n\t}\n\n\tprivate notifyDone() {\n\t\tthis.dispatchEvent(new CustomEvent('done'));\n\t}\n}\n"],"names":["FALLBACK_FILE_SIZE","EmscriptenDownloadMonitor","__privateAdd","_EmscriptenDownloadMonitor_instances","_assetsSizes","_progress","assets","urlLike","size","dummyBaseUrl","filename","__privateGet","fetchPromise","response","cloneResponseMonitorProgress","event","__privateMethod","notify_fn","file","loaded","fileSize","fileName","logger","sumValues","obj","length","value","onProgress","contentLength","cloneStreamMonitorProgress","stream","total","lastNotifyTime","notify","done","now","controller","reader","e","ProgressObserver","_ProgressObserver_instances","_observedProgresses","_lastObserverId","__privateSet","progressBudget","caption","id","__privateWrapper","progress","onProgress_fn","mode","PROGRESS_EPSILON","ProgressTracker","weight","fillTime","subTracker","stopBeforeFinishing","interval","i","captionMaybe","sum","tracker","receiver","type","listener","self"],"mappings":"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"}

@@ -14,7 +14,6 @@ var y = (i) => {

});
import "@php-wasm/node-polyfills";
import { logger as I } from "@php-wasm/logger";
const R = 5 * 1024 * 1024;
var l, g, v, C;
class S extends EventTarget {
class F extends EventTarget {
constructor() {

@@ -110,3 +109,3 @@ super(...arguments);

var d, u, p, P;
class W extends EventTarget {
class S extends EventTarget {
constructor() {

@@ -316,4 +315,4 @@ super(...arguments);

export {
S as EmscriptenDownloadMonitor,
W as ProgressObserver,
F as EmscriptenDownloadMonitor,
S as ProgressObserver,
O as ProgressTracker,

@@ -320,0 +319,0 @@ x as cloneResponseMonitorProgress,

@@ -1,1 +0,1 @@

{"version":3,"file":"index.js","sources":["../../../../packages/php-wasm/progress/src/lib/emscripten-download-monitor.ts","../../../../packages/php-wasm/progress/src/lib/progress-observer.ts","../../../../packages/php-wasm/progress/src/lib/progress-tracker.ts"],"sourcesContent":["import { logger } from '@php-wasm/logger';\n/*\n * An approximate file length to use when the actual\n * length number of bytes is missing.\n *\n * This may happen when the files are compressed before transmission\n * and no content-length header is being sent.\n *\n * The approximation isn't accurate, but it's better than nothing.\n * It's not about being exact but about giving the user a rough sense\n * of #progress.\n */\nconst FALLBACK_FILE_SIZE = 5 * 1024 * 1024;\n\n/**\n * Monitors the download #progress of Emscripten modules\n *\n * Usage:\n *\n * ```js\n * const downloadMonitor = new EmscriptenDownloadMonitor();\n * \t const php = await startPHP(\n * phpLoaderModule,\n * 'web',\n * downloadMonitor.phpArgs\n * );\n * downloadMonitor.addEventListener('#progress', (e) => {\n * console.log( e.detail.#progress);\n * })\n * ```\n */\nexport class EmscriptenDownloadMonitor extends EventTarget {\n\t#assetsSizes: Record<string, number> = {};\n\t#progress: Record<string, number> = {};\n\n\texpectAssets(assets: Record<string, number>) {\n\t\tfor (const [urlLike, size] of Object.entries(assets)) {\n\t\t\tconst dummyBaseUrl = 'http://example.com/';\n\t\t\tconst pathname = new URL(urlLike, dummyBaseUrl).pathname;\n\t\t\tconst filename = pathname.split('/').pop()!;\n\t\t\tif (!(filename in this.#assetsSizes)) {\n\t\t\t\tthis.#assetsSizes[filename] = size;\n\t\t\t}\n\t\t\tif (!(filename in this.#progress)) {\n\t\t\t\tthis.#progress[filename] = 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tasync monitorFetch(fetchPromise: Promise<Response>): Promise<Response> {\n\t\tconst response = await fetchPromise;\n\t\tconst onProgress = (event: CustomEvent<DownloadProgress>) => {\n\t\t\tthis.#notify(response.url, event.detail.loaded, event.detail.total);\n\t\t};\n\t\treturn cloneResponseMonitorProgress(response, onProgress);\n\t}\n\n\t/**\n\t * Notifies about the download #progress of a file.\n\t *\n\t * @param file The file name.\n\t * @param loaded The number of bytes of that file loaded so far.\n\t * @param fileSize The length number of bytes in the loaded file.\n\t */\n\t#notify(file: string, loaded: number, fileSize: number) {\n\t\tconst fileName = new URL(file, 'http://example.com').pathname\n\t\t\t.split('/')\n\t\t\t.pop()!;\n\t\tif (!fileSize) {\n\t\t\tfileSize = this.#assetsSizes[fileName];\n\t\t} else if (!(fileName in this.#assetsSizes)) {\n\t\t\tthis.#assetsSizes[fileName] = fileSize;\n\t\t\tthis.#progress[fileName] = loaded;\n\t\t}\n\t\tif (!(fileName in this.#progress)) {\n\t\t\tlogger.warn(\n\t\t\t\t`Registered a download #progress of an unregistered file \"${fileName}\". ` +\n\t\t\t\t\t`This may cause a sudden **decrease** in the #progress percentage as the ` +\n\t\t\t\t\t`length number of bytes increases during the download.`\n\t\t\t);\n\t\t}\n\n\t\tthis.#progress[fileName] = loaded;\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('progress', {\n\t\t\t\tdetail: {\n\t\t\t\t\tloaded: sumValues(this.#progress),\n\t\t\t\t\ttotal: sumValues(this.#assetsSizes),\n\t\t\t\t},\n\t\t\t})\n\t\t);\n\t}\n}\n\nfunction sumValues(obj: Record<string, number>) {\n\treturn Object.values(obj).reduce((length, value) => length + value, 0);\n}\n\nexport default EmscriptenDownloadMonitor;\n\nexport interface DownloadProgress {\n\t/**\n\t * The number of bytes loaded so far.\n\t */\n\tloaded: number;\n\t/**\n\t * The length number of bytes to load.\n\t */\n\ttotal: number;\n}\n\n/**\n * Clones a fetch Response object and returns a version\n * that calls the `onProgress` callback as the #progress\n * changes.\n *\n * @param response The fetch Response object to clone.\n * @param onProgress The callback to call when the download #progress changes.\n * @returns The cloned response\n */\nexport function cloneResponseMonitorProgress(\n\tresponse: Response,\n\tonProgress: (event: CustomEvent<DownloadProgress>) => void\n): Response {\n\tconst contentLength = response.headers.get('content-length') || '';\n\tconst length = parseInt(contentLength, 10) || FALLBACK_FILE_SIZE;\n\n\treturn new Response(\n\t\tcloneStreamMonitorProgress(response.body, length, onProgress),\n\t\t{\n\t\t\tstatus: response.status,\n\t\t\tstatusText: response.statusText,\n\t\t\theaders: response.headers,\n\t\t}\n\t);\n}\n\n/**\n * Clones a ReadableStream and returns a version\n * that calls the `onProgress` callback as the #progress\n * changes.\n *\n * @param stream The ReadableStream to clone.\n * @param total The total number of bytes to load.\n * @param onProgress The callback to call when the download #progress changes.\n * @returns The cloned ReadableStream\n */\nexport function cloneStreamMonitorProgress(\n\tstream: ReadableStream<Uint8Array> | null,\n\ttotal: number,\n\tonProgress: (event: CustomEvent<DownloadProgress>) => void\n): ReadableStream<Uint8Array> {\n\tlet lastNotifyTime = 0;\n\n\tfunction notify(loaded: number, total: number, done: boolean) {\n\t\tconst now = performance.now();\n\n\t\t/*\n\t\t * This throttling exists to prevent severe UX degradation on mobile browsers,\n\t\t * particularly Safari. In some mobile environments, loading Playground\n\t\t * could take tens of seconds and appear frozen or blank, even though the boot\n\t\t * process eventually completed successfully.\n\t\t *\n\t\t * The issue was an excessive number of progress notifications directly tied\n\t\t * to how often php-wasm was able to read from a download's ReadableStream.\n\t\t * Each time we received a chunk from a readable stream, we sent a corresponding\n\t\t * progress notification. This appeared to work OK in Chrome and other browsers,\n\t\t * but we observed Safari's ReadableStream reading data in such small chunks\n\t\t * that we flooded the message channel with progress notifications.\n\t\t * This caused unnecessary main-thread pressure which impacted performance.\n\t\t *\n\t\t * To avoid this issue, we now throttle these progress notifications.\n\t\t */\n\t\tif (!done && now - lastNotifyTime < 500) return;\n\n\t\tlastNotifyTime = now;\n\n\t\tonProgress(\n\t\t\tnew CustomEvent('progress', {\n\t\t\t\tdetail: {\n\t\t\t\t\tloaded,\n\t\t\t\t\ttotal,\n\t\t\t\t},\n\t\t\t})\n\t\t);\n\t}\n\n\treturn new ReadableStream({\n\t\tasync start(controller) {\n\t\t\tif (!stream) {\n\t\t\t\tcontroller.close();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst reader = stream.getReader();\n\t\t\tlet loaded = 0;\n\t\t\twhile (true) {\n\t\t\t\ttry {\n\t\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\t\tif (value) {\n\t\t\t\t\t\tloaded += value.byteLength;\n\t\t\t\t\t}\n\t\t\t\t\tif (done) {\n\t\t\t\t\t\tnotify(loaded, loaded, done);\n\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnotify(loaded, total, done);\n\t\t\t\t\t\tcontroller.enqueue(value);\n\t\t\t\t\t}\n\t\t\t\t} catch (e) {\n\t\t\t\t\tlogger.error({ e });\n\t\t\t\t\tcontroller.error(e);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t});\n}\n\nexport type DownloadProgressCallback = (progress: DownloadProgress) => void;\n","import type { DownloadProgress } from './emscripten-download-monitor';\n\nexport type ProgressMode =\n\t/**\n\t * Real-time progress is used when we get real-time reports\n\t * about the progress.\n\t */\n\t| 'REAL_TIME'\n\n\t/**\n\t * Slowly increment progress is used when we don't know how long\n\t * an operation will take and just want to keep slowly incrementing\n\t * the progress bar.\n\t */\n\t| 'SLOWLY_INCREMENT';\n\nexport type ProgressObserverEvent = {\n\tprogress: number;\n\tmode: ProgressMode;\n\tcaption: string;\n};\n\nexport class ProgressObserver extends EventTarget {\n\t#observedProgresses: Record<number, number> = {};\n\t#lastObserverId = 0;\n\n\tprogress = 0;\n\tmode: ProgressMode = 'REAL_TIME';\n\tcaption = '';\n\n\tpartialObserver(progressBudget: number, caption = '') {\n\t\tconst id = ++this.#lastObserverId;\n\t\tthis.#observedProgresses[id] = 0;\n\t\treturn (progress: CustomEvent<DownloadProgress>) => {\n\t\t\tconst { loaded, total } = progress?.detail || {};\n\t\t\tthis.#observedProgresses[id] = (loaded / total) * progressBudget;\n\t\t\tthis.#onProgress(this.totalProgress, 'REAL_TIME', caption);\n\t\t};\n\t}\n\n\tslowlyIncrementBy(progress: number) {\n\t\tconst id = ++this.#lastObserverId;\n\t\tthis.#observedProgresses[id] = progress;\n\t\tthis.#onProgress(this.totalProgress, 'SLOWLY_INCREMENT');\n\t}\n\n\tget totalProgress() {\n\t\treturn Object.values(this.#observedProgresses).reduce(\n\t\t\t(total, progress) => total + progress,\n\t\t\t0\n\t\t);\n\t}\n\n\t#onProgress(progress: number, mode: ProgressMode, caption?: string) {\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('progress', {\n\t\t\t\tdetail: {\n\t\t\t\t\tprogress,\n\t\t\t\t\tmode,\n\t\t\t\t\tcaption,\n\t\t\t\t},\n\t\t\t})\n\t\t);\n\t}\n}\n","/**\n * Options for customizing the progress tracker.\n */\nexport interface ProgressTrackerOptions {\n\t/** The weight of the progress, a number between 0 and 1. */\n\tweight?: number;\n\t/** The caption to display during progress, a string. */\n\tcaption?: string;\n\t/** The time in milliseconds to fill the progress, a number. */\n\tfillTime?: number;\n}\n\n/**\n * Custom event providing information about a loading process.\n */\nexport type LoadingEvent = CustomEvent<{\n\t/** The number representing how much was loaded. */\n\tloaded: number;\n\t/** The number representing how much needs to loaded in total. */\n\ttotal: number;\n}>;\n\n/**\n * Custom event providing progress details.\n */\nexport type ProgressTrackerEvent = CustomEvent<ProgressDetails>;\n\n/**\n * Custom event providing progress details when the task is done.\n */\nexport type DoneEvent = CustomEvent<ProgressDetails>;\n\nexport interface ProgressDetails {\n\t/** The progress percentage as a number between 0 and 100. */\n\tprogress: number;\n\t/** The caption to display during progress, a string. */\n\tcaption: string;\n}\n\n/**\n * ProgressObserver A function that receives progress updates.\n *\n * @param progress The progress percentage as a number between 0 and 100.\n */\ntype ProgressObserver = (progress: number) => void;\n\n/**\n * Listener A function for handling specific event types.\n *\n * @param event The event of type T.\n */\nexport type Listener<T> = (event: T) => void;\n\nexport type TSCompatibleListener<T> =\n\t| EventListenerOrEventListenerObject\n\t| null\n\t| Listener<T>;\n\nexport interface ProgressReceiver {\n\tsetProgress(details: ProgressDetails): any;\n\tsetLoaded(): any;\n}\n\n/*\n * Like Number.EPSILON, but better tuned to tracking progress.\n *\n * With Number.EPSILON, progress like 99.99999999999997 is still\n * considered to be below 100 – this is highly undeisrable.\n */\nconst PROGRESS_EPSILON = 0.00001;\n\n/**\n * The ProgressTracker class is a tool for tracking progress in an operation\n * that is divided into multiple stages. It allows you to create sub-trackers\n * for each stage, with individual weights and captions. The main tracker\n * automatically calculates the progress based on the weighted sum of each\n * sub-tracker's progress. This makes it easy to keep track of a complex,\n * multi-stage process and report progress in a user-friendly way.\n *\n * After creating the sub-trackers, you can call the set() method to update the\n * progress of the current stage. You can also call the finish() method to mark\n * the current stage as complete and move on to the next one. Alternatively,\n * you can call the fillSlowly() method to simulate progress filling up slowly\n * to 100% before calling finish().\n *\n * @example\n * ```ts\n * const tracker = new ProgressTracker();\n * tracker.addEventListener('progress', (e) => {\n * \t\tconsole.log(\n * \t\t\t\te.detail.progress,\n * \t\t\t\te.detail.caption\n * \t\t);\n * });\n *\n * const stage1 = tracker.stage(0.5, 'Calculating pi digits');\n * const stage2 = tracker.stage(0.5, 'Downloading data');\n *\n * stage1.fillSlowly();\n * await calc100DigitsOfPi();\n * stage1.finish();\n *\n * await fetchWithProgress(function onProgress(loaded, total) {\n * \t\tstage2.set( loaded / total * 100);\n * });\n * stage2.finish();\n */\nexport class ProgressTracker extends EventTarget {\n\tprivate _selfWeight = 1;\n\tprivate _selfDone = false;\n\tprivate _selfProgress = 0;\n\tprivate _selfCaption = '';\n\tprivate _weight: number;\n\tprivate _progressObserver?: ProgressObserver;\n\tprivate _loadingListener?: Listener<LoadingEvent>;\n\tprivate _isFilling = false;\n\tprivate _fillTime: number;\n\tprivate _fillInterval?: any;\n\tprivate _subTrackers: ProgressTracker[] = [];\n\n\tconstructor({\n\t\tweight = 1,\n\t\tcaption = '',\n\t\tfillTime = 4,\n\t}: ProgressTrackerOptions = {}) {\n\t\tsuper();\n\t\tthis._weight = weight;\n\t\tthis._selfCaption = caption;\n\t\tthis._fillTime = fillTime;\n\t}\n\n\t/**\n\t * Creates a new sub-tracker with a specific weight.\n\t *\n\t * The weight determines what percentage of the overall progress\n\t * the sub-tracker represents. For example, if the main tracker is\n\t * monitoring a process that has two stages, and the first stage\n\t * is expected to take twice as long as the second stage, you could\n\t * create the first sub-tracker with a weight of 0.67 and the second\n\t * sub-tracker with a weight of 0.33.\n\t *\n\t * The caption is an optional string that describes the current stage\n\t * of the operation. If provided, it will be used as the progress caption\n\t * for the sub-tracker. If not provided, the main tracker will look for\n\t * the next sub-tracker with a non-empty caption and use that as the progress\n\t * caption instead.\n\t *\n\t * Returns the newly-created sub-tracker.\n\t *\n\t * @throws {Error} If the weight of the new stage would cause the total weight of all stages to exceed 1.\n\t *\n\t * @param weight The weight of the new stage, as a decimal value between 0 and 1.\n\t * @param caption The caption for the new stage, which will be used as the progress caption for the sub-tracker.\n\t *\n\t * @example\n\t * ```ts\n\t * const tracker = new ProgressTracker();\n\t * const subTracker1 = tracker.stage(0.67, 'Slow stage');\n\t * const subTracker2 = tracker.stage(0.33, 'Fast stage');\n\t *\n\t * subTracker2.set(50);\n\t * subTracker1.set(75);\n\t * subTracker2.set(100);\n\t * subTracker1.set(100);\n\t * ```\n\t */\n\tstage(weight?: number, caption = ''): ProgressTracker {\n\t\tif (!weight) {\n\t\t\tweight = this._selfWeight;\n\t\t}\n\t\tif (this._selfWeight - weight < -PROGRESS_EPSILON) {\n\t\t\tthrow new Error(\n\t\t\t\t`Cannot add a stage with weight ${weight} as the total weight of registered stages would exceed 1.`\n\t\t\t);\n\t\t}\n\t\tthis._selfWeight -= weight;\n\n\t\tconst subTracker = new ProgressTracker({\n\t\t\tcaption,\n\t\t\tweight,\n\t\t\tfillTime: this._fillTime,\n\t\t});\n\t\tthis._subTrackers.push(subTracker);\n\t\tsubTracker.addEventListener('progress', () => this.notifyProgress());\n\t\tsubTracker.addEventListener('done', () => {\n\t\t\tif (this.done) {\n\t\t\t\tthis.notifyDone();\n\t\t\t}\n\t\t});\n\t\treturn subTracker;\n\t}\n\n\t/**\n\t * Fills the progress bar slowly over time, simulating progress.\n\t *\n\t * The progress bar is filled in a 100 steps, and each step, the progress\n\t * is increased by 1. If `stopBeforeFinishing` is true, the progress bar\n\t * will stop filling when it reaches 99% so that you can call `finish()`\n\t * explicitly.\n\t *\n\t * If the progress bar is filling or already filled, this method does nothing.\n\t *\n\t * @example\n\t * ```ts\n\t * const progress = new ProgressTracker({ caption: 'Processing...' });\n\t * progress.fillSlowly();\n\t * ```\n\t *\n\t * @param options Optional options.\n\t */\n\tfillSlowly({ stopBeforeFinishing = true } = {}): void {\n\t\tif (this._isFilling) {\n\t\t\treturn;\n\t\t}\n\t\tthis._isFilling = true;\n\t\tconst steps = 100;\n\t\tconst interval = this._fillTime / steps;\n\t\tthis._fillInterval = setInterval(() => {\n\t\t\tthis.set(this._selfProgress + 1);\n\t\t\tif (stopBeforeFinishing && this._selfProgress >= 99) {\n\t\t\t\tclearInterval(this._fillInterval);\n\t\t\t}\n\t\t}, interval);\n\t}\n\n\tset(value: number): void {\n\t\tthis._selfProgress = Math.min(value, 100);\n\t\tthis.notifyProgress();\n\t\tif (this._selfProgress + PROGRESS_EPSILON >= 100) {\n\t\t\tthis.finish();\n\t\t}\n\t}\n\n\tfinish(): void {\n\t\tif (this._fillInterval) {\n\t\t\tclearInterval(this._fillInterval);\n\t\t}\n\t\tthis._selfDone = true;\n\t\tthis._selfProgress = 100;\n\t\tthis._isFilling = false;\n\t\tthis._fillInterval = undefined;\n\t\tthis.notifyProgress();\n\t\tthis.notifyDone();\n\t}\n\n\tget caption(): string {\n\t\tfor (let i = this._subTrackers.length - 1; i >= 0; i--) {\n\t\t\tif (!this._subTrackers[i].done) {\n\t\t\t\tconst captionMaybe = this._subTrackers[i].caption;\n\t\t\t\tif (captionMaybe) {\n\t\t\t\t\treturn captionMaybe;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn this._selfCaption;\n\t}\n\n\tsetCaption(caption: string) {\n\t\tthis._selfCaption = caption;\n\t\tthis.notifyProgress();\n\t}\n\n\tget done(): boolean {\n\t\treturn this.progress + PROGRESS_EPSILON >= 100;\n\t}\n\n\tget progress(): number {\n\t\tif (this._selfDone) {\n\t\t\treturn 100;\n\t\t}\n\t\tconst sum = this._subTrackers.reduce(\n\t\t\t(sum, tracker) => sum + tracker.progress * tracker.weight,\n\t\t\tthis._selfProgress * this._selfWeight\n\t\t);\n\t\treturn Math.round(sum * 10000) / 10000;\n\t}\n\n\tget weight(): number {\n\t\treturn this._weight;\n\t}\n\n\tget observer() {\n\t\tif (!this._progressObserver) {\n\t\t\tthis._progressObserver = (progress: number) => {\n\t\t\t\tthis.set(progress);\n\t\t\t};\n\t\t}\n\t\treturn this._progressObserver;\n\t}\n\n\tget loadingListener() {\n\t\tif (!this._loadingListener) {\n\t\t\tthis._loadingListener = (event: LoadingEvent) => {\n\t\t\t\tthis.set((event.detail.loaded / event.detail.total) * 100);\n\t\t\t};\n\t\t}\n\t\treturn this._loadingListener;\n\t}\n\n\tpipe(receiver: ProgressReceiver) {\n\t\treceiver.setProgress({\n\t\t\tprogress: this.progress,\n\t\t\tcaption: this.caption,\n\t\t});\n\t\tthis.addEventListener('progress', (event: ProgressTrackerEvent) => {\n\t\t\treceiver.setProgress({\n\t\t\t\tprogress: event.detail.progress,\n\t\t\t\tcaption: event.detail.caption,\n\t\t\t});\n\t\t});\n\t\tthis.addEventListener('done', () => {\n\t\t\treceiver.setLoaded();\n\t\t});\n\t}\n\n\toverride addEventListener(\n\t\ttype: string,\n\t\tlistener: TSCompatibleListener<ProgressTrackerEvent>\n\t) {\n\t\tsuper.addEventListener(type, listener as any);\n\t}\n\n\toverride removeEventListener(\n\t\ttype: string,\n\t\tlistener: TSCompatibleListener<ProgressTrackerEvent>\n\t) {\n\t\tsuper.removeEventListener(type, listener as any);\n\t}\n\n\tprivate notifyProgress() {\n\t\t// eslint-disable-next-line @typescript-eslint/no-this-alias\n\t\tconst self = this;\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('progress', {\n\t\t\t\tdetail: {\n\t\t\t\t\tget progress() {\n\t\t\t\t\t\treturn self.progress;\n\t\t\t\t\t},\n\t\t\t\t\tget caption() {\n\t\t\t\t\t\treturn self.caption;\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t);\n\t}\n\n\tprivate notifyDone() {\n\t\tthis.dispatchEvent(new CustomEvent('done'));\n\t}\n}\n"],"names":["FALLBACK_FILE_SIZE","EmscriptenDownloadMonitor","__privateAdd","_EmscriptenDownloadMonitor_instances","_assetsSizes","_progress","assets","urlLike","size","dummyBaseUrl","filename","__privateGet","fetchPromise","response","cloneResponseMonitorProgress","event","__privateMethod","notify_fn","file","loaded","fileSize","fileName","logger","sumValues","obj","length","value","onProgress","contentLength","cloneStreamMonitorProgress","stream","total","lastNotifyTime","notify","done","now","controller","reader","e","ProgressObserver","_ProgressObserver_instances","_observedProgresses","_lastObserverId","__privateSet","progressBudget","caption","id","__privateWrapper","progress","onProgress_fn","mode","PROGRESS_EPSILON","ProgressTracker","weight","fillTime","subTracker","stopBeforeFinishing","interval","i","captionMaybe","sum","tracker","receiver","type","listener","self"],"mappings":"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"}
{"version":3,"file":"index.js","sources":["../../../../packages/php-wasm/progress/src/lib/emscripten-download-monitor.ts","../../../../packages/php-wasm/progress/src/lib/progress-observer.ts","../../../../packages/php-wasm/progress/src/lib/progress-tracker.ts"],"sourcesContent":["import { logger } from '@php-wasm/logger';\n/*\n * An approximate file length to use when the actual\n * length number of bytes is missing.\n *\n * This may happen when the files are compressed before transmission\n * and no content-length header is being sent.\n *\n * The approximation isn't accurate, but it's better than nothing.\n * It's not about being exact but about giving the user a rough sense\n * of #progress.\n */\nconst FALLBACK_FILE_SIZE = 5 * 1024 * 1024;\n\n/**\n * Monitors the download #progress of Emscripten modules\n *\n * Usage:\n *\n * ```js\n * const downloadMonitor = new EmscriptenDownloadMonitor();\n * \t const php = await startPHP(\n * phpLoaderModule,\n * 'web',\n * downloadMonitor.phpArgs\n * );\n * downloadMonitor.addEventListener('#progress', (e) => {\n * console.log( e.detail.#progress);\n * })\n * ```\n */\nexport class EmscriptenDownloadMonitor extends EventTarget {\n\t#assetsSizes: Record<string, number> = {};\n\t#progress: Record<string, number> = {};\n\n\texpectAssets(assets: Record<string, number>) {\n\t\tfor (const [urlLike, size] of Object.entries(assets)) {\n\t\t\tconst dummyBaseUrl = 'http://example.com/';\n\t\t\tconst pathname = new URL(urlLike, dummyBaseUrl).pathname;\n\t\t\tconst filename = pathname.split('/').pop()!;\n\t\t\tif (!(filename in this.#assetsSizes)) {\n\t\t\t\tthis.#assetsSizes[filename] = size;\n\t\t\t}\n\t\t\tif (!(filename in this.#progress)) {\n\t\t\t\tthis.#progress[filename] = 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tasync monitorFetch(fetchPromise: Promise<Response>): Promise<Response> {\n\t\tconst response = await fetchPromise;\n\t\tconst onProgress = (event: CustomEvent<DownloadProgress>) => {\n\t\t\tthis.#notify(response.url, event.detail.loaded, event.detail.total);\n\t\t};\n\t\treturn cloneResponseMonitorProgress(response, onProgress);\n\t}\n\n\t/**\n\t * Notifies about the download #progress of a file.\n\t *\n\t * @param file The file name.\n\t * @param loaded The number of bytes of that file loaded so far.\n\t * @param fileSize The length number of bytes in the loaded file.\n\t */\n\t#notify(file: string, loaded: number, fileSize: number) {\n\t\tconst fileName = new URL(file, 'http://example.com').pathname\n\t\t\t.split('/')\n\t\t\t.pop()!;\n\t\tif (!fileSize) {\n\t\t\tfileSize = this.#assetsSizes[fileName];\n\t\t} else if (!(fileName in this.#assetsSizes)) {\n\t\t\tthis.#assetsSizes[fileName] = fileSize;\n\t\t\tthis.#progress[fileName] = loaded;\n\t\t}\n\t\tif (!(fileName in this.#progress)) {\n\t\t\tlogger.warn(\n\t\t\t\t`Registered a download #progress of an unregistered file \"${fileName}\". ` +\n\t\t\t\t\t`This may cause a sudden **decrease** in the #progress percentage as the ` +\n\t\t\t\t\t`length number of bytes increases during the download.`\n\t\t\t);\n\t\t}\n\n\t\tthis.#progress[fileName] = loaded;\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('progress', {\n\t\t\t\tdetail: {\n\t\t\t\t\tloaded: sumValues(this.#progress),\n\t\t\t\t\ttotal: sumValues(this.#assetsSizes),\n\t\t\t\t},\n\t\t\t})\n\t\t);\n\t}\n}\n\nfunction sumValues(obj: Record<string, number>) {\n\treturn Object.values(obj).reduce((length, value) => length + value, 0);\n}\n\nexport default EmscriptenDownloadMonitor;\n\nexport interface DownloadProgress {\n\t/**\n\t * The number of bytes loaded so far.\n\t */\n\tloaded: number;\n\t/**\n\t * The length number of bytes to load.\n\t */\n\ttotal: number;\n}\n\n/**\n * Clones a fetch Response object and returns a version\n * that calls the `onProgress` callback as the #progress\n * changes.\n *\n * @param response The fetch Response object to clone.\n * @param onProgress The callback to call when the download #progress changes.\n * @returns The cloned response\n */\nexport function cloneResponseMonitorProgress(\n\tresponse: Response,\n\tonProgress: (event: CustomEvent<DownloadProgress>) => void\n): Response {\n\tconst contentLength = response.headers.get('content-length') || '';\n\tconst length = parseInt(contentLength, 10) || FALLBACK_FILE_SIZE;\n\n\treturn new Response(\n\t\tcloneStreamMonitorProgress(response.body, length, onProgress),\n\t\t{\n\t\t\tstatus: response.status,\n\t\t\tstatusText: response.statusText,\n\t\t\theaders: response.headers,\n\t\t}\n\t);\n}\n\n/**\n * Clones a ReadableStream and returns a version\n * that calls the `onProgress` callback as the #progress\n * changes.\n *\n * @param stream The ReadableStream to clone.\n * @param total The total number of bytes to load.\n * @param onProgress The callback to call when the download #progress changes.\n * @returns The cloned ReadableStream\n */\nexport function cloneStreamMonitorProgress(\n\tstream: ReadableStream<Uint8Array> | null,\n\ttotal: number,\n\tonProgress: (event: CustomEvent<DownloadProgress>) => void\n): ReadableStream<Uint8Array> {\n\tlet lastNotifyTime = 0;\n\n\tfunction notify(loaded: number, total: number, done: boolean) {\n\t\tconst now = performance.now();\n\n\t\t/*\n\t\t * This throttling exists to prevent severe UX degradation on mobile browsers,\n\t\t * particularly Safari. In some mobile environments, loading Playground\n\t\t * could take tens of seconds and appear frozen or blank, even though the boot\n\t\t * process eventually completed successfully.\n\t\t *\n\t\t * The issue was an excessive number of progress notifications directly tied\n\t\t * to how often php-wasm was able to read from a download's ReadableStream.\n\t\t * Each time we received a chunk from a readable stream, we sent a corresponding\n\t\t * progress notification. This appeared to work OK in Chrome and other browsers,\n\t\t * but we observed Safari's ReadableStream reading data in such small chunks\n\t\t * that we flooded the message channel with progress notifications.\n\t\t * This caused unnecessary main-thread pressure which impacted performance.\n\t\t *\n\t\t * To avoid this issue, we now throttle these progress notifications.\n\t\t */\n\t\tif (!done && now - lastNotifyTime < 500) return;\n\n\t\tlastNotifyTime = now;\n\n\t\tonProgress(\n\t\t\tnew CustomEvent('progress', {\n\t\t\t\tdetail: {\n\t\t\t\t\tloaded,\n\t\t\t\t\ttotal,\n\t\t\t\t},\n\t\t\t})\n\t\t);\n\t}\n\n\treturn new ReadableStream({\n\t\tasync start(controller) {\n\t\t\tif (!stream) {\n\t\t\t\tcontroller.close();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst reader = stream.getReader();\n\t\t\tlet loaded = 0;\n\t\t\twhile (true) {\n\t\t\t\ttry {\n\t\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\t\tif (value) {\n\t\t\t\t\t\tloaded += value.byteLength;\n\t\t\t\t\t}\n\t\t\t\t\tif (done) {\n\t\t\t\t\t\tnotify(loaded, loaded, done);\n\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnotify(loaded, total, done);\n\t\t\t\t\t\tcontroller.enqueue(value);\n\t\t\t\t\t}\n\t\t\t\t} catch (e) {\n\t\t\t\t\tlogger.error({ e });\n\t\t\t\t\tcontroller.error(e);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t});\n}\n\nexport type DownloadProgressCallback = (progress: DownloadProgress) => void;\n","import type { DownloadProgress } from './emscripten-download-monitor';\n\nexport type ProgressMode =\n\t/**\n\t * Real-time progress is used when we get real-time reports\n\t * about the progress.\n\t */\n\t| 'REAL_TIME'\n\n\t/**\n\t * Slowly increment progress is used when we don't know how long\n\t * an operation will take and just want to keep slowly incrementing\n\t * the progress bar.\n\t */\n\t| 'SLOWLY_INCREMENT';\n\nexport type ProgressObserverEvent = {\n\tprogress: number;\n\tmode: ProgressMode;\n\tcaption: string;\n};\n\nexport class ProgressObserver extends EventTarget {\n\t#observedProgresses: Record<number, number> = {};\n\t#lastObserverId = 0;\n\n\tprogress = 0;\n\tmode: ProgressMode = 'REAL_TIME';\n\tcaption = '';\n\n\tpartialObserver(progressBudget: number, caption = '') {\n\t\tconst id = ++this.#lastObserverId;\n\t\tthis.#observedProgresses[id] = 0;\n\t\treturn (progress: CustomEvent<DownloadProgress>) => {\n\t\t\tconst { loaded, total } = progress?.detail || {};\n\t\t\tthis.#observedProgresses[id] = (loaded / total) * progressBudget;\n\t\t\tthis.#onProgress(this.totalProgress, 'REAL_TIME', caption);\n\t\t};\n\t}\n\n\tslowlyIncrementBy(progress: number) {\n\t\tconst id = ++this.#lastObserverId;\n\t\tthis.#observedProgresses[id] = progress;\n\t\tthis.#onProgress(this.totalProgress, 'SLOWLY_INCREMENT');\n\t}\n\n\tget totalProgress() {\n\t\treturn Object.values(this.#observedProgresses).reduce(\n\t\t\t(total, progress) => total + progress,\n\t\t\t0\n\t\t);\n\t}\n\n\t#onProgress(progress: number, mode: ProgressMode, caption?: string) {\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('progress', {\n\t\t\t\tdetail: {\n\t\t\t\t\tprogress,\n\t\t\t\t\tmode,\n\t\t\t\t\tcaption,\n\t\t\t\t},\n\t\t\t})\n\t\t);\n\t}\n}\n","/**\n * Options for customizing the progress tracker.\n */\nexport interface ProgressTrackerOptions {\n\t/** The weight of the progress, a number between 0 and 1. */\n\tweight?: number;\n\t/** The caption to display during progress, a string. */\n\tcaption?: string;\n\t/** The time in milliseconds to fill the progress, a number. */\n\tfillTime?: number;\n}\n\n/**\n * Custom event providing information about a loading process.\n */\nexport type LoadingEvent = CustomEvent<{\n\t/** The number representing how much was loaded. */\n\tloaded: number;\n\t/** The number representing how much needs to loaded in total. */\n\ttotal: number;\n}>;\n\n/**\n * Custom event providing progress details.\n */\nexport type ProgressTrackerEvent = CustomEvent<ProgressDetails>;\n\n/**\n * Custom event providing progress details when the task is done.\n */\nexport type DoneEvent = CustomEvent<ProgressDetails>;\n\nexport interface ProgressDetails {\n\t/** The progress percentage as a number between 0 and 100. */\n\tprogress: number;\n\t/** The caption to display during progress, a string. */\n\tcaption: string;\n}\n\n/**\n * ProgressObserver A function that receives progress updates.\n *\n * @param progress The progress percentage as a number between 0 and 100.\n */\ntype ProgressObserver = (progress: number) => void;\n\n/**\n * Listener A function for handling specific event types.\n *\n * @param event The event of type T.\n */\nexport type Listener<T> = (event: T) => void;\n\nexport type TSCompatibleListener<T> =\n\t| EventListenerOrEventListenerObject\n\t| null\n\t| Listener<T>;\n\nexport interface ProgressReceiver {\n\tsetProgress(details: ProgressDetails): any;\n\tsetLoaded(): any;\n}\n\n/*\n * Like Number.EPSILON, but better tuned to tracking progress.\n *\n * With Number.EPSILON, progress like 99.99999999999997 is still\n * considered to be below 100 – this is highly undeisrable.\n */\nconst PROGRESS_EPSILON = 0.00001;\n\n/**\n * The ProgressTracker class is a tool for tracking progress in an operation\n * that is divided into multiple stages. It allows you to create sub-trackers\n * for each stage, with individual weights and captions. The main tracker\n * automatically calculates the progress based on the weighted sum of each\n * sub-tracker's progress. This makes it easy to keep track of a complex,\n * multi-stage process and report progress in a user-friendly way.\n *\n * After creating the sub-trackers, you can call the set() method to update the\n * progress of the current stage. You can also call the finish() method to mark\n * the current stage as complete and move on to the next one. Alternatively,\n * you can call the fillSlowly() method to simulate progress filling up slowly\n * to 100% before calling finish().\n *\n * @example\n * ```ts\n * const tracker = new ProgressTracker();\n * tracker.addEventListener('progress', (e) => {\n * \t\tconsole.log(\n * \t\t\t\te.detail.progress,\n * \t\t\t\te.detail.caption\n * \t\t);\n * });\n *\n * const stage1 = tracker.stage(0.5, 'Calculating pi digits');\n * const stage2 = tracker.stage(0.5, 'Downloading data');\n *\n * stage1.fillSlowly();\n * await calc100DigitsOfPi();\n * stage1.finish();\n *\n * await fetchWithProgress(function onProgress(loaded, total) {\n * \t\tstage2.set( loaded / total * 100);\n * });\n * stage2.finish();\n */\nexport class ProgressTracker extends EventTarget {\n\tprivate _selfWeight = 1;\n\tprivate _selfDone = false;\n\tprivate _selfProgress = 0;\n\tprivate _selfCaption = '';\n\tprivate _weight: number;\n\tprivate _progressObserver?: ProgressObserver;\n\tprivate _loadingListener?: Listener<LoadingEvent>;\n\tprivate _isFilling = false;\n\tprivate _fillTime: number;\n\tprivate _fillInterval?: any;\n\tprivate _subTrackers: ProgressTracker[] = [];\n\n\tconstructor({\n\t\tweight = 1,\n\t\tcaption = '',\n\t\tfillTime = 4,\n\t}: ProgressTrackerOptions = {}) {\n\t\tsuper();\n\t\tthis._weight = weight;\n\t\tthis._selfCaption = caption;\n\t\tthis._fillTime = fillTime;\n\t}\n\n\t/**\n\t * Creates a new sub-tracker with a specific weight.\n\t *\n\t * The weight determines what percentage of the overall progress\n\t * the sub-tracker represents. For example, if the main tracker is\n\t * monitoring a process that has two stages, and the first stage\n\t * is expected to take twice as long as the second stage, you could\n\t * create the first sub-tracker with a weight of 0.67 and the second\n\t * sub-tracker with a weight of 0.33.\n\t *\n\t * The caption is an optional string that describes the current stage\n\t * of the operation. If provided, it will be used as the progress caption\n\t * for the sub-tracker. If not provided, the main tracker will look for\n\t * the next sub-tracker with a non-empty caption and use that as the progress\n\t * caption instead.\n\t *\n\t * Returns the newly-created sub-tracker.\n\t *\n\t * @throws {Error} If the weight of the new stage would cause the total weight of all stages to exceed 1.\n\t *\n\t * @param weight The weight of the new stage, as a decimal value between 0 and 1.\n\t * @param caption The caption for the new stage, which will be used as the progress caption for the sub-tracker.\n\t *\n\t * @example\n\t * ```ts\n\t * const tracker = new ProgressTracker();\n\t * const subTracker1 = tracker.stage(0.67, 'Slow stage');\n\t * const subTracker2 = tracker.stage(0.33, 'Fast stage');\n\t *\n\t * subTracker2.set(50);\n\t * subTracker1.set(75);\n\t * subTracker2.set(100);\n\t * subTracker1.set(100);\n\t * ```\n\t */\n\tstage(weight?: number, caption = ''): ProgressTracker {\n\t\tif (!weight) {\n\t\t\tweight = this._selfWeight;\n\t\t}\n\t\tif (this._selfWeight - weight < -PROGRESS_EPSILON) {\n\t\t\tthrow new Error(\n\t\t\t\t`Cannot add a stage with weight ${weight} as the total weight of registered stages would exceed 1.`\n\t\t\t);\n\t\t}\n\t\tthis._selfWeight -= weight;\n\n\t\tconst subTracker = new ProgressTracker({\n\t\t\tcaption,\n\t\t\tweight,\n\t\t\tfillTime: this._fillTime,\n\t\t});\n\t\tthis._subTrackers.push(subTracker);\n\t\tsubTracker.addEventListener('progress', () => this.notifyProgress());\n\t\tsubTracker.addEventListener('done', () => {\n\t\t\tif (this.done) {\n\t\t\t\tthis.notifyDone();\n\t\t\t}\n\t\t});\n\t\treturn subTracker;\n\t}\n\n\t/**\n\t * Fills the progress bar slowly over time, simulating progress.\n\t *\n\t * The progress bar is filled in a 100 steps, and each step, the progress\n\t * is increased by 1. If `stopBeforeFinishing` is true, the progress bar\n\t * will stop filling when it reaches 99% so that you can call `finish()`\n\t * explicitly.\n\t *\n\t * If the progress bar is filling or already filled, this method does nothing.\n\t *\n\t * @example\n\t * ```ts\n\t * const progress = new ProgressTracker({ caption: 'Processing...' });\n\t * progress.fillSlowly();\n\t * ```\n\t *\n\t * @param options Optional options.\n\t */\n\tfillSlowly({ stopBeforeFinishing = true } = {}): void {\n\t\tif (this._isFilling) {\n\t\t\treturn;\n\t\t}\n\t\tthis._isFilling = true;\n\t\tconst steps = 100;\n\t\tconst interval = this._fillTime / steps;\n\t\tthis._fillInterval = setInterval(() => {\n\t\t\tthis.set(this._selfProgress + 1);\n\t\t\tif (stopBeforeFinishing && this._selfProgress >= 99) {\n\t\t\t\tclearInterval(this._fillInterval);\n\t\t\t}\n\t\t}, interval);\n\t}\n\n\tset(value: number): void {\n\t\tthis._selfProgress = Math.min(value, 100);\n\t\tthis.notifyProgress();\n\t\tif (this._selfProgress + PROGRESS_EPSILON >= 100) {\n\t\t\tthis.finish();\n\t\t}\n\t}\n\n\tfinish(): void {\n\t\tif (this._fillInterval) {\n\t\t\tclearInterval(this._fillInterval);\n\t\t}\n\t\tthis._selfDone = true;\n\t\tthis._selfProgress = 100;\n\t\tthis._isFilling = false;\n\t\tthis._fillInterval = undefined;\n\t\tthis.notifyProgress();\n\t\tthis.notifyDone();\n\t}\n\n\tget caption(): string {\n\t\tfor (let i = this._subTrackers.length - 1; i >= 0; i--) {\n\t\t\tif (!this._subTrackers[i].done) {\n\t\t\t\tconst captionMaybe = this._subTrackers[i].caption;\n\t\t\t\tif (captionMaybe) {\n\t\t\t\t\treturn captionMaybe;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn this._selfCaption;\n\t}\n\n\tsetCaption(caption: string) {\n\t\tthis._selfCaption = caption;\n\t\tthis.notifyProgress();\n\t}\n\n\tget done(): boolean {\n\t\treturn this.progress + PROGRESS_EPSILON >= 100;\n\t}\n\n\tget progress(): number {\n\t\tif (this._selfDone) {\n\t\t\treturn 100;\n\t\t}\n\t\tconst sum = this._subTrackers.reduce(\n\t\t\t(sum, tracker) => sum + tracker.progress * tracker.weight,\n\t\t\tthis._selfProgress * this._selfWeight\n\t\t);\n\t\treturn Math.round(sum * 10000) / 10000;\n\t}\n\n\tget weight(): number {\n\t\treturn this._weight;\n\t}\n\n\tget observer() {\n\t\tif (!this._progressObserver) {\n\t\t\tthis._progressObserver = (progress: number) => {\n\t\t\t\tthis.set(progress);\n\t\t\t};\n\t\t}\n\t\treturn this._progressObserver;\n\t}\n\n\tget loadingListener() {\n\t\tif (!this._loadingListener) {\n\t\t\tthis._loadingListener = (event: LoadingEvent) => {\n\t\t\t\tthis.set((event.detail.loaded / event.detail.total) * 100);\n\t\t\t};\n\t\t}\n\t\treturn this._loadingListener;\n\t}\n\n\tpipe(receiver: ProgressReceiver) {\n\t\treceiver.setProgress({\n\t\t\tprogress: this.progress,\n\t\t\tcaption: this.caption,\n\t\t});\n\t\tthis.addEventListener('progress', (event: ProgressTrackerEvent) => {\n\t\t\treceiver.setProgress({\n\t\t\t\tprogress: event.detail.progress,\n\t\t\t\tcaption: event.detail.caption,\n\t\t\t});\n\t\t});\n\t\tthis.addEventListener('done', () => {\n\t\t\treceiver.setLoaded();\n\t\t});\n\t}\n\n\toverride addEventListener(\n\t\ttype: string,\n\t\tlistener: TSCompatibleListener<ProgressTrackerEvent>\n\t) {\n\t\tsuper.addEventListener(type, listener as any);\n\t}\n\n\toverride removeEventListener(\n\t\ttype: string,\n\t\tlistener: TSCompatibleListener<ProgressTrackerEvent>\n\t) {\n\t\tsuper.removeEventListener(type, listener as any);\n\t}\n\n\tprivate notifyProgress() {\n\t\t// eslint-disable-next-line @typescript-eslint/no-this-alias\n\t\tconst self = this;\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('progress', {\n\t\t\t\tdetail: {\n\t\t\t\t\tget progress() {\n\t\t\t\t\t\treturn self.progress;\n\t\t\t\t\t},\n\t\t\t\t\tget caption() {\n\t\t\t\t\t\treturn self.caption;\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t);\n\t}\n\n\tprivate notifyDone() {\n\t\tthis.dispatchEvent(new CustomEvent('done'));\n\t}\n}\n"],"names":["FALLBACK_FILE_SIZE","EmscriptenDownloadMonitor","__privateAdd","_EmscriptenDownloadMonitor_instances","_assetsSizes","_progress","assets","urlLike","size","dummyBaseUrl","filename","__privateGet","fetchPromise","response","cloneResponseMonitorProgress","event","__privateMethod","notify_fn","file","loaded","fileSize","fileName","logger","sumValues","obj","length","value","onProgress","contentLength","cloneStreamMonitorProgress","stream","total","lastNotifyTime","notify","done","now","controller","reader","e","ProgressObserver","_ProgressObserver_instances","_observedProgresses","_lastObserverId","__privateSet","progressBudget","caption","id","__privateWrapper","progress","onProgress_fn","mode","PROGRESS_EPSILON","ProgressTracker","weight","fillTime","subTracker","stopBeforeFinishing","interval","i","captionMaybe","sum","tracker","receiver","type","listener","self"],"mappings":"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"}
{
"name": "@php-wasm/progress",
"version": "3.1.19",
"version": "3.1.20",
"description": "PHP.wasm – loading progress monitoring",

@@ -40,3 +40,3 @@ "repository": {

"types": "index.d.ts",
"gitHead": "be542ee28a5966eeb28154cd8e3723db5ff9df07",
"gitHead": "98cfca0a050ef1dacce25710d6ebdf816e80b764",
"engines": {

@@ -56,8 +56,8 @@ "node": ">=20.10.0",

"lodash": "^4.17.23",
"glob": "^9.3.0"
"glob": "^9.3.0",
"webpackbar": "^7.0.0"
},
"dependencies": {
"@php-wasm/node-polyfills": "3.1.19",
"@php-wasm/logger": "3.1.19"
"@php-wasm/logger": "3.1.20"
}
}