@hkdigital/lib-sveltekit 0.2.20 → 0.2.21

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 (254) hide show
  1. package/README.md +135 -135
  2. package/dist/assets/autospuiten/car-paint-picker.js +41 -41
  3. package/dist/assets/autospuiten/labels.js +7 -7
  4. package/dist/classes/cache/IndexedDbCache.js +1407 -1407
  5. package/dist/classes/cache/MemoryResponseCache.js +138 -138
  6. package/dist/classes/cache/index.js +5 -5
  7. package/dist/classes/cache/typedef.js +41 -41
  8. package/dist/classes/data/IterableTree.js +243 -243
  9. package/dist/classes/data/Selector.js +190 -190
  10. package/dist/classes/data/index.js +2 -2
  11. package/dist/classes/events/EventEmitter.js +275 -275
  12. package/dist/classes/events/index.js +2 -2
  13. package/dist/classes/index.js +4 -4
  14. package/dist/classes/logging/Logger.js +210 -210
  15. package/dist/classes/logging/constants.js +16 -16
  16. package/dist/classes/logging/index.js +4 -4
  17. package/dist/classes/logging/typedef.js +17 -17
  18. package/dist/classes/promise/HkPromise.js +377 -377
  19. package/dist/classes/promise/index.js +1 -1
  20. package/dist/classes/services/ServiceBase.js +463 -463
  21. package/dist/classes/services/ServiceManager.js +614 -614
  22. package/dist/classes/services/index.js +5 -5
  23. package/dist/classes/services/service-states.js +205 -205
  24. package/dist/classes/services/typedef.js +179 -179
  25. package/dist/classes/stores/SubscribersCount.js +107 -107
  26. package/dist/classes/stores/index.js +1 -1
  27. package/dist/classes/streams/LogTransformStream.js +19 -19
  28. package/dist/classes/streams/ServerEventsStore.js +110 -110
  29. package/dist/classes/streams/TimeStampSource.js +26 -26
  30. package/dist/classes/streams/index.js +3 -3
  31. package/dist/classes/svelte/audio/AudioLoader.svelte.js +58 -58
  32. package/dist/classes/svelte/audio/AudioScene.svelte.js +324 -324
  33. package/dist/classes/svelte/audio/mocks.js +35 -35
  34. package/dist/classes/svelte/finite-state-machine/FiniteStateMachine.svelte.js +133 -133
  35. package/dist/classes/svelte/finite-state-machine/index.js +1 -1
  36. package/dist/classes/svelte/image/ImageLoader.svelte.js +45 -45
  37. package/dist/classes/svelte/image/ImageScene.svelte.js +249 -249
  38. package/dist/classes/svelte/image/ImageVariantsLoader.svelte.js +152 -152
  39. package/dist/classes/svelte/image/index.js +4 -4
  40. package/dist/classes/svelte/image/mocks.js +35 -35
  41. package/dist/classes/svelte/image/typedef.js +8 -8
  42. package/dist/classes/svelte/index.js +14 -14
  43. package/dist/classes/svelte/loading-state-machine/LoadingStateMachine.svelte.js +109 -109
  44. package/dist/classes/svelte/loading-state-machine/constants.js +16 -16
  45. package/dist/classes/svelte/loading-state-machine/index.js +3 -3
  46. package/dist/classes/svelte/network-loader/NetworkLoader.svelte.js +338 -338
  47. package/dist/classes/svelte/network-loader/constants.js +3 -3
  48. package/dist/classes/svelte/network-loader/index.js +3 -3
  49. package/dist/classes/svelte/network-loader/mocks.js +30 -30
  50. package/dist/classes/svelte/network-loader/typedef.js +8 -8
  51. package/dist/components/area/HkArea.svelte +49 -49
  52. package/dist/components/area/HkGridArea.svelte +77 -77
  53. package/dist/components/area/index.js +2 -2
  54. package/dist/components/buttons/button/Button.svelte +82 -82
  55. package/dist/components/buttons/button-icon-steeze/SteezeIconButton.svelte +30 -30
  56. package/dist/components/buttons/button-text/TextButton.svelte +21 -21
  57. package/dist/components/buttons/index.js +3 -3
  58. package/dist/components/debug/debug-panel-design-scaling/DebugPanelDesignScaling.svelte +146 -146
  59. package/dist/components/debug/index.js +1 -1
  60. package/dist/components/drag-drop/DragController.js +44 -44
  61. package/dist/components/drag-drop/DragDropContext.svelte +111 -111
  62. package/dist/components/drag-drop/Draggable.svelte +519 -519
  63. package/dist/components/drag-drop/DropZoneArea.svelte +119 -119
  64. package/dist/components/drag-drop/DropZoneList.svelte +125 -125
  65. package/dist/components/drag-drop/{DropZone.svelte → Dropzone.svelte} +258 -258
  66. package/dist/components/drag-drop/actions.js +26 -26
  67. package/dist/components/drag-drop/drag-state.svelte.js +322 -322
  68. package/dist/components/drag-drop/index.js +7 -7
  69. package/dist/components/drag-drop/util.js +85 -85
  70. package/dist/components/hkdev/blocks/TextBlock.svelte +46 -46
  71. package/dist/components/hkdev/buttons/CheckButton.svelte +62 -62
  72. package/dist/components/icons/HkIcon.svelte +86 -86
  73. package/dist/components/icons/HkTabIcon.svelte +116 -116
  74. package/dist/components/icons/SteezeIcon.svelte +97 -97
  75. package/dist/components/icons/index.js +6 -6
  76. package/dist/components/icons/typedef.js +16 -16
  77. package/dist/components/index.js +2 -2
  78. package/dist/components/inputs/index.js +1 -1
  79. package/dist/components/inputs/text-input/TestTextInput.svelte__ +102 -102
  80. package/dist/components/inputs/text-input/TextInput.svelte +223 -223
  81. package/dist/components/inputs/text-input/TextInput.svelte___ +83 -83
  82. package/dist/components/inputs/text-input/assets/IconInvalid.svelte +14 -14
  83. package/dist/components/inputs/text-input/assets/IconValid.svelte +12 -12
  84. package/dist/components/layout/grid-layers/GridLayers.svelte +63 -63
  85. package/dist/components/layout/grid-layers/util.js +74 -74
  86. package/dist/components/layout/index.js +1 -1
  87. package/dist/components/panels/index.js +1 -1
  88. package/dist/components/panels/panel/Panel.svelte +43 -43
  89. package/dist/components/rows/index.js +3 -3
  90. package/dist/components/rows/panel-grid-row/PanelGridRow.svelte +104 -104
  91. package/dist/components/rows/panel-row-2/PanelRow2.svelte +40 -40
  92. package/dist/components/tab-bar/HkTabBar.state.svelte.js +149 -149
  93. package/dist/components/tab-bar/HkTabBar.svelte +74 -74
  94. package/dist/components/tab-bar/HkTabBarSelector.state.svelte.js +93 -93
  95. package/dist/components/tab-bar/HkTabBarSelector.svelte +49 -49
  96. package/dist/components/tab-bar/index.js +17 -17
  97. package/dist/components/tab-bar/typedef.js +11 -11
  98. package/dist/config/imagetools-config.js +189 -189
  99. package/dist/config/imagetools.d.ts +72 -72
  100. package/dist/constants/bases.js +13 -13
  101. package/dist/constants/errors/api.js +9 -9
  102. package/dist/constants/errors/generic.js +5 -5
  103. package/dist/constants/errors/index.js +3 -3
  104. package/dist/constants/errors/jwt.js +5 -5
  105. package/dist/constants/http/headers.js +6 -6
  106. package/dist/constants/http/index.js +2 -2
  107. package/dist/constants/http/methods.js +14 -14
  108. package/dist/constants/index.js +3 -3
  109. package/dist/constants/mime/application.js +5 -5
  110. package/dist/constants/mime/audio.js +13 -13
  111. package/dist/constants/mime/image.js +3 -3
  112. package/dist/constants/mime/index.js +4 -4
  113. package/dist/constants/mime/text.js +2 -2
  114. package/dist/constants/regexp/index.js +31 -31
  115. package/dist/constants/regexp/inspiratie.js__ +95 -95
  116. package/dist/constants/regexp/text.js +49 -49
  117. package/dist/constants/regexp/user.js +32 -32
  118. package/dist/constants/regexp/web.js +3 -3
  119. package/dist/constants/state-labels/drag-states.js +6 -6
  120. package/dist/constants/state-labels/drop-states.js +6 -6
  121. package/dist/constants/state-labels/input-states.js +11 -11
  122. package/dist/constants/state-labels/submit-states.js +4 -4
  123. package/dist/constants/time.js +28 -28
  124. package/dist/css/utilities.css +43 -43
  125. package/dist/design/design-config.js +73 -73
  126. package/dist/design/tailwind-theme-extend.js +158 -158
  127. package/dist/features/button-group/ButtonGroup.svelte +82 -82
  128. package/dist/features/button-group/typedef.js +10 -10
  129. package/dist/features/compare-left-right/CompareLeftRight.svelte +179 -179
  130. package/dist/features/compare-left-right/index.js +1 -1
  131. package/dist/features/game-box/GameBox.svelte +577 -577
  132. package/dist/features/game-box/gamebox.util.js +83 -83
  133. package/dist/features/hk-app-layout/HkAppLayout.state.svelte.js +25 -25
  134. package/dist/features/hk-app-layout/HkAppLayout.svelte +251 -251
  135. package/dist/features/image-box/ImageBox.svelte +210 -210
  136. package/dist/features/image-box/index.js +5 -5
  137. package/dist/features/image-box/typedef.js +32 -32
  138. package/dist/features/index.js +23 -23
  139. package/dist/features/presenter/ImageSlide.svelte +64 -64
  140. package/dist/features/presenter/Presenter.state.svelte.js +638 -638
  141. package/dist/features/presenter/Presenter.svelte +142 -142
  142. package/dist/features/presenter/constants.js +7 -7
  143. package/dist/features/presenter/index.js +10 -10
  144. package/dist/features/presenter/typedef.js +106 -106
  145. package/dist/features/presenter/util.js +210 -210
  146. package/dist/features/virtual-viewport/VirtualViewport.svelte +196 -196
  147. package/dist/logging/adapters/console.js +114 -114
  148. package/dist/logging/adapters/pino.js +60 -60
  149. package/dist/logging/constants.js +1 -1
  150. package/dist/logging/factories/client.js +21 -21
  151. package/dist/logging/factories/server.js +22 -22
  152. package/dist/logging/factories/universal.js +23 -23
  153. package/dist/logging/index.js +8 -8
  154. package/dist/schemas/index.js +1 -1
  155. package/dist/schemas/validate-url.js +180 -180
  156. package/dist/server/index.js +1 -1
  157. package/dist/server/logger.js +94 -94
  158. package/dist/states/index.js +1 -1
  159. package/dist/states/navigation.svelte.js +55 -55
  160. package/dist/stores/index.js +1 -1
  161. package/dist/stores/theme.js +80 -80
  162. package/dist/themes/hkdev/components/blocks/text-block.css +34 -41
  163. package/dist/themes/hkdev/components/boxes/game-box.css +11 -12
  164. package/dist/themes/hkdev/components/buttons/button-icon-steeze.css +22 -22
  165. package/dist/themes/hkdev/components/buttons/button-text.css +32 -32
  166. package/dist/themes/hkdev/components/buttons/button.css +146 -146
  167. package/dist/themes/hkdev/components/buttons/skip-button.css +5 -6
  168. package/dist/themes/hkdev/components/drag-drop/draggable.css +73 -73
  169. package/dist/themes/hkdev/components/drag-drop/drop-zone.css +58 -48
  170. package/dist/themes/hkdev/components/icons/icon-steeze.css +16 -22
  171. package/dist/themes/hkdev/components/inputs/text-input.css +102 -104
  172. package/dist/themes/hkdev/components/panels/panel.css +25 -27
  173. package/dist/themes/hkdev/components/rows/panel-grid-row.css +4 -6
  174. package/dist/themes/hkdev/components/rows/panel-row-2.css +5 -7
  175. package/dist/themes/hkdev/components.css +29 -53
  176. package/dist/themes/hkdev/debug.css +1 -1
  177. package/dist/themes/hkdev/global/layout.css +32 -39
  178. package/dist/themes/hkdev/global/on-colors.css +32 -53
  179. package/dist/themes/hkdev/globals.css +4 -11
  180. package/dist/themes/hkdev/responsive.css +12 -12
  181. package/dist/themes/hkdev/theme-ext.js +12 -15
  182. package/dist/themes/hkdev/theme.css +219 -0
  183. package/dist/themes/index.d.ts +1 -1
  184. package/dist/themes/index.js +1 -1
  185. package/dist/typedef/context.js +6 -6
  186. package/dist/typedef/drag.js +25 -25
  187. package/dist/typedef/drop.js +12 -12
  188. package/dist/typedef/image.js +38 -38
  189. package/dist/typedef/index.js +4 -4
  190. package/dist/util/array/index.js +436 -436
  191. package/dist/util/bases/base58.js +262 -262
  192. package/dist/util/bases/index.js +1 -1
  193. package/dist/util/compare/index.js +247 -247
  194. package/dist/util/css/css-vars.js +83 -83
  195. package/dist/util/css/index.js +1 -1
  196. package/dist/util/design-system/components/states.js +22 -22
  197. package/dist/util/design-system/css/clamp.js +66 -66
  198. package/dist/util/design-system/css/root-design-vars.js +102 -102
  199. package/dist/util/design-system/index.js +5 -5
  200. package/dist/util/design-system/layout/scaling.js +228 -228
  201. package/dist/util/design-system/skeleton.js +208 -208
  202. package/dist/util/design-system/tailwind.js +288 -288
  203. package/dist/util/env/index.js +9 -9
  204. package/dist/util/expect/arrays.js +47 -47
  205. package/dist/util/expect/index.js +259 -259
  206. package/dist/util/expect/primitives.js +55 -55
  207. package/dist/util/expect/url.js +60 -60
  208. package/dist/util/function/index.js +218 -218
  209. package/dist/util/geo/index.js +26 -26
  210. package/dist/util/http/caching.js +263 -263
  211. package/dist/util/http/errors.js +97 -97
  212. package/dist/util/http/headers.js +75 -75
  213. package/dist/util/http/http-request.js +578 -578
  214. package/dist/util/http/index.js +22 -22
  215. package/dist/util/http/json-request.js +224 -224
  216. package/dist/util/http/mocks.js +65 -65
  217. package/dist/util/http/response.js +294 -294
  218. package/dist/util/http/typedef.js +93 -93
  219. package/dist/util/http/url.js +52 -52
  220. package/dist/util/image/index.js +86 -86
  221. package/dist/util/index.js +2 -2
  222. package/dist/util/is/index.js +140 -140
  223. package/dist/util/iterate/index.js +234 -234
  224. package/dist/util/object/index.js +1361 -1361
  225. package/dist/util/singleton/index.js +97 -97
  226. package/dist/util/string/array-path.js +75 -75
  227. package/dist/util/string/convert.js +54 -54
  228. package/dist/util/string/fs.js +226 -226
  229. package/dist/util/string/index.js +5 -5
  230. package/dist/util/string/interpolate.js +61 -61
  231. package/dist/util/string/pad.js +10 -10
  232. package/dist/util/svelte/index.js +4 -4
  233. package/dist/util/svelte/loading/loading-tracker.svelte.js +108 -108
  234. package/dist/util/svelte/observe/index.js +49 -49
  235. package/dist/util/svelte/state-context/index.js +117 -117
  236. package/dist/util/svelte/wait/index.js +38 -38
  237. package/dist/util/sveltekit/index.js +1 -1
  238. package/dist/util/sveltekit/route-folders/index.js +101 -101
  239. package/dist/util/time/index.js +323 -323
  240. package/dist/util/unique/index.js +249 -249
  241. package/dist/valibot/date.js__ +10 -10
  242. package/dist/valibot/index.js +9 -9
  243. package/dist/valibot/url.js +95 -95
  244. package/dist/valibot/user.js +23 -23
  245. package/dist/zod/all.js +33 -33
  246. package/dist/zod/generic.js +11 -11
  247. package/dist/zod/javascript.js +32 -32
  248. package/dist/zod/user.js +16 -16
  249. package/dist/zod/web.js +52 -52
  250. package/package.json +132 -129
  251. package/dist/components/layout/grid-layers/GridLayers.svelte__heightFrom__ +0 -372
  252. package/dist/themes/hkdev/theme.d.ts +0 -234
  253. package/dist/themes/hkdev/theme.js +0 -235
  254. package/dist/util/http/test-data__/content-length-test-hkdigital-small.V4HfZyBQ.avif +0 -0
@@ -1,294 +1,294 @@
1
- import { ResponseError } from '../../constants/errors/index.js';
2
- import * as expect from '../expect/index.js';
3
- import { toURL } from './url.js';
4
-
5
- import {
6
- WWW_AUTHENTICATE,
7
- CONTENT_LENGTH
8
- } from '../../constants/http/headers.js';
9
-
10
- import { href } from './url.js';
11
-
12
- import { getErrorFromResponse } from './errors.js';
13
-
14
- // > Types
15
-
16
- /**
17
- * Callback function that reports progress of data loading
18
- *
19
- * @callback progressCallback
20
- *
21
- * @param {object} _
22
- * @param {number} _.bytesLoaded - Number of bytes loaded so far
23
- * @param {number} _.size - Total size of the response in bytes (0 if unknown)
24
- */
25
-
26
- // > Exports
27
-
28
- /**
29
- * Check if the response status is ok (in 200-299 range)
30
- * This function examines HTTP status codes and throws appropriate errors for
31
- * non-successful responses, with special handling for 401 Unauthorized.
32
- *
33
- * @param {object} response - Fetch Response object to check
34
- *
35
- * @param {string} url - The URL used for the request (for error messages)
36
- *
37
- * @throws {Error} When response has 401 status with authorization details
38
- * @throws {ResponseError} When response has other non-successful status codes
39
- *
40
- * @example
41
- * // Check if response was successful
42
- * try {
43
- * await expectResponseOk(response, 'https://api.example.com/data');
44
- * // Process successful response here
45
- * } catch (error) {
46
- * // Handle specific error types
47
- * if (error.message.includes('401')) {
48
- * // Handle unauthorized error
49
- * }
50
- * }
51
- */
52
- export async function expectResponseOk(response, url) {
53
- expect.object(response);
54
-
55
- // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/200
56
- // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/201
57
-
58
- if (200 === response.status || 201 === response.status) {
59
- if (!response.ok) {
60
- throw new ResponseError(
61
- `Server returned - ${response.status} ${response.statusText} ` +
62
- `[response.ok=false] [url=${href(url)}]`
63
- );
64
- }
65
-
66
- // All ok
67
- return;
68
- }
69
-
70
- // > Handle 401 Unauthorized
71
-
72
- if (401 === response.status) {
73
- let errorMessage = 'Server returned [401] Unauthorized';
74
-
75
- const authValue = response.headers.get(WWW_AUTHENTICATE);
76
-
77
- if (authValue) {
78
- // Add WWW_AUTHENTICATE response to error message
79
- errorMessage += ` (${authValue})`;
80
- }
81
-
82
- errorMessage += ` [url=${href(url)}]`;
83
-
84
- throw new Error(errorMessage);
85
- }
86
-
87
- // > Handle all other error responses
88
-
89
- const error = await getErrorFromResponse(response);
90
-
91
- throw new ResponseError(
92
- `Server returned - ${response.status} ${response.statusText} ` +
93
- `[url=${href(url)}]`,
94
- { cause: error }
95
- );
96
- }
97
-
98
- /**
99
- * Get the response size from the content-length response header
100
- *
101
- * @param {Response} response - Fetch Response object
102
- *
103
- * @returns {number} Response size in bytes, or 0 if content-length is not set
104
- *
105
- * @example
106
- * const response = await fetch('https://example.com/large-file.zip');
107
- * const size = getResponseSize(response);
108
- * console.log(`Download size: ${size} bytes`);
109
- */
110
- export function getResponseSize(response) {
111
- const sizeStr = response.headers.get(CONTENT_LENGTH);
112
-
113
- if (!sizeStr) {
114
- return 0;
115
- }
116
-
117
- return parseInt(sizeStr, 10);
118
- }
119
-
120
- /**
121
- * Wait for a response and check if the response is ok
122
- * This function awaits a response promise and performs error checking,
123
- * wrapping network errors in a standardized ResponseError format.
124
- *
125
- * @param {Promise<Response>} responsePromise - Promise that resolves to a Response
126
- *
127
- * @param {string|URL} url - URL used for the request (for error messages)
128
- *
129
- * @throws {ResponseError} When a network error occurs or response is not ok
130
- *
131
- * @returns {Promise<Response>} The response if successful
132
- *
133
- * @example
134
- * // Handle a fetch promise with proper error handling
135
- * const responsePromise = fetch('https://api.example.com/data');
136
- * try {
137
- * const response = await waitForAndCheckResponse(
138
- * responsePromise,
139
- * 'https://api.example.com/data'
140
- * );
141
- * // Process response
142
- * } catch (error) {
143
- * // Handle standardized ResponseError
144
- * console.error(error.message);
145
- * }
146
- */
147
- export async function waitForAndCheckResponse(responsePromise, url) {
148
- expect.promise(responsePromise);
149
-
150
- url = toURL(url);
151
-
152
- let response;
153
-
154
- try {
155
- response = await responsePromise;
156
-
157
- if (response && false === response.ok) {
158
- // if response.ok is false, it also indicates a network error
159
- throw new Error(`Response failed [response.ok=false]`);
160
- }
161
- } catch (e) {
162
- if (e instanceof TypeError || response?.ok === false) {
163
- throw new ResponseError(
164
- `A network error occurred for request [${href(url)}]`,
165
- {
166
- cause: e
167
- }
168
- );
169
- } else {
170
- throw e;
171
- }
172
- }
173
-
174
- return response;
175
- }
176
-
177
- /**
178
- * Load response body as ArrayBuffer with progress monitoring and abort capability
179
- *
180
- * This function reads a response body stream chunk by chunk, with optional
181
- * progress reporting. It provides an abort mechanism to cancel an in-progress
182
- * download.
183
- *
184
- * @param {Response} response - Fetch Response object to read
185
- *
186
- * @param {progressCallback} [onProgress] - Optional callback for progress updates
187
- *
188
- * @returns {{
189
- * bufferPromise: Promise<ArrayBuffer>,
190
- * abort: () => void
191
- * }} Object containing the buffer promise and abort function
192
- *
193
- * @example
194
- * // Download a file with progress monitoring and abort capability
195
- * const response = await fetch('https://example.com/large-file.zip');
196
- *
197
- * const { bufferPromise, abort } = loadResponseBuffer(
198
- * response,
199
- * ({ bytesLoaded, size }) => {
200
- * // Update progress UI
201
- * const percent = size ? Math.round((bytesLoaded / size) * 100) : 0;
202
- * console.log(`Downloaded ${bytesLoaded} bytes (${percent}%)`);
203
- * }
204
- * );
205
- *
206
- * // To abort the download:
207
- * // abort();
208
- *
209
- * try {
210
- * const buffer = await bufferPromise;
211
- * // Process the complete buffer
212
- * } catch (error) {
213
- * console.error('Download failed or was aborted', error);
214
- * }
215
- */
216
- export function loadResponseBuffer(response, onProgress) {
217
- // @note size might be 0
218
- // @note might not be send by server in dev mode
219
- const size = getResponseSize(response);
220
-
221
- let bytesLoaded = 0;
222
-
223
- if (onProgress /*&& size*/) {
224
- onProgress({ bytesLoaded, size });
225
- }
226
-
227
- if (!response.body) {
228
- throw new Error('Missing [response.body]');
229
- }
230
-
231
- let reader;
232
- let aborted = false;
233
-
234
- /**
235
- * Read chunks from response body using reader
236
- *
237
- * @returns {Promise<ArrayBuffer>}
238
- */
239
- async function read() {
240
- reader = response.body.getReader();
241
- let chunks = [];
242
-
243
- for (;;) {
244
- const { done, value } = await reader.read();
245
-
246
- if (value) {
247
- // @note value is an ArrayBuffer
248
- bytesLoaded += value.byteLength;
249
-
250
- chunks.push(value);
251
-
252
- if (onProgress /*&& size*/) {
253
- onProgress({ bytesLoaded, size });
254
- }
255
- }
256
-
257
- if (done || aborted) {
258
- // Loading complete or aborted by user
259
- break;
260
- }
261
- } // end for
262
-
263
- if (size && bytesLoaded !== size) {
264
- console.error(`Received [${bytesLoaded}], but expected [${size}] bytes`);
265
- }
266
-
267
- // Concat the chunks into a single array
268
- let buffer = new ArrayBuffer(bytesLoaded);
269
- let body = new Uint8Array(buffer);
270
-
271
- let offset = 0;
272
-
273
- // Place the chunks in the buffer
274
- for (let chunk of chunks) {
275
- body.set(chunk, offset);
276
- offset += chunk.byteLength;
277
- } // end for
278
-
279
- return buffer;
280
- }
281
-
282
- const bufferPromise = read();
283
-
284
- return {
285
- bufferPromise,
286
- abort: () => {
287
- aborted = true;
288
-
289
- if (reader) {
290
- reader.cancel('Aborted by user');
291
- }
292
- }
293
- };
294
- } // end fn
1
+ import { ResponseError } from '../../constants/errors/index.js';
2
+ import * as expect from '../expect/index.js';
3
+ import { toURL } from './url.js';
4
+
5
+ import {
6
+ WWW_AUTHENTICATE,
7
+ CONTENT_LENGTH
8
+ } from '../../constants/http/headers.js';
9
+
10
+ import { href } from './url.js';
11
+
12
+ import { getErrorFromResponse } from './errors.js';
13
+
14
+ // > Types
15
+
16
+ /**
17
+ * Callback function that reports progress of data loading
18
+ *
19
+ * @callback progressCallback
20
+ *
21
+ * @param {object} _
22
+ * @param {number} _.bytesLoaded - Number of bytes loaded so far
23
+ * @param {number} _.size - Total size of the response in bytes (0 if unknown)
24
+ */
25
+
26
+ // > Exports
27
+
28
+ /**
29
+ * Check if the response status is ok (in 200-299 range)
30
+ * This function examines HTTP status codes and throws appropriate errors for
31
+ * non-successful responses, with special handling for 401 Unauthorized.
32
+ *
33
+ * @param {object} response - Fetch Response object to check
34
+ *
35
+ * @param {string} url - The URL used for the request (for error messages)
36
+ *
37
+ * @throws {Error} When response has 401 status with authorization details
38
+ * @throws {ResponseError} When response has other non-successful status codes
39
+ *
40
+ * @example
41
+ * // Check if response was successful
42
+ * try {
43
+ * await expectResponseOk(response, 'https://api.example.com/data');
44
+ * // Process successful response here
45
+ * } catch (error) {
46
+ * // Handle specific error types
47
+ * if (error.message.includes('401')) {
48
+ * // Handle unauthorized error
49
+ * }
50
+ * }
51
+ */
52
+ export async function expectResponseOk(response, url) {
53
+ expect.object(response);
54
+
55
+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/200
56
+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/201
57
+
58
+ if (200 === response.status || 201 === response.status) {
59
+ if (!response.ok) {
60
+ throw new ResponseError(
61
+ `Server returned - ${response.status} ${response.statusText} ` +
62
+ `[response.ok=false] [url=${href(url)}]`
63
+ );
64
+ }
65
+
66
+ // All ok
67
+ return;
68
+ }
69
+
70
+ // > Handle 401 Unauthorized
71
+
72
+ if (401 === response.status) {
73
+ let errorMessage = 'Server returned [401] Unauthorized';
74
+
75
+ const authValue = response.headers.get(WWW_AUTHENTICATE);
76
+
77
+ if (authValue) {
78
+ // Add WWW_AUTHENTICATE response to error message
79
+ errorMessage += ` (${authValue})`;
80
+ }
81
+
82
+ errorMessage += ` [url=${href(url)}]`;
83
+
84
+ throw new Error(errorMessage);
85
+ }
86
+
87
+ // > Handle all other error responses
88
+
89
+ const error = await getErrorFromResponse(response);
90
+
91
+ throw new ResponseError(
92
+ `Server returned - ${response.status} ${response.statusText} ` +
93
+ `[url=${href(url)}]`,
94
+ { cause: error }
95
+ );
96
+ }
97
+
98
+ /**
99
+ * Get the response size from the content-length response header
100
+ *
101
+ * @param {Response} response - Fetch Response object
102
+ *
103
+ * @returns {number} Response size in bytes, or 0 if content-length is not set
104
+ *
105
+ * @example
106
+ * const response = await fetch('https://example.com/large-file.zip');
107
+ * const size = getResponseSize(response);
108
+ * console.log(`Download size: ${size} bytes`);
109
+ */
110
+ export function getResponseSize(response) {
111
+ const sizeStr = response.headers.get(CONTENT_LENGTH);
112
+
113
+ if (!sizeStr) {
114
+ return 0;
115
+ }
116
+
117
+ return parseInt(sizeStr, 10);
118
+ }
119
+
120
+ /**
121
+ * Wait for a response and check if the response is ok
122
+ * This function awaits a response promise and performs error checking,
123
+ * wrapping network errors in a standardized ResponseError format.
124
+ *
125
+ * @param {Promise<Response>} responsePromise - Promise that resolves to a Response
126
+ *
127
+ * @param {string|URL} url - URL used for the request (for error messages)
128
+ *
129
+ * @throws {ResponseError} When a network error occurs or response is not ok
130
+ *
131
+ * @returns {Promise<Response>} The response if successful
132
+ *
133
+ * @example
134
+ * // Handle a fetch promise with proper error handling
135
+ * const responsePromise = fetch('https://api.example.com/data');
136
+ * try {
137
+ * const response = await waitForAndCheckResponse(
138
+ * responsePromise,
139
+ * 'https://api.example.com/data'
140
+ * );
141
+ * // Process response
142
+ * } catch (error) {
143
+ * // Handle standardized ResponseError
144
+ * console.error(error.message);
145
+ * }
146
+ */
147
+ export async function waitForAndCheckResponse(responsePromise, url) {
148
+ expect.promise(responsePromise);
149
+
150
+ url = toURL(url);
151
+
152
+ let response;
153
+
154
+ try {
155
+ response = await responsePromise;
156
+
157
+ if (response && false === response.ok) {
158
+ // if response.ok is false, it also indicates a network error
159
+ throw new Error(`Response failed [response.ok=false]`);
160
+ }
161
+ } catch (e) {
162
+ if (e instanceof TypeError || response?.ok === false) {
163
+ throw new ResponseError(
164
+ `A network error occurred for request [${href(url)}]`,
165
+ {
166
+ cause: e
167
+ }
168
+ );
169
+ } else {
170
+ throw e;
171
+ }
172
+ }
173
+
174
+ return response;
175
+ }
176
+
177
+ /**
178
+ * Load response body as ArrayBuffer with progress monitoring and abort capability
179
+ *
180
+ * This function reads a response body stream chunk by chunk, with optional
181
+ * progress reporting. It provides an abort mechanism to cancel an in-progress
182
+ * download.
183
+ *
184
+ * @param {Response} response - Fetch Response object to read
185
+ *
186
+ * @param {progressCallback} [onProgress] - Optional callback for progress updates
187
+ *
188
+ * @returns {{
189
+ * bufferPromise: Promise<ArrayBuffer>,
190
+ * abort: () => void
191
+ * }} Object containing the buffer promise and abort function
192
+ *
193
+ * @example
194
+ * // Download a file with progress monitoring and abort capability
195
+ * const response = await fetch('https://example.com/large-file.zip');
196
+ *
197
+ * const { bufferPromise, abort } = loadResponseBuffer(
198
+ * response,
199
+ * ({ bytesLoaded, size }) => {
200
+ * // Update progress UI
201
+ * const percent = size ? Math.round((bytesLoaded / size) * 100) : 0;
202
+ * console.log(`Downloaded ${bytesLoaded} bytes (${percent}%)`);
203
+ * }
204
+ * );
205
+ *
206
+ * // To abort the download:
207
+ * // abort();
208
+ *
209
+ * try {
210
+ * const buffer = await bufferPromise;
211
+ * // Process the complete buffer
212
+ * } catch (error) {
213
+ * console.error('Download failed or was aborted', error);
214
+ * }
215
+ */
216
+ export function loadResponseBuffer(response, onProgress) {
217
+ // @note size might be 0
218
+ // @note might not be send by server in dev mode
219
+ const size = getResponseSize(response);
220
+
221
+ let bytesLoaded = 0;
222
+
223
+ if (onProgress /*&& size*/) {
224
+ onProgress({ bytesLoaded, size });
225
+ }
226
+
227
+ if (!response.body) {
228
+ throw new Error('Missing [response.body]');
229
+ }
230
+
231
+ let reader;
232
+ let aborted = false;
233
+
234
+ /**
235
+ * Read chunks from response body using reader
236
+ *
237
+ * @returns {Promise<ArrayBuffer>}
238
+ */
239
+ async function read() {
240
+ reader = response.body.getReader();
241
+ let chunks = [];
242
+
243
+ for (;;) {
244
+ const { done, value } = await reader.read();
245
+
246
+ if (value) {
247
+ // @note value is an ArrayBuffer
248
+ bytesLoaded += value.byteLength;
249
+
250
+ chunks.push(value);
251
+
252
+ if (onProgress /*&& size*/) {
253
+ onProgress({ bytesLoaded, size });
254
+ }
255
+ }
256
+
257
+ if (done || aborted) {
258
+ // Loading complete or aborted by user
259
+ break;
260
+ }
261
+ } // end for
262
+
263
+ if (size && bytesLoaded !== size) {
264
+ console.error(`Received [${bytesLoaded}], but expected [${size}] bytes`);
265
+ }
266
+
267
+ // Concat the chunks into a single array
268
+ let buffer = new ArrayBuffer(bytesLoaded);
269
+ let body = new Uint8Array(buffer);
270
+
271
+ let offset = 0;
272
+
273
+ // Place the chunks in the buffer
274
+ for (let chunk of chunks) {
275
+ body.set(chunk, offset);
276
+ offset += chunk.byteLength;
277
+ } // end for
278
+
279
+ return buffer;
280
+ }
281
+
282
+ const bufferPromise = read();
283
+
284
+ return {
285
+ bufferPromise,
286
+ abort: () => {
287
+ aborted = true;
288
+
289
+ if (reader) {
290
+ reader.cancel('Aborted by user');
291
+ }
292
+ }
293
+ };
294
+ } // end fn