{"version":3,"sources":["jsdelivr-header.js","/npm/horse-sparkle@1.0.3/dist.es2018/index.js"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA,ACNA,aAEA,MAAM,YAAc,SAYpB,MAAM,UACJ,OAAS,GACT,SAAU,EACV,sBAAuB,EACvB,gBAAkB,GAClB,WAAA,EAAY,QACV,EAAO,eACP,GACE,CAAC,GACH,KAAK,QAAU,EACf,KAAK,eAAiB,GAAkB,OAAO,gBACjD,CACA,uBAAA,GAME,OALK,KAAK,gBACR,KAAK,cAAgB,IAAI,SAAQ,IAC/B,KAAK,wBAA0B,CAAO,KAGnC,KAAK,aACd,CAIA,kBAAM,GACJ,IAAI,EAA0B,EAC9B,KAAO,KAAK,UACL,KAAK,OAAO,eACT,KAAK,0BACN,KAAK,WAHO,CAOnB,MAAM,EAAW,KAAK,OAAO,QAC7B,IAAK,EACH,MAAM,IAAI,MAAM,uDAEhB,KAAK,cAAgB,KAAK,6BAA0B,EAElD,KAAK,wBAA0B,KAAK,OAAO,OAAS,KAAK,gBAC3D,KAAK,yBAEP,MAAM,SACJ,EAAQ,QACR,GACE,GACE,KACJ,EAAI,MACJ,SACQ,EAAS,OACnB,IAAK,KAAK,QACR,MAEF,GAAK,EAwBH,EAA0B,OAvB1B,GAAI,IAAU,YACZ,EAAS,eACJ,CAIL,GAHI,KAAK,eACD,KAAK,QAAQ,EAAO,IAEvB,KAAK,QACR,QAEA,EACE,KAAK,OAAO,OAAS,KAAK,eAG5B,KAAK,OAAO,KAAK,IAIjB,EAAS,WACT,KAAK,gBAAgB,KAAK,GAC1B,KAAK,gCAET,CAIJ,CACF,CAQA,KAAA,GAGE,OAFA,KAAK,SAAU,EACf,KAAK,cAAgB,KAAK,eACnB,KAAK,aACd,CAUA,SAAA,CAAU,EAAS,GACjB,IAAK,KAAK,QACR,MAAM,IAAI,MAAM,yEAEd,KAAK,OAAO,OAAS,KAAK,gBAC5B,KAAK,OAAO,KAAK,CACf,UACA,aAEF,KAAK,8BAIL,EAAS,WACT,KAAK,gBAAgB,KAAK,GAC1B,KAAK,gCAET,CAOA,UAAM,GACJ,IAAK,KAAK,cACR,MAAM,IAAI,MAAM,+DAElB,KAAK,SAAU,EACf,KAAK,4BACL,KAAK,gBAAgB,OAAO,GAC5B,KAAK,gCACL,MAAM,cACJ,GACE,KAEJ,OADA,KAAK,mBAAgB,EACd,CACT,CAMA,eAAO,GACL,GAAI,KAAK,qBACP,MAAM,IAAI,MAAM,kEAElB,KAAK,sBAAuB,EAC5B,MAAM,EAAmB,IAAM,IAAI,SAAQ,IACzC,KAAK,4BAA8B,CAAO,IAE5C,IAAI,EAAmB,IACvB,KAAO,KAAK,SAAS,OACb,EACN,EAAmB,IACnB,IAAK,MAAM,KAAY,KAAK,gBAAgB,OAAO,SAC3C,CAEV,CACA,KAAK,iCAA8B,EACnC,KAAK,sBAAuB,CAC9B,CAMA,6BAAM,GACJ,KAAO,KAAK,OAAO,QAAU,KAAK,sBAC1B,IAAI,SAAQ,IAChB,KAAK,uBAAyB,CAAO,IAEvC,KAAK,4BAAyB,CAElC,EAcF,eAAgB,YAAY,GAC1B,OACE,IACE,aAAa,GACf,CAAE,MAAO,SACD,CACR,CAEJ,CAEA,QAAQ,UAAY,UACpB,QAAQ,YAAc,YACtB,QAAQ,YAAc","file":"/npm/horse-sparkle@1.0.3/dist.es2018/index.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/horse-sparkle@1.0.3/dist.es2018/index.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","'use strict';\n\nconst dequeueWork = Symbol();\n/**\n * The work queue class processes multiple pieces of work in order.\n * Any piece of work that fails makes the queue delay the next piece of work\n * and consecutive failures increase the delay exponentially up to a maximum interval.\n * Failed pieces of work are pushed to the back of the queue and resume from the point\n * of failure after they eventually float back to the top of the queue.\n * A piece of work is represented by an AsyncIterator which yields an error whenever one\n * occurs; a piece of work that runs successfully to completion without errors will be an\n * async iterator where the first call to `next()` returns a `done` value of `true`. Each\n * yielded error will be logger by `this.logger`.\n */\nclass WorkQueue {\n  queued = [];\n  running = false;\n  listeningForDequeues = false;\n  pendingDequeues = [];\n  constructor({\n    onError,\n    maxQueueLength\n  } = {}) {\n    this.onError = onError;\n    this.maxQueueLength = maxQueueLength ?? Number.MAX_SAFE_INTEGER;\n  }\n  ensurePendingWorkSignal() {\n    if (!this.onPendingWork) {\n      this.onPendingWork = new Promise(resolve => {\n        this.signalPendingWorkOrStop = resolve;\n      });\n    }\n    return this.onPendingWork;\n  }\n\n  // process the queue indefinitely until stop is called, waiting for work when the queue is\n  // empty\n  async processQueue() {\n    let consecutiveFailureCount = 1;\n    while (this.running) {\n      if (!this.queued.length) {\n        await this.ensurePendingWorkSignal();\n        if (!this.running) {\n          break;\n        }\n      }\n      const nextWork = this.queued.shift();\n      if (!nextWork) {\n        throw new Error('Theoretically impossible empty queue state detected');\n      } else {\n        this.onPendingWork = this.signalPendingWorkOrStop = undefined;\n      }\n      if (this.signalSpaceInWorkQueue && this.queued.length < this.maxQueueLength) {\n        this.signalSpaceInWorkQueue();\n      }\n      const {\n        iterator,\n        context\n      } = nextWork;\n      const {\n        done,\n        value\n      } = await iterator.next();\n      if (!this.running) {\n        break;\n      }\n      if (!done) {\n        if (value === dequeueWork) {\n          iterator.return?.();\n        } else {\n          if (this.onError) {\n            await this.onError(value, consecutiveFailureCount);\n          }\n          if (!this.running) {\n            break;\n          }\n          ++consecutiveFailureCount;\n          if (this.queued.length < this.maxQueueLength) {\n            // thanks to the properties of async iterators the work will resume from where it\n            // failed on the next try\n            this.queued.push(nextWork);\n          } else {\n            // the queue overflowed so force the iterator to end and signal that it has been\n            // dequeued\n            iterator.return?.();\n            this.pendingDequeues.push(context);\n            this.signalPendingDequeuesOrStop?.();\n          }\n        }\n      } else {\n        consecutiveFailureCount = 0;\n      }\n    }\n  }\n\n  /**\n   * Start processing the queue, return a promise that rejects on when a catastrophic\n   * error occurs and resolves after the processing has been stopped via a call to `stop()`\n   * The promise returned from this function will remain unresolved even if the queue is emptied,\n   * future work added to the queue will cause the processing to resume.\n   */\n  start() {\n    this.running = true;\n    this.remainingWork = this.processQueue();\n    return this.remainingWork;\n  }\n\n  /**\n   * Queue a new piece of work.\n   * This work is represented by an async iterator, it should only yield in case of error.\n   * When an error is detected then the code will asynchronously sleep. The first sleep\n   * will be for `this.minDelay`ms and will double for every consecutive error\n   * up to `this.maxDelay`. Any successful piece of work resets the delay incurred on\n   * the next error back to `this.initialDelay`.\n   */\n  queueWork(context, iterator) {\n    if (!this.running) {\n      throw new Error('Cannot queue work when queue has not been started or has been stopped');\n    }\n    if (this.queued.length < this.maxQueueLength) {\n      this.queued.push({\n        context,\n        iterator\n      });\n      this.signalPendingWorkOrStop?.();\n    } else {\n      // the queue cannot accommodate this new work so force the iterator to end and signal that\n      // it has been dequeued\n      iterator.return?.();\n      this.pendingDequeues.push(context);\n      this.signalPendingDequeuesOrStop?.();\n    }\n  }\n\n  /**\n   * Stop processing the queue, the returned promise resolves after the current piece\n   * of asynchronous work has finished or immediately if there are no pending asynchronous\n   * operations.\n   */\n  async stop() {\n    if (!this.remainingWork) {\n      throw new Error('Cannot call stop() on a queue without first calling start()');\n    }\n    this.running = false;\n    this.signalPendingWorkOrStop?.();\n    this.pendingDequeues.splice(0);\n    this.signalPendingDequeuesOrStop?.();\n    const {\n      remainingWork\n    } = this;\n    this.remainingWork = undefined;\n    return remainingWork;\n  }\n\n  /**\n   * Return an async generator that yields the context related to work that was dequeued\n   * when the queue overflowed.\n   */\n  async *overflows() {\n    if (this.listeningForDequeues) {\n      throw new Error('There may only be a single consumer of the overflows generator');\n    }\n    this.listeningForDequeues = true;\n    const getDequeueSignal = () => new Promise(resolve => {\n      this.signalPendingDequeuesOrStop = resolve;\n    });\n    let onPendingDequeue = getDequeueSignal();\n    while (this.running) {\n      await onPendingDequeue;\n      onPendingDequeue = getDequeueSignal();\n      for (const dequeued of this.pendingDequeues.splice(0)) {\n        yield dequeued;\n      }\n    }\n    this.signalPendingDequeuesOrStop = undefined;\n    this.listeningForDequeues = false;\n  }\n\n  /**\n   * Return a promise that resolves when there is space in the work queue for at least one more\n   * piece of work.\n   */\n  async waitForSpaceInWorkQueue() {\n    while (this.queued.length >= this.maxQueueLength) {\n      await new Promise(resolve => {\n        this.signalSpaceInWorkQueue = resolve;\n      });\n      this.signalSpaceInWorkQueue = undefined;\n    }\n  }\n}\n\n/**\n * A useful helper function for building a WorkIterator for consumption by `WorkQueue`.\n * It calls the callback on each `next()` call until it does not throw, yielding each\n * thrown value.\n *\n * @example\n * async function* doSomeWork() {\n *   yield* yieldErrors((): Promise<void> => thisMayThrow());\n *   yield* yieldErrors((): Promise<void> => thisMayAlsoThrow());\n * }\n */\nasync function* yieldErrors(callback) {\n  for (;;) {\n    try {\n      return await callback();\n    } catch (e) {\n      yield e;\n    }\n  }\n}\n\nexports.WorkQueue = WorkQueue;\nexports.dequeueWork = dequeueWork;\nexports.yieldErrors = yieldErrors;\n"]}