{"version":3,"sources":["common/provider.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC;IACzB,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;IAClB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;CACjE;AAED;;;;;;;;;;GAUG;AACH,qBAAa,YAAY,CAAC,CAAC,CAAE,YAAW,QAAQ,CAAC,CAAC,CAAC;IAEjD,OAAO,CAAC,MAAM,CAAoB;IAElC,OAAO,CAAC,MAAM,CAAoB;IAElC,OAAO,CAAC,OAAO,CAAM;IAGrB,OAAO,CAAC,aAAa,CAAK;IAE1B,OAAO,CAAC,MAAM,CAA8B;IAE5C;;;;SAIK;gBACO,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,SAAK;IAKtD;;;;;SAKK;IACE,kBAAkB,CAAC,KAAK,UAAQ,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;QAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;KAAE;IAwC5E,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC;IAIxB;;;;SAIK;IACL,IAAI,YAAY,WAEf;IAED;;;;;;;;;SASK;IACE,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC;CAS3E;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAE9E;AAED,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAEhF;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,MAAM,OAAO,CAAC,CAAC,CAAC,CAExE","file":"../../common/provider.d.ts","sourcesContent":["/**\n * Simple composable factory typeclass\n */\nexport interface Provider<T> {\n  get(): Promise<T>;\n  transform<R>(lambda: (x: T) => R | PromiseLike<R>): Provider<R>;\n}\n\n/**\n * Little lazy singleton provider with memory and mutex\n * that self-updates on get() after a ttl\n * expires.\n *\n * - if ttl < 0, then the LazyProvider acts as a LazySingleton\n * - if ttl === 0, then the LazyProvider calls through to the loader\n *             on every call - there is no cache\n * - if ttl > 0, then the provider does lazy refresh\n *             once the ttl expires\n */\nexport class LazyProvider<T> implements Provider<T> {\n  // eslint-disable-next-line\n  private _thing: Promise<T> = null;\n\n  private reload: Promise<T> = null;\n\n  private ttlSecs = -1;\n\n  // eslint-disable-next-line\n  private _lastLoadTime = 0;\n\n  private loader: () => T | Promise<T> = null;\n\n  /**\n     * @param loader lambda that loads the thing on demand\n     * @param ttlSecs number of seconds to cache the thing before triggering a reload,\n     *          default to never reload (-1)\n     */\n  constructor(loader: () => T | Promise<T>, ttlSecs = -1) {\n    this.loader = loader;\n    this.ttlSecs = ttlSecs;\n  }\n\n  /**\n     * Refresh if ttl expired or force true\n     * @param force\n     * @return cached this.thing and the promise\n     *    that loads the new data when reload is done\n     */\n  public refreshIfNecessary(force = false): { current: Promise<T>, next: Promise<T> } {\n    // ttl === 0 means always invoke the loader\n    // ttl < 0 means invoke the loader once, and cache the result forever as a singleton\n    if (this._thing && this.ttlSecs !== 0) {\n      // trigger reload in background if necessary\n      if (\n        this.ttlSecs > 0 // there's a ttl\n                && this.reload === null // not reloading already\n                && this._lastLoadTime > 0 // initial load complete\n                && (force // reload force requested\n                    || ( // or there's a TTL and it expired\n                      Date.now() - this._lastLoadTime > this.ttlSecs * 1000)\n                )\n      ) {\n        this.reload = Promise.resolve(this.loader());\n        this.reload.then(\n          () => {\n            this._lastLoadTime = Date.now();\n            this._thing = this.reload;\n            this.reload = null;\n          },\n        ).catch(\n          () => {\n            this._lastLoadTime = Date.now();\n            this.reload = null;\n            // leave the previously loaded thing in place\n          },\n        );\n      }\n      return { current: this._thing, next: this.reload || this._thing };\n    }\n\n    // initial load ...\n    this._thing = Promise.resolve(this.loader());\n    this._thing.finally(() => {\n      this._lastLoadTime = Date.now();\n    });\n    return { current: this._thing, next: this._thing };\n  }\n\n  public get(): Promise<T> {\n    return this.refreshIfNecessary(false).current;\n  }\n\n  /**\n     * Date.now of last load attempt completion -\n     * whether it succeeded or not.  Zero until after\n     * the first call to .thing\n     */\n  get lastLoadTime() {\n    return this._lastLoadTime;\n  }\n\n  /**\n     * Apply a transformation on this thing.\n     * Shortcut for new LazyProvider(() => parent.thing.then(...))\n     * Note that refresh() on the child thing\n     * does not force a refresh on the parent, and\n     * vice versa, but the child inherits the ttl from\n     * its parent.\n     *\n     * @param lambda\n     */\n  public transform<R>(lambda: (x: T) => R | PromiseLike<R>): LazyProvider<R> {\n    const result = new LazyProvider(\n      () => this.refreshIfNecessary(false).next.then(\n        (thing) => lambda(thing),\n      ),\n      this.ttlSecs,\n    );\n    return result;\n  }\n}\n\nexport function singletonProvider<T>(loader: () => T | Promise<T>): Provider<T> {\n  return new LazyProvider(loader);\n}\n\nexport function passThroughProvider<T>(loader: () => T | Promise<T>): Provider<T> {\n  return new LazyProvider(loader, 0);\n}\n\nexport function asFactory<T>(provider: LazyProvider<T>): () => Promise<T> {\n  return () => provider.get();\n}\n"]}