@relax.js/core 1.0.4 → 1.0.5

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 (228) hide show
  1. package/dist/DependencyInjection.d.ts +3 -3
  2. package/dist/collections/LinkedList.d.ts +9 -8
  3. package/dist/collections/index.js +1 -1
  4. package/dist/collections/index.js.map +3 -3
  5. package/dist/collections/index.mjs +1 -1
  6. package/dist/collections/index.mjs.map +3 -3
  7. package/dist/di/index.js +1 -1
  8. package/dist/di/index.js.map +2 -2
  9. package/dist/di/index.mjs +1 -1
  10. package/dist/di/index.mjs.map +2 -2
  11. package/dist/elements/index.js +1 -1
  12. package/dist/elements/index.js.map +1 -1
  13. package/dist/forms/FormValidator.d.ts +2 -2
  14. package/dist/forms/ValidationRules.d.ts +2 -6
  15. package/dist/forms/index.js +1 -1
  16. package/dist/forms/index.js.map +3 -3
  17. package/dist/forms/index.mjs +1 -1
  18. package/dist/forms/index.mjs.map +3 -3
  19. package/dist/forms/setFormData.d.ts +39 -1
  20. package/dist/html/index.js +1 -1
  21. package/dist/html/index.js.map +3 -3
  22. package/dist/html/index.mjs +1 -1
  23. package/dist/html/index.mjs.map +3 -3
  24. package/dist/http/ServerSentEvents.d.ts +1 -1
  25. package/dist/http/SimpleWebSocket.d.ts +1 -1
  26. package/dist/http/index.js +1 -1
  27. package/dist/http/index.js.map +3 -3
  28. package/dist/http/index.mjs +1 -1
  29. package/dist/http/index.mjs.map +3 -3
  30. package/dist/i18n/icu.d.ts +1 -1
  31. package/dist/i18n/index.js +1 -1
  32. package/dist/i18n/index.js.map +2 -2
  33. package/dist/i18n/index.mjs +1 -1
  34. package/dist/i18n/index.mjs.map +2 -2
  35. package/dist/index.js +3 -3
  36. package/dist/index.js.map +3 -3
  37. package/dist/index.mjs +3 -3
  38. package/dist/index.mjs.map +3 -3
  39. package/dist/routing/NavigateRouteEvent.d.ts +4 -4
  40. package/dist/routing/index.js +2 -2
  41. package/dist/routing/index.js.map +3 -3
  42. package/dist/routing/index.mjs +3 -3
  43. package/dist/routing/index.mjs.map +3 -3
  44. package/dist/routing/navigation.d.ts +1 -1
  45. package/dist/templates/NodeTemplate.d.ts +1 -1
  46. package/dist/utils/index.d.ts +1 -1
  47. package/dist/utils/index.js +1 -1
  48. package/dist/utils/index.js.map +3 -3
  49. package/dist/utils/index.mjs +1 -1
  50. package/dist/utils/index.mjs.map +3 -3
  51. package/docs/GettingStarted.md +7 -0
  52. package/docs/api.json +34 -12
  53. package/docs/forms/reading-writing.md +101 -1
  54. package/docs/setup/bootstrapping.md +154 -0
  55. package/docs/setup/build-and-deploy.md +183 -0
  56. package/docs/setup/project-structure.md +170 -0
  57. package/docs/setup/vite.md +175 -0
  58. package/package.json +3 -2
  59. package/docs/api/.nojekyll +0 -1
  60. package/docs/api/assets/hierarchy.js +0 -1
  61. package/docs/api/assets/highlight.css +0 -120
  62. package/docs/api/assets/icons.js +0 -18
  63. package/docs/api/assets/icons.svg +0 -1
  64. package/docs/api/assets/main.js +0 -60
  65. package/docs/api/assets/navigation.js +0 -1
  66. package/docs/api/assets/search.js +0 -1
  67. package/docs/api/assets/style.css +0 -1633
  68. package/docs/api/classes/http.WebSocketClient.html +0 -26
  69. package/docs/api/classes/i18n.LocaleChangeEvent.html +0 -66
  70. package/docs/api/classes/index.Blueprint.html +0 -3
  71. package/docs/api/classes/index.BoundNode.html +0 -3
  72. package/docs/api/classes/index.DigitsValidation.html +0 -10
  73. package/docs/api/classes/index.FormValidator.html +0 -32
  74. package/docs/api/classes/index.HttpError.html +0 -13
  75. package/docs/api/classes/index.LinkedList.html +0 -26
  76. package/docs/api/classes/index.NavigateRouteEvent.html +0 -76
  77. package/docs/api/classes/index.Node.html +0 -15
  78. package/docs/api/classes/index.PageSelectedEvent.html +0 -61
  79. package/docs/api/classes/index.Pager.html +0 -4
  80. package/docs/api/classes/index.RangeValidation.html +0 -15
  81. package/docs/api/classes/index.RelaxError.html +0 -17
  82. package/docs/api/classes/index.RequiredValidation.html +0 -10
  83. package/docs/api/classes/index.RouteError.html +0 -11
  84. package/docs/api/classes/index.RouteGuardError.html +0 -12
  85. package/docs/api/classes/index.RouteLink.html +0 -779
  86. package/docs/api/classes/index.RouteTarget.html +0 -788
  87. package/docs/api/classes/index.SSEClient.html +0 -13
  88. package/docs/api/classes/index.SSEDataEvent.html +0 -63
  89. package/docs/api/classes/index.ServiceCollection.html +0 -28
  90. package/docs/api/classes/index.ServiceContainer.html +0 -24
  91. package/docs/api/classes/index.SortChangeEvent.html +0 -61
  92. package/docs/api/classes/index.TableRenderer.html +0 -5
  93. package/docs/api/classes/index.TableSorter.html +0 -4
  94. package/docs/api/enums/index.GuardResult.html +0 -9
  95. package/docs/api/functions/elements.formError.html +0 -6
  96. package/docs/api/functions/elements.selectOne.html +0 -6
  97. package/docs/api/functions/i18n.getCurrentLocale.html +0 -3
  98. package/docs/api/functions/i18n.loadNamespace.html +0 -7
  99. package/docs/api/functions/i18n.loadNamespaces.html +0 -6
  100. package/docs/api/functions/i18n.onMissingTranslation.html +0 -7
  101. package/docs/api/functions/i18n.setLocale.html +0 -7
  102. package/docs/api/functions/i18n.setMessageFormatter.html +0 -7
  103. package/docs/api/functions/i18n.t.html +0 -9
  104. package/docs/api/functions/index.BooleanConverter.html +0 -6
  105. package/docs/api/functions/index.ContainerService.html +0 -13
  106. package/docs/api/functions/index.DateConverter.html +0 -11
  107. package/docs/api/functions/index.Inject.html +0 -16
  108. package/docs/api/functions/index.NumberConverter.html +0 -5
  109. package/docs/api/functions/index.RegisterValidator.html +0 -7
  110. package/docs/api/functions/index.applyPipes.html +0 -17
  111. package/docs/api/functions/index.asyncHandler.html +0 -11
  112. package/docs/api/functions/index.capitalizePipe.html +0 -4
  113. package/docs/api/functions/index.clearPendingNavigations.html +0 -1
  114. package/docs/api/functions/index.compileTemplate.html +0 -26
  115. package/docs/api/functions/index.configure.html +0 -5
  116. package/docs/api/functions/index.createBluePrint.html +0 -1
  117. package/docs/api/functions/index.createConverterFromDataType.html +0 -4
  118. package/docs/api/functions/index.createConverterFromInputType.html +0 -5
  119. package/docs/api/functions/index.createPipeRegistry.html +0 -12
  120. package/docs/api/functions/index.currencyPipe.html +0 -9
  121. package/docs/api/functions/index.datePipe.html +0 -9
  122. package/docs/api/functions/index.daysAgoPipe.html +0 -8
  123. package/docs/api/functions/index.defaultPipe.html +0 -5
  124. package/docs/api/functions/index.defineRoutes.html +0 -8
  125. package/docs/api/functions/index.del.html +0 -8
  126. package/docs/api/functions/index.findRouteByName.html +0 -5
  127. package/docs/api/functions/index.findRouteByUrl.html +0 -4
  128. package/docs/api/functions/index.firstPipe.html +0 -4
  129. package/docs/api/functions/index.generateSequentialId.html +0 -21
  130. package/docs/api/functions/index.get.html +0 -9
  131. package/docs/api/functions/index.getDataConverter.html +0 -11
  132. package/docs/api/functions/index.getParentComponent.html +0 -18
  133. package/docs/api/functions/index.getValidator.html +0 -4
  134. package/docs/api/functions/index.html.html +0 -19
  135. package/docs/api/functions/index.joinPipe.html +0 -5
  136. package/docs/api/functions/index.keysPipe.html +0 -4
  137. package/docs/api/functions/index.lastPipe.html +0 -4
  138. package/docs/api/functions/index.lowercasePipe.html +0 -4
  139. package/docs/api/functions/index.mapFormToClass.html +0 -17
  140. package/docs/api/functions/index.matchRoute.html +0 -5
  141. package/docs/api/functions/index.navigate.html +0 -8
  142. package/docs/api/functions/index.onError.html +0 -8
  143. package/docs/api/functions/index.piecesPipe.html +0 -8
  144. package/docs/api/functions/index.post.html +0 -9
  145. package/docs/api/functions/index.printRoutes.html +0 -2
  146. package/docs/api/functions/index.put.html +0 -9
  147. package/docs/api/functions/index.readData.html +0 -17
  148. package/docs/api/functions/index.registerRouteTarget.html +0 -9
  149. package/docs/api/functions/index.reportError.html +0 -10
  150. package/docs/api/functions/index.request.html +0 -8
  151. package/docs/api/functions/index.resolveValue.html +0 -18
  152. package/docs/api/functions/index.setFetch.html +0 -6
  153. package/docs/api/functions/index.setFormData.html +0 -17
  154. package/docs/api/functions/index.shortenPipe.html +0 -5
  155. package/docs/api/functions/index.startRouting.html +0 -6
  156. package/docs/api/functions/index.ternaryPipe.html +0 -6
  157. package/docs/api/functions/index.trimPipe.html +0 -4
  158. package/docs/api/functions/index.unregisterRouteTarget.html +0 -3
  159. package/docs/api/functions/index.uppercasePipe.html +0 -4
  160. package/docs/api/hierarchy.html +0 -1
  161. package/docs/api/index.html +0 -323
  162. package/docs/api/interfaces/http.SimpleDataEvent.html +0 -3
  163. package/docs/api/interfaces/http.WebSocketAbstraction.html +0 -9
  164. package/docs/api/interfaces/http.WebSocketCodec.html +0 -4
  165. package/docs/api/interfaces/http.WebSocketOptions.html +0 -20
  166. package/docs/api/interfaces/index.CompiledTemplate.html +0 -10
  167. package/docs/api/interfaces/index.DataLoader.html +0 -19
  168. package/docs/api/interfaces/index.EngineConfig.html +0 -11
  169. package/docs/api/interfaces/index.ErrorContext.html +0 -4
  170. package/docs/api/interfaces/index.FormReaderOptions.html +0 -8
  171. package/docs/api/interfaces/index.HttpOptions.html +0 -16
  172. package/docs/api/interfaces/index.HttpResponse.html +0 -17
  173. package/docs/api/interfaces/index.LoadRoute.html +0 -7
  174. package/docs/api/interfaces/index.NavigateOptions.html +0 -7
  175. package/docs/api/interfaces/index.PipeRegistry.html +0 -12
  176. package/docs/api/interfaces/index.RegistrationOptions.html +0 -22
  177. package/docs/api/interfaces/index.RenderTemplate.html +0 -7
  178. package/docs/api/interfaces/index.RequestOptions.html +0 -11
  179. package/docs/api/interfaces/index.Routable.html +0 -10
  180. package/docs/api/interfaces/index.Route.html +0 -13
  181. package/docs/api/interfaces/index.RouteGuard.html +0 -2
  182. package/docs/api/interfaces/index.RouteValue.html +0 -6
  183. package/docs/api/interfaces/index.SSEOptions.html +0 -24
  184. package/docs/api/interfaces/index.ValidationContext.html +0 -8
  185. package/docs/api/interfaces/index.ValidatorOptions.html +0 -14
  186. package/docs/api/media/Architecture.md +0 -333
  187. package/docs/api/media/DependencyInjection.md +0 -277
  188. package/docs/api/media/GettingStarted.md +0 -231
  189. package/docs/api/media/HttpClient.md +0 -459
  190. package/docs/api/media/Pipes.md +0 -211
  191. package/docs/api/media/Routing.md +0 -332
  192. package/docs/api/media/WhyRelaxjs.md +0 -336
  193. package/docs/api/media/forms.md +0 -99
  194. package/docs/api/media/html.md +0 -175
  195. package/docs/api/media/i18n.md +0 -354
  196. package/docs/api/media/utilities.md +0 -143
  197. package/docs/api/media/validation.md +0 -351
  198. package/docs/api/modules/collections_Index.html +0 -1
  199. package/docs/api/modules/di.html +0 -1
  200. package/docs/api/modules/elements.html +0 -1
  201. package/docs/api/modules/forms.html +0 -1
  202. package/docs/api/modules/html.html +0 -1
  203. package/docs/api/modules/http.html +0 -1
  204. package/docs/api/modules/i18n.html +0 -1
  205. package/docs/api/modules/index.html +0 -1
  206. package/docs/api/modules/routing.html +0 -1
  207. package/docs/api/modules/utils.html +0 -1
  208. package/docs/api/modules.html +0 -1
  209. package/docs/api/types/http.WebSocketFactory.html +0 -2
  210. package/docs/api/types/i18n.MessageFormatter.html +0 -3
  211. package/docs/api/types/i18n.MissingTranslationHandler.html +0 -1
  212. package/docs/api/types/index.Constructor.html +0 -7
  213. package/docs/api/types/index.ConverterFunc.html +0 -2
  214. package/docs/api/types/index.DataType.html +0 -2
  215. package/docs/api/types/index.InputType.html +0 -2
  216. package/docs/api/types/index.PipeFunction.html +0 -6
  217. package/docs/api/types/index.RouteData.html +0 -1
  218. package/docs/api/types/index.RouteMatchResult.html +0 -9
  219. package/docs/api/types/index.RouteParamType.html +0 -1
  220. package/docs/api/types/index.RouteSegmentType.html +0 -2
  221. package/docs/api/types/index.SSEEventFactory.html +0 -5
  222. package/docs/api/types/index.ServiceScope.html +0 -10
  223. package/docs/api/types/index.SortColumn.html +0 -3
  224. package/docs/api/variables/i18n.formatICU.html +0 -3
  225. package/docs/api/variables/index.container.html +0 -6
  226. package/docs/api/variables/index.defaultPipes.html +0 -6
  227. package/docs/api/variables/index.internalRoutes.html +0 -1
  228. package/docs/api/variables/index.serviceCollection.html +0 -6
@@ -102,7 +102,7 @@ export declare class SSEClient {
102
102
  * Whether the client is currently connected.
103
103
  */
104
104
  get connected(): boolean;
105
- constructor(url: string, options?: SSEOptions);
105
+ constructor(url: string, options?: SSEOptions | undefined);
106
106
  /**
107
107
  * Establish connection to the SSE endpoint.
108
108
  */
@@ -82,7 +82,7 @@ export declare class WebSocketClient<TMessage> {
82
82
  private reconnectAttempts;
83
83
  private shouldReconnect;
84
84
  get connected(): boolean;
85
- constructor(urlOrWebSocketFactory: string | WebSocketFactory, options?: WebSocketOptions<TMessage>);
85
+ constructor(urlOrWebSocketFactory: string | WebSocketFactory, options?: WebSocketOptions<TMessage> | undefined);
86
86
  connect(): void;
87
87
  disconnect(): void;
88
88
  send(data: TMessage): void;
@@ -1,2 +1,2 @@
1
- var f=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var x=Object.prototype.hasOwnProperty;var _=(s,e)=>{for(var t in e)f(s,t,{get:e[t],enumerable:!0})},R=(s,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of k(e))!x.call(s,r)&&r!==t&&f(s,r,{get:()=>e[r],enumerable:!(n=w(e,r))||n.enumerable});return s};var C=s=>R(f({},"__esModule",{value:!0}),s);var P={};_(P,{HttpError:()=>u,SSEClient:()=>h,SSEDataEvent:()=>c,WebSocketClient:()=>d,configure:()=>T,del:()=>E,get:()=>y,post:()=>b,put:()=>S,request:()=>o,setFetch:()=>m});module.exports=C(P);var u=class extends Error{constructor(e){super(e.statusReason),this.message=e.statusReason,this.response=e}},i={bearerTokenName:"jwt"},g=fetch;function m(s){g=s??fetch}function T(s){i={...i,...s},s.bearerTokenName===void 0&&(i.bearerTokenName="jwt")}async function o(s,e){if(i.bearerTokenName){let r=localStorage.getItem(i.bearerTokenName);if(r&&e){let a=e?.headers?new Headers(e.headers):new Headers;a.get("Authorization")||a.set("Authorization","Bearer "+r),e.headers=a}}i.timeout&&!e?.signal&&(e??={},e.signal=AbortSignal.timeout(i.timeout)),i.baseUrl&&(s[0]!=="/"&&i.baseUrl[i.baseUrl.length-1]!=="/"?s=`${i.baseUrl}/${s}`:s=i.baseUrl+s);let t=await g(s,e);if(!t.ok)return{statusCode:t.status,statusReason:t.statusText,success:!1,contentType:t.headers.get("content-type"),body:await t.text(),charset:t.headers.get("charset"),as(){throw new Error("No response received")}};let n=null;return t.status!==204&&(n=await t.json()),{success:!0,statusCode:t.status,statusReason:t.statusText,contentType:t.headers.get("content-type"),body:n,charset:t.headers.get("charset"),as(){return n}}}async function y(s,e,t){if(t?t.method="GET":t={method:"GET",headers:{"content-type":i.contentType??"application/json"}},e){let n="&";s.indexOf("?")===-1&&(n="?");for(let r in e){let a=e[r];s+=`${n}${r}=${a}`,n="&"}}return o(s,t)}async function b(s,e,t){return t?(t.method="POST",t.body=e):t={method:"POST",body:e,headers:{"content-type":i.contentType??"application/json"}},o(s,t)}async function S(s,e,t){return t?(t.method="PUT",t.body=e):t={method:"PUT",body:e,headers:{"content-type":i.contentType??"application/json"}},o(s,t)}async function E(s,e){return e?e.method="DELETE":e={method:"DELETE",headers:{"content-type":i.contentType??"application/json"}},o(s,e)}var c=class extends Event{constructor(t,n,r){super(t,{bubbles:!0,...r});this.data=n}},h=class{constructor(e,t){this.url=e;this.options=t;this.target=this.resolveTarget(t?.target)}get connected(){return this.eventSource?.readyState===EventSource.OPEN}connect(){if(this.eventSource)return;let e=new EventSource(this.url,{withCredentials:this.options?.withCredentials??!1});if(this.eventSource=e,e.onopen=()=>{this.options?.onConnect?.(this)},e.onerror=t=>{this.options?.onError?.(this,t)},this.options?.eventTypes&&this.options.eventTypes.length>0)for(let t of this.options.eventTypes)e.addEventListener(t,n=>{this.dispatchEvent(t,n.data)});else e.onmessage=t=>{this.dispatchEvent("message",t.data)}}disconnect(){this.eventSource?.close(),this.eventSource=void 0}resolveTarget(e){if(!e)return document;if(typeof e=="string"){let t=document.querySelector(e);if(!t)throw new Error(`SSEClient: Target element not found: ${e}`);return t}return e}dispatchEvent(e,t){let n;if(t.length>0&&(t[0]==="{"||t[0]==="["||t[0]==='"'))try{n=JSON.parse(t)}catch{n=t}else n=t;let r=this.options?.eventFactory?this.options.eventFactory(e,n):new c(e,n);this.target.dispatchEvent(r)}};var p=class{constructor(e,t){this.value=e;this.removeCallback=t;this.next=null;this.prev=null}remove(){this.prev.next=this.next,this.next.prev=this.prev,this.removeCallback()}},l=class{constructor(){this._length=0}addFirst(e){let t=new p(e,()=>this._length--);this._first?(t.next=this._first,this._first.prev=t,this._first=t):(this._first=t,this._last=this._first),this._length++}addLast(e){let t=new p(e,()=>this._length--);this._first?(t.prev=this._last,this._last.next=t,this._last=t):(this._first=t,this._last=this._first),this._length++}removeFirst(){if(!this.first)throw new Error("The list is empty.");let e=this._first.value;return this._first=this._first.next,this._length--,e}removeLast(){if(!this.last)throw new Error("The list is empty.");let e=this._last.value;return this._last=this._last.prev,this._length--,e}get length(){return this._length}get first(){return this._first}get firstValue(){return this._first?.value}get last(){return this._last}get lastValue(){return this._last?.value}};var d=class{constructor(e,t){this.options=t;this.receiveQueue=new l;this.sendQueue=new l;this._isConnected=!1;this.isSendingQueue=!1;this.reconnectAttempts=0;this.shouldReconnect=!0;typeof e=="string"?this.url=e:this.wsFactory=e}get connected(){return this._isConnected}connect(){this.shouldReconnect=!0,this.reconnectAttempts=0,this.reConnect()}disconnect(){this.shouldReconnect=!1,this.ws?.close()}send(e){if(!this._isConnected||this.isSendingQueue){this.sendQueue.addLast(e);return}this.sendQueue.length>0&&this.sendQueueItems(),this.sendInternal(e)}receive(){if(this.receivePromiseWrapper)throw new Error("You can only invoke receive() once at a time.");return this.receiveQueue.firstValue?Promise.resolve(this.receiveQueue.removeFirst()):(this.receivePromiseWrapper=new v,new Promise((e,t)=>{this.receivePromiseWrapper.resolve=e,this.receivePromiseWrapper.reject=t}))}onMessage(e){let t;if(this.options?.codec?t=this.options.codec.decode(e.data):typeof e.data=="string"&&e.data.length>0&&(e.data[0]==='"'||e.data[0]==="["||e.data[0]==="{")?t=JSON.parse(e.data):t=e.data,this.receivePromiseWrapper){this.receivePromiseWrapper.resolve(t),this.receivePromiseWrapper=void 0;return}this.receiveQueue.addLast(t)}reConnect(){let e=this.url?new WebSocket(this.url):this.wsFactory();this.ws=e,e.onmessage=t=>this.onMessage(t),e.onerror=()=>e.close(),e.onopen=()=>{this._isConnected=!0,this.reconnectAttempts=0,this.options?.onConnect?.(this),this.sendQueueItems()},e.onclose=()=>{if(this._isConnected=!1,this.receivePromiseWrapper&&(this.receivePromiseWrapper.reject(new Error("WebSocket connection closed")),this.receivePromiseWrapper=void 0),this.options?.onClose?.(this),this.shouldReconnect&&this.options?.autoReconnect!==!1){let t=this.options?.reconnectDelay??1e3,n=this.options?.maxReconnectDelay??3e4,r=Math.min(t*Math.pow(2,this.reconnectAttempts),n);this.reconnectAttempts++,setTimeout(()=>this.reConnect(),r)}}}sendInternal(e){let t;typeof e!="string"?this.options?.codec?t=this.options.codec.encode(e):t=JSON.stringify(e):t=e,this.ws.send(t)}sendQueueItems(){if(!this.isSendingQueue){for(this.isSendingQueue=!0;this.sendQueue.length>0;){let e=this.sendQueue.removeFirst();if(e==null)break;this.sendInternal(e)}this.isSendingQueue=!1}}},v=class{};
1
+ "use strict";var d=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var _=Object.prototype.hasOwnProperty;var x=(s,e)=>{for(var t in e)d(s,t,{get:e[t],enumerable:!0})},R=(s,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of k(e))!_.call(s,r)&&r!==t&&d(s,r,{get:()=>e[r],enumerable:!(n=w(e,r))||n.enumerable});return s};var C=s=>R(d({},"__esModule",{value:!0}),s);var M={};x(M,{HttpError:()=>u,SSEClient:()=>h,SSEDataEvent:()=>c,WebSocketClient:()=>p,configure:()=>T,del:()=>E,get:()=>y,post:()=>b,put:()=>S,request:()=>o,setFetch:()=>m});module.exports=C(M);var u=class extends Error{constructor(e){super(e.statusReason),this.message=e.statusReason,this.response=e}},i={bearerTokenName:"jwt"},g=fetch;function m(s){g=s??fetch}function T(s){i={...i,...s},s.bearerTokenName===void 0&&(i.bearerTokenName="jwt")}async function o(s,e){if(i.bearerTokenName){let r=localStorage.getItem(i.bearerTokenName);if(r&&e){let a=e?.headers?new Headers(e.headers):new Headers;a.get("Authorization")||a.set("Authorization","Bearer "+r),e.headers=a}}i.timeout&&!e?.signal&&(e??={},e.signal=AbortSignal.timeout(i.timeout)),i.baseUrl&&(s[0]!=="/"&&i.baseUrl[i.baseUrl.length-1]!=="/"?s=`${i.baseUrl}/${s}`:s=i.baseUrl+s);let t=await g(s,e);if(!t.ok)return{statusCode:t.status,statusReason:t.statusText,success:!1,contentType:t.headers.get("content-type"),body:await t.text(),charset:t.headers.get("charset"),as(){throw new Error("No response received")}};let n=null;return t.status!==204&&(n=await t.json()),{success:!0,statusCode:t.status,statusReason:t.statusText,contentType:t.headers.get("content-type"),body:n,charset:t.headers.get("charset"),as(){return n}}}async function y(s,e,t){if(t?t.method="GET":t={method:"GET",headers:{"content-type":i.contentType??"application/json"}},e){let n="&";s.indexOf("?")===-1&&(n="?");for(let r in e){let a=e[r];s+=`${n}${r}=${a}`,n="&"}}return o(s,t)}async function b(s,e,t){return t?(t.method="POST",t.body=e):t={method:"POST",body:e,headers:{"content-type":i.contentType??"application/json"}},o(s,t)}async function S(s,e,t){return t?(t.method="PUT",t.body=e):t={method:"PUT",body:e,headers:{"content-type":i.contentType??"application/json"}},o(s,t)}async function E(s,e){return e?e.method="DELETE":e={method:"DELETE",headers:{"content-type":i.contentType??"application/json"}},o(s,e)}var c=class extends Event{constructor(t,n,r){super(t,{bubbles:!0,...r});this.data=n}},h=class{constructor(e,t){this.url=e;this.options=t;this.target=this.resolveTarget(t?.target)}get connected(){return this.eventSource?.readyState===EventSource.OPEN}connect(){if(this.eventSource)return;let e=new EventSource(this.url,{withCredentials:this.options?.withCredentials??!1});if(this.eventSource=e,e.onopen=()=>{this.options?.onConnect?.(this)},e.onerror=t=>{this.options?.onError?.(this,t)},this.options?.eventTypes&&this.options.eventTypes.length>0)for(let t of this.options.eventTypes)e.addEventListener(t,n=>{this.dispatchEvent(t,n.data)});else e.onmessage=t=>{this.dispatchEvent("message",t.data)}}disconnect(){this.eventSource?.close(),this.eventSource=void 0}resolveTarget(e){if(!e)return document;if(typeof e=="string"){let t=document.querySelector(e);if(!t)throw new Error(`SSEClient: Target element not found: ${e}`);return t}return e}dispatchEvent(e,t){let n;if(t.length>0&&(t[0]==="{"||t[0]==="["||t[0]==='"'))try{n=JSON.parse(t)}catch{n=t}else n=t;let r=this.options?.eventFactory?this.options.eventFactory(e,n):new c(e,n);this.target.dispatchEvent(r)}};var f=class{constructor(e,t){this.value=e;this.removeCallback=t;this.next=null;this.prev=null}remove(){this.prev&&(this.prev.next=this.next),this.next&&(this.next.prev=this.prev),this.removeCallback()}},l=class{constructor(){this._first=null;this._last=null;this._length=0}addFirst(e){let t=this.createNode(e);this._first?(t.next=this._first,this._first.prev=t,this._first=t):(this._first=t,this._last=this._first),this._length++}addLast(e){let t=this.createNode(e);this._last?(t.prev=this._last,this._last.next=t,this._last=t):(this._first=t,this._last=t),this._length++}createNode(e){let t;return t=new f(e,()=>{this._first===t&&(this._first=t.next),this._last===t&&(this._last=t.prev),this._length--}),t}removeFirst(){if(!this._first)throw new Error("The list is empty.");let e=this._first.value;return this._first=this._first.next,this._first||(this._last=null),this._length--,e}removeLast(){if(!this._last)throw new Error("The list is empty.");let e=this._last.value;return this._last=this._last.prev,this._last||(this._first=null),this._length--,e}get length(){return this._length}get first(){return this._first}get firstValue(){return this._first?.value}get last(){return this._last}get lastValue(){return this._last?.value}};var p=class{constructor(e,t){this.options=t;this.receiveQueue=new l;this.sendQueue=new l;this._isConnected=!1;this.isSendingQueue=!1;this.reconnectAttempts=0;this.shouldReconnect=!0;typeof e=="string"?this.url=e:this.wsFactory=e}get connected(){return this._isConnected}connect(){this.shouldReconnect=!0,this.reconnectAttempts=0,this.reConnect()}disconnect(){this.shouldReconnect=!1,this.ws?.close()}send(e){if(!this._isConnected||this.isSendingQueue){this.sendQueue.addLast(e);return}this.sendQueue.length>0&&this.sendQueueItems(),this.sendInternal(e)}receive(){if(this.receivePromiseWrapper)throw new Error("You can only invoke receive() once at a time.");if(this.receiveQueue.firstValue)return Promise.resolve(this.receiveQueue.removeFirst());let e=new v;return this.receivePromiseWrapper=e,new Promise((t,n)=>{e.resolve=t,e.reject=n})}onMessage(e){let t;if(this.options?.codec?t=this.options.codec.decode(e.data):typeof e.data=="string"&&e.data.length>0&&(e.data[0]==='"'||e.data[0]==="["||e.data[0]==="{")?t=JSON.parse(e.data):t=e.data,this.receivePromiseWrapper){this.receivePromiseWrapper.resolve(t),this.receivePromiseWrapper=void 0;return}this.receiveQueue.addLast(t)}reConnect(){let e=this.url?new WebSocket(this.url):this.wsFactory();this.ws=e,e.onmessage=t=>this.onMessage(t),e.onerror=()=>e.close(),e.onopen=()=>{this._isConnected=!0,this.reconnectAttempts=0,this.options?.onConnect?.(this),this.sendQueueItems()},e.onclose=()=>{if(this._isConnected=!1,this.receivePromiseWrapper&&(this.receivePromiseWrapper.reject(new Error("WebSocket connection closed")),this.receivePromiseWrapper=void 0),this.options?.onClose?.(this),this.shouldReconnect&&this.options?.autoReconnect!==!1){let t=this.options?.reconnectDelay??1e3,n=this.options?.maxReconnectDelay??3e4,r=Math.min(t*Math.pow(2,this.reconnectAttempts),n);this.reconnectAttempts++,setTimeout(()=>this.reConnect(),r)}}}sendInternal(e){let t;typeof e!="string"?this.options?.codec?t=this.options.codec.encode(e):t=JSON.stringify(e):t=e,this.ws.send(t)}sendQueueItems(){if(!this.isSendingQueue){for(this.isSendingQueue=!0;this.sendQueue.length>0;){let e=this.sendQueue.removeFirst();if(e==null)break;this.sendInternal(e)}this.isSendingQueue=!1}}},v=class{};
2
2
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/http/index.ts", "../../src/http/http.ts", "../../src/http/ServerSentEvents.ts", "../../src/collections/LinkedList.ts", "../../src/http/SimpleWebSocket.ts"],
4
- "sourcesContent": ["export {\r\n HttpOptions,\r\n HttpResponse,\r\n HttpError,\r\n RequestOptions,\r\n configure,\r\n setFetch,\r\n request,\r\n get,\r\n post,\r\n put,\r\n del\r\n} from './http';\r\n\r\nexport {\r\n SSEDataEvent,\r\n SSEOptions,\r\n SSEEventFactory,\r\n SSEClient\r\n} from './ServerSentEvents';\r\n\r\nexport {\r\n SimpleDataEvent,\r\n WebSocketAbstraction,\r\n WebSocketFactory,\r\n WebSocketClient,\r\n WebSocketCodec,\r\n WebSocketOptions\r\n} from './SimpleWebSocket';\r\n", "/**\r\n * @module http\r\n * Type-safe HTTP module built on fetch() with automatic JWT handling.\r\n *\r\n * @example\r\n * import { configure, get, post } from './http';\r\n *\r\n * configure({ baseUrl: '/api' });\r\n * const response = await get('/users');\r\n * const users = response.as<User[]>();\r\n */\r\n\r\n/**\r\n * Configuration options for the http module.\r\n */\r\nexport interface HttpOptions {\r\n /**\r\n * Root URL to remote endpoint. Used so that each method only has to specify path in requests.\r\n */\r\n baseUrl?: string;\r\n\r\n /**\r\n * Default content type to use if none is specified in the request method.\r\n */\r\n contentType?: string;\r\n\r\n /**\r\n * Checks for a JWT token in localStorage to automatically include it in requests.\r\n *\r\n * Undefined = use \"jwt\", null = disable.\r\n */\r\n bearerTokenName?: string | null;\r\n\r\n /**\r\n * Default request timeout in milliseconds.\r\n * Uses `AbortSignal.timeout()` to automatically abort requests that take too long.\r\n * Can be overridden per-request by passing a `signal` in `RequestInit`.\r\n *\r\n * @example\r\n * configure({ baseUrl: '/api', timeout: 10000 }); // 10 second timeout\r\n */\r\n timeout?: number;\r\n}\r\n\r\n/**\r\n * Response for request methods.\r\n */\r\nexport interface HttpResponse {\r\n /**\r\n * Http status code.\r\n */\r\n statusCode: number;\r\n\r\n /**\r\n * Reason to why the status code was used.\r\n */\r\n statusReason: string;\r\n\r\n /**\r\n * True if this is a 2xx response.\r\n */\r\n success: boolean;\r\n\r\n /**\r\n * Content type of response body.\r\n */\r\n contentType: string | null;\r\n\r\n /**\r\n * Body returned.\r\n *\r\n * Body has been read and deserialized from json (if the request content type was 'application/json' which is the default).\r\n */\r\n body: unknown;\r\n\r\n /**\r\n * Charset used in body.\r\n */\r\n charset: string | null;\r\n\r\n /**\r\n * Cast body to a type.\r\n */\r\n as<T>(): T;\r\n}\r\n\r\n/**\r\n * Error thrown when a request fails.\r\n */\r\nexport class HttpError extends Error {\r\n message: string;\r\n response: HttpResponse;\r\n\r\n constructor(response: HttpResponse) {\r\n super(response.statusReason);\r\n this.message = response.statusReason;\r\n this.response = response;\r\n }\r\n}\r\n\r\n/**\r\n * HTTP request options.\r\n */\r\nexport interface RequestOptions {\r\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE';\r\n mode?: 'cors' | 'no-cors' | '*cors' | 'same-origin';\r\n cache:\r\n | 'default'\r\n | 'no-store'\r\n | 'reload'\r\n | 'no-cache'\r\n | 'force-cache'\r\n | 'only-if-cached';\r\n credentials: 'omit' | 'same-origin' | 'include';\r\n headers: Map<string, string>;\r\n redirect: 'follow' | 'manual' | '*follow' | 'error';\r\n referrerPolicy:\r\n | 'no-referrer'\r\n | '*no-referrer-when-downgrade'\r\n | 'origin'\r\n | 'origin-when-cross-origin'\r\n | 'same-origin'\r\n | 'strict-origin'\r\n | 'strict-origin-when-cross-origin'\r\n | 'unsafe-url';\r\n\r\n /**\r\n * Will be serialized if the content type is json (and the body is an object).\r\n */\r\n body: unknown;\r\n}\r\n\r\n/** @internal */\r\ndeclare type FetchFn = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\r\n\r\nlet config: HttpOptions = {\r\n bearerTokenName: 'jwt'\r\n};\r\n\r\nlet fetchImpl: FetchFn = fetch;\r\n\r\n/**\r\n * Replace the fetch implementation for testing purposes.\r\n *\r\n * @param fn - Custom fetch function, or undefined to restore the default.\r\n *\r\n * @example\r\n * setFetch(async (url, options) => {\r\n * return new Response(JSON.stringify({ id: 1 }), { status: 200 });\r\n * });\r\n */\r\nexport function setFetch(fn?: FetchFn): void {\r\n fetchImpl = fn ?? fetch;\r\n}\r\n\r\n/**\r\n * Configure the http module.\r\n *\r\n * @example\r\n * configure({ baseUrl: '/api/v1', bearerTokenName: 'auth_token' });\r\n */\r\nexport function configure(options: HttpOptions): void {\r\n config = {\r\n ...config,\r\n ...options\r\n };\r\n if (options.bearerTokenName === undefined) {\r\n config.bearerTokenName = 'jwt';\r\n }\r\n}\r\n\r\n/**\r\n * Make an HTTP request.\r\n *\r\n * @param url - URL to make the request against.\r\n * @param options - Request options.\r\n * @returns Response from server.\r\n *\r\n * @example\r\n * const response = await request('/users', { method: 'GET' });\r\n */\r\nexport async function request(url: string, options?: RequestInit): Promise<HttpResponse> {\r\n if (config.bearerTokenName) {\r\n const token = localStorage.getItem(config.bearerTokenName);\r\n if (token && options) {\r\n const headers = options?.headers\r\n ? new Headers(options.headers)\r\n : new Headers();\r\n\r\n if (!headers.get('Authorization')) {\r\n headers.set('Authorization', 'Bearer ' + token);\r\n }\r\n\r\n options.headers = headers;\r\n }\r\n }\r\n\r\n if (config.timeout && !options?.signal) {\r\n options ??= {};\r\n options.signal = AbortSignal.timeout(config.timeout);\r\n }\r\n\r\n if (config.baseUrl) {\r\n if (url[0] !== '/' && config.baseUrl[config.baseUrl.length - 1] !== '/') {\r\n url = `${config.baseUrl}/${url}`;\r\n } else {\r\n url = config.baseUrl + url;\r\n }\r\n }\r\n\r\n const response = await fetchImpl(url, options);\r\n\r\n if (!response.ok) {\r\n return {\r\n statusCode: response.status,\r\n statusReason: response.statusText,\r\n success: false,\r\n contentType: response.headers.get('content-type'),\r\n body: await response.text(),\r\n charset: response.headers.get('charset'),\r\n\r\n as() {\r\n throw new Error('No response received');\r\n }\r\n };\r\n }\r\n\r\n let body: unknown | null = null;\r\n if (response.status !== 204) {\r\n body = await response.json();\r\n }\r\n\r\n return {\r\n success: true,\r\n statusCode: response.status,\r\n statusReason: response.statusText,\r\n contentType: response.headers.get('content-type'),\r\n body: body,\r\n charset: response.headers.get('charset'),\r\n as<T>() {\r\n return <T>body;\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * GET a resource.\r\n *\r\n * @param url - URL to get resource from.\r\n * @param queryString - Optional query string parameters.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await get('/users', { page: '1', limit: '10' });\r\n * const users = response.as<User[]>();\r\n */\r\nexport async function get(\r\n url: string,\r\n queryString?: Record<string, string>,\r\n options?: RequestInit\r\n): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'GET',\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'GET';\r\n }\r\n\r\n if (queryString) {\r\n let prefix = '&';\r\n if (url.indexOf('?') === -1) {\r\n prefix = '?';\r\n }\r\n\r\n for (const key in queryString) {\r\n const value = queryString[key];\r\n url += `${prefix}${key}=${value}`;\r\n prefix = '&';\r\n }\r\n }\r\n\r\n return request(url, options);\r\n}\r\n\r\n/**\r\n * POST a resource.\r\n *\r\n * @param url - URL to post to.\r\n * @param data - Data to post.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await post('/users', JSON.stringify({ name: 'John' }));\r\n */\r\nexport async function post(\r\n url: string,\r\n data: BodyInit,\r\n options?: RequestInit\r\n): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'POST',\r\n body: data,\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'POST';\r\n options.body = data;\r\n }\r\n\r\n return request(url, options);\r\n}\r\n\r\n/**\r\n * PUT a resource.\r\n *\r\n * @param url - URL to resource.\r\n * @param data - Data to put.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await put('/users/1', JSON.stringify({ name: 'Jane' }));\r\n */\r\nexport async function put(\r\n url: string,\r\n data: BodyInit,\r\n options?: RequestInit\r\n): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'PUT',\r\n body: data,\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'PUT';\r\n options.body = data;\r\n }\r\n\r\n return request(url, options);\r\n}\r\n\r\n/**\r\n * DELETE a resource.\r\n *\r\n * @param url - URL to resource.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await del('/users/1');\r\n */\r\nexport async function del(url: string, options?: RequestInit): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'DELETE',\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'DELETE';\r\n }\r\n\r\n return request(url, options);\r\n}\r\n", "/**\r\n * @module ServerSentEvents\r\n * SSE client that dispatches received events as DOM events.\r\n * Uses the browser's built-in EventSource reconnection.\r\n *\r\n * @example\r\n * const sse = new SSEClient('/api/events', {\r\n * eventTypes: ['user-updated', 'order-created']\r\n * });\r\n * sse.connect();\r\n *\r\n * document.addEventListener('user-updated', (e: SSEDataEvent) => {\r\n * console.log('User updated:', e.data);\r\n * });\r\n */\r\n\r\n/**\r\n * Event dispatched when an SSE message is received.\r\n * The event name matches the SSE event type.\r\n */\r\nexport class SSEDataEvent extends Event {\r\n constructor(\r\n eventName: string,\r\n public data: unknown,\r\n eventInit?: EventInit\r\n ) {\r\n super(eventName, { bubbles: true, ...eventInit });\r\n }\r\n}\r\n\r\n/**\r\n * Factory function for creating custom event instances.\r\n *\r\n * @example\r\n * const factory: SSEEventFactory = (eventName, data) => {\r\n * switch (eventName) {\r\n * case 'user-updated':\r\n * return new UserUpdatedEvent(data as User);\r\n * default:\r\n * return new SSEDataEvent(eventName, data);\r\n * }\r\n * };\r\n */\r\nexport type SSEEventFactory = (eventName: string, data: unknown) => Event;\r\n\r\n/**\r\n * Configuration options for SSEClient.\r\n */\r\nexport interface SSEOptions {\r\n /**\r\n * Target element or CSS selector for event dispatching.\r\n * Defaults to document.\r\n */\r\n target?: string | Element;\r\n\r\n /**\r\n * Whether to send credentials with the request (default: false).\r\n */\r\n withCredentials?: boolean;\r\n\r\n /**\r\n * Specific SSE event types to listen for.\r\n * If not specified, listens to the default 'message' event.\r\n *\r\n * @example\r\n * eventTypes: ['user-updated', 'order-created']\r\n */\r\n eventTypes?: string[];\r\n\r\n /**\r\n * Factory function for creating custom event instances.\r\n * If not provided, SSEDataEvent is used.\r\n *\r\n * @example\r\n * eventFactory: (name, data) => new MyCustomEvent(name, data)\r\n */\r\n eventFactory?: SSEEventFactory;\r\n\r\n /**\r\n * Callback when connection is established.\r\n */\r\n onConnect?: (client: SSEClient) => void;\r\n\r\n /**\r\n * Callback when an error occurs.\r\n * Note: EventSource automatically reconnects on errors.\r\n */\r\n onError?: (client: SSEClient, error: Event) => void;\r\n}\r\n\r\n/**\r\n * Server-Sent Events client that dispatches received events as DOM events.\r\n * Uses the browser's built-in EventSource with automatic reconnection.\r\n *\r\n * @example\r\n * const sse = new SSEClient('/api/events', {\r\n * target: '#notifications',\r\n * eventTypes: ['notification', 'alert']\r\n * });\r\n *\r\n * sse.connect();\r\n *\r\n * document.querySelector('#notifications')\r\n * .addEventListener('notification', (e: SSEDataEvent) => {\r\n * showNotification(e.data);\r\n * });\r\n *\r\n * sse.disconnect();\r\n */\r\nexport class SSEClient {\r\n private eventSource?: EventSource;\r\n private target: Element | Document;\r\n\r\n /**\r\n * Whether the client is currently connected.\r\n */\r\n get connected(): boolean {\r\n return this.eventSource?.readyState === EventSource.OPEN;\r\n }\r\n\r\n constructor(\r\n private url: string,\r\n private options?: SSEOptions\r\n ) {\r\n this.target = this.resolveTarget(options?.target);\r\n }\r\n\r\n /**\r\n * Establish connection to the SSE endpoint.\r\n */\r\n connect(): void {\r\n if (this.eventSource) {\r\n return;\r\n }\r\n\r\n const eventSource = new EventSource(this.url, {\r\n withCredentials: this.options?.withCredentials ?? false\r\n });\r\n\r\n this.eventSource = eventSource;\r\n\r\n eventSource.onopen = () => {\r\n this.options?.onConnect?.(this);\r\n };\r\n\r\n eventSource.onerror = (error) => {\r\n this.options?.onError?.(this, error);\r\n };\r\n\r\n if (this.options?.eventTypes && this.options.eventTypes.length > 0) {\r\n for (const eventType of this.options.eventTypes) {\r\n eventSource.addEventListener(eventType, (e: MessageEvent) => {\r\n this.dispatchEvent(eventType, e.data);\r\n });\r\n }\r\n } else {\r\n eventSource.onmessage = (e: MessageEvent) => {\r\n this.dispatchEvent('message', e.data);\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Close the connection.\r\n */\r\n disconnect(): void {\r\n this.eventSource?.close();\r\n this.eventSource = undefined;\r\n }\r\n\r\n private resolveTarget(target?: string | Element): Element | Document {\r\n if (!target) {\r\n return document;\r\n }\r\n if (typeof target === 'string') {\r\n const element = document.querySelector(target);\r\n if (!element) {\r\n throw new Error(`SSEClient: Target element not found: ${target}`);\r\n }\r\n return element;\r\n }\r\n return target;\r\n }\r\n\r\n private dispatchEvent(eventName: string, rawData: string): void {\r\n let data: unknown;\r\n\r\n if (rawData.length > 0 && (rawData[0] === '{' || rawData[0] === '[' || rawData[0] === '\"')) {\r\n try {\r\n data = JSON.parse(rawData);\r\n } catch {\r\n data = rawData;\r\n }\r\n } else {\r\n data = rawData;\r\n }\r\n\r\n const event = this.options?.eventFactory\r\n ? this.options.eventFactory(eventName, data)\r\n : new SSEDataEvent(eventName, data);\r\n\r\n this.target.dispatchEvent(event);\r\n }\r\n}\r\n", "/**\r\n * A node in the @see LinkedList.\r\n */\r\nexport class Node<T> {\r\n /**\r\n * Next node unless last one.\r\n */\r\n public next: Node<T> | null = null;\r\n /**\r\n * Previous node unless first one.\r\n */\r\n public prev: Node<T> | null = null;\r\n\r\n /**\r\n * Constructor.\r\n * @param value Value contained in the node.\r\n */\r\n constructor(public value: T, private removeCallback: () => void) {}\r\n\r\n /**\r\n * Remove this node.\r\n * Will notify the list of the update to ensure correct element count.\r\n */\r\n remove() {\r\n this.prev.next = this.next;\r\n this.next.prev = this.prev;\r\n this.removeCallback();\r\n }\r\n}\r\n\r\n/**\r\n * A trivial linked list implementation.\r\n */\r\nexport class LinkedList<T> {\r\n private _first?: Node<T>;\r\n private _last?: Node<T>;\r\n private _length = 0;\r\n\r\n /**\r\n * Add a value to the beginning of the list.\r\n * @param value Value that should be contained in the node.\r\n */\r\n addFirst(value: T) {\r\n const newNode = new Node(value, () => this._length--);\r\n if (!this._first) {\r\n this._first = newNode;\r\n this._last = this._first;\r\n } else {\r\n newNode.next = this._first;\r\n this._first.prev = newNode;\r\n this._first = newNode;\r\n }\r\n\r\n this._length++;\r\n }\r\n\r\n /**\r\n * Add a value to the end of the list.\r\n * @param value Value that should be contained in a node.\r\n */\r\n addLast(value: T) {\r\n const newNode = new Node(value, () => this._length--);\r\n if (!this._first) {\r\n this._first = newNode;\r\n this._last = this._first;\r\n } else {\r\n newNode.prev = this._last;\r\n this._last.next = newNode;\r\n this._last = newNode;\r\n }\r\n\r\n this._length++;\r\n }\r\n\r\n /**\r\n * Remove a node from the beginning of the list.\r\n * @returns Value contained in the first node.\r\n */\r\n removeFirst(): T {\r\n if (!this.first) {\r\n throw new Error('The list is empty.');\r\n }\r\n\r\n const value = this._first.value;\r\n this._first = this._first.next;\r\n this._length--;\r\n return value;\r\n }\r\n\r\n /**\r\n * Remove a node from the end of the list.\r\n * @returns Value contained in the last node.\r\n */\r\n removeLast(): T {\r\n if (!this.last) {\r\n throw new Error('The list is empty.');\r\n }\r\n\r\n const value = this._last.value;\r\n this._last = this._last.prev;\r\n this._length--;\r\n return value;\r\n }\r\n\r\n /**\r\n * Number of nodes in the list.\r\n *\r\n * The count works as long as you do not manually remove nodes (by assigning next/prev to the neighbors).\r\n */\r\n get length(): number {\r\n return this._length;\r\n }\r\n\r\n /**\r\n * First ndoe.\r\n */\r\n get first(): Node<T> | undefined {\r\n return this._first;\r\n }\r\n\r\n /**\r\n * Contained value of the first node.\r\n */\r\n get firstValue(): T | undefined {\r\n return this._first?.value;\r\n }\r\n\r\n /**\r\n * Last node.\r\n */\r\n get last(): Node<T> | undefined {\r\n return this._last;\r\n }\r\n\r\n /**\r\n * Contained value of the last node.\r\n */\r\n get lastValue(): T | undefined {\r\n return this._last?.value;\r\n }\r\n}\r\n", "/**\r\n * @module SimpleWebSocket\r\n * WebSocket client with automatic reconnection and message queuing.\r\n * Provides a reliable messaging layer over WebSocket connections.\r\n *\r\n * @example\r\n * // Create and connect\r\n * const ws = new WebSocketClient<ChatMessage>('wss://chat.example.com');\r\n * ws.connect();\r\n *\r\n * // Send and receive\r\n * await ws.send({ text: 'Hello' });\r\n * const msg = await ws.receive();\r\n */\r\n\r\nimport { LinkedList } from '../collections/LinkedList';\r\n\r\n/**\r\n * Simplified message event for WebSocket data.\r\n */\r\nexport interface SimpleDataEvent {\r\n data: string | ArrayBufferLike | Blob | ArrayBufferView;\r\n}\r\n\r\n/**\r\n * Abstraction interface for WebSocket to enable unit testing.\r\n * Implement this for custom WebSocket instances or mocks.\r\n */\r\nexport interface WebSocketAbstraction {\r\n onopen: ((event: Event) => void) | null;\r\n onerror: ((event: ErrorEvent) => void) | null;\r\n onclose: ((event: CloseEvent) => void) | null;\r\n onmessage: ((event: SimpleDataEvent) => void) | null;\r\n send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void;\r\n close(): void;\r\n}\r\n\r\n/**\r\n * Factory function type for creating WebSocket instances.\r\n */\r\nexport type WebSocketFactory = () => WebSocketAbstraction;\r\n\r\n/**\r\n * Managed WebSocket client with automatic reconnection and message queuing.\r\n *\r\n * Features:\r\n * - Automatic reconnection on disconnect\r\n * - Message queuing when disconnected\r\n * - Type-safe message handling with optional codecs\r\n * - Promise-based receive API\r\n *\r\n * @template TMessage - The type of messages sent and received\r\n *\r\n * @example\r\n * // Basic usage\r\n * interface ChatMessage { user: string; text: string; }\r\n *\r\n * const client = new WebSocketClient<ChatMessage>('wss://chat.example.com');\r\n * client.connect();\r\n *\r\n * // Send messages\r\n * await client.send({ user: 'John', text: 'Hello!' });\r\n *\r\n * // Receive messages\r\n * while (true) {\r\n * const message = await client.receive();\r\n * console.log(`${message.user}: ${message.text}`);\r\n * }\r\n *\r\n * @example\r\n * // With options\r\n * const client = new WebSocketClient<Message>('wss://api.example.com', {\r\n * autoReconnect: true,\r\n * onConnect: (socket) => console.log('Connected'),\r\n * onClose: () => console.log('Disconnected')\r\n * });\r\n */\r\nexport class WebSocketClient<TMessage> {\r\n private ws?: WebSocketAbstraction;\r\n private receiveQueue = new LinkedList<TMessage>();\r\n private receivePromiseWrapper?: PromiseWrapper<TMessage>;\r\n private sendQueue = new LinkedList<TMessage>();\r\n private _isConnected = false;\r\n private isSendingQueue = false;\r\n private url?: string;\r\n private wsFactory?: WebSocketFactory;\r\n private reconnectAttempts = 0;\r\n private shouldReconnect = true;\r\n\r\n get connected(): boolean {\r\n return this._isConnected;\r\n }\r\n\r\n constructor(\r\n urlOrWebSocketFactory: string | WebSocketFactory,\r\n private options?: WebSocketOptions<TMessage>\r\n ) {\r\n if (typeof urlOrWebSocketFactory === 'string') {\r\n this.url = urlOrWebSocketFactory;\r\n } else {\r\n this.wsFactory = urlOrWebSocketFactory;\r\n }\r\n }\r\n\r\n connect() {\r\n this.shouldReconnect = true;\r\n this.reconnectAttempts = 0;\r\n this.reConnect();\r\n }\r\n\r\n disconnect() {\r\n this.shouldReconnect = false;\r\n this.ws?.close();\r\n }\r\n\r\n send(data: TMessage): void {\r\n if (!this._isConnected || this.isSendingQueue) {\r\n this.sendQueue.addLast(data);\r\n return;\r\n }\r\n\r\n if (this.sendQueue.length > 0) {\r\n this.sendQueueItems();\r\n }\r\n\r\n this.sendInternal(data);\r\n }\r\n\r\n /**\r\n * Receive a new message.\r\n *\r\n * @throws Error if called while another receive() is pending.\r\n * @throws Error if connection closes while waiting.\r\n */\r\n receive(): Promise<TMessage> {\r\n if (this.receivePromiseWrapper) {\r\n throw new Error('You can only invoke receive() once at a time.');\r\n }\r\n\r\n if (this.receiveQueue.firstValue) {\r\n return Promise.resolve(this.receiveQueue.removeFirst());\r\n }\r\n\r\n this.receivePromiseWrapper = new PromiseWrapper();\r\n return new Promise((resolve, reject) => {\r\n this.receivePromiseWrapper.resolve = resolve;\r\n this.receivePromiseWrapper.reject = reject;\r\n });\r\n }\r\n\r\n private onMessage(ev: SimpleDataEvent) {\r\n let msg: TMessage;\r\n if (this.options?.codec) {\r\n msg = this.options.codec.decode(ev.data);\r\n } else if (typeof ev.data === 'string') {\r\n if (\r\n ev.data.length > 0 &&\r\n (ev.data[0] === '\"' || ev.data[0] === '[' || ev.data[0] === '{')\r\n ) {\r\n msg = JSON.parse(ev.data);\r\n } else {\r\n msg = ev.data as TMessage;\r\n }\r\n } else {\r\n msg = ev.data as TMessage;\r\n }\r\n\r\n if (this.receivePromiseWrapper) {\r\n this.receivePromiseWrapper.resolve(msg);\r\n this.receivePromiseWrapper = undefined;\r\n return;\r\n }\r\n\r\n this.receiveQueue.addLast(msg);\r\n }\r\n\r\n private reConnect() {\r\n const ws = this.url ? new WebSocket(this.url) : this.wsFactory();\r\n this.ws = ws;\r\n ws.onmessage = (evt: SimpleDataEvent) => this.onMessage(evt);\r\n ws.onerror = () => ws.close();\r\n ws.onopen = () => {\r\n this._isConnected = true;\r\n this.reconnectAttempts = 0;\r\n this.options?.onConnect?.(this);\r\n this.sendQueueItems();\r\n };\r\n ws.onclose = () => {\r\n this._isConnected = false;\r\n\r\n if (this.receivePromiseWrapper) {\r\n this.receivePromiseWrapper.reject(new Error('WebSocket connection closed'));\r\n this.receivePromiseWrapper = undefined;\r\n }\r\n\r\n this.options?.onClose?.(this);\r\n\r\n if (this.shouldReconnect && this.options?.autoReconnect !== false) {\r\n const baseDelay = this.options?.reconnectDelay ?? 1000;\r\n const maxDelay = this.options?.maxReconnectDelay ?? 30000;\r\n const delay = Math.min(baseDelay * Math.pow(2, this.reconnectAttempts), maxDelay);\r\n this.reconnectAttempts++;\r\n setTimeout(() => this.reConnect(), delay);\r\n }\r\n };\r\n }\r\n\r\n private sendInternal(data: TMessage) {\r\n let dataToSend: string | ArrayBufferLike | Blob | ArrayBufferView;\r\n if (typeof data !== 'string') {\r\n if (this.options?.codec) {\r\n dataToSend = this.options.codec.encode(data);\r\n } else {\r\n dataToSend = JSON.stringify(data);\r\n }\r\n } else {\r\n dataToSend = data;\r\n }\r\n\r\n this.ws.send(dataToSend);\r\n }\r\n\r\n private sendQueueItems(): void {\r\n if (this.isSendingQueue) {\r\n return;\r\n }\r\n\r\n this.isSendingQueue = true;\r\n while (this.sendQueue.length > 0) {\r\n const item = this.sendQueue.removeFirst();\r\n if (item == null) {\r\n break;\r\n }\r\n\r\n this.sendInternal(item);\r\n }\r\n\r\n this.isSendingQueue = false;\r\n }\r\n}\r\n\r\n/**\r\n * CODEC used for messages.\r\n */\r\nexport interface WebSocketCodec<TMessage> {\r\n /**\r\n *\r\n * @param data\r\n */\r\n encode(data: TMessage): string | ArrayBufferLike | Blob | ArrayBufferView;\r\n\r\n /**\r\n *\r\n * @param data\r\n */\r\n decode(data: string | ArrayBufferLike | Blob | ArrayBufferView): TMessage;\r\n}\r\n\r\n/**\r\n * Configuration options for @see WebSocketClient.\r\n */\r\nexport interface WebSocketOptions<TMessage> {\r\n /**\r\n * CODEC to use for inbound and outbound messages (if something else that JSON should be used).\r\n */\r\n codec?: WebSocketCodec<TMessage>;\r\n\r\n /**\r\n * Automatically reconnect when getting disconnected (default: true).\r\n */\r\n autoReconnect?: boolean;\r\n\r\n /**\r\n * Initial delay in milliseconds before reconnecting (default: 1000).\r\n * Uses exponential backoff on subsequent attempts.\r\n */\r\n reconnectDelay?: number;\r\n\r\n /**\r\n * Maximum delay in milliseconds between reconnect attempts (default: 30000).\r\n */\r\n maxReconnectDelay?: number;\r\n\r\n /**\r\n * Callback when the WS is connected.\r\n *\r\n * Can be used for authentication messages etc.\r\n *\r\n * @param socket Socket\r\n */\r\n onConnect?: (socket: WebSocketClient<TMessage>) => void;\r\n\r\n /**\r\n * Invoked when the connection is closed.\r\n *\r\n * The connection will be automatically reconnected if configured (on by default).\r\n *\r\n * @param socket Socket.\r\n */\r\n onClose?: (socket: WebSocketClient<TMessage>) => void;\r\n}\r\n\r\nclass PromiseWrapper<TMessage> {\r\n resolve!: (value: TMessage | PromiseLike<TMessage>) => void;\r\n reject!: (reason?: unknown) => void;\r\n}\r\n"],
5
- "mappings": "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",
6
- "names": ["index_exports", "__export", "HttpError", "SSEClient", "SSEDataEvent", "WebSocketClient", "configure", "del", "get", "post", "put", "request", "setFetch", "__toCommonJS", "HttpError", "response", "config", "fetchImpl", "setFetch", "fn", "configure", "options", "request", "url", "token", "headers", "body", "get", "queryString", "prefix", "key", "value", "post", "data", "put", "del", "SSEDataEvent", "eventName", "data", "eventInit", "SSEClient", "url", "options", "eventSource", "error", "eventType", "e", "target", "element", "rawData", "event", "Node", "value", "removeCallback", "LinkedList", "newNode", "WebSocketClient", "urlOrWebSocketFactory", "options", "LinkedList", "data", "PromiseWrapper", "resolve", "reject", "ev", "msg", "ws", "evt", "baseDelay", "maxDelay", "delay", "dataToSend", "item"]
4
+ "sourcesContent": ["export {\r\n HttpOptions,\r\n HttpResponse,\r\n HttpError,\r\n RequestOptions,\r\n configure,\r\n setFetch,\r\n request,\r\n get,\r\n post,\r\n put,\r\n del\r\n} from './http';\r\n\r\nexport {\r\n SSEDataEvent,\r\n SSEOptions,\r\n SSEEventFactory,\r\n SSEClient\r\n} from './ServerSentEvents';\r\n\r\nexport {\r\n SimpleDataEvent,\r\n WebSocketAbstraction,\r\n WebSocketFactory,\r\n WebSocketClient,\r\n WebSocketCodec,\r\n WebSocketOptions\r\n} from './SimpleWebSocket';\r\n", "/**\r\n * @module http\r\n * Type-safe HTTP module built on fetch() with automatic JWT handling.\r\n *\r\n * @example\r\n * import { configure, get, post } from './http';\r\n *\r\n * configure({ baseUrl: '/api' });\r\n * const response = await get('/users');\r\n * const users = response.as<User[]>();\r\n */\r\n\r\n/**\r\n * Configuration options for the http module.\r\n */\r\nexport interface HttpOptions {\r\n /**\r\n * Root URL to remote endpoint. Used so that each method only has to specify path in requests.\r\n */\r\n baseUrl?: string;\r\n\r\n /**\r\n * Default content type to use if none is specified in the request method.\r\n */\r\n contentType?: string;\r\n\r\n /**\r\n * Checks for a JWT token in localStorage to automatically include it in requests.\r\n *\r\n * Undefined = use \"jwt\", null = disable.\r\n */\r\n bearerTokenName?: string | null;\r\n\r\n /**\r\n * Default request timeout in milliseconds.\r\n * Uses `AbortSignal.timeout()` to automatically abort requests that take too long.\r\n * Can be overridden per-request by passing a `signal` in `RequestInit`.\r\n *\r\n * @example\r\n * configure({ baseUrl: '/api', timeout: 10000 }); // 10 second timeout\r\n */\r\n timeout?: number;\r\n}\r\n\r\n/**\r\n * Response for request methods.\r\n */\r\nexport interface HttpResponse {\r\n /**\r\n * Http status code.\r\n */\r\n statusCode: number;\r\n\r\n /**\r\n * Reason to why the status code was used.\r\n */\r\n statusReason: string;\r\n\r\n /**\r\n * True if this is a 2xx response.\r\n */\r\n success: boolean;\r\n\r\n /**\r\n * Content type of response body.\r\n */\r\n contentType: string | null;\r\n\r\n /**\r\n * Body returned.\r\n *\r\n * Body has been read and deserialized from json (if the request content type was 'application/json' which is the default).\r\n */\r\n body: unknown;\r\n\r\n /**\r\n * Charset used in body.\r\n */\r\n charset: string | null;\r\n\r\n /**\r\n * Cast body to a type.\r\n */\r\n as<T>(): T;\r\n}\r\n\r\n/**\r\n * Error thrown when a request fails.\r\n */\r\nexport class HttpError extends Error {\r\n message: string;\r\n response: HttpResponse;\r\n\r\n constructor(response: HttpResponse) {\r\n super(response.statusReason);\r\n this.message = response.statusReason;\r\n this.response = response;\r\n }\r\n}\r\n\r\n/**\r\n * HTTP request options.\r\n */\r\nexport interface RequestOptions {\r\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE';\r\n mode?: 'cors' | 'no-cors' | '*cors' | 'same-origin';\r\n cache:\r\n | 'default'\r\n | 'no-store'\r\n | 'reload'\r\n | 'no-cache'\r\n | 'force-cache'\r\n | 'only-if-cached';\r\n credentials: 'omit' | 'same-origin' | 'include';\r\n headers: Map<string, string>;\r\n redirect: 'follow' | 'manual' | '*follow' | 'error';\r\n referrerPolicy:\r\n | 'no-referrer'\r\n | '*no-referrer-when-downgrade'\r\n | 'origin'\r\n | 'origin-when-cross-origin'\r\n | 'same-origin'\r\n | 'strict-origin'\r\n | 'strict-origin-when-cross-origin'\r\n | 'unsafe-url';\r\n\r\n /**\r\n * Will be serialized if the content type is json (and the body is an object).\r\n */\r\n body: unknown;\r\n}\r\n\r\n/** @internal */\r\ndeclare type FetchFn = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\r\n\r\nlet config: HttpOptions = {\r\n bearerTokenName: 'jwt'\r\n};\r\n\r\nlet fetchImpl: FetchFn = fetch;\r\n\r\n/**\r\n * Replace the fetch implementation for testing purposes.\r\n *\r\n * @param fn - Custom fetch function, or undefined to restore the default.\r\n *\r\n * @example\r\n * setFetch(async (url, options) => {\r\n * return new Response(JSON.stringify({ id: 1 }), { status: 200 });\r\n * });\r\n */\r\nexport function setFetch(fn?: FetchFn): void {\r\n fetchImpl = fn ?? fetch;\r\n}\r\n\r\n/**\r\n * Configure the http module.\r\n *\r\n * @example\r\n * configure({ baseUrl: '/api/v1', bearerTokenName: 'auth_token' });\r\n */\r\nexport function configure(options: HttpOptions): void {\r\n config = {\r\n ...config,\r\n ...options\r\n };\r\n if (options.bearerTokenName === undefined) {\r\n config.bearerTokenName = 'jwt';\r\n }\r\n}\r\n\r\n/**\r\n * Make an HTTP request.\r\n *\r\n * @param url - URL to make the request against.\r\n * @param options - Request options.\r\n * @returns Response from server.\r\n *\r\n * @example\r\n * const response = await request('/users', { method: 'GET' });\r\n */\r\nexport async function request(url: string, options?: RequestInit): Promise<HttpResponse> {\r\n if (config.bearerTokenName) {\r\n const token = localStorage.getItem(config.bearerTokenName);\r\n if (token && options) {\r\n const headers = options?.headers\r\n ? new Headers(options.headers)\r\n : new Headers();\r\n\r\n if (!headers.get('Authorization')) {\r\n headers.set('Authorization', 'Bearer ' + token);\r\n }\r\n\r\n options.headers = headers;\r\n }\r\n }\r\n\r\n if (config.timeout && !options?.signal) {\r\n options ??= {};\r\n options.signal = AbortSignal.timeout(config.timeout);\r\n }\r\n\r\n if (config.baseUrl) {\r\n if (url[0] !== '/' && config.baseUrl[config.baseUrl.length - 1] !== '/') {\r\n url = `${config.baseUrl}/${url}`;\r\n } else {\r\n url = config.baseUrl + url;\r\n }\r\n }\r\n\r\n const response = await fetchImpl(url, options);\r\n\r\n if (!response.ok) {\r\n return {\r\n statusCode: response.status,\r\n statusReason: response.statusText,\r\n success: false,\r\n contentType: response.headers.get('content-type'),\r\n body: await response.text(),\r\n charset: response.headers.get('charset'),\r\n\r\n as() {\r\n throw new Error('No response received');\r\n }\r\n };\r\n }\r\n\r\n let body: unknown | null = null;\r\n if (response.status !== 204) {\r\n body = await response.json();\r\n }\r\n\r\n return {\r\n success: true,\r\n statusCode: response.status,\r\n statusReason: response.statusText,\r\n contentType: response.headers.get('content-type'),\r\n body: body,\r\n charset: response.headers.get('charset'),\r\n as<T>() {\r\n return <T>body;\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * GET a resource.\r\n *\r\n * @param url - URL to get resource from.\r\n * @param queryString - Optional query string parameters.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await get('/users', { page: '1', limit: '10' });\r\n * const users = response.as<User[]>();\r\n */\r\nexport async function get(\r\n url: string,\r\n queryString?: Record<string, string>,\r\n options?: RequestInit\r\n): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'GET',\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'GET';\r\n }\r\n\r\n if (queryString) {\r\n let prefix = '&';\r\n if (url.indexOf('?') === -1) {\r\n prefix = '?';\r\n }\r\n\r\n for (const key in queryString) {\r\n const value = queryString[key];\r\n url += `${prefix}${key}=${value}`;\r\n prefix = '&';\r\n }\r\n }\r\n\r\n return request(url, options);\r\n}\r\n\r\n/**\r\n * POST a resource.\r\n *\r\n * @param url - URL to post to.\r\n * @param data - Data to post.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await post('/users', JSON.stringify({ name: 'John' }));\r\n */\r\nexport async function post(\r\n url: string,\r\n data: BodyInit,\r\n options?: RequestInit\r\n): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'POST',\r\n body: data,\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'POST';\r\n options.body = data;\r\n }\r\n\r\n return request(url, options);\r\n}\r\n\r\n/**\r\n * PUT a resource.\r\n *\r\n * @param url - URL to resource.\r\n * @param data - Data to put.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await put('/users/1', JSON.stringify({ name: 'Jane' }));\r\n */\r\nexport async function put(\r\n url: string,\r\n data: BodyInit,\r\n options?: RequestInit\r\n): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'PUT',\r\n body: data,\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'PUT';\r\n options.body = data;\r\n }\r\n\r\n return request(url, options);\r\n}\r\n\r\n/**\r\n * DELETE a resource.\r\n *\r\n * @param url - URL to resource.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await del('/users/1');\r\n */\r\nexport async function del(url: string, options?: RequestInit): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'DELETE',\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'DELETE';\r\n }\r\n\r\n return request(url, options);\r\n}\r\n", "/**\r\n * @module ServerSentEvents\r\n * SSE client that dispatches received events as DOM events.\r\n * Uses the browser's built-in EventSource reconnection.\r\n *\r\n * @example\r\n * const sse = new SSEClient('/api/events', {\r\n * eventTypes: ['user-updated', 'order-created']\r\n * });\r\n * sse.connect();\r\n *\r\n * document.addEventListener('user-updated', (e: SSEDataEvent) => {\r\n * console.log('User updated:', e.data);\r\n * });\r\n */\r\n\r\n/**\r\n * Event dispatched when an SSE message is received.\r\n * The event name matches the SSE event type.\r\n */\r\nexport class SSEDataEvent extends Event {\r\n constructor(\r\n eventName: string,\r\n public data: unknown,\r\n eventInit?: EventInit\r\n ) {\r\n super(eventName, { bubbles: true, ...eventInit });\r\n }\r\n}\r\n\r\n/**\r\n * Factory function for creating custom event instances.\r\n *\r\n * @example\r\n * const factory: SSEEventFactory = (eventName, data) => {\r\n * switch (eventName) {\r\n * case 'user-updated':\r\n * return new UserUpdatedEvent(data as User);\r\n * default:\r\n * return new SSEDataEvent(eventName, data);\r\n * }\r\n * };\r\n */\r\nexport type SSEEventFactory = (eventName: string, data: unknown) => Event;\r\n\r\n/**\r\n * Configuration options for SSEClient.\r\n */\r\nexport interface SSEOptions {\r\n /**\r\n * Target element or CSS selector for event dispatching.\r\n * Defaults to document.\r\n */\r\n target?: string | Element;\r\n\r\n /**\r\n * Whether to send credentials with the request (default: false).\r\n */\r\n withCredentials?: boolean;\r\n\r\n /**\r\n * Specific SSE event types to listen for.\r\n * If not specified, listens to the default 'message' event.\r\n *\r\n * @example\r\n * eventTypes: ['user-updated', 'order-created']\r\n */\r\n eventTypes?: string[];\r\n\r\n /**\r\n * Factory function for creating custom event instances.\r\n * If not provided, SSEDataEvent is used.\r\n *\r\n * @example\r\n * eventFactory: (name, data) => new MyCustomEvent(name, data)\r\n */\r\n eventFactory?: SSEEventFactory;\r\n\r\n /**\r\n * Callback when connection is established.\r\n */\r\n onConnect?: (client: SSEClient) => void;\r\n\r\n /**\r\n * Callback when an error occurs.\r\n * Note: EventSource automatically reconnects on errors.\r\n */\r\n onError?: (client: SSEClient, error: Event) => void;\r\n}\r\n\r\n/**\r\n * Server-Sent Events client that dispatches received events as DOM events.\r\n * Uses the browser's built-in EventSource with automatic reconnection.\r\n *\r\n * @example\r\n * const sse = new SSEClient('/api/events', {\r\n * target: '#notifications',\r\n * eventTypes: ['notification', 'alert']\r\n * });\r\n *\r\n * sse.connect();\r\n *\r\n * document.querySelector('#notifications')\r\n * .addEventListener('notification', (e: SSEDataEvent) => {\r\n * showNotification(e.data);\r\n * });\r\n *\r\n * sse.disconnect();\r\n */\r\nexport class SSEClient {\r\n private eventSource?: EventSource;\r\n private target: Element | Document;\r\n\r\n /**\r\n * Whether the client is currently connected.\r\n */\r\n get connected(): boolean {\r\n return this.eventSource?.readyState === EventSource.OPEN;\r\n }\r\n\r\n constructor(\r\n private url: string,\r\n private options?: SSEOptions\r\n ) {\r\n this.target = this.resolveTarget(options?.target);\r\n }\r\n\r\n /**\r\n * Establish connection to the SSE endpoint.\r\n */\r\n connect(): void {\r\n if (this.eventSource) {\r\n return;\r\n }\r\n\r\n const eventSource = new EventSource(this.url, {\r\n withCredentials: this.options?.withCredentials ?? false\r\n });\r\n\r\n this.eventSource = eventSource;\r\n\r\n eventSource.onopen = () => {\r\n this.options?.onConnect?.(this);\r\n };\r\n\r\n eventSource.onerror = (error) => {\r\n this.options?.onError?.(this, error);\r\n };\r\n\r\n if (this.options?.eventTypes && this.options.eventTypes.length > 0) {\r\n for (const eventType of this.options.eventTypes) {\r\n eventSource.addEventListener(eventType, (e: MessageEvent) => {\r\n this.dispatchEvent(eventType, e.data);\r\n });\r\n }\r\n } else {\r\n eventSource.onmessage = (e: MessageEvent) => {\r\n this.dispatchEvent('message', e.data);\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Close the connection.\r\n */\r\n disconnect(): void {\r\n this.eventSource?.close();\r\n this.eventSource = undefined;\r\n }\r\n\r\n private resolveTarget(target?: string | Element): Element | Document {\r\n if (!target) {\r\n return document;\r\n }\r\n if (typeof target === 'string') {\r\n const element = document.querySelector(target);\r\n if (!element) {\r\n throw new Error(`SSEClient: Target element not found: ${target}`);\r\n }\r\n return element;\r\n }\r\n return target;\r\n }\r\n\r\n private dispatchEvent(eventName: string, rawData: string): void {\r\n let data: unknown;\r\n\r\n if (rawData.length > 0 && (rawData[0] === '{' || rawData[0] === '[' || rawData[0] === '\"')) {\r\n try {\r\n data = JSON.parse(rawData);\r\n } catch {\r\n data = rawData;\r\n }\r\n } else {\r\n data = rawData;\r\n }\r\n\r\n const event = this.options?.eventFactory\r\n ? this.options.eventFactory(eventName, data)\r\n : new SSEDataEvent(eventName, data);\r\n\r\n this.target.dispatchEvent(event);\r\n }\r\n}\r\n", "/**\r\n * A node in the @see LinkedList.\r\n */\r\nexport class Node<T> {\r\n /**\r\n * Next node unless last one.\r\n */\r\n public next: Node<T> | null = null;\r\n /**\r\n * Previous node unless first one.\r\n */\r\n public prev: Node<T> | null = null;\r\n\r\n /**\r\n * Constructor.\r\n * @param value Value contained in the node.\r\n */\r\n constructor(public value: T, private removeCallback: () => void) {}\r\n\r\n /**\r\n * Remove this node.\r\n * Will notify the list of the update to ensure correct element count.\r\n */\r\n remove() {\r\n if (this.prev) this.prev.next = this.next;\r\n if (this.next) this.next.prev = this.prev;\r\n this.removeCallback();\r\n }\r\n}\r\n\r\n/**\r\n * A trivial linked list implementation.\r\n */\r\nexport class LinkedList<T> {\r\n private _first: Node<T> | null = null;\r\n private _last: Node<T> | null = null;\r\n private _length = 0;\r\n\r\n /**\r\n * Add a value to the beginning of the list.\r\n * @param value Value that should be contained in the node.\r\n */\r\n addFirst(value: T) {\r\n const newNode = this.createNode(value);\r\n if (!this._first) {\r\n this._first = newNode;\r\n this._last = this._first;\r\n } else {\r\n newNode.next = this._first;\r\n this._first.prev = newNode;\r\n this._first = newNode;\r\n }\r\n\r\n this._length++;\r\n }\r\n\r\n /**\r\n * Add a value to the end of the list.\r\n * @param value Value that should be contained in a node.\r\n */\r\n addLast(value: T) {\r\n const newNode = this.createNode(value);\r\n if (!this._last) {\r\n this._first = newNode;\r\n this._last = newNode;\r\n } else {\r\n newNode.prev = this._last;\r\n this._last.next = newNode;\r\n this._last = newNode;\r\n }\r\n\r\n this._length++;\r\n }\r\n\r\n private createNode(value: T): Node<T> {\r\n let node: Node<T>;\r\n node = new Node(value, () => {\r\n if (this._first === node) this._first = node.next;\r\n if (this._last === node) this._last = node.prev;\r\n this._length--;\r\n });\r\n return node;\r\n }\r\n\r\n /**\r\n * Remove a node from the beginning of the list.\r\n * @returns Value contained in the first node.\r\n */\r\n removeFirst(): T {\r\n if (!this._first) {\r\n throw new Error('The list is empty.');\r\n }\r\n\r\n const value = this._first.value;\r\n this._first = this._first.next;\r\n if (!this._first) this._last = null;\r\n this._length--;\r\n return value;\r\n }\r\n\r\n /**\r\n * Remove a node from the end of the list.\r\n * @returns Value contained in the last node.\r\n */\r\n removeLast(): T {\r\n if (!this._last) {\r\n throw new Error('The list is empty.');\r\n }\r\n\r\n const value = this._last.value;\r\n this._last = this._last.prev;\r\n if (!this._last) this._first = null;\r\n this._length--;\r\n return value;\r\n }\r\n\r\n /**\r\n * Number of nodes in the list.\r\n *\r\n * The count works as long as you do not manually remove nodes (by assigning next/prev to the neighbors).\r\n */\r\n get length(): number {\r\n return this._length;\r\n }\r\n\r\n /**\r\n * First node, or `null` if the list is empty.\r\n */\r\n get first(): Node<T> | null {\r\n return this._first;\r\n }\r\n\r\n /**\r\n * Contained value of the first node, or `undefined` if the list is empty.\r\n */\r\n get firstValue(): T | undefined {\r\n return this._first?.value;\r\n }\r\n\r\n /**\r\n * Last node, or `null` if the list is empty.\r\n */\r\n get last(): Node<T> | null {\r\n return this._last;\r\n }\r\n\r\n /**\r\n * Contained value of the last node, or `undefined` if the list is empty.\r\n */\r\n get lastValue(): T | undefined {\r\n return this._last?.value;\r\n }\r\n}\r\n", "/**\r\n * @module SimpleWebSocket\r\n * WebSocket client with automatic reconnection and message queuing.\r\n * Provides a reliable messaging layer over WebSocket connections.\r\n *\r\n * @example\r\n * // Create and connect\r\n * const ws = new WebSocketClient<ChatMessage>('wss://chat.example.com');\r\n * ws.connect();\r\n *\r\n * // Send and receive\r\n * await ws.send({ text: 'Hello' });\r\n * const msg = await ws.receive();\r\n */\r\n\r\nimport { LinkedList } from '../collections/LinkedList';\r\n\r\n/**\r\n * Simplified message event for WebSocket data.\r\n */\r\nexport interface SimpleDataEvent {\r\n data: string | ArrayBufferLike | Blob | ArrayBufferView;\r\n}\r\n\r\n/**\r\n * Abstraction interface for WebSocket to enable unit testing.\r\n * Implement this for custom WebSocket instances or mocks.\r\n */\r\nexport interface WebSocketAbstraction {\r\n onopen: ((event: Event) => void) | null;\r\n onerror: ((event: ErrorEvent) => void) | null;\r\n onclose: ((event: CloseEvent) => void) | null;\r\n onmessage: ((event: SimpleDataEvent) => void) | null;\r\n send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void;\r\n close(): void;\r\n}\r\n\r\n/**\r\n * Factory function type for creating WebSocket instances.\r\n */\r\nexport type WebSocketFactory = () => WebSocketAbstraction;\r\n\r\n/**\r\n * Managed WebSocket client with automatic reconnection and message queuing.\r\n *\r\n * Features:\r\n * - Automatic reconnection on disconnect\r\n * - Message queuing when disconnected\r\n * - Type-safe message handling with optional codecs\r\n * - Promise-based receive API\r\n *\r\n * @template TMessage - The type of messages sent and received\r\n *\r\n * @example\r\n * // Basic usage\r\n * interface ChatMessage { user: string; text: string; }\r\n *\r\n * const client = new WebSocketClient<ChatMessage>('wss://chat.example.com');\r\n * client.connect();\r\n *\r\n * // Send messages\r\n * await client.send({ user: 'John', text: 'Hello!' });\r\n *\r\n * // Receive messages\r\n * while (true) {\r\n * const message = await client.receive();\r\n * console.log(`${message.user}: ${message.text}`);\r\n * }\r\n *\r\n * @example\r\n * // With options\r\n * const client = new WebSocketClient<Message>('wss://api.example.com', {\r\n * autoReconnect: true,\r\n * onConnect: (socket) => console.log('Connected'),\r\n * onClose: () => console.log('Disconnected')\r\n * });\r\n */\r\nexport class WebSocketClient<TMessage> {\r\n private ws?: WebSocketAbstraction;\r\n private receiveQueue = new LinkedList<TMessage>();\r\n private receivePromiseWrapper?: PromiseWrapper<TMessage>;\r\n private sendQueue = new LinkedList<TMessage>();\r\n private _isConnected = false;\r\n private isSendingQueue = false;\r\n private url?: string;\r\n private wsFactory?: WebSocketFactory;\r\n private reconnectAttempts = 0;\r\n private shouldReconnect = true;\r\n\r\n get connected(): boolean {\r\n return this._isConnected;\r\n }\r\n\r\n constructor(\r\n urlOrWebSocketFactory: string | WebSocketFactory,\r\n private options?: WebSocketOptions<TMessage>\r\n ) {\r\n if (typeof urlOrWebSocketFactory === 'string') {\r\n this.url = urlOrWebSocketFactory;\r\n } else {\r\n this.wsFactory = urlOrWebSocketFactory;\r\n }\r\n }\r\n\r\n connect() {\r\n this.shouldReconnect = true;\r\n this.reconnectAttempts = 0;\r\n this.reConnect();\r\n }\r\n\r\n disconnect() {\r\n this.shouldReconnect = false;\r\n this.ws?.close();\r\n }\r\n\r\n send(data: TMessage): void {\r\n if (!this._isConnected || this.isSendingQueue) {\r\n this.sendQueue.addLast(data);\r\n return;\r\n }\r\n\r\n if (this.sendQueue.length > 0) {\r\n this.sendQueueItems();\r\n }\r\n\r\n this.sendInternal(data);\r\n }\r\n\r\n /**\r\n * Receive a new message.\r\n *\r\n * @throws Error if called while another receive() is pending.\r\n * @throws Error if connection closes while waiting.\r\n */\r\n receive(): Promise<TMessage> {\r\n if (this.receivePromiseWrapper) {\r\n throw new Error('You can only invoke receive() once at a time.');\r\n }\r\n\r\n if (this.receiveQueue.firstValue) {\r\n return Promise.resolve(this.receiveQueue.removeFirst());\r\n }\r\n\r\n const wrapper = new PromiseWrapper<TMessage>();\r\n this.receivePromiseWrapper = wrapper;\r\n return new Promise((resolve, reject) => {\r\n wrapper.resolve = resolve;\r\n wrapper.reject = reject;\r\n });\r\n }\r\n\r\n private onMessage(ev: SimpleDataEvent) {\r\n let msg: TMessage;\r\n if (this.options?.codec) {\r\n msg = this.options.codec.decode(ev.data);\r\n } else if (typeof ev.data === 'string') {\r\n if (\r\n ev.data.length > 0 &&\r\n (ev.data[0] === '\"' || ev.data[0] === '[' || ev.data[0] === '{')\r\n ) {\r\n msg = JSON.parse(ev.data);\r\n } else {\r\n msg = ev.data as TMessage;\r\n }\r\n } else {\r\n msg = ev.data as TMessage;\r\n }\r\n\r\n if (this.receivePromiseWrapper) {\r\n this.receivePromiseWrapper.resolve(msg);\r\n this.receivePromiseWrapper = undefined;\r\n return;\r\n }\r\n\r\n this.receiveQueue.addLast(msg);\r\n }\r\n\r\n private reConnect() {\r\n const ws: WebSocketAbstraction = this.url\r\n ? (new WebSocket(this.url) as unknown as WebSocketAbstraction)\r\n : this.wsFactory!();\r\n this.ws = ws;\r\n ws.onmessage = (evt: SimpleDataEvent) => this.onMessage(evt);\r\n ws.onerror = () => ws.close();\r\n ws.onopen = () => {\r\n this._isConnected = true;\r\n this.reconnectAttempts = 0;\r\n this.options?.onConnect?.(this);\r\n this.sendQueueItems();\r\n };\r\n ws.onclose = () => {\r\n this._isConnected = false;\r\n\r\n if (this.receivePromiseWrapper) {\r\n this.receivePromiseWrapper.reject(new Error('WebSocket connection closed'));\r\n this.receivePromiseWrapper = undefined;\r\n }\r\n\r\n this.options?.onClose?.(this);\r\n\r\n if (this.shouldReconnect && this.options?.autoReconnect !== false) {\r\n const baseDelay = this.options?.reconnectDelay ?? 1000;\r\n const maxDelay = this.options?.maxReconnectDelay ?? 30000;\r\n const delay = Math.min(baseDelay * Math.pow(2, this.reconnectAttempts), maxDelay);\r\n this.reconnectAttempts++;\r\n setTimeout(() => this.reConnect(), delay);\r\n }\r\n };\r\n }\r\n\r\n private sendInternal(data: TMessage) {\r\n let dataToSend: string | ArrayBufferLike | Blob | ArrayBufferView;\r\n if (typeof data !== 'string') {\r\n if (this.options?.codec) {\r\n dataToSend = this.options.codec.encode(data);\r\n } else {\r\n dataToSend = JSON.stringify(data);\r\n }\r\n } else {\r\n dataToSend = data;\r\n }\r\n\r\n this.ws!.send(dataToSend);\r\n }\r\n\r\n private sendQueueItems(): void {\r\n if (this.isSendingQueue) {\r\n return;\r\n }\r\n\r\n this.isSendingQueue = true;\r\n while (this.sendQueue.length > 0) {\r\n const item = this.sendQueue.removeFirst();\r\n if (item == null) {\r\n break;\r\n }\r\n\r\n this.sendInternal(item);\r\n }\r\n\r\n this.isSendingQueue = false;\r\n }\r\n}\r\n\r\n/**\r\n * CODEC used for messages.\r\n */\r\nexport interface WebSocketCodec<TMessage> {\r\n /**\r\n *\r\n * @param data\r\n */\r\n encode(data: TMessage): string | ArrayBufferLike | Blob | ArrayBufferView;\r\n\r\n /**\r\n *\r\n * @param data\r\n */\r\n decode(data: string | ArrayBufferLike | Blob | ArrayBufferView): TMessage;\r\n}\r\n\r\n/**\r\n * Configuration options for @see WebSocketClient.\r\n */\r\nexport interface WebSocketOptions<TMessage> {\r\n /**\r\n * CODEC to use for inbound and outbound messages (if something else that JSON should be used).\r\n */\r\n codec?: WebSocketCodec<TMessage>;\r\n\r\n /**\r\n * Automatically reconnect when getting disconnected (default: true).\r\n */\r\n autoReconnect?: boolean;\r\n\r\n /**\r\n * Initial delay in milliseconds before reconnecting (default: 1000).\r\n * Uses exponential backoff on subsequent attempts.\r\n */\r\n reconnectDelay?: number;\r\n\r\n /**\r\n * Maximum delay in milliseconds between reconnect attempts (default: 30000).\r\n */\r\n maxReconnectDelay?: number;\r\n\r\n /**\r\n * Callback when the WS is connected.\r\n *\r\n * Can be used for authentication messages etc.\r\n *\r\n * @param socket Socket\r\n */\r\n onConnect?: (socket: WebSocketClient<TMessage>) => void;\r\n\r\n /**\r\n * Invoked when the connection is closed.\r\n *\r\n * The connection will be automatically reconnected if configured (on by default).\r\n *\r\n * @param socket Socket.\r\n */\r\n onClose?: (socket: WebSocketClient<TMessage>) => void;\r\n}\r\n\r\nclass PromiseWrapper<TMessage> {\r\n resolve!: (value: TMessage | PromiseLike<TMessage>) => void;\r\n reject!: (reason?: unknown) => void;\r\n}\r\n"],
5
+ "mappings": "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",
6
+ "names": ["index_exports", "__export", "HttpError", "SSEClient", "SSEDataEvent", "WebSocketClient", "configure", "del", "get", "post", "put", "request", "setFetch", "__toCommonJS", "HttpError", "response", "config", "fetchImpl", "setFetch", "fn", "configure", "options", "request", "url", "token", "headers", "body", "get", "queryString", "prefix", "key", "value", "post", "data", "put", "del", "SSEDataEvent", "eventName", "data", "eventInit", "SSEClient", "url", "options", "eventSource", "error", "eventType", "e", "target", "element", "rawData", "event", "Node", "value", "removeCallback", "LinkedList", "newNode", "node", "WebSocketClient", "urlOrWebSocketFactory", "options", "LinkedList", "data", "wrapper", "PromiseWrapper", "resolve", "reject", "ev", "msg", "ws", "evt", "baseDelay", "maxDelay", "delay", "dataToSend", "item"]
7
7
  }
@@ -1,2 +1,2 @@
1
- var h=class extends Error{constructor(e){super(e.statusReason),this.message=e.statusReason,this.response=e}},r={bearerTokenName:"jwt"},v=fetch;function g(s){v=s??fetch}function m(s){r={...r,...s},s.bearerTokenName===void 0&&(r.bearerTokenName="jwt")}async function a(s,e){if(r.bearerTokenName){let i=localStorage.getItem(r.bearerTokenName);if(i&&e){let o=e?.headers?new Headers(e.headers):new Headers;o.get("Authorization")||o.set("Authorization","Bearer "+i),e.headers=o}}r.timeout&&!e?.signal&&(e??={},e.signal=AbortSignal.timeout(r.timeout)),r.baseUrl&&(s[0]!=="/"&&r.baseUrl[r.baseUrl.length-1]!=="/"?s=`${r.baseUrl}/${s}`:s=r.baseUrl+s);let t=await v(s,e);if(!t.ok)return{statusCode:t.status,statusReason:t.statusText,success:!1,contentType:t.headers.get("content-type"),body:await t.text(),charset:t.headers.get("charset"),as(){throw new Error("No response received")}};let n=null;return t.status!==204&&(n=await t.json()),{success:!0,statusCode:t.status,statusReason:t.statusText,contentType:t.headers.get("content-type"),body:n,charset:t.headers.get("charset"),as(){return n}}}async function T(s,e,t){if(t?t.method="GET":t={method:"GET",headers:{"content-type":r.contentType??"application/json"}},e){let n="&";s.indexOf("?")===-1&&(n="?");for(let i in e){let o=e[i];s+=`${n}${i}=${o}`,n="&"}}return a(s,t)}async function y(s,e,t){return t?(t.method="POST",t.body=e):t={method:"POST",body:e,headers:{"content-type":r.contentType??"application/json"}},a(s,t)}async function b(s,e,t){return t?(t.method="PUT",t.body=e):t={method:"PUT",body:e,headers:{"content-type":r.contentType??"application/json"}},a(s,t)}async function S(s,e){return e?e.method="DELETE":e={method:"DELETE",headers:{"content-type":r.contentType??"application/json"}},a(s,e)}var l=class extends Event{constructor(t,n,i){super(t,{bubbles:!0,...i});this.data=n}},p=class{constructor(e,t){this.url=e;this.options=t;this.target=this.resolveTarget(t?.target)}get connected(){return this.eventSource?.readyState===EventSource.OPEN}connect(){if(this.eventSource)return;let e=new EventSource(this.url,{withCredentials:this.options?.withCredentials??!1});if(this.eventSource=e,e.onopen=()=>{this.options?.onConnect?.(this)},e.onerror=t=>{this.options?.onError?.(this,t)},this.options?.eventTypes&&this.options.eventTypes.length>0)for(let t of this.options.eventTypes)e.addEventListener(t,n=>{this.dispatchEvent(t,n.data)});else e.onmessage=t=>{this.dispatchEvent("message",t.data)}}disconnect(){this.eventSource?.close(),this.eventSource=void 0}resolveTarget(e){if(!e)return document;if(typeof e=="string"){let t=document.querySelector(e);if(!t)throw new Error(`SSEClient: Target element not found: ${e}`);return t}return e}dispatchEvent(e,t){let n;if(t.length>0&&(t[0]==="{"||t[0]==="["||t[0]==='"'))try{n=JSON.parse(t)}catch{n=t}else n=t;let i=this.options?.eventFactory?this.options.eventFactory(e,n):new l(e,n);this.target.dispatchEvent(i)}};var u=class{constructor(e,t){this.value=e;this.removeCallback=t;this.next=null;this.prev=null}remove(){this.prev.next=this.next,this.next.prev=this.prev,this.removeCallback()}},c=class{constructor(){this._length=0}addFirst(e){let t=new u(e,()=>this._length--);this._first?(t.next=this._first,this._first.prev=t,this._first=t):(this._first=t,this._last=this._first),this._length++}addLast(e){let t=new u(e,()=>this._length--);this._first?(t.prev=this._last,this._last.next=t,this._last=t):(this._first=t,this._last=this._first),this._length++}removeFirst(){if(!this.first)throw new Error("The list is empty.");let e=this._first.value;return this._first=this._first.next,this._length--,e}removeLast(){if(!this.last)throw new Error("The list is empty.");let e=this._last.value;return this._last=this._last.prev,this._length--,e}get length(){return this._length}get first(){return this._first}get firstValue(){return this._first?.value}get last(){return this._last}get lastValue(){return this._last?.value}};var d=class{constructor(e,t){this.options=t;this.receiveQueue=new c;this.sendQueue=new c;this._isConnected=!1;this.isSendingQueue=!1;this.reconnectAttempts=0;this.shouldReconnect=!0;typeof e=="string"?this.url=e:this.wsFactory=e}get connected(){return this._isConnected}connect(){this.shouldReconnect=!0,this.reconnectAttempts=0,this.reConnect()}disconnect(){this.shouldReconnect=!1,this.ws?.close()}send(e){if(!this._isConnected||this.isSendingQueue){this.sendQueue.addLast(e);return}this.sendQueue.length>0&&this.sendQueueItems(),this.sendInternal(e)}receive(){if(this.receivePromiseWrapper)throw new Error("You can only invoke receive() once at a time.");return this.receiveQueue.firstValue?Promise.resolve(this.receiveQueue.removeFirst()):(this.receivePromiseWrapper=new f,new Promise((e,t)=>{this.receivePromiseWrapper.resolve=e,this.receivePromiseWrapper.reject=t}))}onMessage(e){let t;if(this.options?.codec?t=this.options.codec.decode(e.data):typeof e.data=="string"&&e.data.length>0&&(e.data[0]==='"'||e.data[0]==="["||e.data[0]==="{")?t=JSON.parse(e.data):t=e.data,this.receivePromiseWrapper){this.receivePromiseWrapper.resolve(t),this.receivePromiseWrapper=void 0;return}this.receiveQueue.addLast(t)}reConnect(){let e=this.url?new WebSocket(this.url):this.wsFactory();this.ws=e,e.onmessage=t=>this.onMessage(t),e.onerror=()=>e.close(),e.onopen=()=>{this._isConnected=!0,this.reconnectAttempts=0,this.options?.onConnect?.(this),this.sendQueueItems()},e.onclose=()=>{if(this._isConnected=!1,this.receivePromiseWrapper&&(this.receivePromiseWrapper.reject(new Error("WebSocket connection closed")),this.receivePromiseWrapper=void 0),this.options?.onClose?.(this),this.shouldReconnect&&this.options?.autoReconnect!==!1){let t=this.options?.reconnectDelay??1e3,n=this.options?.maxReconnectDelay??3e4,i=Math.min(t*Math.pow(2,this.reconnectAttempts),n);this.reconnectAttempts++,setTimeout(()=>this.reConnect(),i)}}}sendInternal(e){let t;typeof e!="string"?this.options?.codec?t=this.options.codec.encode(e):t=JSON.stringify(e):t=e,this.ws.send(t)}sendQueueItems(){if(!this.isSendingQueue){for(this.isSendingQueue=!0;this.sendQueue.length>0;){let e=this.sendQueue.removeFirst();if(e==null)break;this.sendInternal(e)}this.isSendingQueue=!1}}},f=class{};export{h as HttpError,p as SSEClient,l as SSEDataEvent,d as WebSocketClient,m as configure,S as del,T as get,y as post,b as put,a as request,g as setFetch};
1
+ var u=class extends Error{constructor(e){super(e.statusReason),this.message=e.statusReason,this.response=e}},r={bearerTokenName:"jwt"},v=fetch;function g(s){v=s??fetch}function m(s){r={...r,...s},s.bearerTokenName===void 0&&(r.bearerTokenName="jwt")}async function a(s,e){if(r.bearerTokenName){let i=localStorage.getItem(r.bearerTokenName);if(i&&e){let o=e?.headers?new Headers(e.headers):new Headers;o.get("Authorization")||o.set("Authorization","Bearer "+i),e.headers=o}}r.timeout&&!e?.signal&&(e??={},e.signal=AbortSignal.timeout(r.timeout)),r.baseUrl&&(s[0]!=="/"&&r.baseUrl[r.baseUrl.length-1]!=="/"?s=`${r.baseUrl}/${s}`:s=r.baseUrl+s);let t=await v(s,e);if(!t.ok)return{statusCode:t.status,statusReason:t.statusText,success:!1,contentType:t.headers.get("content-type"),body:await t.text(),charset:t.headers.get("charset"),as(){throw new Error("No response received")}};let n=null;return t.status!==204&&(n=await t.json()),{success:!0,statusCode:t.status,statusReason:t.statusText,contentType:t.headers.get("content-type"),body:n,charset:t.headers.get("charset"),as(){return n}}}async function T(s,e,t){if(t?t.method="GET":t={method:"GET",headers:{"content-type":r.contentType??"application/json"}},e){let n="&";s.indexOf("?")===-1&&(n="?");for(let i in e){let o=e[i];s+=`${n}${i}=${o}`,n="&"}}return a(s,t)}async function y(s,e,t){return t?(t.method="POST",t.body=e):t={method:"POST",body:e,headers:{"content-type":r.contentType??"application/json"}},a(s,t)}async function b(s,e,t){return t?(t.method="PUT",t.body=e):t={method:"PUT",body:e,headers:{"content-type":r.contentType??"application/json"}},a(s,t)}async function S(s,e){return e?e.method="DELETE":e={method:"DELETE",headers:{"content-type":r.contentType??"application/json"}},a(s,e)}var l=class extends Event{constructor(t,n,i){super(t,{bubbles:!0,...i});this.data=n}},h=class{constructor(e,t){this.url=e;this.options=t;this.target=this.resolveTarget(t?.target)}get connected(){return this.eventSource?.readyState===EventSource.OPEN}connect(){if(this.eventSource)return;let e=new EventSource(this.url,{withCredentials:this.options?.withCredentials??!1});if(this.eventSource=e,e.onopen=()=>{this.options?.onConnect?.(this)},e.onerror=t=>{this.options?.onError?.(this,t)},this.options?.eventTypes&&this.options.eventTypes.length>0)for(let t of this.options.eventTypes)e.addEventListener(t,n=>{this.dispatchEvent(t,n.data)});else e.onmessage=t=>{this.dispatchEvent("message",t.data)}}disconnect(){this.eventSource?.close(),this.eventSource=void 0}resolveTarget(e){if(!e)return document;if(typeof e=="string"){let t=document.querySelector(e);if(!t)throw new Error(`SSEClient: Target element not found: ${e}`);return t}return e}dispatchEvent(e,t){let n;if(t.length>0&&(t[0]==="{"||t[0]==="["||t[0]==='"'))try{n=JSON.parse(t)}catch{n=t}else n=t;let i=this.options?.eventFactory?this.options.eventFactory(e,n):new l(e,n);this.target.dispatchEvent(i)}};var p=class{constructor(e,t){this.value=e;this.removeCallback=t;this.next=null;this.prev=null}remove(){this.prev&&(this.prev.next=this.next),this.next&&(this.next.prev=this.prev),this.removeCallback()}},c=class{constructor(){this._first=null;this._last=null;this._length=0}addFirst(e){let t=this.createNode(e);this._first?(t.next=this._first,this._first.prev=t,this._first=t):(this._first=t,this._last=this._first),this._length++}addLast(e){let t=this.createNode(e);this._last?(t.prev=this._last,this._last.next=t,this._last=t):(this._first=t,this._last=t),this._length++}createNode(e){let t;return t=new p(e,()=>{this._first===t&&(this._first=t.next),this._last===t&&(this._last=t.prev),this._length--}),t}removeFirst(){if(!this._first)throw new Error("The list is empty.");let e=this._first.value;return this._first=this._first.next,this._first||(this._last=null),this._length--,e}removeLast(){if(!this._last)throw new Error("The list is empty.");let e=this._last.value;return this._last=this._last.prev,this._last||(this._first=null),this._length--,e}get length(){return this._length}get first(){return this._first}get firstValue(){return this._first?.value}get last(){return this._last}get lastValue(){return this._last?.value}};var d=class{constructor(e,t){this.options=t;this.receiveQueue=new c;this.sendQueue=new c;this._isConnected=!1;this.isSendingQueue=!1;this.reconnectAttempts=0;this.shouldReconnect=!0;typeof e=="string"?this.url=e:this.wsFactory=e}get connected(){return this._isConnected}connect(){this.shouldReconnect=!0,this.reconnectAttempts=0,this.reConnect()}disconnect(){this.shouldReconnect=!1,this.ws?.close()}send(e){if(!this._isConnected||this.isSendingQueue){this.sendQueue.addLast(e);return}this.sendQueue.length>0&&this.sendQueueItems(),this.sendInternal(e)}receive(){if(this.receivePromiseWrapper)throw new Error("You can only invoke receive() once at a time.");if(this.receiveQueue.firstValue)return Promise.resolve(this.receiveQueue.removeFirst());let e=new f;return this.receivePromiseWrapper=e,new Promise((t,n)=>{e.resolve=t,e.reject=n})}onMessage(e){let t;if(this.options?.codec?t=this.options.codec.decode(e.data):typeof e.data=="string"&&e.data.length>0&&(e.data[0]==='"'||e.data[0]==="["||e.data[0]==="{")?t=JSON.parse(e.data):t=e.data,this.receivePromiseWrapper){this.receivePromiseWrapper.resolve(t),this.receivePromiseWrapper=void 0;return}this.receiveQueue.addLast(t)}reConnect(){let e=this.url?new WebSocket(this.url):this.wsFactory();this.ws=e,e.onmessage=t=>this.onMessage(t),e.onerror=()=>e.close(),e.onopen=()=>{this._isConnected=!0,this.reconnectAttempts=0,this.options?.onConnect?.(this),this.sendQueueItems()},e.onclose=()=>{if(this._isConnected=!1,this.receivePromiseWrapper&&(this.receivePromiseWrapper.reject(new Error("WebSocket connection closed")),this.receivePromiseWrapper=void 0),this.options?.onClose?.(this),this.shouldReconnect&&this.options?.autoReconnect!==!1){let t=this.options?.reconnectDelay??1e3,n=this.options?.maxReconnectDelay??3e4,i=Math.min(t*Math.pow(2,this.reconnectAttempts),n);this.reconnectAttempts++,setTimeout(()=>this.reConnect(),i)}}}sendInternal(e){let t;typeof e!="string"?this.options?.codec?t=this.options.codec.encode(e):t=JSON.stringify(e):t=e,this.ws.send(t)}sendQueueItems(){if(!this.isSendingQueue){for(this.isSendingQueue=!0;this.sendQueue.length>0;){let e=this.sendQueue.removeFirst();if(e==null)break;this.sendInternal(e)}this.isSendingQueue=!1}}},f=class{};export{u as HttpError,h as SSEClient,l as SSEDataEvent,d as WebSocketClient,m as configure,S as del,T as get,y as post,b as put,a as request,g as setFetch};
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/http/http.ts", "../../src/http/ServerSentEvents.ts", "../../src/collections/LinkedList.ts", "../../src/http/SimpleWebSocket.ts"],
4
- "sourcesContent": ["/**\r\n * @module http\r\n * Type-safe HTTP module built on fetch() with automatic JWT handling.\r\n *\r\n * @example\r\n * import { configure, get, post } from './http';\r\n *\r\n * configure({ baseUrl: '/api' });\r\n * const response = await get('/users');\r\n * const users = response.as<User[]>();\r\n */\r\n\r\n/**\r\n * Configuration options for the http module.\r\n */\r\nexport interface HttpOptions {\r\n /**\r\n * Root URL to remote endpoint. Used so that each method only has to specify path in requests.\r\n */\r\n baseUrl?: string;\r\n\r\n /**\r\n * Default content type to use if none is specified in the request method.\r\n */\r\n contentType?: string;\r\n\r\n /**\r\n * Checks for a JWT token in localStorage to automatically include it in requests.\r\n *\r\n * Undefined = use \"jwt\", null = disable.\r\n */\r\n bearerTokenName?: string | null;\r\n\r\n /**\r\n * Default request timeout in milliseconds.\r\n * Uses `AbortSignal.timeout()` to automatically abort requests that take too long.\r\n * Can be overridden per-request by passing a `signal` in `RequestInit`.\r\n *\r\n * @example\r\n * configure({ baseUrl: '/api', timeout: 10000 }); // 10 second timeout\r\n */\r\n timeout?: number;\r\n}\r\n\r\n/**\r\n * Response for request methods.\r\n */\r\nexport interface HttpResponse {\r\n /**\r\n * Http status code.\r\n */\r\n statusCode: number;\r\n\r\n /**\r\n * Reason to why the status code was used.\r\n */\r\n statusReason: string;\r\n\r\n /**\r\n * True if this is a 2xx response.\r\n */\r\n success: boolean;\r\n\r\n /**\r\n * Content type of response body.\r\n */\r\n contentType: string | null;\r\n\r\n /**\r\n * Body returned.\r\n *\r\n * Body has been read and deserialized from json (if the request content type was 'application/json' which is the default).\r\n */\r\n body: unknown;\r\n\r\n /**\r\n * Charset used in body.\r\n */\r\n charset: string | null;\r\n\r\n /**\r\n * Cast body to a type.\r\n */\r\n as<T>(): T;\r\n}\r\n\r\n/**\r\n * Error thrown when a request fails.\r\n */\r\nexport class HttpError extends Error {\r\n message: string;\r\n response: HttpResponse;\r\n\r\n constructor(response: HttpResponse) {\r\n super(response.statusReason);\r\n this.message = response.statusReason;\r\n this.response = response;\r\n }\r\n}\r\n\r\n/**\r\n * HTTP request options.\r\n */\r\nexport interface RequestOptions {\r\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE';\r\n mode?: 'cors' | 'no-cors' | '*cors' | 'same-origin';\r\n cache:\r\n | 'default'\r\n | 'no-store'\r\n | 'reload'\r\n | 'no-cache'\r\n | 'force-cache'\r\n | 'only-if-cached';\r\n credentials: 'omit' | 'same-origin' | 'include';\r\n headers: Map<string, string>;\r\n redirect: 'follow' | 'manual' | '*follow' | 'error';\r\n referrerPolicy:\r\n | 'no-referrer'\r\n | '*no-referrer-when-downgrade'\r\n | 'origin'\r\n | 'origin-when-cross-origin'\r\n | 'same-origin'\r\n | 'strict-origin'\r\n | 'strict-origin-when-cross-origin'\r\n | 'unsafe-url';\r\n\r\n /**\r\n * Will be serialized if the content type is json (and the body is an object).\r\n */\r\n body: unknown;\r\n}\r\n\r\n/** @internal */\r\ndeclare type FetchFn = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\r\n\r\nlet config: HttpOptions = {\r\n bearerTokenName: 'jwt'\r\n};\r\n\r\nlet fetchImpl: FetchFn = fetch;\r\n\r\n/**\r\n * Replace the fetch implementation for testing purposes.\r\n *\r\n * @param fn - Custom fetch function, or undefined to restore the default.\r\n *\r\n * @example\r\n * setFetch(async (url, options) => {\r\n * return new Response(JSON.stringify({ id: 1 }), { status: 200 });\r\n * });\r\n */\r\nexport function setFetch(fn?: FetchFn): void {\r\n fetchImpl = fn ?? fetch;\r\n}\r\n\r\n/**\r\n * Configure the http module.\r\n *\r\n * @example\r\n * configure({ baseUrl: '/api/v1', bearerTokenName: 'auth_token' });\r\n */\r\nexport function configure(options: HttpOptions): void {\r\n config = {\r\n ...config,\r\n ...options\r\n };\r\n if (options.bearerTokenName === undefined) {\r\n config.bearerTokenName = 'jwt';\r\n }\r\n}\r\n\r\n/**\r\n * Make an HTTP request.\r\n *\r\n * @param url - URL to make the request against.\r\n * @param options - Request options.\r\n * @returns Response from server.\r\n *\r\n * @example\r\n * const response = await request('/users', { method: 'GET' });\r\n */\r\nexport async function request(url: string, options?: RequestInit): Promise<HttpResponse> {\r\n if (config.bearerTokenName) {\r\n const token = localStorage.getItem(config.bearerTokenName);\r\n if (token && options) {\r\n const headers = options?.headers\r\n ? new Headers(options.headers)\r\n : new Headers();\r\n\r\n if (!headers.get('Authorization')) {\r\n headers.set('Authorization', 'Bearer ' + token);\r\n }\r\n\r\n options.headers = headers;\r\n }\r\n }\r\n\r\n if (config.timeout && !options?.signal) {\r\n options ??= {};\r\n options.signal = AbortSignal.timeout(config.timeout);\r\n }\r\n\r\n if (config.baseUrl) {\r\n if (url[0] !== '/' && config.baseUrl[config.baseUrl.length - 1] !== '/') {\r\n url = `${config.baseUrl}/${url}`;\r\n } else {\r\n url = config.baseUrl + url;\r\n }\r\n }\r\n\r\n const response = await fetchImpl(url, options);\r\n\r\n if (!response.ok) {\r\n return {\r\n statusCode: response.status,\r\n statusReason: response.statusText,\r\n success: false,\r\n contentType: response.headers.get('content-type'),\r\n body: await response.text(),\r\n charset: response.headers.get('charset'),\r\n\r\n as() {\r\n throw new Error('No response received');\r\n }\r\n };\r\n }\r\n\r\n let body: unknown | null = null;\r\n if (response.status !== 204) {\r\n body = await response.json();\r\n }\r\n\r\n return {\r\n success: true,\r\n statusCode: response.status,\r\n statusReason: response.statusText,\r\n contentType: response.headers.get('content-type'),\r\n body: body,\r\n charset: response.headers.get('charset'),\r\n as<T>() {\r\n return <T>body;\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * GET a resource.\r\n *\r\n * @param url - URL to get resource from.\r\n * @param queryString - Optional query string parameters.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await get('/users', { page: '1', limit: '10' });\r\n * const users = response.as<User[]>();\r\n */\r\nexport async function get(\r\n url: string,\r\n queryString?: Record<string, string>,\r\n options?: RequestInit\r\n): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'GET',\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'GET';\r\n }\r\n\r\n if (queryString) {\r\n let prefix = '&';\r\n if (url.indexOf('?') === -1) {\r\n prefix = '?';\r\n }\r\n\r\n for (const key in queryString) {\r\n const value = queryString[key];\r\n url += `${prefix}${key}=${value}`;\r\n prefix = '&';\r\n }\r\n }\r\n\r\n return request(url, options);\r\n}\r\n\r\n/**\r\n * POST a resource.\r\n *\r\n * @param url - URL to post to.\r\n * @param data - Data to post.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await post('/users', JSON.stringify({ name: 'John' }));\r\n */\r\nexport async function post(\r\n url: string,\r\n data: BodyInit,\r\n options?: RequestInit\r\n): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'POST',\r\n body: data,\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'POST';\r\n options.body = data;\r\n }\r\n\r\n return request(url, options);\r\n}\r\n\r\n/**\r\n * PUT a resource.\r\n *\r\n * @param url - URL to resource.\r\n * @param data - Data to put.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await put('/users/1', JSON.stringify({ name: 'Jane' }));\r\n */\r\nexport async function put(\r\n url: string,\r\n data: BodyInit,\r\n options?: RequestInit\r\n): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'PUT',\r\n body: data,\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'PUT';\r\n options.body = data;\r\n }\r\n\r\n return request(url, options);\r\n}\r\n\r\n/**\r\n * DELETE a resource.\r\n *\r\n * @param url - URL to resource.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await del('/users/1');\r\n */\r\nexport async function del(url: string, options?: RequestInit): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'DELETE',\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'DELETE';\r\n }\r\n\r\n return request(url, options);\r\n}\r\n", "/**\r\n * @module ServerSentEvents\r\n * SSE client that dispatches received events as DOM events.\r\n * Uses the browser's built-in EventSource reconnection.\r\n *\r\n * @example\r\n * const sse = new SSEClient('/api/events', {\r\n * eventTypes: ['user-updated', 'order-created']\r\n * });\r\n * sse.connect();\r\n *\r\n * document.addEventListener('user-updated', (e: SSEDataEvent) => {\r\n * console.log('User updated:', e.data);\r\n * });\r\n */\r\n\r\n/**\r\n * Event dispatched when an SSE message is received.\r\n * The event name matches the SSE event type.\r\n */\r\nexport class SSEDataEvent extends Event {\r\n constructor(\r\n eventName: string,\r\n public data: unknown,\r\n eventInit?: EventInit\r\n ) {\r\n super(eventName, { bubbles: true, ...eventInit });\r\n }\r\n}\r\n\r\n/**\r\n * Factory function for creating custom event instances.\r\n *\r\n * @example\r\n * const factory: SSEEventFactory = (eventName, data) => {\r\n * switch (eventName) {\r\n * case 'user-updated':\r\n * return new UserUpdatedEvent(data as User);\r\n * default:\r\n * return new SSEDataEvent(eventName, data);\r\n * }\r\n * };\r\n */\r\nexport type SSEEventFactory = (eventName: string, data: unknown) => Event;\r\n\r\n/**\r\n * Configuration options for SSEClient.\r\n */\r\nexport interface SSEOptions {\r\n /**\r\n * Target element or CSS selector for event dispatching.\r\n * Defaults to document.\r\n */\r\n target?: string | Element;\r\n\r\n /**\r\n * Whether to send credentials with the request (default: false).\r\n */\r\n withCredentials?: boolean;\r\n\r\n /**\r\n * Specific SSE event types to listen for.\r\n * If not specified, listens to the default 'message' event.\r\n *\r\n * @example\r\n * eventTypes: ['user-updated', 'order-created']\r\n */\r\n eventTypes?: string[];\r\n\r\n /**\r\n * Factory function for creating custom event instances.\r\n * If not provided, SSEDataEvent is used.\r\n *\r\n * @example\r\n * eventFactory: (name, data) => new MyCustomEvent(name, data)\r\n */\r\n eventFactory?: SSEEventFactory;\r\n\r\n /**\r\n * Callback when connection is established.\r\n */\r\n onConnect?: (client: SSEClient) => void;\r\n\r\n /**\r\n * Callback when an error occurs.\r\n * Note: EventSource automatically reconnects on errors.\r\n */\r\n onError?: (client: SSEClient, error: Event) => void;\r\n}\r\n\r\n/**\r\n * Server-Sent Events client that dispatches received events as DOM events.\r\n * Uses the browser's built-in EventSource with automatic reconnection.\r\n *\r\n * @example\r\n * const sse = new SSEClient('/api/events', {\r\n * target: '#notifications',\r\n * eventTypes: ['notification', 'alert']\r\n * });\r\n *\r\n * sse.connect();\r\n *\r\n * document.querySelector('#notifications')\r\n * .addEventListener('notification', (e: SSEDataEvent) => {\r\n * showNotification(e.data);\r\n * });\r\n *\r\n * sse.disconnect();\r\n */\r\nexport class SSEClient {\r\n private eventSource?: EventSource;\r\n private target: Element | Document;\r\n\r\n /**\r\n * Whether the client is currently connected.\r\n */\r\n get connected(): boolean {\r\n return this.eventSource?.readyState === EventSource.OPEN;\r\n }\r\n\r\n constructor(\r\n private url: string,\r\n private options?: SSEOptions\r\n ) {\r\n this.target = this.resolveTarget(options?.target);\r\n }\r\n\r\n /**\r\n * Establish connection to the SSE endpoint.\r\n */\r\n connect(): void {\r\n if (this.eventSource) {\r\n return;\r\n }\r\n\r\n const eventSource = new EventSource(this.url, {\r\n withCredentials: this.options?.withCredentials ?? false\r\n });\r\n\r\n this.eventSource = eventSource;\r\n\r\n eventSource.onopen = () => {\r\n this.options?.onConnect?.(this);\r\n };\r\n\r\n eventSource.onerror = (error) => {\r\n this.options?.onError?.(this, error);\r\n };\r\n\r\n if (this.options?.eventTypes && this.options.eventTypes.length > 0) {\r\n for (const eventType of this.options.eventTypes) {\r\n eventSource.addEventListener(eventType, (e: MessageEvent) => {\r\n this.dispatchEvent(eventType, e.data);\r\n });\r\n }\r\n } else {\r\n eventSource.onmessage = (e: MessageEvent) => {\r\n this.dispatchEvent('message', e.data);\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Close the connection.\r\n */\r\n disconnect(): void {\r\n this.eventSource?.close();\r\n this.eventSource = undefined;\r\n }\r\n\r\n private resolveTarget(target?: string | Element): Element | Document {\r\n if (!target) {\r\n return document;\r\n }\r\n if (typeof target === 'string') {\r\n const element = document.querySelector(target);\r\n if (!element) {\r\n throw new Error(`SSEClient: Target element not found: ${target}`);\r\n }\r\n return element;\r\n }\r\n return target;\r\n }\r\n\r\n private dispatchEvent(eventName: string, rawData: string): void {\r\n let data: unknown;\r\n\r\n if (rawData.length > 0 && (rawData[0] === '{' || rawData[0] === '[' || rawData[0] === '\"')) {\r\n try {\r\n data = JSON.parse(rawData);\r\n } catch {\r\n data = rawData;\r\n }\r\n } else {\r\n data = rawData;\r\n }\r\n\r\n const event = this.options?.eventFactory\r\n ? this.options.eventFactory(eventName, data)\r\n : new SSEDataEvent(eventName, data);\r\n\r\n this.target.dispatchEvent(event);\r\n }\r\n}\r\n", "/**\r\n * A node in the @see LinkedList.\r\n */\r\nexport class Node<T> {\r\n /**\r\n * Next node unless last one.\r\n */\r\n public next: Node<T> | null = null;\r\n /**\r\n * Previous node unless first one.\r\n */\r\n public prev: Node<T> | null = null;\r\n\r\n /**\r\n * Constructor.\r\n * @param value Value contained in the node.\r\n */\r\n constructor(public value: T, private removeCallback: () => void) {}\r\n\r\n /**\r\n * Remove this node.\r\n * Will notify the list of the update to ensure correct element count.\r\n */\r\n remove() {\r\n this.prev.next = this.next;\r\n this.next.prev = this.prev;\r\n this.removeCallback();\r\n }\r\n}\r\n\r\n/**\r\n * A trivial linked list implementation.\r\n */\r\nexport class LinkedList<T> {\r\n private _first?: Node<T>;\r\n private _last?: Node<T>;\r\n private _length = 0;\r\n\r\n /**\r\n * Add a value to the beginning of the list.\r\n * @param value Value that should be contained in the node.\r\n */\r\n addFirst(value: T) {\r\n const newNode = new Node(value, () => this._length--);\r\n if (!this._first) {\r\n this._first = newNode;\r\n this._last = this._first;\r\n } else {\r\n newNode.next = this._first;\r\n this._first.prev = newNode;\r\n this._first = newNode;\r\n }\r\n\r\n this._length++;\r\n }\r\n\r\n /**\r\n * Add a value to the end of the list.\r\n * @param value Value that should be contained in a node.\r\n */\r\n addLast(value: T) {\r\n const newNode = new Node(value, () => this._length--);\r\n if (!this._first) {\r\n this._first = newNode;\r\n this._last = this._first;\r\n } else {\r\n newNode.prev = this._last;\r\n this._last.next = newNode;\r\n this._last = newNode;\r\n }\r\n\r\n this._length++;\r\n }\r\n\r\n /**\r\n * Remove a node from the beginning of the list.\r\n * @returns Value contained in the first node.\r\n */\r\n removeFirst(): T {\r\n if (!this.first) {\r\n throw new Error('The list is empty.');\r\n }\r\n\r\n const value = this._first.value;\r\n this._first = this._first.next;\r\n this._length--;\r\n return value;\r\n }\r\n\r\n /**\r\n * Remove a node from the end of the list.\r\n * @returns Value contained in the last node.\r\n */\r\n removeLast(): T {\r\n if (!this.last) {\r\n throw new Error('The list is empty.');\r\n }\r\n\r\n const value = this._last.value;\r\n this._last = this._last.prev;\r\n this._length--;\r\n return value;\r\n }\r\n\r\n /**\r\n * Number of nodes in the list.\r\n *\r\n * The count works as long as you do not manually remove nodes (by assigning next/prev to the neighbors).\r\n */\r\n get length(): number {\r\n return this._length;\r\n }\r\n\r\n /**\r\n * First ndoe.\r\n */\r\n get first(): Node<T> | undefined {\r\n return this._first;\r\n }\r\n\r\n /**\r\n * Contained value of the first node.\r\n */\r\n get firstValue(): T | undefined {\r\n return this._first?.value;\r\n }\r\n\r\n /**\r\n * Last node.\r\n */\r\n get last(): Node<T> | undefined {\r\n return this._last;\r\n }\r\n\r\n /**\r\n * Contained value of the last node.\r\n */\r\n get lastValue(): T | undefined {\r\n return this._last?.value;\r\n }\r\n}\r\n", "/**\r\n * @module SimpleWebSocket\r\n * WebSocket client with automatic reconnection and message queuing.\r\n * Provides a reliable messaging layer over WebSocket connections.\r\n *\r\n * @example\r\n * // Create and connect\r\n * const ws = new WebSocketClient<ChatMessage>('wss://chat.example.com');\r\n * ws.connect();\r\n *\r\n * // Send and receive\r\n * await ws.send({ text: 'Hello' });\r\n * const msg = await ws.receive();\r\n */\r\n\r\nimport { LinkedList } from '../collections/LinkedList';\r\n\r\n/**\r\n * Simplified message event for WebSocket data.\r\n */\r\nexport interface SimpleDataEvent {\r\n data: string | ArrayBufferLike | Blob | ArrayBufferView;\r\n}\r\n\r\n/**\r\n * Abstraction interface for WebSocket to enable unit testing.\r\n * Implement this for custom WebSocket instances or mocks.\r\n */\r\nexport interface WebSocketAbstraction {\r\n onopen: ((event: Event) => void) | null;\r\n onerror: ((event: ErrorEvent) => void) | null;\r\n onclose: ((event: CloseEvent) => void) | null;\r\n onmessage: ((event: SimpleDataEvent) => void) | null;\r\n send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void;\r\n close(): void;\r\n}\r\n\r\n/**\r\n * Factory function type for creating WebSocket instances.\r\n */\r\nexport type WebSocketFactory = () => WebSocketAbstraction;\r\n\r\n/**\r\n * Managed WebSocket client with automatic reconnection and message queuing.\r\n *\r\n * Features:\r\n * - Automatic reconnection on disconnect\r\n * - Message queuing when disconnected\r\n * - Type-safe message handling with optional codecs\r\n * - Promise-based receive API\r\n *\r\n * @template TMessage - The type of messages sent and received\r\n *\r\n * @example\r\n * // Basic usage\r\n * interface ChatMessage { user: string; text: string; }\r\n *\r\n * const client = new WebSocketClient<ChatMessage>('wss://chat.example.com');\r\n * client.connect();\r\n *\r\n * // Send messages\r\n * await client.send({ user: 'John', text: 'Hello!' });\r\n *\r\n * // Receive messages\r\n * while (true) {\r\n * const message = await client.receive();\r\n * console.log(`${message.user}: ${message.text}`);\r\n * }\r\n *\r\n * @example\r\n * // With options\r\n * const client = new WebSocketClient<Message>('wss://api.example.com', {\r\n * autoReconnect: true,\r\n * onConnect: (socket) => console.log('Connected'),\r\n * onClose: () => console.log('Disconnected')\r\n * });\r\n */\r\nexport class WebSocketClient<TMessage> {\r\n private ws?: WebSocketAbstraction;\r\n private receiveQueue = new LinkedList<TMessage>();\r\n private receivePromiseWrapper?: PromiseWrapper<TMessage>;\r\n private sendQueue = new LinkedList<TMessage>();\r\n private _isConnected = false;\r\n private isSendingQueue = false;\r\n private url?: string;\r\n private wsFactory?: WebSocketFactory;\r\n private reconnectAttempts = 0;\r\n private shouldReconnect = true;\r\n\r\n get connected(): boolean {\r\n return this._isConnected;\r\n }\r\n\r\n constructor(\r\n urlOrWebSocketFactory: string | WebSocketFactory,\r\n private options?: WebSocketOptions<TMessage>\r\n ) {\r\n if (typeof urlOrWebSocketFactory === 'string') {\r\n this.url = urlOrWebSocketFactory;\r\n } else {\r\n this.wsFactory = urlOrWebSocketFactory;\r\n }\r\n }\r\n\r\n connect() {\r\n this.shouldReconnect = true;\r\n this.reconnectAttempts = 0;\r\n this.reConnect();\r\n }\r\n\r\n disconnect() {\r\n this.shouldReconnect = false;\r\n this.ws?.close();\r\n }\r\n\r\n send(data: TMessage): void {\r\n if (!this._isConnected || this.isSendingQueue) {\r\n this.sendQueue.addLast(data);\r\n return;\r\n }\r\n\r\n if (this.sendQueue.length > 0) {\r\n this.sendQueueItems();\r\n }\r\n\r\n this.sendInternal(data);\r\n }\r\n\r\n /**\r\n * Receive a new message.\r\n *\r\n * @throws Error if called while another receive() is pending.\r\n * @throws Error if connection closes while waiting.\r\n */\r\n receive(): Promise<TMessage> {\r\n if (this.receivePromiseWrapper) {\r\n throw new Error('You can only invoke receive() once at a time.');\r\n }\r\n\r\n if (this.receiveQueue.firstValue) {\r\n return Promise.resolve(this.receiveQueue.removeFirst());\r\n }\r\n\r\n this.receivePromiseWrapper = new PromiseWrapper();\r\n return new Promise((resolve, reject) => {\r\n this.receivePromiseWrapper.resolve = resolve;\r\n this.receivePromiseWrapper.reject = reject;\r\n });\r\n }\r\n\r\n private onMessage(ev: SimpleDataEvent) {\r\n let msg: TMessage;\r\n if (this.options?.codec) {\r\n msg = this.options.codec.decode(ev.data);\r\n } else if (typeof ev.data === 'string') {\r\n if (\r\n ev.data.length > 0 &&\r\n (ev.data[0] === '\"' || ev.data[0] === '[' || ev.data[0] === '{')\r\n ) {\r\n msg = JSON.parse(ev.data);\r\n } else {\r\n msg = ev.data as TMessage;\r\n }\r\n } else {\r\n msg = ev.data as TMessage;\r\n }\r\n\r\n if (this.receivePromiseWrapper) {\r\n this.receivePromiseWrapper.resolve(msg);\r\n this.receivePromiseWrapper = undefined;\r\n return;\r\n }\r\n\r\n this.receiveQueue.addLast(msg);\r\n }\r\n\r\n private reConnect() {\r\n const ws = this.url ? new WebSocket(this.url) : this.wsFactory();\r\n this.ws = ws;\r\n ws.onmessage = (evt: SimpleDataEvent) => this.onMessage(evt);\r\n ws.onerror = () => ws.close();\r\n ws.onopen = () => {\r\n this._isConnected = true;\r\n this.reconnectAttempts = 0;\r\n this.options?.onConnect?.(this);\r\n this.sendQueueItems();\r\n };\r\n ws.onclose = () => {\r\n this._isConnected = false;\r\n\r\n if (this.receivePromiseWrapper) {\r\n this.receivePromiseWrapper.reject(new Error('WebSocket connection closed'));\r\n this.receivePromiseWrapper = undefined;\r\n }\r\n\r\n this.options?.onClose?.(this);\r\n\r\n if (this.shouldReconnect && this.options?.autoReconnect !== false) {\r\n const baseDelay = this.options?.reconnectDelay ?? 1000;\r\n const maxDelay = this.options?.maxReconnectDelay ?? 30000;\r\n const delay = Math.min(baseDelay * Math.pow(2, this.reconnectAttempts), maxDelay);\r\n this.reconnectAttempts++;\r\n setTimeout(() => this.reConnect(), delay);\r\n }\r\n };\r\n }\r\n\r\n private sendInternal(data: TMessage) {\r\n let dataToSend: string | ArrayBufferLike | Blob | ArrayBufferView;\r\n if (typeof data !== 'string') {\r\n if (this.options?.codec) {\r\n dataToSend = this.options.codec.encode(data);\r\n } else {\r\n dataToSend = JSON.stringify(data);\r\n }\r\n } else {\r\n dataToSend = data;\r\n }\r\n\r\n this.ws.send(dataToSend);\r\n }\r\n\r\n private sendQueueItems(): void {\r\n if (this.isSendingQueue) {\r\n return;\r\n }\r\n\r\n this.isSendingQueue = true;\r\n while (this.sendQueue.length > 0) {\r\n const item = this.sendQueue.removeFirst();\r\n if (item == null) {\r\n break;\r\n }\r\n\r\n this.sendInternal(item);\r\n }\r\n\r\n this.isSendingQueue = false;\r\n }\r\n}\r\n\r\n/**\r\n * CODEC used for messages.\r\n */\r\nexport interface WebSocketCodec<TMessage> {\r\n /**\r\n *\r\n * @param data\r\n */\r\n encode(data: TMessage): string | ArrayBufferLike | Blob | ArrayBufferView;\r\n\r\n /**\r\n *\r\n * @param data\r\n */\r\n decode(data: string | ArrayBufferLike | Blob | ArrayBufferView): TMessage;\r\n}\r\n\r\n/**\r\n * Configuration options for @see WebSocketClient.\r\n */\r\nexport interface WebSocketOptions<TMessage> {\r\n /**\r\n * CODEC to use for inbound and outbound messages (if something else that JSON should be used).\r\n */\r\n codec?: WebSocketCodec<TMessage>;\r\n\r\n /**\r\n * Automatically reconnect when getting disconnected (default: true).\r\n */\r\n autoReconnect?: boolean;\r\n\r\n /**\r\n * Initial delay in milliseconds before reconnecting (default: 1000).\r\n * Uses exponential backoff on subsequent attempts.\r\n */\r\n reconnectDelay?: number;\r\n\r\n /**\r\n * Maximum delay in milliseconds between reconnect attempts (default: 30000).\r\n */\r\n maxReconnectDelay?: number;\r\n\r\n /**\r\n * Callback when the WS is connected.\r\n *\r\n * Can be used for authentication messages etc.\r\n *\r\n * @param socket Socket\r\n */\r\n onConnect?: (socket: WebSocketClient<TMessage>) => void;\r\n\r\n /**\r\n * Invoked when the connection is closed.\r\n *\r\n * The connection will be automatically reconnected if configured (on by default).\r\n *\r\n * @param socket Socket.\r\n */\r\n onClose?: (socket: WebSocketClient<TMessage>) => void;\r\n}\r\n\r\nclass PromiseWrapper<TMessage> {\r\n resolve!: (value: TMessage | PromiseLike<TMessage>) => void;\r\n reject!: (reason?: unknown) => void;\r\n}\r\n"],
5
- "mappings": "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",
6
- "names": ["HttpError", "response", "config", "fetchImpl", "setFetch", "fn", "configure", "options", "request", "url", "token", "headers", "body", "get", "queryString", "prefix", "key", "value", "post", "data", "put", "del", "SSEDataEvent", "eventName", "data", "eventInit", "SSEClient", "url", "options", "eventSource", "error", "eventType", "e", "target", "element", "rawData", "event", "Node", "value", "removeCallback", "LinkedList", "newNode", "WebSocketClient", "urlOrWebSocketFactory", "options", "LinkedList", "data", "PromiseWrapper", "resolve", "reject", "ev", "msg", "ws", "evt", "baseDelay", "maxDelay", "delay", "dataToSend", "item"]
4
+ "sourcesContent": ["/**\r\n * @module http\r\n * Type-safe HTTP module built on fetch() with automatic JWT handling.\r\n *\r\n * @example\r\n * import { configure, get, post } from './http';\r\n *\r\n * configure({ baseUrl: '/api' });\r\n * const response = await get('/users');\r\n * const users = response.as<User[]>();\r\n */\r\n\r\n/**\r\n * Configuration options for the http module.\r\n */\r\nexport interface HttpOptions {\r\n /**\r\n * Root URL to remote endpoint. Used so that each method only has to specify path in requests.\r\n */\r\n baseUrl?: string;\r\n\r\n /**\r\n * Default content type to use if none is specified in the request method.\r\n */\r\n contentType?: string;\r\n\r\n /**\r\n * Checks for a JWT token in localStorage to automatically include it in requests.\r\n *\r\n * Undefined = use \"jwt\", null = disable.\r\n */\r\n bearerTokenName?: string | null;\r\n\r\n /**\r\n * Default request timeout in milliseconds.\r\n * Uses `AbortSignal.timeout()` to automatically abort requests that take too long.\r\n * Can be overridden per-request by passing a `signal` in `RequestInit`.\r\n *\r\n * @example\r\n * configure({ baseUrl: '/api', timeout: 10000 }); // 10 second timeout\r\n */\r\n timeout?: number;\r\n}\r\n\r\n/**\r\n * Response for request methods.\r\n */\r\nexport interface HttpResponse {\r\n /**\r\n * Http status code.\r\n */\r\n statusCode: number;\r\n\r\n /**\r\n * Reason to why the status code was used.\r\n */\r\n statusReason: string;\r\n\r\n /**\r\n * True if this is a 2xx response.\r\n */\r\n success: boolean;\r\n\r\n /**\r\n * Content type of response body.\r\n */\r\n contentType: string | null;\r\n\r\n /**\r\n * Body returned.\r\n *\r\n * Body has been read and deserialized from json (if the request content type was 'application/json' which is the default).\r\n */\r\n body: unknown;\r\n\r\n /**\r\n * Charset used in body.\r\n */\r\n charset: string | null;\r\n\r\n /**\r\n * Cast body to a type.\r\n */\r\n as<T>(): T;\r\n}\r\n\r\n/**\r\n * Error thrown when a request fails.\r\n */\r\nexport class HttpError extends Error {\r\n message: string;\r\n response: HttpResponse;\r\n\r\n constructor(response: HttpResponse) {\r\n super(response.statusReason);\r\n this.message = response.statusReason;\r\n this.response = response;\r\n }\r\n}\r\n\r\n/**\r\n * HTTP request options.\r\n */\r\nexport interface RequestOptions {\r\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE';\r\n mode?: 'cors' | 'no-cors' | '*cors' | 'same-origin';\r\n cache:\r\n | 'default'\r\n | 'no-store'\r\n | 'reload'\r\n | 'no-cache'\r\n | 'force-cache'\r\n | 'only-if-cached';\r\n credentials: 'omit' | 'same-origin' | 'include';\r\n headers: Map<string, string>;\r\n redirect: 'follow' | 'manual' | '*follow' | 'error';\r\n referrerPolicy:\r\n | 'no-referrer'\r\n | '*no-referrer-when-downgrade'\r\n | 'origin'\r\n | 'origin-when-cross-origin'\r\n | 'same-origin'\r\n | 'strict-origin'\r\n | 'strict-origin-when-cross-origin'\r\n | 'unsafe-url';\r\n\r\n /**\r\n * Will be serialized if the content type is json (and the body is an object).\r\n */\r\n body: unknown;\r\n}\r\n\r\n/** @internal */\r\ndeclare type FetchFn = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\r\n\r\nlet config: HttpOptions = {\r\n bearerTokenName: 'jwt'\r\n};\r\n\r\nlet fetchImpl: FetchFn = fetch;\r\n\r\n/**\r\n * Replace the fetch implementation for testing purposes.\r\n *\r\n * @param fn - Custom fetch function, or undefined to restore the default.\r\n *\r\n * @example\r\n * setFetch(async (url, options) => {\r\n * return new Response(JSON.stringify({ id: 1 }), { status: 200 });\r\n * });\r\n */\r\nexport function setFetch(fn?: FetchFn): void {\r\n fetchImpl = fn ?? fetch;\r\n}\r\n\r\n/**\r\n * Configure the http module.\r\n *\r\n * @example\r\n * configure({ baseUrl: '/api/v1', bearerTokenName: 'auth_token' });\r\n */\r\nexport function configure(options: HttpOptions): void {\r\n config = {\r\n ...config,\r\n ...options\r\n };\r\n if (options.bearerTokenName === undefined) {\r\n config.bearerTokenName = 'jwt';\r\n }\r\n}\r\n\r\n/**\r\n * Make an HTTP request.\r\n *\r\n * @param url - URL to make the request against.\r\n * @param options - Request options.\r\n * @returns Response from server.\r\n *\r\n * @example\r\n * const response = await request('/users', { method: 'GET' });\r\n */\r\nexport async function request(url: string, options?: RequestInit): Promise<HttpResponse> {\r\n if (config.bearerTokenName) {\r\n const token = localStorage.getItem(config.bearerTokenName);\r\n if (token && options) {\r\n const headers = options?.headers\r\n ? new Headers(options.headers)\r\n : new Headers();\r\n\r\n if (!headers.get('Authorization')) {\r\n headers.set('Authorization', 'Bearer ' + token);\r\n }\r\n\r\n options.headers = headers;\r\n }\r\n }\r\n\r\n if (config.timeout && !options?.signal) {\r\n options ??= {};\r\n options.signal = AbortSignal.timeout(config.timeout);\r\n }\r\n\r\n if (config.baseUrl) {\r\n if (url[0] !== '/' && config.baseUrl[config.baseUrl.length - 1] !== '/') {\r\n url = `${config.baseUrl}/${url}`;\r\n } else {\r\n url = config.baseUrl + url;\r\n }\r\n }\r\n\r\n const response = await fetchImpl(url, options);\r\n\r\n if (!response.ok) {\r\n return {\r\n statusCode: response.status,\r\n statusReason: response.statusText,\r\n success: false,\r\n contentType: response.headers.get('content-type'),\r\n body: await response.text(),\r\n charset: response.headers.get('charset'),\r\n\r\n as() {\r\n throw new Error('No response received');\r\n }\r\n };\r\n }\r\n\r\n let body: unknown | null = null;\r\n if (response.status !== 204) {\r\n body = await response.json();\r\n }\r\n\r\n return {\r\n success: true,\r\n statusCode: response.status,\r\n statusReason: response.statusText,\r\n contentType: response.headers.get('content-type'),\r\n body: body,\r\n charset: response.headers.get('charset'),\r\n as<T>() {\r\n return <T>body;\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * GET a resource.\r\n *\r\n * @param url - URL to get resource from.\r\n * @param queryString - Optional query string parameters.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await get('/users', { page: '1', limit: '10' });\r\n * const users = response.as<User[]>();\r\n */\r\nexport async function get(\r\n url: string,\r\n queryString?: Record<string, string>,\r\n options?: RequestInit\r\n): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'GET',\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'GET';\r\n }\r\n\r\n if (queryString) {\r\n let prefix = '&';\r\n if (url.indexOf('?') === -1) {\r\n prefix = '?';\r\n }\r\n\r\n for (const key in queryString) {\r\n const value = queryString[key];\r\n url += `${prefix}${key}=${value}`;\r\n prefix = '&';\r\n }\r\n }\r\n\r\n return request(url, options);\r\n}\r\n\r\n/**\r\n * POST a resource.\r\n *\r\n * @param url - URL to post to.\r\n * @param data - Data to post.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await post('/users', JSON.stringify({ name: 'John' }));\r\n */\r\nexport async function post(\r\n url: string,\r\n data: BodyInit,\r\n options?: RequestInit\r\n): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'POST',\r\n body: data,\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'POST';\r\n options.body = data;\r\n }\r\n\r\n return request(url, options);\r\n}\r\n\r\n/**\r\n * PUT a resource.\r\n *\r\n * @param url - URL to resource.\r\n * @param data - Data to put.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await put('/users/1', JSON.stringify({ name: 'Jane' }));\r\n */\r\nexport async function put(\r\n url: string,\r\n data: BodyInit,\r\n options?: RequestInit\r\n): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'PUT',\r\n body: data,\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'PUT';\r\n options.body = data;\r\n }\r\n\r\n return request(url, options);\r\n}\r\n\r\n/**\r\n * DELETE a resource.\r\n *\r\n * @param url - URL to resource.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await del('/users/1');\r\n */\r\nexport async function del(url: string, options?: RequestInit): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'DELETE',\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'DELETE';\r\n }\r\n\r\n return request(url, options);\r\n}\r\n", "/**\r\n * @module ServerSentEvents\r\n * SSE client that dispatches received events as DOM events.\r\n * Uses the browser's built-in EventSource reconnection.\r\n *\r\n * @example\r\n * const sse = new SSEClient('/api/events', {\r\n * eventTypes: ['user-updated', 'order-created']\r\n * });\r\n * sse.connect();\r\n *\r\n * document.addEventListener('user-updated', (e: SSEDataEvent) => {\r\n * console.log('User updated:', e.data);\r\n * });\r\n */\r\n\r\n/**\r\n * Event dispatched when an SSE message is received.\r\n * The event name matches the SSE event type.\r\n */\r\nexport class SSEDataEvent extends Event {\r\n constructor(\r\n eventName: string,\r\n public data: unknown,\r\n eventInit?: EventInit\r\n ) {\r\n super(eventName, { bubbles: true, ...eventInit });\r\n }\r\n}\r\n\r\n/**\r\n * Factory function for creating custom event instances.\r\n *\r\n * @example\r\n * const factory: SSEEventFactory = (eventName, data) => {\r\n * switch (eventName) {\r\n * case 'user-updated':\r\n * return new UserUpdatedEvent(data as User);\r\n * default:\r\n * return new SSEDataEvent(eventName, data);\r\n * }\r\n * };\r\n */\r\nexport type SSEEventFactory = (eventName: string, data: unknown) => Event;\r\n\r\n/**\r\n * Configuration options for SSEClient.\r\n */\r\nexport interface SSEOptions {\r\n /**\r\n * Target element or CSS selector for event dispatching.\r\n * Defaults to document.\r\n */\r\n target?: string | Element;\r\n\r\n /**\r\n * Whether to send credentials with the request (default: false).\r\n */\r\n withCredentials?: boolean;\r\n\r\n /**\r\n * Specific SSE event types to listen for.\r\n * If not specified, listens to the default 'message' event.\r\n *\r\n * @example\r\n * eventTypes: ['user-updated', 'order-created']\r\n */\r\n eventTypes?: string[];\r\n\r\n /**\r\n * Factory function for creating custom event instances.\r\n * If not provided, SSEDataEvent is used.\r\n *\r\n * @example\r\n * eventFactory: (name, data) => new MyCustomEvent(name, data)\r\n */\r\n eventFactory?: SSEEventFactory;\r\n\r\n /**\r\n * Callback when connection is established.\r\n */\r\n onConnect?: (client: SSEClient) => void;\r\n\r\n /**\r\n * Callback when an error occurs.\r\n * Note: EventSource automatically reconnects on errors.\r\n */\r\n onError?: (client: SSEClient, error: Event) => void;\r\n}\r\n\r\n/**\r\n * Server-Sent Events client that dispatches received events as DOM events.\r\n * Uses the browser's built-in EventSource with automatic reconnection.\r\n *\r\n * @example\r\n * const sse = new SSEClient('/api/events', {\r\n * target: '#notifications',\r\n * eventTypes: ['notification', 'alert']\r\n * });\r\n *\r\n * sse.connect();\r\n *\r\n * document.querySelector('#notifications')\r\n * .addEventListener('notification', (e: SSEDataEvent) => {\r\n * showNotification(e.data);\r\n * });\r\n *\r\n * sse.disconnect();\r\n */\r\nexport class SSEClient {\r\n private eventSource?: EventSource;\r\n private target: Element | Document;\r\n\r\n /**\r\n * Whether the client is currently connected.\r\n */\r\n get connected(): boolean {\r\n return this.eventSource?.readyState === EventSource.OPEN;\r\n }\r\n\r\n constructor(\r\n private url: string,\r\n private options?: SSEOptions\r\n ) {\r\n this.target = this.resolveTarget(options?.target);\r\n }\r\n\r\n /**\r\n * Establish connection to the SSE endpoint.\r\n */\r\n connect(): void {\r\n if (this.eventSource) {\r\n return;\r\n }\r\n\r\n const eventSource = new EventSource(this.url, {\r\n withCredentials: this.options?.withCredentials ?? false\r\n });\r\n\r\n this.eventSource = eventSource;\r\n\r\n eventSource.onopen = () => {\r\n this.options?.onConnect?.(this);\r\n };\r\n\r\n eventSource.onerror = (error) => {\r\n this.options?.onError?.(this, error);\r\n };\r\n\r\n if (this.options?.eventTypes && this.options.eventTypes.length > 0) {\r\n for (const eventType of this.options.eventTypes) {\r\n eventSource.addEventListener(eventType, (e: MessageEvent) => {\r\n this.dispatchEvent(eventType, e.data);\r\n });\r\n }\r\n } else {\r\n eventSource.onmessage = (e: MessageEvent) => {\r\n this.dispatchEvent('message', e.data);\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Close the connection.\r\n */\r\n disconnect(): void {\r\n this.eventSource?.close();\r\n this.eventSource = undefined;\r\n }\r\n\r\n private resolveTarget(target?: string | Element): Element | Document {\r\n if (!target) {\r\n return document;\r\n }\r\n if (typeof target === 'string') {\r\n const element = document.querySelector(target);\r\n if (!element) {\r\n throw new Error(`SSEClient: Target element not found: ${target}`);\r\n }\r\n return element;\r\n }\r\n return target;\r\n }\r\n\r\n private dispatchEvent(eventName: string, rawData: string): void {\r\n let data: unknown;\r\n\r\n if (rawData.length > 0 && (rawData[0] === '{' || rawData[0] === '[' || rawData[0] === '\"')) {\r\n try {\r\n data = JSON.parse(rawData);\r\n } catch {\r\n data = rawData;\r\n }\r\n } else {\r\n data = rawData;\r\n }\r\n\r\n const event = this.options?.eventFactory\r\n ? this.options.eventFactory(eventName, data)\r\n : new SSEDataEvent(eventName, data);\r\n\r\n this.target.dispatchEvent(event);\r\n }\r\n}\r\n", "/**\r\n * A node in the @see LinkedList.\r\n */\r\nexport class Node<T> {\r\n /**\r\n * Next node unless last one.\r\n */\r\n public next: Node<T> | null = null;\r\n /**\r\n * Previous node unless first one.\r\n */\r\n public prev: Node<T> | null = null;\r\n\r\n /**\r\n * Constructor.\r\n * @param value Value contained in the node.\r\n */\r\n constructor(public value: T, private removeCallback: () => void) {}\r\n\r\n /**\r\n * Remove this node.\r\n * Will notify the list of the update to ensure correct element count.\r\n */\r\n remove() {\r\n if (this.prev) this.prev.next = this.next;\r\n if (this.next) this.next.prev = this.prev;\r\n this.removeCallback();\r\n }\r\n}\r\n\r\n/**\r\n * A trivial linked list implementation.\r\n */\r\nexport class LinkedList<T> {\r\n private _first: Node<T> | null = null;\r\n private _last: Node<T> | null = null;\r\n private _length = 0;\r\n\r\n /**\r\n * Add a value to the beginning of the list.\r\n * @param value Value that should be contained in the node.\r\n */\r\n addFirst(value: T) {\r\n const newNode = this.createNode(value);\r\n if (!this._first) {\r\n this._first = newNode;\r\n this._last = this._first;\r\n } else {\r\n newNode.next = this._first;\r\n this._first.prev = newNode;\r\n this._first = newNode;\r\n }\r\n\r\n this._length++;\r\n }\r\n\r\n /**\r\n * Add a value to the end of the list.\r\n * @param value Value that should be contained in a node.\r\n */\r\n addLast(value: T) {\r\n const newNode = this.createNode(value);\r\n if (!this._last) {\r\n this._first = newNode;\r\n this._last = newNode;\r\n } else {\r\n newNode.prev = this._last;\r\n this._last.next = newNode;\r\n this._last = newNode;\r\n }\r\n\r\n this._length++;\r\n }\r\n\r\n private createNode(value: T): Node<T> {\r\n let node: Node<T>;\r\n node = new Node(value, () => {\r\n if (this._first === node) this._first = node.next;\r\n if (this._last === node) this._last = node.prev;\r\n this._length--;\r\n });\r\n return node;\r\n }\r\n\r\n /**\r\n * Remove a node from the beginning of the list.\r\n * @returns Value contained in the first node.\r\n */\r\n removeFirst(): T {\r\n if (!this._first) {\r\n throw new Error('The list is empty.');\r\n }\r\n\r\n const value = this._first.value;\r\n this._first = this._first.next;\r\n if (!this._first) this._last = null;\r\n this._length--;\r\n return value;\r\n }\r\n\r\n /**\r\n * Remove a node from the end of the list.\r\n * @returns Value contained in the last node.\r\n */\r\n removeLast(): T {\r\n if (!this._last) {\r\n throw new Error('The list is empty.');\r\n }\r\n\r\n const value = this._last.value;\r\n this._last = this._last.prev;\r\n if (!this._last) this._first = null;\r\n this._length--;\r\n return value;\r\n }\r\n\r\n /**\r\n * Number of nodes in the list.\r\n *\r\n * The count works as long as you do not manually remove nodes (by assigning next/prev to the neighbors).\r\n */\r\n get length(): number {\r\n return this._length;\r\n }\r\n\r\n /**\r\n * First node, or `null` if the list is empty.\r\n */\r\n get first(): Node<T> | null {\r\n return this._first;\r\n }\r\n\r\n /**\r\n * Contained value of the first node, or `undefined` if the list is empty.\r\n */\r\n get firstValue(): T | undefined {\r\n return this._first?.value;\r\n }\r\n\r\n /**\r\n * Last node, or `null` if the list is empty.\r\n */\r\n get last(): Node<T> | null {\r\n return this._last;\r\n }\r\n\r\n /**\r\n * Contained value of the last node, or `undefined` if the list is empty.\r\n */\r\n get lastValue(): T | undefined {\r\n return this._last?.value;\r\n }\r\n}\r\n", "/**\r\n * @module SimpleWebSocket\r\n * WebSocket client with automatic reconnection and message queuing.\r\n * Provides a reliable messaging layer over WebSocket connections.\r\n *\r\n * @example\r\n * // Create and connect\r\n * const ws = new WebSocketClient<ChatMessage>('wss://chat.example.com');\r\n * ws.connect();\r\n *\r\n * // Send and receive\r\n * await ws.send({ text: 'Hello' });\r\n * const msg = await ws.receive();\r\n */\r\n\r\nimport { LinkedList } from '../collections/LinkedList';\r\n\r\n/**\r\n * Simplified message event for WebSocket data.\r\n */\r\nexport interface SimpleDataEvent {\r\n data: string | ArrayBufferLike | Blob | ArrayBufferView;\r\n}\r\n\r\n/**\r\n * Abstraction interface for WebSocket to enable unit testing.\r\n * Implement this for custom WebSocket instances or mocks.\r\n */\r\nexport interface WebSocketAbstraction {\r\n onopen: ((event: Event) => void) | null;\r\n onerror: ((event: ErrorEvent) => void) | null;\r\n onclose: ((event: CloseEvent) => void) | null;\r\n onmessage: ((event: SimpleDataEvent) => void) | null;\r\n send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void;\r\n close(): void;\r\n}\r\n\r\n/**\r\n * Factory function type for creating WebSocket instances.\r\n */\r\nexport type WebSocketFactory = () => WebSocketAbstraction;\r\n\r\n/**\r\n * Managed WebSocket client with automatic reconnection and message queuing.\r\n *\r\n * Features:\r\n * - Automatic reconnection on disconnect\r\n * - Message queuing when disconnected\r\n * - Type-safe message handling with optional codecs\r\n * - Promise-based receive API\r\n *\r\n * @template TMessage - The type of messages sent and received\r\n *\r\n * @example\r\n * // Basic usage\r\n * interface ChatMessage { user: string; text: string; }\r\n *\r\n * const client = new WebSocketClient<ChatMessage>('wss://chat.example.com');\r\n * client.connect();\r\n *\r\n * // Send messages\r\n * await client.send({ user: 'John', text: 'Hello!' });\r\n *\r\n * // Receive messages\r\n * while (true) {\r\n * const message = await client.receive();\r\n * console.log(`${message.user}: ${message.text}`);\r\n * }\r\n *\r\n * @example\r\n * // With options\r\n * const client = new WebSocketClient<Message>('wss://api.example.com', {\r\n * autoReconnect: true,\r\n * onConnect: (socket) => console.log('Connected'),\r\n * onClose: () => console.log('Disconnected')\r\n * });\r\n */\r\nexport class WebSocketClient<TMessage> {\r\n private ws?: WebSocketAbstraction;\r\n private receiveQueue = new LinkedList<TMessage>();\r\n private receivePromiseWrapper?: PromiseWrapper<TMessage>;\r\n private sendQueue = new LinkedList<TMessage>();\r\n private _isConnected = false;\r\n private isSendingQueue = false;\r\n private url?: string;\r\n private wsFactory?: WebSocketFactory;\r\n private reconnectAttempts = 0;\r\n private shouldReconnect = true;\r\n\r\n get connected(): boolean {\r\n return this._isConnected;\r\n }\r\n\r\n constructor(\r\n urlOrWebSocketFactory: string | WebSocketFactory,\r\n private options?: WebSocketOptions<TMessage>\r\n ) {\r\n if (typeof urlOrWebSocketFactory === 'string') {\r\n this.url = urlOrWebSocketFactory;\r\n } else {\r\n this.wsFactory = urlOrWebSocketFactory;\r\n }\r\n }\r\n\r\n connect() {\r\n this.shouldReconnect = true;\r\n this.reconnectAttempts = 0;\r\n this.reConnect();\r\n }\r\n\r\n disconnect() {\r\n this.shouldReconnect = false;\r\n this.ws?.close();\r\n }\r\n\r\n send(data: TMessage): void {\r\n if (!this._isConnected || this.isSendingQueue) {\r\n this.sendQueue.addLast(data);\r\n return;\r\n }\r\n\r\n if (this.sendQueue.length > 0) {\r\n this.sendQueueItems();\r\n }\r\n\r\n this.sendInternal(data);\r\n }\r\n\r\n /**\r\n * Receive a new message.\r\n *\r\n * @throws Error if called while another receive() is pending.\r\n * @throws Error if connection closes while waiting.\r\n */\r\n receive(): Promise<TMessage> {\r\n if (this.receivePromiseWrapper) {\r\n throw new Error('You can only invoke receive() once at a time.');\r\n }\r\n\r\n if (this.receiveQueue.firstValue) {\r\n return Promise.resolve(this.receiveQueue.removeFirst());\r\n }\r\n\r\n const wrapper = new PromiseWrapper<TMessage>();\r\n this.receivePromiseWrapper = wrapper;\r\n return new Promise((resolve, reject) => {\r\n wrapper.resolve = resolve;\r\n wrapper.reject = reject;\r\n });\r\n }\r\n\r\n private onMessage(ev: SimpleDataEvent) {\r\n let msg: TMessage;\r\n if (this.options?.codec) {\r\n msg = this.options.codec.decode(ev.data);\r\n } else if (typeof ev.data === 'string') {\r\n if (\r\n ev.data.length > 0 &&\r\n (ev.data[0] === '\"' || ev.data[0] === '[' || ev.data[0] === '{')\r\n ) {\r\n msg = JSON.parse(ev.data);\r\n } else {\r\n msg = ev.data as TMessage;\r\n }\r\n } else {\r\n msg = ev.data as TMessage;\r\n }\r\n\r\n if (this.receivePromiseWrapper) {\r\n this.receivePromiseWrapper.resolve(msg);\r\n this.receivePromiseWrapper = undefined;\r\n return;\r\n }\r\n\r\n this.receiveQueue.addLast(msg);\r\n }\r\n\r\n private reConnect() {\r\n const ws: WebSocketAbstraction = this.url\r\n ? (new WebSocket(this.url) as unknown as WebSocketAbstraction)\r\n : this.wsFactory!();\r\n this.ws = ws;\r\n ws.onmessage = (evt: SimpleDataEvent) => this.onMessage(evt);\r\n ws.onerror = () => ws.close();\r\n ws.onopen = () => {\r\n this._isConnected = true;\r\n this.reconnectAttempts = 0;\r\n this.options?.onConnect?.(this);\r\n this.sendQueueItems();\r\n };\r\n ws.onclose = () => {\r\n this._isConnected = false;\r\n\r\n if (this.receivePromiseWrapper) {\r\n this.receivePromiseWrapper.reject(new Error('WebSocket connection closed'));\r\n this.receivePromiseWrapper = undefined;\r\n }\r\n\r\n this.options?.onClose?.(this);\r\n\r\n if (this.shouldReconnect && this.options?.autoReconnect !== false) {\r\n const baseDelay = this.options?.reconnectDelay ?? 1000;\r\n const maxDelay = this.options?.maxReconnectDelay ?? 30000;\r\n const delay = Math.min(baseDelay * Math.pow(2, this.reconnectAttempts), maxDelay);\r\n this.reconnectAttempts++;\r\n setTimeout(() => this.reConnect(), delay);\r\n }\r\n };\r\n }\r\n\r\n private sendInternal(data: TMessage) {\r\n let dataToSend: string | ArrayBufferLike | Blob | ArrayBufferView;\r\n if (typeof data !== 'string') {\r\n if (this.options?.codec) {\r\n dataToSend = this.options.codec.encode(data);\r\n } else {\r\n dataToSend = JSON.stringify(data);\r\n }\r\n } else {\r\n dataToSend = data;\r\n }\r\n\r\n this.ws!.send(dataToSend);\r\n }\r\n\r\n private sendQueueItems(): void {\r\n if (this.isSendingQueue) {\r\n return;\r\n }\r\n\r\n this.isSendingQueue = true;\r\n while (this.sendQueue.length > 0) {\r\n const item = this.sendQueue.removeFirst();\r\n if (item == null) {\r\n break;\r\n }\r\n\r\n this.sendInternal(item);\r\n }\r\n\r\n this.isSendingQueue = false;\r\n }\r\n}\r\n\r\n/**\r\n * CODEC used for messages.\r\n */\r\nexport interface WebSocketCodec<TMessage> {\r\n /**\r\n *\r\n * @param data\r\n */\r\n encode(data: TMessage): string | ArrayBufferLike | Blob | ArrayBufferView;\r\n\r\n /**\r\n *\r\n * @param data\r\n */\r\n decode(data: string | ArrayBufferLike | Blob | ArrayBufferView): TMessage;\r\n}\r\n\r\n/**\r\n * Configuration options for @see WebSocketClient.\r\n */\r\nexport interface WebSocketOptions<TMessage> {\r\n /**\r\n * CODEC to use for inbound and outbound messages (if something else that JSON should be used).\r\n */\r\n codec?: WebSocketCodec<TMessage>;\r\n\r\n /**\r\n * Automatically reconnect when getting disconnected (default: true).\r\n */\r\n autoReconnect?: boolean;\r\n\r\n /**\r\n * Initial delay in milliseconds before reconnecting (default: 1000).\r\n * Uses exponential backoff on subsequent attempts.\r\n */\r\n reconnectDelay?: number;\r\n\r\n /**\r\n * Maximum delay in milliseconds between reconnect attempts (default: 30000).\r\n */\r\n maxReconnectDelay?: number;\r\n\r\n /**\r\n * Callback when the WS is connected.\r\n *\r\n * Can be used for authentication messages etc.\r\n *\r\n * @param socket Socket\r\n */\r\n onConnect?: (socket: WebSocketClient<TMessage>) => void;\r\n\r\n /**\r\n * Invoked when the connection is closed.\r\n *\r\n * The connection will be automatically reconnected if configured (on by default).\r\n *\r\n * @param socket Socket.\r\n */\r\n onClose?: (socket: WebSocketClient<TMessage>) => void;\r\n}\r\n\r\nclass PromiseWrapper<TMessage> {\r\n resolve!: (value: TMessage | PromiseLike<TMessage>) => void;\r\n reject!: (reason?: unknown) => void;\r\n}\r\n"],
5
+ "mappings": "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",
6
+ "names": ["HttpError", "response", "config", "fetchImpl", "setFetch", "fn", "configure", "options", "request", "url", "token", "headers", "body", "get", "queryString", "prefix", "key", "value", "post", "data", "put", "del", "SSEDataEvent", "eventName", "data", "eventInit", "SSEClient", "url", "options", "eventSource", "error", "eventType", "e", "target", "element", "rawData", "event", "Node", "value", "removeCallback", "LinkedList", "newNode", "node", "WebSocketClient", "urlOrWebSocketFactory", "options", "LinkedList", "data", "wrapper", "PromiseWrapper", "resolve", "reject", "ev", "msg", "ws", "evt", "baseDelay", "maxDelay", "delay", "dataToSend", "item"]
7
7
  }
@@ -40,7 +40,7 @@ export type MessageFormatter = (message: string, values?: Record<string, any>, l
40
40
  * defaultFormatICU('{role, select, admin {Full access} other {Limited access}}', { role: 'admin' });
41
41
  * // Returns: 'Full access'
42
42
  */
43
- export declare function defaultFormatICU(message: string, values: Record<string, any>, locale?: string): string;
43
+ export declare function defaultFormatICU(message: string, values?: Record<string, any>, locale?: string): string;
44
44
  /**
45
45
  * The active message formatter. Defaults to `defaultFormatICU`.
46
46
  * Can be replaced with `setMessageFormatter` for custom formatting.
@@ -1,2 +1,2 @@
1
- var z=Object.create;var m=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var O=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,B=Object.prototype.hasOwnProperty;var b=e=>t=>{var n=e[t];if(n)return n();throw new Error("Module not found in bundle: "+t)};var i=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),G=(e,t)=>{for(var n in t)m(e,n,{get:t[n],enumerable:!0})},v=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of O(t))!B.call(e,r)&&r!==n&&m(e,r,{get:()=>t[r],enumerable:!(o=D(t,r))||o.enumerable});return e};var l=(e,t,n)=>(n=e!=null?z(_(e)):{},v(t||!e||!e.__esModule?m(n,"default",{value:e,enumerable:!0}):n,e)),J=e=>v(m({},"__esModule",{value:!0}),e);var N=i((se,W)=>{W.exports={greeting:"Hello, {name}!",items:"{count, plural, one {# item} other {# items}}"}});var E=i((oe,X)=>{X.exports={today:"today",yesterday:"yesterday",daysAgo:"{count, plural, one {# day ago} other {# days ago}}",pieces:"{count, plural, =0 {none} one {one} other {# pcs}}"}});var S=i((ie,Y)=>{Y.exports={required:"This field is required.",range:"Number must be between {min} and {max}, was {actual}.",digits:"Please enter only digits."}});var C=i((le,Z)=>{Z.exports={greeting:"Hej, {name}!",items:"{count, plural, one {# sak} other {# saker}}"}});var F=i((ce,K)=>{K.exports={today:"idag",yesterday:"ig\xE5r",daysAgo:"{count, plural, one {# dag sedan} other {# dagar sedan}}",pieces:"{count, plural, =0 {inga} one {en} other {# st}}"}});var H=i((ge,ee)=>{ee.exports={required:"Detta f\xE4lt \xE4r obligatoriskt.",range:"Talet m\xE5ste vara mellan {min} och {max}, var {actual}.",digits:"Ange endast siffror."}});var ne={};G(ne,{LocaleChangeEvent:()=>u,formatICU:()=>g,getCurrentLocale:()=>j,loadNamespace:()=>x,loadNamespaces:()=>P,onMissingTranslation:()=>q,setLocale:()=>k,setMessageFormatter:()=>T,t:()=>U});module.exports=J(ne);var h=new Map;function Q(e){return h.has(e)||h.set(e,new Intl.PluralRules(e)),h.get(e)}function L(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function V(e,t,n="en"){return e.replace(/\{(\w+)(?:, (plural|select),((?:[^{}]*\{[^{}]*\})+))?\}/g,(o,r,R,c)=>{let a=t[r];if(R==="plural"){let p=new RegExp(`=${L(String(a))}\\s*\\{([^{}]*)\\}`).exec(c);if(p)return p[1].replace(`{${r}}`,String(a)).replace("#",String(a));let A=Q(n).select(a),$=new RegExp(`${A}\\s*\\{([^{}]*)\\}`).exec(c)||new RegExp("other\\s*\\{([^{}]*)\\}").exec(c);return $?$[1].replace(`{${r}}`,String(a)).replace("#",String(a)):String(a)}if(R==="select"){let p=L(String(a)),y=new RegExp(`\\b${p}\\s*\\{([^{}]*)\\}`).exec(c)||new RegExp("\\bother\\s*\\{([^{}]*)\\}").exec(c);return y?y[1]:String(a)}return a!==void 0?String(a):`{${r}}`})}var g=V;function T(e){g=e}var I=b({"./locales/en/r-common.json":()=>Promise.resolve().then(()=>l(N())),"./locales/en/r-pipes.json":()=>Promise.resolve().then(()=>l(E())),"./locales/en/r-validation.json":()=>Promise.resolve().then(()=>l(S())),"./locales/sv/r-common.json":()=>Promise.resolve().then(()=>l(C())),"./locales/sv/r-pipes.json":()=>Promise.resolve().then(()=>l(F())),"./locales/sv/r-validation.json":()=>Promise.resolve().then(()=>l(H()))});var u=class extends Event{constructor(t){super("localechange",{bubbles:!1}),this.locale=t}},w="en",s=w,f=new Set,d={},M=null;function te(e){return e.toLowerCase().split("-")[0]}async function k(e){let t=te(e);s=t,f.clear(),Object.keys(d).forEach(n=>delete d[n]),await x("r-common"),typeof document<"u"&&document.dispatchEvent(new u(t))}async function x(e){if(!f.has(e))try{let t=await I(`./locales/${s}/${e}.json`);d[e]=t.default,f.add(e)}catch{if(s!==w){let n=await I(`./locales/${w}/${e}.json`);d[e]=n.default,f.add(e)}else console.warn(`i18n: Failed to load namespace '${e}' for locale '${s}'`)}}async function P(e){await Promise.all(e.map(t=>x(t)))}function U(e,t){let[n,o]=e.includes(":")?e.split(":"):["r-common",e],r=d[n]?.[o];if(!r)return M&&M(o,n,s),e;try{return g(r,t,s)}catch{return e}}function j(){return s}function q(e){M=e}
1
+ "use strict";var z=Object.create;var m=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var O=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,B=Object.prototype.hasOwnProperty;var b=e=>t=>{var n=e[t];if(n)return n();throw new Error("Module not found in bundle: "+t)};var i=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),G=(e,t)=>{for(var n in t)m(e,n,{get:t[n],enumerable:!0})},v=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of O(t))!B.call(e,r)&&r!==n&&m(e,r,{get:()=>t[r],enumerable:!(o=D(t,r))||o.enumerable});return e};var l=(e,t,n)=>(n=e!=null?z(_(e)):{},v(t||!e||!e.__esModule?m(n,"default",{value:e,enumerable:!0}):n,e)),J=e=>v(m({},"__esModule",{value:!0}),e);var N=i((se,W)=>{W.exports={greeting:"Hello, {name}!",items:"{count, plural, one {# item} other {# items}}"}});var E=i((oe,X)=>{X.exports={today:"today",yesterday:"yesterday",daysAgo:"{count, plural, one {# day ago} other {# days ago}}",pieces:"{count, plural, =0 {none} one {one} other {# pcs}}"}});var S=i((ie,Y)=>{Y.exports={required:"This field is required.",range:"Number must be between {min} and {max}, was {actual}.",digits:"Please enter only digits."}});var C=i((le,Z)=>{Z.exports={greeting:"Hej, {name}!",items:"{count, plural, one {# sak} other {# saker}}"}});var F=i((ce,K)=>{K.exports={today:"idag",yesterday:"ig\xE5r",daysAgo:"{count, plural, one {# dag sedan} other {# dagar sedan}}",pieces:"{count, plural, =0 {inga} one {en} other {# st}}"}});var H=i((ge,ee)=>{ee.exports={required:"Detta f\xE4lt \xE4r obligatoriskt.",range:"Talet m\xE5ste vara mellan {min} och {max}, var {actual}.",digits:"Ange endast siffror."}});var ne={};G(ne,{LocaleChangeEvent:()=>u,formatICU:()=>g,getCurrentLocale:()=>j,loadNamespace:()=>x,loadNamespaces:()=>P,onMissingTranslation:()=>q,setLocale:()=>k,setMessageFormatter:()=>T,t:()=>U});module.exports=J(ne);var h=new Map;function Q(e){return h.has(e)||h.set(e,new Intl.PluralRules(e)),h.get(e)}function L(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function V(e,t,n="en"){return e.replace(/\{(\w+)(?:, (plural|select),((?:[^{}]*\{[^{}]*\})+))?\}/g,(o,r,R,c)=>{let a=t?.[r];if(R==="plural"){let p=new RegExp(`=${L(String(a))}\\s*\\{([^{}]*)\\}`).exec(c);if(p)return p[1].replace(`{${r}}`,String(a)).replace("#",String(a));let A=Q(n).select(a),$=new RegExp(`${A}\\s*\\{([^{}]*)\\}`).exec(c)||new RegExp("other\\s*\\{([^{}]*)\\}").exec(c);return $?$[1].replace(`{${r}}`,String(a)).replace("#",String(a)):String(a)}if(R==="select"){let p=L(String(a)),y=new RegExp(`\\b${p}\\s*\\{([^{}]*)\\}`).exec(c)||new RegExp("\\bother\\s*\\{([^{}]*)\\}").exec(c);return y?y[1]:String(a)}return a!==void 0?String(a):`{${r}}`})}var g=V;function T(e){g=e}var I=b({"./locales/en/r-common.json":()=>Promise.resolve().then(()=>l(N())),"./locales/en/r-pipes.json":()=>Promise.resolve().then(()=>l(E())),"./locales/en/r-validation.json":()=>Promise.resolve().then(()=>l(S())),"./locales/sv/r-common.json":()=>Promise.resolve().then(()=>l(C())),"./locales/sv/r-pipes.json":()=>Promise.resolve().then(()=>l(F())),"./locales/sv/r-validation.json":()=>Promise.resolve().then(()=>l(H()))});var u=class extends Event{constructor(t){super("localechange",{bubbles:!1}),this.locale=t}},w="en",s=w,f=new Set,d={},M=null;function te(e){return e.toLowerCase().split("-")[0]}async function k(e){let t=te(e);s=t,f.clear(),Object.keys(d).forEach(n=>delete d[n]),await x("r-common"),typeof document<"u"&&document.dispatchEvent(new u(t))}async function x(e){if(!f.has(e))try{let t=await I(`./locales/${s}/${e}.json`);d[e]=t.default,f.add(e)}catch{if(s!==w){let n=await I(`./locales/${w}/${e}.json`);d[e]=n.default,f.add(e)}else console.warn(`i18n: Failed to load namespace '${e}' for locale '${s}'`)}}async function P(e){await Promise.all(e.map(t=>x(t)))}function U(e,t){let[n,o]=e.includes(":")?e.split(":"):["r-common",e],r=d[n]?.[o];if(!r)return M&&M(o,n,s),e;try{return g(r,t,s)}catch{return e}}function j(){return s}function q(e){M=e}
2
2
  //# sourceMappingURL=index.js.map