@relax.js/core 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/README.md +194 -188
  2. package/dist/DependencyInjection.d.ts +42 -24
  3. package/dist/collections/Index.d.ts +2 -0
  4. package/dist/collections/index.js +1 -1
  5. package/dist/collections/index.js.map +4 -4
  6. package/dist/collections/index.mjs +1 -1
  7. package/dist/collections/index.mjs.map +4 -4
  8. package/dist/di/index.js +1 -1
  9. package/dist/di/index.js.map +3 -3
  10. package/dist/di/index.mjs +1 -1
  11. package/dist/di/index.mjs.map +3 -3
  12. package/dist/errors.d.ts +20 -0
  13. package/dist/forms/FormValidator.d.ts +1 -20
  14. package/dist/forms/ValidationRules.d.ts +2 -0
  15. package/dist/forms/index.js +1 -1
  16. package/dist/forms/index.js.map +4 -4
  17. package/dist/forms/index.mjs +1 -1
  18. package/dist/forms/index.mjs.map +4 -4
  19. package/dist/html/TableRenderer.d.ts +1 -0
  20. package/dist/html/index.js.map +2 -2
  21. package/dist/html/index.mjs.map +2 -2
  22. package/dist/html/template.d.ts +4 -0
  23. package/dist/http/http.d.ts +1 -0
  24. package/dist/http/index.js.map +2 -2
  25. package/dist/http/index.mjs.map +2 -2
  26. package/dist/index.d.ts +0 -2
  27. package/dist/index.js +3 -3
  28. package/dist/index.js.map +4 -4
  29. package/dist/index.mjs +3 -3
  30. package/dist/index.mjs.map +4 -4
  31. package/dist/routing/index.js +3 -3
  32. package/dist/routing/index.js.map +3 -3
  33. package/dist/routing/index.mjs +3 -3
  34. package/dist/routing/index.mjs.map +3 -3
  35. package/dist/routing/routeTargetRegistry.d.ts +1 -0
  36. package/dist/routing/types.d.ts +2 -1
  37. package/dist/templates/NodeTemplate.d.ts +2 -0
  38. package/dist/utils/index.js +1 -1
  39. package/dist/utils/index.js.map +2 -2
  40. package/dist/utils/index.mjs +1 -1
  41. package/dist/utils/index.mjs.map +2 -2
  42. package/docs/Architecture.md +333 -333
  43. package/docs/DependencyInjection.md +277 -237
  44. package/docs/Errors.md +87 -87
  45. package/docs/GettingStarted.md +231 -231
  46. package/docs/Pipes.md +5 -5
  47. package/docs/Translations.md +167 -312
  48. package/docs/WhyRelaxjs.md +336 -336
  49. package/docs/api/.nojekyll +1 -0
  50. package/docs/api/assets/hierarchy.js +1 -0
  51. package/docs/api/assets/highlight.css +120 -0
  52. package/docs/api/assets/icons.js +18 -0
  53. package/docs/api/assets/icons.svg +1 -0
  54. package/docs/api/assets/main.js +60 -0
  55. package/docs/api/assets/navigation.js +1 -0
  56. package/docs/api/assets/search.js +1 -0
  57. package/docs/api/assets/style.css +1633 -0
  58. package/docs/api/classes/http.WebSocketClient.html +26 -0
  59. package/docs/api/classes/i18n.LocaleChangeEvent.html +66 -0
  60. package/docs/api/classes/index.Blueprint.html +3 -0
  61. package/docs/api/classes/index.BoundNode.html +3 -0
  62. package/docs/api/classes/index.DigitsValidation.html +10 -0
  63. package/docs/api/classes/index.FormValidator.html +32 -0
  64. package/docs/api/classes/index.HttpError.html +13 -0
  65. package/docs/api/classes/index.LinkedList.html +26 -0
  66. package/docs/api/classes/index.NavigateRouteEvent.html +76 -0
  67. package/docs/api/classes/index.Node.html +15 -0
  68. package/docs/api/classes/index.PageSelectedEvent.html +61 -0
  69. package/docs/api/classes/index.Pager.html +4 -0
  70. package/docs/api/classes/index.RangeValidation.html +15 -0
  71. package/docs/api/classes/index.RelaxError.html +17 -0
  72. package/docs/api/classes/index.RequiredValidation.html +10 -0
  73. package/docs/api/classes/index.RouteError.html +11 -0
  74. package/docs/api/classes/index.RouteGuardError.html +12 -0
  75. package/docs/api/classes/index.RouteLink.html +779 -0
  76. package/docs/api/classes/index.RouteTarget.html +788 -0
  77. package/docs/api/classes/index.SSEClient.html +13 -0
  78. package/docs/api/classes/index.SSEDataEvent.html +63 -0
  79. package/docs/api/classes/index.ServiceCollection.html +28 -0
  80. package/docs/api/classes/index.ServiceContainer.html +24 -0
  81. package/docs/api/classes/index.SortChangeEvent.html +61 -0
  82. package/docs/api/classes/index.TableRenderer.html +5 -0
  83. package/docs/api/classes/index.TableSorter.html +4 -0
  84. package/docs/api/enums/index.GuardResult.html +9 -0
  85. package/docs/api/functions/elements.formError.html +6 -0
  86. package/docs/api/functions/elements.selectOne.html +6 -0
  87. package/docs/api/functions/i18n.getCurrentLocale.html +3 -0
  88. package/docs/api/functions/i18n.loadNamespace.html +7 -0
  89. package/docs/api/functions/i18n.loadNamespaces.html +6 -0
  90. package/docs/api/functions/i18n.onMissingTranslation.html +7 -0
  91. package/docs/api/functions/i18n.setLocale.html +7 -0
  92. package/docs/api/functions/i18n.setMessageFormatter.html +7 -0
  93. package/docs/api/functions/i18n.t.html +9 -0
  94. package/docs/api/functions/index.BooleanConverter.html +6 -0
  95. package/docs/api/functions/index.ContainerService.html +13 -0
  96. package/docs/api/functions/index.DateConverter.html +11 -0
  97. package/docs/api/functions/index.Inject.html +16 -0
  98. package/docs/api/functions/index.NumberConverter.html +5 -0
  99. package/docs/api/functions/index.RegisterValidator.html +7 -0
  100. package/docs/api/functions/index.applyPipes.html +17 -0
  101. package/docs/api/functions/index.asyncHandler.html +11 -0
  102. package/docs/api/functions/index.capitalizePipe.html +4 -0
  103. package/docs/api/functions/index.clearPendingNavigations.html +1 -0
  104. package/docs/api/functions/index.compileTemplate.html +26 -0
  105. package/docs/api/functions/index.configure.html +5 -0
  106. package/docs/api/functions/index.createBluePrint.html +1 -0
  107. package/docs/api/functions/index.createConverterFromDataType.html +4 -0
  108. package/docs/api/functions/index.createConverterFromInputType.html +5 -0
  109. package/docs/api/functions/index.createPipeRegistry.html +12 -0
  110. package/docs/api/functions/index.currencyPipe.html +9 -0
  111. package/docs/api/functions/index.datePipe.html +9 -0
  112. package/docs/api/functions/index.daysAgoPipe.html +8 -0
  113. package/docs/api/functions/index.defaultPipe.html +5 -0
  114. package/docs/api/functions/index.defineRoutes.html +8 -0
  115. package/docs/api/functions/index.del.html +8 -0
  116. package/docs/api/functions/index.findRouteByName.html +5 -0
  117. package/docs/api/functions/index.findRouteByUrl.html +4 -0
  118. package/docs/api/functions/index.firstPipe.html +4 -0
  119. package/docs/api/functions/index.generateSequentialId.html +21 -0
  120. package/docs/api/functions/index.get.html +9 -0
  121. package/docs/api/functions/index.getDataConverter.html +11 -0
  122. package/docs/api/functions/index.getParentComponent.html +18 -0
  123. package/docs/api/functions/index.getValidator.html +4 -0
  124. package/docs/api/functions/index.html.html +19 -0
  125. package/docs/api/functions/index.joinPipe.html +5 -0
  126. package/docs/api/functions/index.keysPipe.html +4 -0
  127. package/docs/api/functions/index.lastPipe.html +4 -0
  128. package/docs/api/functions/index.lowercasePipe.html +4 -0
  129. package/docs/api/functions/index.mapFormToClass.html +17 -0
  130. package/docs/api/functions/index.matchRoute.html +5 -0
  131. package/docs/api/functions/index.navigate.html +8 -0
  132. package/docs/api/functions/index.onError.html +8 -0
  133. package/docs/api/functions/index.piecesPipe.html +8 -0
  134. package/docs/api/functions/index.post.html +9 -0
  135. package/docs/api/functions/index.printRoutes.html +2 -0
  136. package/docs/api/functions/index.put.html +9 -0
  137. package/docs/api/functions/index.readData.html +17 -0
  138. package/docs/api/functions/index.registerRouteTarget.html +9 -0
  139. package/docs/api/functions/index.reportError.html +10 -0
  140. package/docs/api/functions/index.request.html +8 -0
  141. package/docs/api/functions/index.resolveValue.html +18 -0
  142. package/docs/api/functions/index.setFetch.html +6 -0
  143. package/docs/api/functions/index.setFormData.html +17 -0
  144. package/docs/api/functions/index.shortenPipe.html +5 -0
  145. package/docs/api/functions/index.startRouting.html +6 -0
  146. package/docs/api/functions/index.ternaryPipe.html +6 -0
  147. package/docs/api/functions/index.trimPipe.html +4 -0
  148. package/docs/api/functions/index.unregisterRouteTarget.html +3 -0
  149. package/docs/api/functions/index.uppercasePipe.html +4 -0
  150. package/docs/api/hierarchy.html +1 -0
  151. package/docs/api/index.html +323 -0
  152. package/docs/api/interfaces/http.SimpleDataEvent.html +3 -0
  153. package/docs/api/interfaces/http.WebSocketAbstraction.html +9 -0
  154. package/docs/api/interfaces/http.WebSocketCodec.html +4 -0
  155. package/docs/api/interfaces/http.WebSocketOptions.html +20 -0
  156. package/docs/api/interfaces/index.CompiledTemplate.html +10 -0
  157. package/docs/api/interfaces/index.DataLoader.html +19 -0
  158. package/docs/api/interfaces/index.EngineConfig.html +11 -0
  159. package/docs/api/interfaces/index.ErrorContext.html +4 -0
  160. package/docs/api/interfaces/index.FormReaderOptions.html +8 -0
  161. package/docs/api/interfaces/index.HttpOptions.html +16 -0
  162. package/docs/api/interfaces/index.HttpResponse.html +17 -0
  163. package/docs/api/interfaces/index.LoadRoute.html +7 -0
  164. package/docs/api/interfaces/index.NavigateOptions.html +7 -0
  165. package/docs/api/interfaces/index.PipeRegistry.html +12 -0
  166. package/docs/api/interfaces/index.RegistrationOptions.html +22 -0
  167. package/docs/api/interfaces/index.RenderTemplate.html +7 -0
  168. package/docs/api/interfaces/index.RequestOptions.html +11 -0
  169. package/docs/api/interfaces/index.Routable.html +10 -0
  170. package/docs/api/interfaces/index.Route.html +13 -0
  171. package/docs/api/interfaces/index.RouteGuard.html +2 -0
  172. package/docs/api/interfaces/index.RouteValue.html +6 -0
  173. package/docs/api/interfaces/index.SSEOptions.html +24 -0
  174. package/docs/api/interfaces/index.ValidationContext.html +8 -0
  175. package/docs/api/interfaces/index.ValidatorOptions.html +14 -0
  176. package/docs/api/media/Architecture.md +333 -0
  177. package/docs/api/media/DependencyInjection.md +277 -0
  178. package/docs/api/media/GettingStarted.md +231 -0
  179. package/docs/api/media/HttpClient.md +459 -0
  180. package/docs/api/media/Pipes.md +211 -0
  181. package/docs/api/media/Routing.md +332 -0
  182. package/docs/api/media/WhyRelaxjs.md +336 -0
  183. package/docs/api/media/forms.md +99 -0
  184. package/docs/api/media/html.md +175 -0
  185. package/docs/api/media/i18n.md +354 -0
  186. package/docs/api/media/utilities.md +143 -0
  187. package/docs/api/media/validation.md +351 -0
  188. package/docs/api/modules/collections_Index.html +1 -0
  189. package/docs/api/modules/di.html +1 -0
  190. package/docs/api/modules/elements.html +1 -0
  191. package/docs/api/modules/forms.html +1 -0
  192. package/docs/api/modules/html.html +1 -0
  193. package/docs/api/modules/http.html +1 -0
  194. package/docs/api/modules/i18n.html +1 -0
  195. package/docs/api/modules/index.html +1 -0
  196. package/docs/api/modules/routing.html +1 -0
  197. package/docs/api/modules/utils.html +1 -0
  198. package/docs/api/modules.html +1 -0
  199. package/docs/api/types/http.WebSocketFactory.html +2 -0
  200. package/docs/api/types/i18n.MessageFormatter.html +3 -0
  201. package/docs/api/types/i18n.MissingTranslationHandler.html +1 -0
  202. package/docs/api/types/index.Constructor.html +7 -0
  203. package/docs/api/types/index.ConverterFunc.html +2 -0
  204. package/docs/api/types/index.DataType.html +2 -0
  205. package/docs/api/types/index.InputType.html +2 -0
  206. package/docs/api/types/index.PipeFunction.html +6 -0
  207. package/docs/api/types/index.RouteData.html +1 -0
  208. package/docs/api/types/index.RouteMatchResult.html +9 -0
  209. package/docs/api/types/index.RouteParamType.html +1 -0
  210. package/docs/api/types/index.RouteSegmentType.html +2 -0
  211. package/docs/api/types/index.SSEEventFactory.html +5 -0
  212. package/docs/api/types/index.ServiceScope.html +10 -0
  213. package/docs/api/types/index.SortColumn.html +3 -0
  214. package/docs/api/variables/i18n.formatICU.html +3 -0
  215. package/docs/api/variables/index.container.html +6 -0
  216. package/docs/api/variables/index.defaultPipes.html +6 -0
  217. package/docs/api/variables/index.internalRoutes.html +1 -0
  218. package/docs/api/variables/index.serviceCollection.html +6 -0
  219. package/docs/api.json +93171 -0
  220. package/docs/elements/dom.md +102 -102
  221. package/docs/forms/creating-form-components.md +924 -924
  222. package/docs/forms/form-api.md +94 -94
  223. package/docs/forms/forms.md +99 -99
  224. package/docs/forms/patterns.md +311 -311
  225. package/docs/forms/reading-writing.md +365 -365
  226. package/docs/forms/validation.md +351 -351
  227. package/docs/html/TableRenderer.md +291 -291
  228. package/docs/html/html.md +175 -175
  229. package/docs/html/index.md +54 -54
  230. package/docs/html/template.md +422 -422
  231. package/docs/http/HttpClient.md +459 -459
  232. package/docs/http/ServerSentEvents.md +184 -184
  233. package/docs/http/index.md +109 -109
  234. package/docs/i18n/i18n.md +49 -4
  235. package/docs/i18n/intl-standard.md +178 -178
  236. package/docs/routing/RouteLink.md +98 -98
  237. package/docs/routing/Routing.md +332 -332
  238. package/docs/routing/layouts.md +207 -207
  239. package/docs/utilities.md +143 -143
  240. package/package.json +4 -3
@@ -89,6 +89,8 @@ export type TemplateValue = string | number | boolean | null | undefined;
89
89
  * items: ['a', 'b', 'c'],
90
90
  * isActive: true
91
91
  * };
92
+ *
93
+ * @internal
92
94
  */
93
95
  export interface Context {
94
96
  [key: string]: ContextValue;
@@ -103,6 +105,8 @@ export interface Context {
103
105
  * add: (a, b) => a + b,
104
106
  * greet: (name) => `Hello, ${name}!`
105
107
  * };
108
+ *
109
+ * @internal
106
110
  */
107
111
  export interface FunctionsContext {
108
112
  [key: string]: (...args: any[]) => any;
@@ -96,6 +96,7 @@ export interface RequestOptions {
96
96
  */
97
97
  body: unknown;
98
98
  }
99
+ /** @internal */
99
100
  declare type FetchFn = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
100
101
  /**
101
102
  * Replace the fetch implementation for testing purposes.
@@ -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\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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",
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
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"]
7
7
  }
@@ -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\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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",
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
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"]
7
7
  }
package/dist/index.d.ts CHANGED
@@ -14,5 +14,3 @@ export * from "./http/http";
14
14
  export * from "./http/ServerSentEvents";
15
15
  export * from './pipes';
16
16
  export * from './tools';
17
- export * from './collections/Pager';
18
- export * from './collections/DataLoader';