34 lines
1.4 KiB
TypeScript
34 lines
1.4 KiB
TypeScript
/**
|
|
* Shared, cross-hook "one export operation at a time" guard.
|
|
*
|
|
* Every browser-side export path — the ZIP build ({@link useExportVideo}) and the
|
|
* subtitles-only download ({@link useDownloadSubtitles}) — funnels through
|
|
* `compileStageIr`, which reads the live stage store, hits Dexie, and (for the
|
|
* ZIP) drives off-screen renders. Running two at once would read/mutate the same
|
|
* state and duplicate that work, so they must be mutually exclusive.
|
|
*
|
|
* This is a **module singleton**, not a per-hook ref: the export UI unmounts as
|
|
* soon as its dropdown/dialog closes, which would reset a per-instance ref to
|
|
* false and let a second pipeline start. A module-level flag survives remounts
|
|
* and is shared across every export hook, so acquiring it here excludes the
|
|
* others too. (The in-app render path has its own equivalent guard in the render
|
|
* store's `status`.)
|
|
*/
|
|
let inFlight = false;
|
|
|
|
/**
|
|
* Try to enter the export critical section. Returns true when acquired (the
|
|
* caller must later {@link releaseExport}); false when another export already
|
|
* holds it and the caller should bail out.
|
|
*/
|
|
export function acquireExport(): boolean {
|
|
if (inFlight) return false;
|
|
inFlight = true;
|
|
return true;
|
|
}
|
|
|
|
/** Leave the export critical section. Call in a `finally` after {@link acquireExport}. */
|
|
export function releaseExport(): void {
|
|
inFlight = false;
|
|
}
|