@8wave/ai-elements 0.103.0-beta.3 → 0.103.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/dist/_chunks/PkLazyImg-CyeqD59M.js +34 -0
  2. package/dist/_chunks/{PkLazyImg-_389yCnQ.js.map → PkLazyImg-CyeqD59M.js.map} +1 -1
  3. package/dist/_chunks/{PkStreamingMarkdown-YJDdYD0E.js → PkStreamingMarkdown-DIkusrTI.js} +28 -28
  4. package/dist/_chunks/{PkStreamingMarkdown-YJDdYD0E.js.map → PkStreamingMarkdown-DIkusrTI.js.map} +1 -1
  5. package/dist/_chunks/PkToolRequestGeolocation-Cgus94KF.js +69 -0
  6. package/dist/_chunks/{PkToolRequestGeolocation-T16QI-Uv.js.map → PkToolRequestGeolocation-Cgus94KF.js.map} +1 -1
  7. package/dist/_chunks/{PkToolRequestOAuthConnection-C8e5np2q.js → PkToolRequestOAuthConnection-DsUpUh97.js} +21 -21
  8. package/dist/_chunks/{PkToolRequestOAuthConnection-C8e5np2q.js.map → PkToolRequestOAuthConnection-DsUpUh97.js.map} +1 -1
  9. package/dist/_chunks/PkToolShowArtifact-griVx9w3.js +93 -0
  10. package/dist/_chunks/{PkToolShowArtifact-D15GjBm6.js.map → PkToolShowArtifact-griVx9w3.js.map} +1 -1
  11. package/dist/_chunks/{PkToolShowCalendarEvent-D_GjXl2_.js → PkToolShowCalendarEvent-DyiNmqqo.js} +43 -43
  12. package/dist/_chunks/{PkToolShowCalendarEvent-D_GjXl2_.js.map → PkToolShowCalendarEvent-DyiNmqqo.js.map} +1 -1
  13. package/dist/_chunks/PkToolShowComparison-RA72YL7R.js +66 -0
  14. package/dist/_chunks/{PkToolShowComparison-Bp2rP2Hx.js.map → PkToolShowComparison-RA72YL7R.js.map} +1 -1
  15. package/dist/_chunks/{PkToolShowContactForm-NVzIu2t0.js → PkToolShowContactForm-BzDhv2yd.js} +41 -41
  16. package/dist/_chunks/{PkToolShowContactForm-NVzIu2t0.js.map → PkToolShowContactForm-BzDhv2yd.js.map} +1 -1
  17. package/dist/_chunks/{PkToolShowDiagram-BnZrDPVC.js → PkToolShowDiagram-DhXe8IPm.js} +79 -79
  18. package/dist/_chunks/{PkToolShowDiagram-BnZrDPVC.js.map → PkToolShowDiagram-DhXe8IPm.js.map} +1 -1
  19. package/dist/_chunks/{PkToolShowEmail-DCSj4328.js → PkToolShowEmail-CBmfy_I9.js} +34 -34
  20. package/dist/_chunks/{PkToolShowEmail-DCSj4328.js.map → PkToolShowEmail-CBmfy_I9.js.map} +1 -1
  21. package/dist/_chunks/PkToolShowForm-CzIfm5de.js +365 -0
  22. package/dist/_chunks/{PkToolShowForm-ztQFyFd9.js.map → PkToolShowForm-CzIfm5de.js.map} +1 -1
  23. package/dist/_chunks/PkToolShowImageGallery-CSIiRuSC.js +74 -0
  24. package/dist/_chunks/{PkToolShowImageGallery-DiOR0vYa.js.map → PkToolShowImageGallery-CSIiRuSC.js.map} +1 -1
  25. package/dist/_chunks/{PkToolShowLocation-CQmgakEo.js → PkToolShowLocation-BHoUqpx4.js} +4079 -4079
  26. package/dist/_chunks/{PkToolShowLocation-CQmgakEo.js.map → PkToolShowLocation-BHoUqpx4.js.map} +1 -1
  27. package/dist/_chunks/PkToolShowMessage-CpDmPfCG.js +77 -0
  28. package/dist/_chunks/{PkToolShowMessage-BysjJ1oS.js.map → PkToolShowMessage-CpDmPfCG.js.map} +1 -1
  29. package/dist/_chunks/{PkToolShowProductList-D-JXSRmA.js → PkToolShowProductList-B8uuIvGo.js} +28 -28
  30. package/dist/_chunks/{PkToolShowProductList-D-JXSRmA.js.map → PkToolShowProductList-B8uuIvGo.js.map} +1 -1
  31. package/dist/_chunks/{PkToolShowQrCode-BcIwuGqm.js → PkToolShowQrCode-CD2lo3O0.js} +23 -23
  32. package/dist/_chunks/{PkToolShowQrCode-BcIwuGqm.js.map → PkToolShowQrCode-CD2lo3O0.js.map} +1 -1
  33. package/dist/_chunks/{PkToolShowSources-U7etupUP.js → PkToolShowSources-JxaTAEpc.js} +98 -98
  34. package/dist/_chunks/{PkToolShowSources-U7etupUP.js.map → PkToolShowSources-JxaTAEpc.js.map} +1 -1
  35. package/dist/_chunks/{PkToolShowSuggestedReply-Dqe4gtEY.js → PkToolShowSuggestedReply-BTxqEwEm.js} +18 -18
  36. package/dist/_chunks/{PkToolShowSuggestedReply-Dqe4gtEY.js.map → PkToolShowSuggestedReply-BTxqEwEm.js.map} +1 -1
  37. package/dist/_chunks/{PkToolShowVideo-DYMhfXKH.js → PkToolShowVideo-CVksKdPD.js} +17 -17
  38. package/dist/_chunks/{PkToolShowVideo-DYMhfXKH.js.map → PkToolShowVideo-CVksKdPD.js.map} +1 -1
  39. package/dist/_chunks/{PkToolShowWeather-D_pJe5DI.js → PkToolShowWeather-IDwTDozU.js} +68 -68
  40. package/dist/_chunks/{PkToolShowWeather-D_pJe5DI.js.map → PkToolShowWeather-IDwTDozU.js.map} +1 -1
  41. package/dist/_chunks/PkToolShowWebPages-D9Yst_2O.js +78 -0
  42. package/dist/_chunks/{PkToolShowWebPages-CPNgXzrS.js.map → PkToolShowWebPages-D9Yst_2O.js.map} +1 -1
  43. package/dist/_chunks/{PkUrl-C3gMPCjz.js → PkUrl-B3FTSURr.js} +19 -19
  44. package/dist/_chunks/{PkUrl-C3gMPCjz.js.map → PkUrl-B3FTSURr.js.map} +1 -1
  45. package/dist/_chunks/{VvCheckbox.es-CEfwI84M.js → VvCheckbox.es-C_dlDzrr.js} +78 -78
  46. package/dist/_chunks/{VvCheckbox.es-CEfwI84M.js.map → VvCheckbox.es-C_dlDzrr.js.map} +1 -1
  47. package/dist/_chunks/{VvCheckboxGroup.es-B-eWqe8G.js → VvCheckboxGroup.es-hY0kWpC2.js} +197 -197
  48. package/dist/_chunks/{VvCheckboxGroup.es-B-eWqe8G.js.map → VvCheckboxGroup.es-hY0kWpC2.js.map} +1 -1
  49. package/dist/_chunks/VvCombobox.es-DxhDF7ab.js +2044 -0
  50. package/dist/_chunks/{VvCombobox.es-CfRJtWOd.js.map → VvCombobox.es-DxhDF7ab.js.map} +1 -1
  51. package/dist/_chunks/{VvInputText.es-B0HHD6Th.js → VvInputText.es-CdpU8kvP.js} +460 -460
  52. package/dist/_chunks/{VvInputText.es-B0HHD6Th.js.map → VvInputText.es-CdpU8kvP.js.map} +1 -1
  53. package/dist/_chunks/{VvRadio.es-B3u8JJFF.js → VvRadio.es-BruZ5FHR.js} +144 -144
  54. package/dist/_chunks/{VvRadio.es-B3u8JJFF.js.map → VvRadio.es-BruZ5FHR.js.map} +1 -1
  55. package/dist/_chunks/{VvRadioGroup.es--AMV1wAw.js → VvRadioGroup.es-DSv6UdEy.js} +148 -148
  56. package/dist/_chunks/{VvRadioGroup.es--AMV1wAw.js.map → VvRadioGroup.es-DSv6UdEy.js.map} +1 -1
  57. package/dist/_chunks/{VvSelect.es-BfrDID0e.js → VvSelect.es-C244CAei.js} +155 -155
  58. package/dist/_chunks/{VvSelect.es-BfrDID0e.js.map → VvSelect.es-C244CAei.js.map} +1 -1
  59. package/dist/_chunks/VvTextarea.es-DbaPIcWl.js +1166 -0
  60. package/dist/_chunks/{VvTextarea.es-CAzFW944.js.map → VvTextarea.es-DbaPIcWl.js.map} +1 -1
  61. package/dist/_chunks/{dist-BvSGMyWS.js → dist-BgJVX4FG.js} +12 -12
  62. package/dist/_chunks/{dist-BvSGMyWS.js.map → dist-BgJVX4FG.js.map} +1 -1
  63. package/dist/_chunks/{dist-TFHdNK0W.js → dist-C5Y-NI3i.js} +230 -230
  64. package/dist/_chunks/{dist-TFHdNK0W.js.map → dist-C5Y-NI3i.js.map} +1 -1
  65. package/dist/_chunks/{esm-CUYQMpeA.js → esm-BTbGj6W3.js} +25 -25
  66. package/dist/_chunks/{esm-CUYQMpeA.js.map → esm-BTbGj6W3.js.map} +1 -1
  67. package/dist/_chunks/{floating-ui.vue-Br_zOLJv.js → floating-ui.vue-CoA4oagI.js} +16 -16
  68. package/dist/_chunks/{floating-ui.vue-Br_zOLJv.js.map → floating-ui.vue-CoA4oagI.js.map} +1 -1
  69. package/dist/_chunks/{iconify-BGSTR7vH.js → iconify-6ObncgfH.js} +36 -36
  70. package/dist/_chunks/{iconify-BGSTR7vH.js.map → iconify-6ObncgfH.js.map} +1 -1
  71. package/dist/_chunks/{index.es-B9rhQl9Z.js → index.es-BbyodRh9.js} +258 -258
  72. package/dist/_chunks/{index.es-B9rhQl9Z.js.map → index.es-BbyodRh9.js.map} +1 -1
  73. package/dist/_chunks/index.es-gbmOq0Nu.js +3124 -0
  74. package/dist/_chunks/index.es-gbmOq0Nu.js.map +1 -0
  75. package/dist/_chunks/{rolldown-runtime-CEFd7nDs.js → rolldown-runtime-CoeuCKPe.js} +4 -11
  76. package/dist/_chunks/{src-BjFv9Ag8.js → src-CIEdKLKO.js} +2 -2
  77. package/dist/_chunks/{src-BjFv9Ag8.js.map → src-CIEdKLKO.js.map} +1 -1
  78. package/dist/_chunks/useImageFallback-BAsLRsyg.js +19 -0
  79. package/dist/_chunks/{useImageFallback-8kfLDjXm.js.map → useImageFallback-BAsLRsyg.js.map} +1 -1
  80. package/dist/_chunks/{useLightbox-Bq6k-Wlt.js → useLightbox-Epg2fN87.js} +7 -7
  81. package/dist/_chunks/{useLightbox-Bq6k-Wlt.js.map → useLightbox-Epg2fN87.js.map} +1 -1
  82. package/dist/_chunks/useShortUrlResolver--HRa6Od3.js +72 -0
  83. package/dist/_chunks/{useShortUrlResolver-BTJM8XRw.js.map → useShortUrlResolver--HRa6Od3.js.map} +1 -1
  84. package/dist/_chunks/{vue-i18n-BJ7nxwO3.js → vue-i18n-t25g63Be.js} +81 -81
  85. package/dist/_chunks/{vue-i18n-BJ7nxwO3.js.map → vue-i18n-t25g63Be.js.map} +1 -1
  86. package/dist/_chunks/vue.runtime.esm-bundler-B3bThTaf.js +3747 -0
  87. package/dist/_chunks/vue.runtime.esm-bundler-B3bThTaf.js.map +1 -0
  88. package/dist/ai-elements.es.js +1861 -1861
  89. package/dist/ai-elements.es.js.map +1 -1
  90. package/dist-vue/PkChatbot.js +1 -1
  91. package/dist-vue/PkChatbotAuth.js +1 -1
  92. package/dist-vue/PkChatbotFeedbackForm.js +1 -1
  93. package/dist-vue/PkChatbotMessages.js +1 -1
  94. package/dist-vue/PkChatbotViewChat.js +1 -1
  95. package/dist-vue/_chunks/{PkChatbot-DZ6TaZHh.js → PkChatbot-Ch8FlZjC.js} +2 -2
  96. package/dist-vue/_chunks/{PkChatbot-DZ6TaZHh.js.map → PkChatbot-Ch8FlZjC.js.map} +1 -1
  97. package/dist-vue/_chunks/{PkChatbotAuth-CqwTN8ih.js → PkChatbotAuth-DvnmIukc.js} +2 -2
  98. package/dist-vue/_chunks/{PkChatbotAuth-CqwTN8ih.js.map → PkChatbotAuth-DvnmIukc.js.map} +1 -1
  99. package/dist-vue/_chunks/{PkChatbotFeedbackForm-nEevDHmI.js → PkChatbotFeedbackForm-D0RNa7bE.js} +2 -2
  100. package/dist-vue/_chunks/{PkChatbotFeedbackForm-nEevDHmI.js.map → PkChatbotFeedbackForm-D0RNa7bE.js.map} +1 -1
  101. package/dist-vue/_chunks/{PkChatbotMessages-BgsyN-mB.js → PkChatbotMessages-DGO0WIqx.js} +4 -4
  102. package/dist-vue/_chunks/{PkChatbotMessages-BgsyN-mB.js.map → PkChatbotMessages-DGO0WIqx.js.map} +1 -1
  103. package/dist-vue/_chunks/{PkChatbotViewChat-0g30_sQH.js → PkChatbotViewChat-Dkz8dq8N.js} +3 -3
  104. package/dist-vue/_chunks/{PkChatbotViewChat-0g30_sQH.js.map → PkChatbotViewChat-Dkz8dq8N.js.map} +1 -1
  105. package/dist-vue/_chunks/{PkToolShowContactForm-CMK4zR2J.js → PkToolShowContactForm-CkkWxSSz.js} +2 -2
  106. package/dist-vue/_chunks/{PkToolShowContactForm-CMK4zR2J.js.map → PkToolShowContactForm-CkkWxSSz.js.map} +1 -1
  107. package/dist-vue/_chunks/{PkToolShowDiagram-DoklcF3f.js → PkToolShowDiagram-D0NBG-Gy.js} +2 -2
  108. package/dist-vue/_chunks/{PkToolShowDiagram-DoklcF3f.js.map → PkToolShowDiagram-D0NBG-Gy.js.map} +1 -1
  109. package/dist-vue/_chunks/{index.es-BT6Jr2yi.js → index.es-BKxzs6Sh.js} +2 -2
  110. package/dist-vue/_chunks/{index.es-BT6Jr2yi.js.map → index.es-BKxzs6Sh.js.map} +1 -1
  111. package/dist-vue/index.js +10 -10
  112. package/package.json +2 -2
  113. package/dist/_chunks/PkLazyImg-_389yCnQ.js +0 -34
  114. package/dist/_chunks/PkToolRequestGeolocation-T16QI-Uv.js +0 -69
  115. package/dist/_chunks/PkToolShowArtifact-D15GjBm6.js +0 -93
  116. package/dist/_chunks/PkToolShowComparison-Bp2rP2Hx.js +0 -66
  117. package/dist/_chunks/PkToolShowForm-ztQFyFd9.js +0 -365
  118. package/dist/_chunks/PkToolShowImageGallery-DiOR0vYa.js +0 -74
  119. package/dist/_chunks/PkToolShowMessage-BysjJ1oS.js +0 -77
  120. package/dist/_chunks/PkToolShowWebPages-CPNgXzrS.js +0 -78
  121. package/dist/_chunks/VvCombobox.es-CfRJtWOd.js +0 -2044
  122. package/dist/_chunks/VvTextarea.es-CAzFW944.js +0 -1166
  123. package/dist/_chunks/index.es-DvV0VhDa.js +0 -9832
  124. package/dist/_chunks/index.es-DvV0VhDa.js.map +0 -1
  125. package/dist/_chunks/useImageFallback-8kfLDjXm.js +0 -19
  126. package/dist/_chunks/useShortUrlResolver-BTJM8XRw.js +0 -72
  127. package/dist/_chunks/vue.runtime.esm-bundler-DF2of3lp.js +0 -5007
  128. package/dist/_chunks/vue.runtime.esm-bundler-DF2of3lp.js.map +0 -1
@@ -6,25 +6,18 @@ var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescr
6
6
  } catch (e) {
7
7
  throw n = [e], e;
8
8
  }
9
- }, s = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t.exports), c = (e, n) => {
10
- let r = {};
11
- for (var i in e) t(r, i, {
12
- get: e[i],
13
- enumerable: !0
14
- });
15
- return n || t(r, Symbol.toStringTag, { value: "Module" }), r;
16
- }, l = (e, i, o, s) => {
9
+ }, s = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t.exports), c = (e, i, o, s) => {
17
10
  if (i && typeof i == "object" || typeof i == "function") for (var c = r(i), l = 0, u = c.length, d; l < u; l++) d = c[l], !a.call(e, d) && d !== o && t(e, d, {
18
11
  get: ((e) => i[e]).bind(null, d),
19
12
  enumerable: !(s = n(i, d)) || s.enumerable
20
13
  });
21
14
  return e;
22
- }, u = (n, r, o) => (o = n == null ? {} : e(i(n)), l(r || !n || !n.__esModule || !a.call(n, "default") ? t(o, "default", {
15
+ }, l = (n, r, o) => (o = n == null ? {} : e(i(n)), c(r || !n || !n.__esModule || !a.call(n, "default") ? t(o, "default", {
23
16
  value: n,
24
17
  enumerable: !0
25
- }) : o, n)), d = (e) => a.call(e, "module.exports") ? e["module.exports"] : l(t({}, "__esModule", { value: !0 }), e), f = /* @__PURE__ */ ((e) => typeof require < "u" ? require : typeof Proxy < "u" ? new Proxy(e, { get: (e, t) => (typeof require < "u" ? require : e)[t] }) : e)(function(e) {
18
+ }) : o, n)), u = /* @__PURE__ */ ((e) => typeof require < "u" ? require : typeof Proxy < "u" ? new Proxy(e, { get: (e, t) => (typeof require < "u" ? require : e)[t] }) : e)(function(e) {
26
19
  if (typeof require < "u") return require.apply(this, arguments);
27
20
  throw Error("Calling `require` for \"" + e + "\" in an environment that doesn't expose the `require` function. See https://rolldown.rs/in-depth/bundling-cjs#require-external-modules for more details.");
28
21
  });
29
22
  //#endregion
30
- export { d as a, f as i, o as n, u as o, c as r, s as t };
23
+ export { l as i, o as n, u as r, s as t };
@@ -1,4 +1,4 @@
1
- import "./vue.runtime.esm-bundler-DF2of3lp.js";
1
+ import "./vue.runtime.esm-bundler-B3bThTaf.js";
2
2
  //#region ../../packages/utils/src/logger.ts
3
3
  var e = null, t = (e) => e.find((e) => e instanceof Error) || Error(e.map(String).join(" ")), n = (e) => e instanceof Error ? e.stack ?? e.message : String(e), r = (e) => e.map(n).join(" "), i = typeof window > "u", a = (i ? process?.env?.VITE_LOCAL === "true" : !1) || i, o = {
4
4
  log: (...t) => {
@@ -46,4 +46,4 @@ var e = null, t = (e) => e.find((e) => e instanceof Error) || Error(e.map(String
46
46
  //#endregion
47
47
  export { o as t };
48
48
 
49
- //# sourceMappingURL=src-BjFv9Ag8.js.map
49
+ //# sourceMappingURL=src-CIEdKLKO.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"src-BjFv9Ag8.js","names":[],"sources":["../../../../packages/utils/src/logger.ts"],"sourcesContent":["import type { Ref } from 'vue'\n\ntype ExceptionTracker = (\n error: Error,\n properties?: Record<string, string>,\n) => void\n\ntype OtelLoggerBridge = {\n logInfo: (msg: string) => void\n logDebug: (msg: string) => void\n logWarn: (msg: string) => void\n logError: (msg: string) => void\n logException: (error: Error) => void\n} | null\n\nlet _exceptionTracker: ExceptionTracker | undefined\n/** Runtime-set bridge to OTel LoggerProvider (set during backend init) */\nlet _otelBridge: OtelLoggerBridge = null\n\n/**\n * Registers the OTel logger bridge at runtime.\n * Called by the backend during startup; no-op in the frontend.\n */\nexport const setOtelLoggerBridge = (bridge: OtelLoggerBridge) => {\n _otelBridge = bridge\n}\n\n/**\n * Registers a callback invoked by error/warn/logError/logWarn to track exceptions\n * (e.g. OTel recordException + span status ERROR).\n */\nexport const setExceptionTracker = (tracker: ExceptionTracker) => {\n _exceptionTracker = tracker\n}\n\nconst extractError = (params: unknown[]): Error => {\n const found = params.find((p): p is Error => p instanceof Error)\n if (found) {\n return found\n }\n return new Error(params.map(String).join(' '))\n}\n\nconst formatParam = (param: unknown): string => {\n if (param instanceof Error) {\n return param.stack ?? param.message\n }\n return String(param)\n}\n\nconst formatParams = (params: unknown[]): string => {\n return params.map(formatParam).join(' ')\n}\n\nconst isServerSide = typeof window === 'undefined'\n// `import.meta.env` only exists in Vite builds: the cast keeps this file\n// compilable under plain Node tsconfigs (e.g. apps/azure-functions)\nconst isLocal = isServerSide\n ? process?.env?.VITE_LOCAL === 'true'\n : (import.meta as { env?: Record<string, unknown> }).env?.VITE_LOCAL ===\n 'true'\n\nconst isLoggingEnabled = isLocal || isServerSide\n\nexport const log = (...params: unknown[]) => {\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.log(...params)\n }\n _otelBridge?.logInfo(formatParams(params))\n}\n\nexport const error = (...params: unknown[]) => {\n const err = extractError(params)\n _exceptionTracker?.(err)\n _otelBridge?.logException(err)\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.error(formatParams(params))\n }\n}\n\nexport const info = (...params: unknown[]) => {\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.info(...params)\n }\n _otelBridge?.logInfo(formatParams(params))\n}\n\nexport const debug = (...params: unknown[]) => {\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.debug(...params)\n }\n _otelBridge?.logDebug(formatParams(params))\n}\n\nexport const warn = (...params: unknown[]) => {\n const err = extractError(params)\n _exceptionTracker?.(err)\n _otelBridge?.logException(err)\n _otelBridge?.logWarn(formatParams(params))\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.warn(formatParams(params))\n }\n}\n\nexport const assert = (condition: boolean | undefined, message: string) => {\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.assert(condition, message)\n }\n}\n\nexport const clear = () => {\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.clear()\n }\n}\n\nexport const table = (table: unknown) => {\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.table(table)\n }\n}\n\nexport const group = (name: string) => {\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.group(name)\n }\n}\n\nexport const groupEnd = () => {\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.groupEnd()\n }\n}\n\nexport const time = (name: string) => {\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.time(name)\n }\n}\n\nexport const timeEnd = (name: string) => {\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.timeEnd(name)\n }\n}\n\nexport const timeLog = (name: string, ...params: unknown[]) => {\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.timeLog(name, ...params)\n }\n}\n\nexport const logger = {\n log,\n error,\n info,\n debug,\n warn,\n assert,\n clear,\n table,\n group,\n groupEnd,\n time,\n timeEnd,\n timeLog,\n}\n\nexport const useErrorsLogger = (errors: Ref<Error | null | undefined>[]) => {\n // Vue is an optional runtime dependency for the backend build.\n // Lazily import it only when running in a browser/Vue environment.\n if (typeof window === 'undefined') {\n return\n }\n\n void import('vue').then(({ watch }) => {\n errors.forEach((error) => {\n watch(error, (value) => {\n logger.error(value)\n })\n })\n })\n}\n"],"mappings":";;AAeA,IAEI,IAAgC,MAkB9B,KAAgB,MACJ,EAAO,MAAM,MAAkB,aAAa,KACtD,KAGO,MAAM,EAAO,IAAI,MAAM,CAAC,CAAC,KAAK,GAAG,CAAC,GAG3C,KAAe,MACb,aAAiB,QACV,EAAM,SAAS,EAAM,UAEzB,OAAO,CAAK,GAGjB,KAAgB,MACX,EAAO,IAAI,CAAW,CAAC,CAAC,KAAK,GAAG,GAGrC,IAAe,OAAO,SAAW,KAQjC,KALU,IACV,SAAS,KAAK,eAAe,SAC5B,OAG6B,GAuGvB,IAAS;CAClB,MAtGgB,GAAG,MAAsB;EAKzC,AAJI,KAEA,QAAQ,IAAI,GAAG,CAAM,GAEzB,GAAa,QAAQ,EAAa,CAAM,CAAC;CAC7C;CAiGI,QA/FkB,GAAG,MAAsB;EAC3C,IAAM,IAAM,EAAa,CAAM;EAG/B,AADA,GAAa,aAAa,CAAG,GACzB,KAEA,QAAQ,MAAM,EAAa,CAAM,CAAC;CAE1C;CAwFI,OAtFiB,GAAG,MAAsB;EAK1C,AAJI,KAEA,QAAQ,KAAK,GAAG,CAAM,GAE1B,GAAa,QAAQ,EAAa,CAAM,CAAC;CAC7C;CAiFI,QA/EkB,GAAG,MAAsB;EAK3C,AAJI,KAEA,QAAQ,MAAM,GAAG,CAAM,GAE3B,GAAa,SAAS,EAAa,CAAM,CAAC;CAC9C;CA0EI,OAxEiB,GAAG,MAAsB;EAC1C,IAAM,IAAM,EAAa,CAAM;EAI/B,AAFA,GAAa,aAAa,CAAG,GAC7B,GAAa,QAAQ,EAAa,CAAM,CAAC,GACrC,KAEA,QAAQ,KAAK,EAAa,CAAM,CAAC;CAEzC;CAgEI,SA9DmB,GAAgC,MAAoB;EACvE,AAAI,KAEA,QAAQ,OAAO,GAAW,CAAO;CAEzC;CA0DI,aAxDuB;EACvB,AAAI,KAEA,QAAQ,MAAM;CAEtB;CAoDI,QAlDkB,MAAmB;EACrC,AAAI,KAEA,QAAQ,MAAM,CAAK;CAE3B;CA8CI,QA5CkB,MAAiB;EACnC,AAAI,KAEA,QAAQ,MAAM,CAAI;CAE1B;CAwCI,gBAtC0B;EAC1B,AAAI,KAEA,QAAQ,SAAS;CAEzB;CAkCI,OAhCiB,MAAiB;EAClC,AAAI,KAEA,QAAQ,KAAK,CAAI;CAEzB;CA4BI,UA1BoB,MAAiB;EACrC,AAAI,KAEA,QAAQ,QAAQ,CAAI;CAE5B;CAsBI,UApBoB,GAAc,GAAG,MAAsB;EAC3D,AAAI,KAEA,QAAQ,QAAQ,GAAM,GAAG,CAAM;CAEvC;AAgBA"}
1
+ {"version":3,"file":"src-CIEdKLKO.js","names":[],"sources":["../../../../packages/utils/src/logger.ts"],"sourcesContent":["import type { Ref } from 'vue'\n\ntype ExceptionTracker = (\n error: Error,\n properties?: Record<string, string>,\n) => void\n\ntype OtelLoggerBridge = {\n logInfo: (msg: string) => void\n logDebug: (msg: string) => void\n logWarn: (msg: string) => void\n logError: (msg: string) => void\n logException: (error: Error) => void\n} | null\n\nlet _exceptionTracker: ExceptionTracker | undefined\n/** Runtime-set bridge to OTel LoggerProvider (set during backend init) */\nlet _otelBridge: OtelLoggerBridge = null\n\n/**\n * Registers the OTel logger bridge at runtime.\n * Called by the backend during startup; no-op in the frontend.\n */\nexport const setOtelLoggerBridge = (bridge: OtelLoggerBridge) => {\n _otelBridge = bridge\n}\n\n/**\n * Registers a callback invoked by error/warn/logError/logWarn to track exceptions\n * (e.g. OTel recordException + span status ERROR).\n */\nexport const setExceptionTracker = (tracker: ExceptionTracker) => {\n _exceptionTracker = tracker\n}\n\nconst extractError = (params: unknown[]): Error => {\n const found = params.find((p): p is Error => p instanceof Error)\n if (found) {\n return found\n }\n return new Error(params.map(String).join(' '))\n}\n\nconst formatParam = (param: unknown): string => {\n if (param instanceof Error) {\n return param.stack ?? param.message\n }\n return String(param)\n}\n\nconst formatParams = (params: unknown[]): string => {\n return params.map(formatParam).join(' ')\n}\n\nconst isServerSide = typeof window === 'undefined'\n// `import.meta.env` only exists in Vite builds: the cast keeps this file\n// compilable under plain Node tsconfigs (e.g. apps/azure-functions)\nconst isLocal = isServerSide\n ? process?.env?.VITE_LOCAL === 'true'\n : (import.meta as { env?: Record<string, unknown> }).env?.VITE_LOCAL ===\n 'true'\n\nconst isLoggingEnabled = isLocal || isServerSide\n\nexport const log = (...params: unknown[]) => {\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.log(...params)\n }\n _otelBridge?.logInfo(formatParams(params))\n}\n\nexport const error = (...params: unknown[]) => {\n const err = extractError(params)\n _exceptionTracker?.(err)\n _otelBridge?.logException(err)\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.error(formatParams(params))\n }\n}\n\nexport const info = (...params: unknown[]) => {\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.info(...params)\n }\n _otelBridge?.logInfo(formatParams(params))\n}\n\nexport const debug = (...params: unknown[]) => {\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.debug(...params)\n }\n _otelBridge?.logDebug(formatParams(params))\n}\n\nexport const warn = (...params: unknown[]) => {\n const err = extractError(params)\n _exceptionTracker?.(err)\n _otelBridge?.logException(err)\n _otelBridge?.logWarn(formatParams(params))\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.warn(formatParams(params))\n }\n}\n\nexport const assert = (condition: boolean | undefined, message: string) => {\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.assert(condition, message)\n }\n}\n\nexport const clear = () => {\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.clear()\n }\n}\n\nexport const table = (table: unknown) => {\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.table(table)\n }\n}\n\nexport const group = (name: string) => {\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.group(name)\n }\n}\n\nexport const groupEnd = () => {\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.groupEnd()\n }\n}\n\nexport const time = (name: string) => {\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.time(name)\n }\n}\n\nexport const timeEnd = (name: string) => {\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.timeEnd(name)\n }\n}\n\nexport const timeLog = (name: string, ...params: unknown[]) => {\n if (isLoggingEnabled) {\n // eslint-disable-next-line no-console\n console.timeLog(name, ...params)\n }\n}\n\nexport const logger = {\n log,\n error,\n info,\n debug,\n warn,\n assert,\n clear,\n table,\n group,\n groupEnd,\n time,\n timeEnd,\n timeLog,\n}\n\nexport const useErrorsLogger = (errors: Ref<Error | null | undefined>[]) => {\n // Vue is an optional runtime dependency for the backend build.\n // Lazily import it only when running in a browser/Vue environment.\n if (typeof window === 'undefined') {\n return\n }\n\n void import('vue').then(({ watch }) => {\n errors.forEach((error) => {\n watch(error, (value) => {\n logger.error(value)\n })\n })\n })\n}\n"],"mappings":";;AAeA,IAEI,IAAgC,MAkB9B,KAAgB,MACJ,EAAO,MAAM,MAAkB,aAAa,KACtD,KAGO,MAAM,EAAO,IAAI,MAAM,CAAC,CAAC,KAAK,GAAG,CAAC,GAG3C,KAAe,MACb,aAAiB,QACV,EAAM,SAAS,EAAM,UAEzB,OAAO,CAAK,GAGjB,KAAgB,MACX,EAAO,IAAI,CAAW,CAAC,CAAC,KAAK,GAAG,GAGrC,IAAe,OAAO,SAAW,KAQjC,KALU,IACV,SAAS,KAAK,eAAe,SAC5B,OAG6B,GAuGvB,IAAS;CAClB,MAtGgB,GAAG,MAAsB;EAKzC,AAJI,KAEA,QAAQ,IAAI,GAAG,CAAM,GAEzB,GAAa,QAAQ,EAAa,CAAM,CAAC;CAC7C;CAiGI,QA/FkB,GAAG,MAAsB;EAC3C,IAAM,IAAM,EAAa,CAAM;EAG/B,AADA,GAAa,aAAa,CAAG,GACzB,KAEA,QAAQ,MAAM,EAAa,CAAM,CAAC;CAE1C;CAwFI,OAtFiB,GAAG,MAAsB;EAK1C,AAJI,KAEA,QAAQ,KAAK,GAAG,CAAM,GAE1B,GAAa,QAAQ,EAAa,CAAM,CAAC;CAC7C;CAiFI,QA/EkB,GAAG,MAAsB;EAK3C,AAJI,KAEA,QAAQ,MAAM,GAAG,CAAM,GAE3B,GAAa,SAAS,EAAa,CAAM,CAAC;CAC9C;CA0EI,OAxEiB,GAAG,MAAsB;EAC1C,IAAM,IAAM,EAAa,CAAM;EAI/B,AAFA,GAAa,aAAa,CAAG,GAC7B,GAAa,QAAQ,EAAa,CAAM,CAAC,GACrC,KAEA,QAAQ,KAAK,EAAa,CAAM,CAAC;CAEzC;CAgEI,SA9DmB,GAAgC,MAAoB;EACvE,AAAI,KAEA,QAAQ,OAAO,GAAW,CAAO;CAEzC;CA0DI,aAxDuB;EACvB,AAAI,KAEA,QAAQ,MAAM;CAEtB;CAoDI,QAlDkB,MAAmB;EACrC,AAAI,KAEA,QAAQ,MAAM,CAAK;CAE3B;CA8CI,QA5CkB,MAAiB;EACnC,AAAI,KAEA,QAAQ,MAAM,CAAI;CAE1B;CAwCI,gBAtC0B;EAC1B,AAAI,KAEA,QAAQ,SAAS;CAEzB;CAkCI,OAhCiB,MAAiB;EAClC,AAAI,KAEA,QAAQ,KAAK,CAAI;CAEzB;CA4BI,UA1BoB,MAAiB;EACrC,AAAI,KAEA,QAAQ,QAAQ,CAAI;CAE5B;CAsBI,UApBoB,GAAc,GAAG,MAAsB;EAC3D,AAAI,KAEA,QAAQ,QAAQ,GAAM,GAAG,CAAM;CAEvC;AAgBA"}
@@ -0,0 +1,19 @@
1
+ import { dt as e, it as t } from "./vue.runtime.esm-bundler-B3bThTaf.js";
2
+ //#region ../../packages/composable/src/useImageFallback.ts
3
+ t();
4
+ function n() {
5
+ let t = e(/* @__PURE__ */ new Set());
6
+ return {
7
+ canShowImage: (e) => !!e && !t.has(e),
8
+ onImageError: (e) => {
9
+ e && t.add(e);
10
+ },
11
+ resetImageError: (e) => {
12
+ e && t.delete(e);
13
+ }
14
+ };
15
+ }
16
+ //#endregion
17
+ export { n as t };
18
+
19
+ //# sourceMappingURL=useImageFallback-BAsLRsyg.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useImageFallback-8kfLDjXm.js","names":[],"sources":["../../../../packages/composable/src/useImageFallback.ts"],"sourcesContent":["import { reactive } from 'vue'\n\n/**\n * Tracks image sources that failed to load, so a template can swap in a\n * placeholder (icon, initials, next-best image) instead of leaving the\n * browser's broken-image glyph.\n *\n * Any `<img>` pointing at a url we don't control needs this: OAuth avatar urls\n * expire, uploaded logos get deleted, og:images and favicons rot, and preview\n * blobs may not be generated yet.\n *\n * ```vue\n * <img v-if=\"canShowImage(page.image)\" :src=\"page.image\" @error=\"onImageError(page.image)\" />\n * <VvIcon v-else name=\"ri:image-off-line\" />\n * ```\n */\nexport function useImageFallback() {\n const failed = reactive(new Set<string>())\n\n /** True when there is a source and it has not failed yet. */\n const canShowImage = (src?: string | null): boolean =>\n !!src && !failed.has(src)\n\n const onImageError = (src?: string | null): void => {\n if (src) {\n failed.add(src)\n }\n }\n\n /** Lets a retry (new upload, refreshed sas url) show the image again. */\n const resetImageError = (src?: string | null): void => {\n if (src) {\n failed.delete(src)\n }\n }\n\n return { canShowImage, onImageError, resetImageError }\n}\n"],"mappings":";;;AAgBA,SAAgB,IAAmB;CAC/B,IAAM,IAAS,kBAAS,IAAI,IAAY,CAAC;CAmBzC,OAAO;EAAE,eAhBa,MAClB,CAAC,CAAC,KAAO,CAAC,EAAO,IAAI,CAAG;EAeL,eAbD,MAA8B;GAChD,AAAI,KACA,EAAO,IAAI,CAAG;EAEtB;EASqC,kBANZ,MAA8B;GACnD,AAAI,KACA,EAAO,OAAO,CAAG;EAEzB;CAEqD;AACzD"}
1
+ {"version":3,"file":"useImageFallback-BAsLRsyg.js","names":[],"sources":["../../../../packages/composable/src/useImageFallback.ts"],"sourcesContent":["import { reactive } from 'vue'\n\n/**\n * Tracks image sources that failed to load, so a template can swap in a\n * placeholder (icon, initials, next-best image) instead of leaving the\n * browser's broken-image glyph.\n *\n * Any `<img>` pointing at a url we don't control needs this: OAuth avatar urls\n * expire, uploaded logos get deleted, og:images and favicons rot, and preview\n * blobs may not be generated yet.\n *\n * ```vue\n * <img v-if=\"canShowImage(page.image)\" :src=\"page.image\" @error=\"onImageError(page.image)\" />\n * <VvIcon v-else name=\"ri:image-off-line\" />\n * ```\n */\nexport function useImageFallback() {\n const failed = reactive(new Set<string>())\n\n /** True when there is a source and it has not failed yet. */\n const canShowImage = (src?: string | null): boolean =>\n !!src && !failed.has(src)\n\n const onImageError = (src?: string | null): void => {\n if (src) {\n failed.add(src)\n }\n }\n\n /** Lets a retry (new upload, refreshed sas url) show the image again. */\n const resetImageError = (src?: string | null): void => {\n if (src) {\n failed.delete(src)\n }\n }\n\n return { canShowImage, onImageError, resetImageError }\n}\n"],"mappings":";;;AAgBA,SAAgB,IAAmB;CAC/B,IAAM,IAAS,kBAAS,IAAI,IAAY,CAAC;CAmBzC,OAAO;EAAE,eAhBa,MAClB,CAAC,CAAC,KAAO,CAAC,EAAO,IAAI,CAAG;EAeL,eAbD,MAA8B;GAChD,AAAI,KACA,EAAO,IAAI,CAAG;EAEtB;EASqC,kBANZ,MAA8B;GACnD,AAAI,KACA,EAAO,OAAO,CAAG;EAEzB;CAEqD;AACzD"}
@@ -1,15 +1,15 @@
1
- import { F as e, at as t, gt as n, k as r, mt as i } from "./vue.runtime.esm-bundler-DF2of3lp.js";
1
+ import { O as e, P as t, ht as n, it as r, pt as i } from "./vue.runtime.esm-bundler-B3bThTaf.js";
2
2
  import { n as a } from "./cdn-css-JUUNhyQ6.js";
3
- import "./src-BjFv9Ag8.js";
3
+ import "./src-CIEdKLKO.js";
4
4
  //#region ../../packages/components/src/composables/useLightbox.ts
5
- r(), t();
5
+ e(), r();
6
6
  var o = "https://cdn.jsdelivr.net/npm/photoswipe@5/dist/photoswipe.css", s = {
7
7
  width: 1200,
8
8
  height: 800
9
9
  };
10
- function c(t) {
11
- let { gallery: r, children: i = "a[data-pswp-src]", loop: s = !0, downloadable: c = !0, openInNewTab: l = !0 } = t, f = n(null);
12
- return e(() => {
10
+ function c(e) {
11
+ let { gallery: r, children: i = "a[data-pswp-src]", loop: s = !0, downloadable: c = !0, openInNewTab: l = !0 } = e, f = n(null);
12
+ return t(() => {
13
13
  f.value?.destroy(), f.value = null;
14
14
  }), {
15
15
  lightbox: f,
@@ -116,4 +116,4 @@ function h() {
116
116
  //#endregion
117
117
  export { c as n, l as t };
118
118
 
119
- //# sourceMappingURL=useLightbox-Bq6k-Wlt.js.map
119
+ //# sourceMappingURL=useLightbox-Epg2fN87.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useLightbox-Bq6k-Wlt.js","names":[],"sources":["../../../../packages/components/src/composables/useLightbox.ts"],"sourcesContent":["import {\n onBeforeUnmount,\n ref,\n shallowRef,\n type Ref,\n type ShallowRef,\n} from 'vue'\nimport type PhotoSwipeLightbox from 'photoswipe/lightbox'\nimport type PhotoSwipe from 'photoswipe'\nimport { loadCdnCss } from 'utils'\n\nconst PHOTOSWIPE_CSS =\n 'https://cdn.jsdelivr.net/npm/photoswipe@5/dist/photoswipe.css'\n\nconst DEFAULT_IMAGE_SIZE = { width: 1200, height: 800 }\n\nexport interface LightboxImage {\n url: string\n caption?: string\n alt?: string\n /** Natural width in px — used by PhotoSwipe for proper sizing. */\n width?: number\n /** Natural height in px — used by PhotoSwipe for proper sizing. */\n height?: number\n}\n\nexport interface LightboxOptions {\n /** Container element whose child anchors are the gallery items */\n gallery: Ref<HTMLElement | undefined>\n /** CSS selector for gallery items inside the container (default: `'a[data-pswp-src]'`) */\n children?: string\n loop?: boolean\n /** Show a download button in the lightbox toolbar */\n downloadable?: boolean\n /** Show an open-in-new-tab button in the lightbox toolbar */\n openInNewTab?: boolean\n}\n\nexport interface UseLightboxReturn {\n lightbox: ShallowRef<PhotoSwipeLightbox | null>\n /** Initialises PhotoSwipe. Call this inside `onMounted`. */\n init: () => Promise<void>\n}\n\n/**\n * Encapsulates PhotoSwipe 5 initialisation, toolbar customisation, and lifecycle cleanup.\n * CSS is injected into `document.head` so the overlay works in both regular DOM and Shadow DOM.\n *\n * Usage:\n * ```ts\n * const { init } = useLightbox({ gallery: galleryRef, downloadable: true })\n * onMounted(init)\n * ```\n */\nexport function useLightbox(options: LightboxOptions): UseLightboxReturn {\n const {\n gallery,\n children = 'a[data-pswp-src]',\n loop = true,\n downloadable = true,\n openInNewTab = true,\n } = options\n\n const lightbox = shallowRef<PhotoSwipeLightbox | null>(null)\n\n const init = async () => {\n if (!gallery.value) {\n return\n }\n\n // PhotoSwipe renders its overlay into document.body, so CSS must be in\n // document.head — not inside a shadow root.\n loadCdnCss(PHOTOSWIPE_CSS)\n injectPhotoSwipeOverrides()\n\n const { default: PhotoSwipeLightbox } =\n await import('photoswipe/lightbox')\n\n lightbox.value = new PhotoSwipeLightbox({\n gallery: gallery.value,\n children,\n pswpModule: () => import('photoswipe'),\n loop,\n arrowPrevSVG:\n '<svg aria-hidden=\"true\" class=\"pswp__icn\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"#ffffff\" d=\"m10.828 12l4.95 4.95l-1.414 1.415L8 12l6.364-6.364l1.414 1.414z\"/></svg>',\n arrowNextSVG:\n '<svg aria-hidden=\"true\" class=\"pswp__icn\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"#ffffff\" d=\"m13.172 12l-4.95-4.95l1.414-1.413L16 12l-6.364 6.364l-1.414-1.415z\"/></svg>',\n closeSVG:\n '<svg aria-hidden=\"true\" class=\"pswp__icn\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"#ffffff\" d=\"m12 10.587l4.95-4.95l1.414 1.414l-4.95 4.95l4.95 4.95l-1.415 1.414l-4.95-4.95l-4.949 4.95l-1.414-1.415l4.95-4.95l-4.95-4.95L7.05 5.638z\"/></svg>',\n zoomSVG:\n '<svg aria-hidden=\"true\" class=\"pswp__icn\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><g class=\"pswp__icn--zoom-in\"><path fill=\"#ffffff\" d=\"m18.031 16.617l4.283 4.282l-1.415 1.415l-4.282-4.283A8.96 8.96 0 0 1 11 20c-4.968 0-9-4.032-9-9s4.032-9 9-9s9 4.032 9 9a8.96 8.96 0 0 1-1.969 5.617m-2.006-.742A6.98 6.98 0 0 0 18 11c0-3.867-3.133-7-7-7s-7 3.133-7 7s3.133 7 7 7a6.98 6.98 0 0 0 4.875-1.975zM10 10V7h2v3h3v2h-3v3h-2v-3H7v-2z\"/></g><g class=\"pswp__icn--zoom-out\"><path fill=\"#ffffff\" d=\"m18.031 16.617l4.283 4.282l-1.415 1.415l-4.282-4.283A8.96 8.96 0 0 1 11 20c-4.968 0-9-4.032-9-9s4.032-9 9-9s9 4.032 9 9a8.96 8.96 0 0 1-1.969 5.617m-2.006-.742A6.98 6.98 0 0 0 18 11c0-3.867-3.133-7-7-7s-7 3.133-7 7s3.133 7 7 7a6.98 6.98 0 0 0 4.875-1.975zM7 10h8v2H7z\"/></g></svg>',\n })\n\n if (openInNewTab || downloadable) {\n lightbox.value.on('uiRegister', () => {\n const ui = lightbox.value!.pswp?.ui\n if (!ui) {\n return\n }\n\n if (openInNewTab) {\n ui.registerElement({\n name: 'open-in-new-tab-button',\n order: 8,\n isButton: true,\n html: '<svg aria-hidden=\"true\" class=\"pswp__icn\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"#ffffff\" d=\"M10 6v2H5v11h11v-5h2v6a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm11-3v8h-2V6.413l-7.793 7.794l-1.414-1.414L17.585 5H13V3z\"/></svg>',\n title: 'Open in new tab',\n onClick: (_, __, pswp) => {\n const url = getCurrentSlideUrl(pswp)\n if (url) {\n window.open(\n url,\n '_blank',\n 'noopener,noreferrer',\n )\n }\n },\n })\n }\n\n if (downloadable) {\n ui.registerElement({\n name: 'download-button',\n order: 9,\n isButton: true,\n html: '<svg aria-hidden=\"true\" class=\"pswp__icn\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"#ffffff\" d=\"M3 19h18v2H3zm10-5.828L19.071 7.1l1.414 1.414L12 17L3.515 8.515L4.929 7.1L11 13.173V2h2z\"/></svg>',\n title: 'Download',\n onClick: (_, __, pswp) => {\n const url = getCurrentSlideUrl(pswp)\n if (url) {\n downloadImage(url)\n }\n },\n })\n }\n })\n }\n\n lightbox.value.init()\n }\n\n onBeforeUnmount(() => {\n lightbox.value?.destroy()\n lightbox.value = null\n })\n\n return { lightbox, init }\n}\n\n// ---------------------------------------------------------------------------\n// Image size preloading\n// ---------------------------------------------------------------------------\n\nexport interface UseImageSizesReturn {\n preload: (\n images: Array<{ url: string; width?: number; height?: number }>,\n ) => void\n getSize: (url: string) => { width: number; height: number }\n}\n\n/**\n * Preloads natural image dimensions so PhotoSwipe can size its slides correctly.\n * When `width`/`height` are already provided they are used as-is;\n * otherwise the image is loaded in the background to read `naturalWidth`/`naturalHeight`.\n */\nexport function useImageSizes(): UseImageSizesReturn {\n const sizes = ref(new Map<string, { width: number; height: number }>())\n\n const preload = (\n images: Array<{ url: string; width?: number; height?: number }>,\n ) => {\n for (const image of images) {\n if (image.width && image.height) {\n sizes.value.set(image.url, {\n width: image.width,\n height: image.height,\n })\n continue\n }\n const img = new Image()\n img.onload = () => {\n sizes.value.set(image.url, {\n width: img.naturalWidth,\n height: img.naturalHeight,\n })\n }\n img.src = image.url\n }\n }\n\n const getSize = (url: string) => sizes.value.get(url) ?? DEFAULT_IMAGE_SIZE\n\n return { preload, getSize }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction getCurrentSlideUrl(pswp: PhotoSwipe): string | undefined {\n return (\n pswp.currSlide?.data?.src ??\n pswp.currSlide?.data?.element\n ?.querySelector('img')\n ?.getAttribute('src') ??\n pswp.currSlide?.data?.element\n ?.querySelector('source')\n ?.getAttribute('srcset') ??\n pswp.currSlide?.data?.element?.getAttribute('src') ??\n undefined\n )\n}\n\n/**\n * Triggers a client-side download for an image URL.\n *\n * For backend media URLs (.../media/:file/view), navigates to the\n * corresponding /download endpoint which redirects to an Azure SAS URL\n * with `Content-Disposition: attachment` — no CORS issues.\n *\n * For blob: URLs (in-session uploads), uses the fetch → blob approach.\n *\n * For data: URLs (inline SVGs, etc.), use the download attribute.\n *\n * Falls back to opening in a new tab for all other cases.\n */\nfunction downloadImage(url: string): void {\n const downloadUrl = toDownloadUrl(url)\n\n const anchor = document.createElement('a')\n anchor.href = downloadUrl\n anchor.target = '_blank'\n anchor.rel = 'noopener noreferrer'\n // `download` attribute works for same-origin, data: and blob: URLs; for\n // cross-origin it is ignored but the browser still follows Content-Disposition.\n anchor.download = getFilenameFromUrl(url)\n document.body.appendChild(anchor)\n anchor.click()\n document.body.removeChild(anchor)\n}\n\n/**\n * Converts a `/view` media URL to its `/download` counterpart.\n * Leaves blob:, data: and all other URLs untouched.\n */\nfunction toDownloadUrl(url: string): string {\n return url.replace(/\\/view(\\?|$)/, '/download$1')\n}\n\nfunction getFilenameFromUrl(url: string): string {\n if (url.startsWith('data:image/svg+xml')) {\n return 'diagram.svg'\n }\n if (url.startsWith('data:')) {\n const mime = url.split(':')[1].split(';')[0]\n const ext = mime.split('/')[1] || 'bin'\n return `image.${ext}`\n }\n try {\n const pathname = new URL(url).pathname\n const name = pathname.split('/').pop()\n return name && name.includes('.') ? name : 'image'\n } catch {\n return 'image'\n }\n}\n\nlet overridesInjected = false\n\n/**\n * Injects a one-time `<style>` into `document.head` that raises\n * PhotoSwipe's z-index above any host UI (e.g. floating chat widgets\n * that use `z-index: 2147483647`).\n */\nfunction injectPhotoSwipeOverrides(): void {\n if (overridesInjected) {\n return\n }\n overridesInjected = true\n const style = document.createElement('style')\n style.textContent = [\n '.pswp__counter { font-family: sans-serif; }',\n '.pswp { z-index: 2147483647 !important; }',\n '.pswp__icn { width: 20px; height: 20px; }',\n '.pswp__button { width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; }',\n '.pswp__icn--zoom-out { display: none; }',\n '.pswp--zoomed-in .pswp__icn--zoom-in { display: none; }',\n '.pswp--zoomed-in .pswp__icn--zoom-out { display: block; }',\n '.pswp__button--arrow .pswp__icn {left: auto; right: auto; width: 40px; height: 40px; transform: none; margin-top: -20px; }',\n ].join(' ')\n document.head.appendChild(style)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"useLightbox-Epg2fN87.js","names":[],"sources":["../../../../packages/components/src/composables/useLightbox.ts"],"sourcesContent":["import {\n onBeforeUnmount,\n ref,\n shallowRef,\n type Ref,\n type ShallowRef,\n} from 'vue'\nimport type PhotoSwipeLightbox from 'photoswipe/lightbox'\nimport type PhotoSwipe from 'photoswipe'\nimport { loadCdnCss } from 'utils'\n\nconst PHOTOSWIPE_CSS =\n 'https://cdn.jsdelivr.net/npm/photoswipe@5/dist/photoswipe.css'\n\nconst DEFAULT_IMAGE_SIZE = { width: 1200, height: 800 }\n\nexport interface LightboxImage {\n url: string\n caption?: string\n alt?: string\n /** Natural width in px — used by PhotoSwipe for proper sizing. */\n width?: number\n /** Natural height in px — used by PhotoSwipe for proper sizing. */\n height?: number\n}\n\nexport interface LightboxOptions {\n /** Container element whose child anchors are the gallery items */\n gallery: Ref<HTMLElement | undefined>\n /** CSS selector for gallery items inside the container (default: `'a[data-pswp-src]'`) */\n children?: string\n loop?: boolean\n /** Show a download button in the lightbox toolbar */\n downloadable?: boolean\n /** Show an open-in-new-tab button in the lightbox toolbar */\n openInNewTab?: boolean\n}\n\nexport interface UseLightboxReturn {\n lightbox: ShallowRef<PhotoSwipeLightbox | null>\n /** Initialises PhotoSwipe. Call this inside `onMounted`. */\n init: () => Promise<void>\n}\n\n/**\n * Encapsulates PhotoSwipe 5 initialisation, toolbar customisation, and lifecycle cleanup.\n * CSS is injected into `document.head` so the overlay works in both regular DOM and Shadow DOM.\n *\n * Usage:\n * ```ts\n * const { init } = useLightbox({ gallery: galleryRef, downloadable: true })\n * onMounted(init)\n * ```\n */\nexport function useLightbox(options: LightboxOptions): UseLightboxReturn {\n const {\n gallery,\n children = 'a[data-pswp-src]',\n loop = true,\n downloadable = true,\n openInNewTab = true,\n } = options\n\n const lightbox = shallowRef<PhotoSwipeLightbox | null>(null)\n\n const init = async () => {\n if (!gallery.value) {\n return\n }\n\n // PhotoSwipe renders its overlay into document.body, so CSS must be in\n // document.head — not inside a shadow root.\n loadCdnCss(PHOTOSWIPE_CSS)\n injectPhotoSwipeOverrides()\n\n const { default: PhotoSwipeLightbox } =\n await import('photoswipe/lightbox')\n\n lightbox.value = new PhotoSwipeLightbox({\n gallery: gallery.value,\n children,\n pswpModule: () => import('photoswipe'),\n loop,\n arrowPrevSVG:\n '<svg aria-hidden=\"true\" class=\"pswp__icn\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"#ffffff\" d=\"m10.828 12l4.95 4.95l-1.414 1.415L8 12l6.364-6.364l1.414 1.414z\"/></svg>',\n arrowNextSVG:\n '<svg aria-hidden=\"true\" class=\"pswp__icn\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"#ffffff\" d=\"m13.172 12l-4.95-4.95l1.414-1.413L16 12l-6.364 6.364l-1.414-1.415z\"/></svg>',\n closeSVG:\n '<svg aria-hidden=\"true\" class=\"pswp__icn\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"#ffffff\" d=\"m12 10.587l4.95-4.95l1.414 1.414l-4.95 4.95l4.95 4.95l-1.415 1.414l-4.95-4.95l-4.949 4.95l-1.414-1.415l4.95-4.95l-4.95-4.95L7.05 5.638z\"/></svg>',\n zoomSVG:\n '<svg aria-hidden=\"true\" class=\"pswp__icn\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><g class=\"pswp__icn--zoom-in\"><path fill=\"#ffffff\" d=\"m18.031 16.617l4.283 4.282l-1.415 1.415l-4.282-4.283A8.96 8.96 0 0 1 11 20c-4.968 0-9-4.032-9-9s4.032-9 9-9s9 4.032 9 9a8.96 8.96 0 0 1-1.969 5.617m-2.006-.742A6.98 6.98 0 0 0 18 11c0-3.867-3.133-7-7-7s-7 3.133-7 7s3.133 7 7 7a6.98 6.98 0 0 0 4.875-1.975zM10 10V7h2v3h3v2h-3v3h-2v-3H7v-2z\"/></g><g class=\"pswp__icn--zoom-out\"><path fill=\"#ffffff\" d=\"m18.031 16.617l4.283 4.282l-1.415 1.415l-4.282-4.283A8.96 8.96 0 0 1 11 20c-4.968 0-9-4.032-9-9s4.032-9 9-9s9 4.032 9 9a8.96 8.96 0 0 1-1.969 5.617m-2.006-.742A6.98 6.98 0 0 0 18 11c0-3.867-3.133-7-7-7s-7 3.133-7 7s3.133 7 7 7a6.98 6.98 0 0 0 4.875-1.975zM7 10h8v2H7z\"/></g></svg>',\n })\n\n if (openInNewTab || downloadable) {\n lightbox.value.on('uiRegister', () => {\n const ui = lightbox.value!.pswp?.ui\n if (!ui) {\n return\n }\n\n if (openInNewTab) {\n ui.registerElement({\n name: 'open-in-new-tab-button',\n order: 8,\n isButton: true,\n html: '<svg aria-hidden=\"true\" class=\"pswp__icn\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"#ffffff\" d=\"M10 6v2H5v11h11v-5h2v6a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm11-3v8h-2V6.413l-7.793 7.794l-1.414-1.414L17.585 5H13V3z\"/></svg>',\n title: 'Open in new tab',\n onClick: (_, __, pswp) => {\n const url = getCurrentSlideUrl(pswp)\n if (url) {\n window.open(\n url,\n '_blank',\n 'noopener,noreferrer',\n )\n }\n },\n })\n }\n\n if (downloadable) {\n ui.registerElement({\n name: 'download-button',\n order: 9,\n isButton: true,\n html: '<svg aria-hidden=\"true\" class=\"pswp__icn\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"#ffffff\" d=\"M3 19h18v2H3zm10-5.828L19.071 7.1l1.414 1.414L12 17L3.515 8.515L4.929 7.1L11 13.173V2h2z\"/></svg>',\n title: 'Download',\n onClick: (_, __, pswp) => {\n const url = getCurrentSlideUrl(pswp)\n if (url) {\n downloadImage(url)\n }\n },\n })\n }\n })\n }\n\n lightbox.value.init()\n }\n\n onBeforeUnmount(() => {\n lightbox.value?.destroy()\n lightbox.value = null\n })\n\n return { lightbox, init }\n}\n\n// ---------------------------------------------------------------------------\n// Image size preloading\n// ---------------------------------------------------------------------------\n\nexport interface UseImageSizesReturn {\n preload: (\n images: Array<{ url: string; width?: number; height?: number }>,\n ) => void\n getSize: (url: string) => { width: number; height: number }\n}\n\n/**\n * Preloads natural image dimensions so PhotoSwipe can size its slides correctly.\n * When `width`/`height` are already provided they are used as-is;\n * otherwise the image is loaded in the background to read `naturalWidth`/`naturalHeight`.\n */\nexport function useImageSizes(): UseImageSizesReturn {\n const sizes = ref(new Map<string, { width: number; height: number }>())\n\n const preload = (\n images: Array<{ url: string; width?: number; height?: number }>,\n ) => {\n for (const image of images) {\n if (image.width && image.height) {\n sizes.value.set(image.url, {\n width: image.width,\n height: image.height,\n })\n continue\n }\n const img = new Image()\n img.onload = () => {\n sizes.value.set(image.url, {\n width: img.naturalWidth,\n height: img.naturalHeight,\n })\n }\n img.src = image.url\n }\n }\n\n const getSize = (url: string) => sizes.value.get(url) ?? DEFAULT_IMAGE_SIZE\n\n return { preload, getSize }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction getCurrentSlideUrl(pswp: PhotoSwipe): string | undefined {\n return (\n pswp.currSlide?.data?.src ??\n pswp.currSlide?.data?.element\n ?.querySelector('img')\n ?.getAttribute('src') ??\n pswp.currSlide?.data?.element\n ?.querySelector('source')\n ?.getAttribute('srcset') ??\n pswp.currSlide?.data?.element?.getAttribute('src') ??\n undefined\n )\n}\n\n/**\n * Triggers a client-side download for an image URL.\n *\n * For backend media URLs (.../media/:file/view), navigates to the\n * corresponding /download endpoint which redirects to an Azure SAS URL\n * with `Content-Disposition: attachment` — no CORS issues.\n *\n * For blob: URLs (in-session uploads), uses the fetch → blob approach.\n *\n * For data: URLs (inline SVGs, etc.), use the download attribute.\n *\n * Falls back to opening in a new tab for all other cases.\n */\nfunction downloadImage(url: string): void {\n const downloadUrl = toDownloadUrl(url)\n\n const anchor = document.createElement('a')\n anchor.href = downloadUrl\n anchor.target = '_blank'\n anchor.rel = 'noopener noreferrer'\n // `download` attribute works for same-origin, data: and blob: URLs; for\n // cross-origin it is ignored but the browser still follows Content-Disposition.\n anchor.download = getFilenameFromUrl(url)\n document.body.appendChild(anchor)\n anchor.click()\n document.body.removeChild(anchor)\n}\n\n/**\n * Converts a `/view` media URL to its `/download` counterpart.\n * Leaves blob:, data: and all other URLs untouched.\n */\nfunction toDownloadUrl(url: string): string {\n return url.replace(/\\/view(\\?|$)/, '/download$1')\n}\n\nfunction getFilenameFromUrl(url: string): string {\n if (url.startsWith('data:image/svg+xml')) {\n return 'diagram.svg'\n }\n if (url.startsWith('data:')) {\n const mime = url.split(':')[1].split(';')[0]\n const ext = mime.split('/')[1] || 'bin'\n return `image.${ext}`\n }\n try {\n const pathname = new URL(url).pathname\n const name = pathname.split('/').pop()\n return name && name.includes('.') ? name : 'image'\n } catch {\n return 'image'\n }\n}\n\nlet overridesInjected = false\n\n/**\n * Injects a one-time `<style>` into `document.head` that raises\n * PhotoSwipe's z-index above any host UI (e.g. floating chat widgets\n * that use `z-index: 2147483647`).\n */\nfunction injectPhotoSwipeOverrides(): void {\n if (overridesInjected) {\n return\n }\n overridesInjected = true\n const style = document.createElement('style')\n style.textContent = [\n '.pswp__counter { font-family: sans-serif; }',\n '.pswp { z-index: 2147483647 !important; }',\n '.pswp__icn { width: 20px; height: 20px; }',\n '.pswp__button { width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; }',\n '.pswp__icn--zoom-out { display: none; }',\n '.pswp--zoomed-in .pswp__icn--zoom-in { display: none; }',\n '.pswp--zoomed-in .pswp__icn--zoom-out { display: block; }',\n '.pswp__button--arrow .pswp__icn {left: auto; right: auto; width: 40px; height: 40px; transform: none; margin-top: -20px; }',\n ].join(' ')\n document.head.appendChild(style)\n}\n"],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ import { O as e, R as t, dt as n, it as r, k as i, m as a, yt as o } from "./vue.runtime.esm-bundler-B3bThTaf.js";
2
+ //#region ../../packages/composable/src/chatbot/useShortUrlResolver.ts
3
+ e(), r();
4
+ var s = /\/api\/r\/([A-Za-z0-9_-]{1,20})(?:[?#]|$)/, c = /https?:\/\/[^\s)"'<>]*\/api\/r\/([A-Za-z0-9_-]{1,20})/g;
5
+ function l(e) {
6
+ return s.exec(e)?.[1];
7
+ }
8
+ function u(e) {
9
+ let t = n(/* @__PURE__ */ new Map()), r = n(/* @__PURE__ */ new Set()), i = /* @__PURE__ */ new Set(), s = !1;
10
+ async function u() {
11
+ s = !1;
12
+ let n = [...i];
13
+ if (i.clear(), n.length !== 0) try {
14
+ let r = await e(n);
15
+ for (let [e, n] of Object.entries(r)) t.set(e, n);
16
+ } catch {} finally {
17
+ for (let e of n) r.add(e);
18
+ }
19
+ }
20
+ function d(e) {
21
+ t.has(e) || i.has(e) || (i.add(e), s || (s = !0, queueMicrotask(u)));
22
+ }
23
+ function f(e) {
24
+ return a(() => {
25
+ let n = o(e), i = n ? l(n) : void 0;
26
+ if (!i) return {
27
+ url: n,
28
+ loading: !1
29
+ };
30
+ let a = t.get(i);
31
+ return a === void 0 ? (d(i), {
32
+ url: n,
33
+ loading: !r.has(i)
34
+ }) : {
35
+ url: a,
36
+ loading: !1
37
+ };
38
+ });
39
+ }
40
+ function p(e) {
41
+ return a(() => {
42
+ let n = o(e) ?? "";
43
+ return n && n.replace(c, (e, n) => {
44
+ let r = t.get(n);
45
+ return r === void 0 ? (d(n), e) : r;
46
+ });
47
+ });
48
+ }
49
+ return {
50
+ resolve: f,
51
+ resolveText: p
52
+ };
53
+ }
54
+ var d = Symbol("shortUrlResolver");
55
+ function f(e) {
56
+ let n = u(e);
57
+ return t(d, n), n;
58
+ }
59
+ var p = {
60
+ resolve: (e) => a(() => ({
61
+ url: o(e),
62
+ loading: !1
63
+ })),
64
+ resolveText: (e) => a(() => o(e) ?? "")
65
+ };
66
+ function m() {
67
+ return i(d, p);
68
+ }
69
+ //#endregion
70
+ export { m as n, f as t };
71
+
72
+ //# sourceMappingURL=useShortUrlResolver--HRa6Od3.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useShortUrlResolver-BTJM8XRw.js","names":[],"sources":["../../../../packages/composable/src/chatbot/useShortUrlResolver.ts"],"sourcesContent":["import {\n computed,\n inject,\n provide,\n reactive,\n toValue,\n type ComputedRef,\n type InjectionKey,\n type MaybeRefOrGetter,\n} from 'vue'\n\n/** Matches the short-url shape produced by the backend: `<host>/api/r/<hash>` */\nconst SHORT_URL_RE = /\\/api\\/r\\/([A-Za-z0-9_-]{1,20})(?:[?#]|$)/\n\n/** Global variant matching whole short urls embedded in free text (group 1 = hash) */\nconst FULL_SHORT_URL_RE =\n /https?:\\/\\/[^\\s)\"'<>]*\\/api\\/r\\/([A-Za-z0-9_-]{1,20})/g\n\nexport type ShortUrlBatchResolver = (\n hashes: string[],\n) => Promise<Record<string, string>>\n\nfunction extractHash(url: string): string | undefined {\n return SHORT_URL_RE.exec(url)?.[1]\n}\n\nexport interface ResolvedUrl {\n /** The resolved url, or the original short url until it arrives / on failure */\n url: string | undefined\n /** True while the short url is being resolved (use to show a skeleton) */\n loading: boolean\n}\n\nexport function createShortUrlResolver(batchResolve: ShortUrlBatchResolver) {\n // hash -> resolved long url (reactive so templates update on arrival)\n const cache = reactive(new Map<string, string>())\n // hashes whose batch has settled (resolved or not) — stops the loading state\n const settled = reactive(new Set<string>())\n const pending = new Set<string>()\n let scheduled = false\n\n async function flush() {\n scheduled = false\n const hashes = [...pending]\n pending.clear()\n if (hashes.length === 0) {\n return\n }\n try {\n const urls = await batchResolve(hashes)\n for (const [hash, url] of Object.entries(urls)) {\n cache.set(hash, url)\n }\n } catch {\n // leave short urls untouched on failure\n } finally {\n // mark every requested hash as settled so it stops loading even\n // when the backend returned no match (falls back to the short url)\n for (const hash of hashes) {\n settled.add(hash)\n }\n }\n }\n\n function request(hash: string) {\n if (cache.has(hash) || pending.has(hash)) {\n return\n }\n pending.add(hash)\n if (!scheduled) {\n scheduled = true\n // batch every hash requested within the same tick into one call\n queueMicrotask(flush)\n }\n }\n\n /** Resolves a short url, exposing both the value and its loading state */\n function resolve(\n input: MaybeRefOrGetter<string | undefined>,\n ): ComputedRef<ResolvedUrl> {\n return computed(() => {\n const url = toValue(input)\n const hash = url ? extractHash(url) : undefined\n if (!hash) {\n return { url, loading: false }\n }\n const resolved = cache.get(hash)\n if (resolved !== undefined) {\n return { url: resolved, loading: false }\n }\n request(hash)\n return { url, loading: !settled.has(hash) }\n })\n }\n\n /**\n * Resolves every short url embedded in a free-text string, replacing each\n * with its real target (full substitution). Unresolved hashes stay as short\n * urls until their batch settles. Meant for exported/copied content (email,\n * message bodies) and prose, where a short url must become the real one.\n */\n function resolveText(\n input: MaybeRefOrGetter<string | undefined>,\n ): ComputedRef<string> {\n return computed(() => {\n const text = toValue(input) ?? ''\n if (!text) {\n return text\n }\n return text.replace(FULL_SHORT_URL_RE, (full, hash: string) => {\n const resolved = cache.get(hash)\n if (resolved !== undefined) {\n return resolved\n }\n request(hash)\n return full\n })\n })\n }\n\n return { resolve, resolveText }\n}\n\nexport type ShortUrlResolver = ReturnType<typeof createShortUrlResolver>\n\nconst ShortUrlResolverKey: InjectionKey<ShortUrlResolver> =\n Symbol('shortUrlResolver')\n\n/** Call once in the chat root, passing the api client's batch resolver */\nexport function provideShortUrlResolver(\n batchResolve: ShortUrlBatchResolver,\n): ShortUrlResolver {\n const resolver = createShortUrlResolver(batchResolve)\n provide(ShortUrlResolverKey, resolver)\n return resolver\n}\n\n/** No-op fallback when no resolver is provided: returns urls untouched */\nconst identityResolver: ShortUrlResolver = {\n resolve: (input) =>\n computed(() => ({ url: toValue(input), loading: false })),\n resolveText: (input) => computed(() => toValue(input) ?? ''),\n}\n\nexport function useShortUrlResolver(): ShortUrlResolver {\n return inject(ShortUrlResolverKey, identityResolver)\n}\n"],"mappings":";;;AAYA,IAAM,IAAe,6CAGf,IACF;AAMJ,SAAS,EAAY,GAAiC;CAClD,OAAO,EAAa,KAAK,CAAG,CAAC,GAAG;AACpC;AASA,SAAgB,EAAuB,GAAqC;CAExE,IAAM,IAAQ,kBAAS,IAAI,IAAoB,CAAC,GAE1C,IAAU,kBAAS,IAAI,IAAY,CAAC,GACpC,oBAAU,IAAI,IAAY,GAC5B,IAAY;CAEhB,eAAe,IAAQ;EACnB,IAAY;EACZ,IAAM,IAAS,CAAC,GAAG,CAAO;EAC1B,MAAQ,MAAM,GACV,EAAO,WAAW,GAGtB,IAAI;GACA,IAAM,IAAO,MAAM,EAAa,CAAM;GACtC,KAAK,IAAM,CAAC,GAAM,MAAQ,OAAO,QAAQ,CAAI,GACzC,EAAM,IAAI,GAAM,CAAG;EAE3B,QAAQ,CAER,UAAU;GAGN,KAAK,IAAM,KAAQ,GACf,EAAQ,IAAI,CAAI;EAExB;CACJ;CAEA,SAAS,EAAQ,GAAc;EACvB,EAAM,IAAI,CAAI,KAAK,EAAQ,IAAI,CAAI,MAGvC,EAAQ,IAAI,CAAI,GACX,MACD,IAAY,IAEZ,eAAe,CAAK;CAE5B;CAGA,SAAS,EACL,GACwB;EACxB,OAAO,QAAe;GAClB,IAAM,IAAM,EAAQ,CAAK,GACnB,IAAO,IAAM,EAAY,CAAG,IAAI,KAAA;GACtC,IAAI,CAAC,GACD,OAAO;IAAE;IAAK,SAAS;GAAM;GAEjC,IAAM,IAAW,EAAM,IAAI,CAAI;GAK/B,OAJI,MAAa,KAAA,KAGjB,EAAQ,CAAI,GACL;IAAE;IAAK,SAAS,CAAC,EAAQ,IAAI,CAAI;GAAE,KAH/B;IAAE,KAAK;IAAU,SAAS;GAAM;EAI/C,CAAC;CACL;CAQA,SAAS,EACL,GACmB;EACnB,OAAO,QAAe;GAClB,IAAM,IAAO,EAAQ,CAAK,KAAK;GAI/B,OAHK,KAGE,EAAK,QAAQ,IAAoB,GAAM,MAAiB;IAC3D,IAAM,IAAW,EAAM,IAAI,CAAI;IAK/B,OAJI,MAAa,KAAA,KAGjB,EAAQ,CAAI,GACL,KAHI;GAIf,CAAC;EACL,CAAC;CACL;CAEA,OAAO;EAAE;EAAS;CAAY;AAClC;AAIA,IAAM,IACF,OAAO,kBAAkB;AAG7B,SAAgB,EACZ,GACgB;CAChB,IAAM,IAAW,EAAuB,CAAY;CAEpD,OADA,EAAQ,GAAqB,CAAQ,GAC9B;AACX;AAGA,IAAM,IAAqC;CACvC,UAAU,MACN,SAAgB;EAAE,KAAK,EAAQ,CAAK;EAAG,SAAS;CAAM,EAAE;CAC5D,cAAc,MAAU,QAAe,EAAQ,CAAK,KAAK,EAAE;AAC/D;AAEA,SAAgB,IAAwC;CACpD,OAAO,EAAO,GAAqB,CAAgB;AACvD"}
1
+ {"version":3,"file":"useShortUrlResolver--HRa6Od3.js","names":[],"sources":["../../../../packages/composable/src/chatbot/useShortUrlResolver.ts"],"sourcesContent":["import {\n computed,\n inject,\n provide,\n reactive,\n toValue,\n type ComputedRef,\n type InjectionKey,\n type MaybeRefOrGetter,\n} from 'vue'\n\n/** Matches the short-url shape produced by the backend: `<host>/api/r/<hash>` */\nconst SHORT_URL_RE = /\\/api\\/r\\/([A-Za-z0-9_-]{1,20})(?:[?#]|$)/\n\n/** Global variant matching whole short urls embedded in free text (group 1 = hash) */\nconst FULL_SHORT_URL_RE =\n /https?:\\/\\/[^\\s)\"'<>]*\\/api\\/r\\/([A-Za-z0-9_-]{1,20})/g\n\nexport type ShortUrlBatchResolver = (\n hashes: string[],\n) => Promise<Record<string, string>>\n\nfunction extractHash(url: string): string | undefined {\n return SHORT_URL_RE.exec(url)?.[1]\n}\n\nexport interface ResolvedUrl {\n /** The resolved url, or the original short url until it arrives / on failure */\n url: string | undefined\n /** True while the short url is being resolved (use to show a skeleton) */\n loading: boolean\n}\n\nexport function createShortUrlResolver(batchResolve: ShortUrlBatchResolver) {\n // hash -> resolved long url (reactive so templates update on arrival)\n const cache = reactive(new Map<string, string>())\n // hashes whose batch has settled (resolved or not) — stops the loading state\n const settled = reactive(new Set<string>())\n const pending = new Set<string>()\n let scheduled = false\n\n async function flush() {\n scheduled = false\n const hashes = [...pending]\n pending.clear()\n if (hashes.length === 0) {\n return\n }\n try {\n const urls = await batchResolve(hashes)\n for (const [hash, url] of Object.entries(urls)) {\n cache.set(hash, url)\n }\n } catch {\n // leave short urls untouched on failure\n } finally {\n // mark every requested hash as settled so it stops loading even\n // when the backend returned no match (falls back to the short url)\n for (const hash of hashes) {\n settled.add(hash)\n }\n }\n }\n\n function request(hash: string) {\n if (cache.has(hash) || pending.has(hash)) {\n return\n }\n pending.add(hash)\n if (!scheduled) {\n scheduled = true\n // batch every hash requested within the same tick into one call\n queueMicrotask(flush)\n }\n }\n\n /** Resolves a short url, exposing both the value and its loading state */\n function resolve(\n input: MaybeRefOrGetter<string | undefined>,\n ): ComputedRef<ResolvedUrl> {\n return computed(() => {\n const url = toValue(input)\n const hash = url ? extractHash(url) : undefined\n if (!hash) {\n return { url, loading: false }\n }\n const resolved = cache.get(hash)\n if (resolved !== undefined) {\n return { url: resolved, loading: false }\n }\n request(hash)\n return { url, loading: !settled.has(hash) }\n })\n }\n\n /**\n * Resolves every short url embedded in a free-text string, replacing each\n * with its real target (full substitution). Unresolved hashes stay as short\n * urls until their batch settles. Meant for exported/copied content (email,\n * message bodies) and prose, where a short url must become the real one.\n */\n function resolveText(\n input: MaybeRefOrGetter<string | undefined>,\n ): ComputedRef<string> {\n return computed(() => {\n const text = toValue(input) ?? ''\n if (!text) {\n return text\n }\n return text.replace(FULL_SHORT_URL_RE, (full, hash: string) => {\n const resolved = cache.get(hash)\n if (resolved !== undefined) {\n return resolved\n }\n request(hash)\n return full\n })\n })\n }\n\n return { resolve, resolveText }\n}\n\nexport type ShortUrlResolver = ReturnType<typeof createShortUrlResolver>\n\nconst ShortUrlResolverKey: InjectionKey<ShortUrlResolver> =\n Symbol('shortUrlResolver')\n\n/** Call once in the chat root, passing the api client's batch resolver */\nexport function provideShortUrlResolver(\n batchResolve: ShortUrlBatchResolver,\n): ShortUrlResolver {\n const resolver = createShortUrlResolver(batchResolve)\n provide(ShortUrlResolverKey, resolver)\n return resolver\n}\n\n/** No-op fallback when no resolver is provided: returns urls untouched */\nconst identityResolver: ShortUrlResolver = {\n resolve: (input) =>\n computed(() => ({ url: toValue(input), loading: false })),\n resolveText: (input) => computed(() => toValue(input) ?? ''),\n}\n\nexport function useShortUrlResolver(): ShortUrlResolver {\n return inject(ShortUrlResolverKey, identityResolver)\n}\n"],"mappings":";;;AAYA,IAAM,IAAe,6CAGf,IACF;AAMJ,SAAS,EAAY,GAAiC;CAClD,OAAO,EAAa,KAAK,CAAG,CAAC,GAAG;AACpC;AASA,SAAgB,EAAuB,GAAqC;CAExE,IAAM,IAAQ,kBAAS,IAAI,IAAoB,CAAC,GAE1C,IAAU,kBAAS,IAAI,IAAY,CAAC,GACpC,oBAAU,IAAI,IAAY,GAC5B,IAAY;CAEhB,eAAe,IAAQ;EACnB,IAAY;EACZ,IAAM,IAAS,CAAC,GAAG,CAAO;EAC1B,MAAQ,MAAM,GACV,EAAO,WAAW,GAGtB,IAAI;GACA,IAAM,IAAO,MAAM,EAAa,CAAM;GACtC,KAAK,IAAM,CAAC,GAAM,MAAQ,OAAO,QAAQ,CAAI,GACzC,EAAM,IAAI,GAAM,CAAG;EAE3B,QAAQ,CAER,UAAU;GAGN,KAAK,IAAM,KAAQ,GACf,EAAQ,IAAI,CAAI;EAExB;CACJ;CAEA,SAAS,EAAQ,GAAc;EACvB,EAAM,IAAI,CAAI,KAAK,EAAQ,IAAI,CAAI,MAGvC,EAAQ,IAAI,CAAI,GACX,MACD,IAAY,IAEZ,eAAe,CAAK;CAE5B;CAGA,SAAS,EACL,GACwB;EACxB,OAAO,QAAe;GAClB,IAAM,IAAM,EAAQ,CAAK,GACnB,IAAO,IAAM,EAAY,CAAG,IAAI,KAAA;GACtC,IAAI,CAAC,GACD,OAAO;IAAE;IAAK,SAAS;GAAM;GAEjC,IAAM,IAAW,EAAM,IAAI,CAAI;GAK/B,OAJI,MAAa,KAAA,KAGjB,EAAQ,CAAI,GACL;IAAE;IAAK,SAAS,CAAC,EAAQ,IAAI,CAAI;GAAE,KAH/B;IAAE,KAAK;IAAU,SAAS;GAAM;EAI/C,CAAC;CACL;CAQA,SAAS,EACL,GACmB;EACnB,OAAO,QAAe;GAClB,IAAM,IAAO,EAAQ,CAAK,KAAK;GAI/B,OAHK,KAGE,EAAK,QAAQ,IAAoB,GAAM,MAAiB;IAC3D,IAAM,IAAW,EAAM,IAAI,CAAI;IAK/B,OAJI,MAAa,KAAA,KAGjB,EAAQ,CAAI,GACL,KAHI;GAIf,CAAC;EACL,CAAC;CACL;CAEA,OAAO;EAAE;EAAS;CAAY;AAClC;AAIA,IAAM,IACF,OAAO,kBAAkB;AAG7B,SAAgB,EACZ,GACgB;CAChB,IAAM,IAAW,EAAuB,CAAY;CAEpD,OADA,EAAQ,GAAqB,CAAQ,GAC9B;AACX;AAGA,IAAM,IAAqC;CACvC,UAAU,MACN,SAAgB;EAAE,KAAK,EAAQ,CAAK;EAAG,SAAS;CAAM,EAAE;CAC5D,cAAc,MAAU,QAAe,EAAQ,CAAK,KAAK,EAAE;AAC/D;AAEA,SAAgB,IAAwC;CACpD,OAAO,EAAO,GAAqB,CAAgB;AACvD"}