{"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\tfileName,\n\t\t\t\t\tfileLoaded: loaded,\n\t\t\t\t\tfileTotal: fileSize,\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\t/**\n\t * The file that emitted this progress update.\n\t */\n\tfileName?: string;\n\t/**\n\t * The number of bytes loaded for the current file.\n\t */\n\tfileLoaded?: number;\n\t/**\n\t * The length number of bytes to load for the current file.\n\t */\n\tfileTotal?: 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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"}