{"version":3,"file":"renderWidgets-CeIczubt.mjs","names":[],"sources":["../src/widgets/defaultWidgetOnError.ts","../src/widgets/getWidgetManagerConstructor.ts","../src/widgets/getWidgetManagerPrototype.ts","../src/widgets/hasRequiredWidgetManagerMethods.ts","../src/widgets/isKnownStaffbaseRenderError.ts","../src/widgets/renderWidgets.ts"],"sourcesContent":["/**\n * Default onError for renderWidgets: warns only on the critical\n * 'manager-unavailable' context so a platform regression stays visible in logs\n * without spamming per-widget noise. Consumers can pass their own onError.\n * @param {unknown} error - The swallowed error.\n * @param {string} context - Where it happened.\n * @returns {void}\n */\nexport const defaultWidgetOnError = (error: unknown, context: string): void => {\n  if (context === 'manager-unavailable') {\n    console.warn(\n      '[staffbase-utils] Staffbase widget manager unavailable; embedded widgets were not rendered.',\n      error,\n    )\n  }\n}\n","import type { StaffbaseWidgetManagerConstructor } from '../types/widgets/StaffbaseWidgetManagerConstructor'\n\n/**\n * Resolves the host widget-manager constructor from the global Staffbase object,\n * or null when it is not a function (older runtimes / platform regression).\n * @returns {StaffbaseWidgetManagerConstructor | null} The constructor or null.\n */\nexport const getWidgetManagerConstructor =\n  (): StaffbaseWidgetManagerConstructor | null => {\n    if (typeof window === 'undefined') return null\n    const ctor = (\n      window as unknown as {\n        staffbase?: { content?: { widgetMgr?: unknown } }\n      }\n    ).staffbase?.content?.widgetMgr\n    return typeof ctor === 'function'\n      ? (ctor as StaffbaseWidgetManagerConstructor)\n      : null\n  }\n","import type { StaffbaseWidgetManagerPrototype } from '../types/widgets/StaffbaseWidgetManagerPrototype'\n\n/**\n * Resolves the host widget-manager prototype (the private fallback API) from the\n * global Staffbase object, or null when it is unavailable.\n * @returns {StaffbaseWidgetManagerPrototype | null} The prototype or null.\n */\nexport const getWidgetManagerPrototype =\n  (): StaffbaseWidgetManagerPrototype | null => {\n    if (typeof window === 'undefined') return null\n    const proto = (\n      window as unknown as {\n        staffbase?: {\n          content?: {\n            widgetMgr?: { prototype?: StaffbaseWidgetManagerPrototype }\n          }\n        }\n      }\n    ).staffbase?.content?.widgetMgr?.prototype\n    return proto ?? null\n  }\n","import type { StaffbaseWidgetManagerPrototype } from '../types/widgets/StaffbaseWidgetManagerPrototype'\n\n/**\n * Type guard asserting the widget-manager prototype exposes the methods the\n * prototype render path needs.\n * @param {StaffbaseWidgetManagerPrototype} widgetMgr - The resolved prototype.\n * @returns {boolean} True when both _extractWidgets and _renderWidget are functions.\n */\nexport const hasRequiredWidgetManagerMethods = (\n  widgetMgr: StaffbaseWidgetManagerPrototype,\n): widgetMgr is StaffbaseWidgetManagerPrototype & {\n  _extractWidgets: (container: HTMLElement) => unknown[]\n  _renderWidget: (\n    this: StaffbaseWidgetManagerPrototype,\n    container: HTMLElement,\n    widget: unknown,\n  ) => void\n} =>\n  typeof widgetMgr._extractWidgets === 'function' &&\n  typeof widgetMgr._renderWidget === 'function'\n","/**\n * Detects known, benign internal Staffbase errors thrown by `_renderWidget` for\n * individual widgets, so they can be swallowed without aborting the batch.\n * Promoted from unacknowledged-bulletins (`each` / `undefined is not an object`).\n * @param {unknown} error - The thrown value.\n * @returns {boolean} True when the error is a known internal render error.\n */\nexport const isKnownStaffbaseRenderError = (error: unknown): boolean =>\n  error instanceof TypeError &&\n  (error.message?.includes('each') ||\n    error.message?.includes('undefined is not an object'))\n","import type { RenderWidgetsOptions } from '../types/widgets/RenderWidgetsOptions'\nimport type { RenderWidgetsResult } from '../types/widgets/RenderWidgetsResult'\n\nimport { defaultWidgetOnError } from './defaultWidgetOnError'\nimport { getWidgetManagerConstructor } from './getWidgetManagerConstructor'\nimport { getWidgetManagerPrototype } from './getWidgetManagerPrototype'\nimport { hasRequiredWidgetManagerMethods } from './hasRequiredWidgetManagerMethods'\nimport { isKnownStaffbaseRenderError } from './isKnownStaffbaseRenderError'\n\n// Global serialization chain: all renders run one at a time so they never race\n// on the host's shared `_widgets` array (unacknowledged-bulletins' lock, made\n// queue-based). Per-cancelKey run ids drop superseded renders (alerts' WeakMap\n// cancellation; no AbortController, for old webviews). warn-once keeps a missing\n// manager observable without spam (alerts).\nlet queue: Promise<unknown> = Promise.resolve()\nconst cancelTokens = new WeakMap<object, number>()\nlet hasWarnedManagerUnavailable = false\n\n/**\n * Runs the retry loop for a single render: constructor path first, prototype\n * fallback, with cancellation checks and known-error swallowing.\n * @param {HTMLElement} container - The container to render widgets into.\n * @param {object} cancelKey - The cancellation key for this render.\n * @param {number} runId - This render's run id for the cancel key.\n * @param {number} maxRetries - Maximum render attempts.\n * @param {number} retryDelay - Delay between attempts, in milliseconds.\n * @param {(error: unknown, context: string) => void} onError - Error reporter.\n * @returns {Promise<RenderWidgetsResult>} The typed render result.\n */\nconst executeRender = async (\n  container: HTMLElement,\n  cancelKey: object,\n  runId: number,\n  maxRetries: number,\n  retryDelay: number,\n  onError: (error: unknown, context: string) => void,\n): Promise<RenderWidgetsResult> => {\n  let attempts = 0\n  let managerSeen = false\n\n  while (attempts < maxRetries) {\n    attempts++\n    if (cancelTokens.get(cancelKey) !== runId)\n      return { ok: false, reason: 'cancelled' }\n    if (typeof container.querySelectorAll !== 'function') {\n      return { ok: false, reason: 'no-container' }\n    }\n\n    // Prefer Staffbase's real widget manager (closest to host behavior).\n    const ctor = getWidgetManagerConstructor()\n    if (ctor) {\n      managerSeen = true\n      try {\n        const instance = new ctor(undefined, false)\n        if (typeof instance.render === 'function') {\n          await instance.render(container)\n          return { ok: true, rendered: 0 }\n        }\n      } catch {\n        // Fall back to the private prototype path below.\n      }\n    }\n\n    const proto = getWidgetManagerPrototype()\n    if (proto && hasRequiredWidgetManagerMethods(proto)) {\n      managerSeen = true\n      if (!Array.isArray(proto._widgets)) proto._widgets = []\n\n      let widgets: unknown[]\n      try {\n        widgets = proto._extractWidgets(container)\n      } catch (error) {\n        onError(error, 'extract')\n        widgets = []\n      }\n\n      if (widgets.length > 0) {\n        let rendered = 0\n        for (const widget of widgets) {\n          if (cancelTokens.get(cancelKey) !== runId) {\n            return { ok: false, reason: 'cancelled' }\n          }\n          try {\n            proto._renderWidget.call(proto, container, widget)\n            rendered++\n          } catch (error) {\n            if (!isKnownStaffbaseRenderError(error))\n              onError(error, 'render-widget')\n          }\n        }\n        return { ok: true, rendered }\n      }\n    }\n\n    if (attempts >= maxRetries) break\n    await new Promise((resolve) => setTimeout(resolve, retryDelay))\n  }\n\n  if (!managerSeen) {\n    if (!hasWarnedManagerUnavailable) {\n      hasWarnedManagerUnavailable = true\n      onError(\n        new Error('Staffbase widget manager unavailable after retries.'),\n        'manager-unavailable',\n      )\n    }\n    return { ok: false, reason: 'manager-unavailable' }\n  }\n  return { ok: false, reason: 'no-widgets' }\n}\n\n/**\n * Renders the widgets embedded in `container` using the host's private widget\n * manager. Superset of the four widget services: constructor path first with a\n * prototype fallback, a global queue that serializes renders, per-cancelKey\n * cancellation of superseded renders, configurable retries, swallowing of known\n * internal Staffbase errors, and a once-per-session warning when the manager is\n * missing. Returns a typed result so callers can react (e.g. mark a\n * data-widget-render-error attribute).\n * @param {HTMLElement | null} container - The element whose embedded widgets are rendered.\n * @param {RenderWidgetsOptions} options - Retry, error and cancellation options.\n * @returns {Promise<RenderWidgetsResult>} The typed render result.\n */\nexport const renderWidgets = (\n  container: HTMLElement | null,\n  options: RenderWidgetsOptions = {},\n): Promise<RenderWidgetsResult> => {\n  if (!container) return Promise.resolve({ ok: false, reason: 'no-container' })\n\n  const {\n    maxRetries = 10,\n    retryDelay = 300,\n    onError = defaultWidgetOnError,\n    cancelKey = container,\n  } = options\n\n  // Bump the run id synchronously so any older in-flight/queued render for the\n  // same key sees itself as superseded.\n  const runId = (cancelTokens.get(cancelKey) ?? 0) + 1\n  cancelTokens.set(cancelKey, runId)\n\n  const run = queue.then(() =>\n    executeRender(container, cancelKey, runId, maxRetries, retryDelay, onError),\n  )\n  // Keep the queue chain alive regardless of individual outcomes.\n  queue = run.then(\n    () => undefined,\n    () => undefined,\n  )\n  return run\n}\n"],"mappings":";AAQA,IAAa,KAAwB,GAAgB,MAA0B;CAC7E,AAAI,MAAY,yBACd,QAAQ,KACN,+FACA,CACF;AAEJ,GCRa,UACqC;CAC9C,IAAI,OAAO,SAAW,KAAa,OAAO;CAC1C,IAAM,IACJ,OAGA,WAAW,SAAS;CACtB,OAAO,OAAO,KAAS,aAClB,IACD;AACN,GCXW,UAEL,OAAO,SAAW,MAAoB,OAExC,OAOA,WAAW,SAAS,WAAW,aACjB,MCXP,KACX,MASA,OAAO,EAAU,mBAAoB,cACrC,OAAO,EAAU,iBAAkB,YCZxB,KAA+B,MAC1C,aAAiB,cAChB,EAAM,SAAS,SAAS,MAAM,KAC7B,EAAM,SAAS,SAAS,4BAA4B,ICIpD,IAA0B,QAAQ,QAAQ,GACxC,oBAAe,IAAI,QAAwB,GAC7C,IAA8B,IAa5B,IAAgB,OACpB,GACA,GACA,GACA,GACA,GACA,MACiC;CACjC,IAAI,IAAW,GACX,IAAc;CAElB,OAAO,IAAW,IAAY;EAE5B,IADA,KACI,EAAa,IAAI,CAAS,MAAM,GAClC,OAAO;GAAE,IAAI;GAAO,QAAQ;EAAY;EAC1C,IAAI,OAAO,EAAU,oBAAqB,YACxC,OAAO;GAAE,IAAI;GAAO,QAAQ;EAAe;EAI7C,IAAM,IAAO,EAA4B;EACzC,IAAI,GAAM;GACR,IAAc;GACd,IAAI;IACF,IAAM,IAAW,IAAI,EAAK,KAAA,GAAW,EAAK;IAC1C,IAAI,OAAO,EAAS,UAAW,YAE7B,OADA,MAAM,EAAS,OAAO,CAAS,GACxB;KAAE,IAAI;KAAM,UAAU;IAAE;GAEnC,QAAQ,CAER;EACF;EAEA,IAAM,IAAQ,EAA0B;EACxC,IAAI,KAAS,EAAgC,CAAK,GAAG;GAEnD,AADA,IAAc,IACT,MAAM,QAAQ,EAAM,QAAQ,MAAG,EAAM,WAAW,CAAC;GAEtD,IAAI;GACJ,IAAI;IACF,IAAU,EAAM,gBAAgB,CAAS;GAC3C,SAAS,GAAO;IAEd,AADA,EAAQ,GAAO,SAAS,GACxB,IAAU,CAAC;GACb;GAEA,IAAI,EAAQ,SAAS,GAAG;IACtB,IAAI,IAAW;IACf,KAAK,IAAM,KAAU,GAAS;KAC5B,IAAI,EAAa,IAAI,CAAS,MAAM,GAClC,OAAO;MAAE,IAAI;MAAO,QAAQ;KAAY;KAE1C,IAAI;MAEF,AADA,EAAM,cAAc,KAAK,GAAO,GAAW,CAAM,GACjD;KACF,SAAS,GAAO;MACd,AAAK,EAA4B,CAAK,KACpC,EAAQ,GAAO,eAAe;KAClC;IACF;IACA,OAAO;KAAE,IAAI;KAAM;IAAS;GAC9B;EACF;EAEA,IAAI,KAAY,GAAY;EAC5B,MAAM,IAAI,SAAS,MAAY,WAAW,GAAS,CAAU,CAAC;CAChE;CAYA,OAVK,IAUE;EAAE,IAAI;EAAO,QAAQ;CAAa,KATlC,MACH,IAA8B,IAC9B,EACE,gBAAI,MAAM,qDAAqD,GAC/D,qBACF,IAEK;EAAE,IAAI;EAAO,QAAQ;CAAsB;AAGtD,GAca,KACX,GACA,IAAgC,CAAC,MACA;CACjC,IAAI,CAAC,GAAW,OAAO,QAAQ,QAAQ;EAAE,IAAI;EAAO,QAAQ;CAAe,CAAC;CAE5E,IAAM,EACJ,gBAAa,IACb,gBAAa,KACb,aAAU,GACV,eAAY,MACV,GAIE,KAAS,EAAa,IAAI,CAAS,KAAK,KAAK;CACnD,EAAa,IAAI,GAAW,CAAK;CAEjC,IAAM,IAAM,EAAM,WAChB,EAAc,GAAW,GAAW,GAAO,GAAY,GAAY,CAAO,CAC5E;CAMA,OAJA,IAAQ,EAAI,WACJ,KAAA,SACA,KAAA,CACR,GACO;AACT"}