@hkdigital/lib-sveltekit 0.1.68 → 0.1.70

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.
@@ -1,64 +1,84 @@
1
1
  /**
2
2
  * Make a GET request to fetch JSON encoded data
3
- * - Expect JSON response from server
4
3
  *
5
- * @param {object} _
6
- * @param {string|URL} _.url - Url string or URL object
4
+ * This function performs a GET request and expects a JSON response from the server.
5
+ * It handles common error cases and parses the JSON response.
7
6
  *
8
- * @param {object} [_.urlSearchParams]
9
- * Parameters that should be added to the request url
7
+ * @param {import('./typedef').JsonGetOptions} options
8
+ * Request configuration options
10
9
  *
11
- * @param {[string, string][]} [_.headers]
12
- * List of custom headers. Each header is an array that contains
13
- * the header name and the header value.
14
- * E.g. [ "content-type", "application/json" ]
10
+ * @returns {Promise<any>} Parsed JSON data
15
11
  *
16
- * @param {boolean} [_.withCredentials=false]
12
+ * @example
13
+ * // Basic JSON GET request
14
+ * try {
15
+ * const data = await jsonGet({
16
+ * url: 'https://api.example.com/users/123'
17
+ * });
18
+ * console.log(data); // { id: 123, name: "John Doe", ... }
19
+ * } catch (error) {
20
+ * console.error('Failed to fetch user data:', error.message);
21
+ * }
17
22
  *
18
- * @throws ResponseError
19
- * If a network error occurred or the response was not ok
23
+ * @example
24
+ * // JSON GET request with parameters
25
+ * const data = await jsonGet({
26
+ * url: 'https://api.example.com/search',
27
+ * urlSearchParams: new URLSearchParams({ q: 'search term' }),
28
+ * withCredentials: true
29
+ * });
20
30
  *
21
- * @returns {Promise<any>} parsed JSON data
31
+ * @example
32
+ * // Using advanced options
33
+ * const data = await jsonGet({
34
+ * url: 'https://api.example.com/data',
35
+ * timeoutMs: 5000,
36
+ * requestHandler: ({ abort }) => {
37
+ * // Store abort function
38
+ * window.abortDataRequest = abort;
39
+ * }
40
+ * });
22
41
  */
23
- export function jsonGet({ url, urlSearchParams, headers, withCredentials }: {
24
- url: string | URL;
25
- urlSearchParams?: object;
26
- headers?: [string, string][];
27
- withCredentials?: boolean;
28
- }): Promise<any>;
42
+ export function jsonGet(options: import("./typedef").JsonGetOptions): Promise<any>;
29
43
  /**
30
44
  * Make a POST request to fetch JSON encoded data
31
- * - Expect JSON response from server
32
45
  *
33
- * @param {object} _
34
- * @param {string|URL} _.url - Url string or URL object
46
+ * This function performs a POST request with JSON data and expects a JSON
47
+ * response from the server. It handles common error cases and parses the JSON response.
35
48
  *
36
- * @param {any} _.body
37
- * Data that will be converted to a JSON encoded string and send to the server
49
+ * @param {import('./typedef').JsonPostOptions} options
50
+ * Request configuration options
38
51
  *
39
- * @param {object} [_.urlSearchParams]
40
- * Parameters that should be added to the request url.
52
+ * @returns {Promise<any>} Parsed JSON data
41
53
  *
42
- * - Be careful when using urlSearchParams in POST requests, it can be
43
- * confusing since the parameters usually go in the body part of
44
- * the request.
54
+ * @example
55
+ * // Basic JSON POST request
56
+ * try {
57
+ * const newUser = {
58
+ * name: "Jane Smith",
59
+ * email: "jane@example.com"
60
+ * };
45
61
  *
46
- * @param {[string, string][]} [_.headers]
47
- * List of custom headers. Each header is an array that contains
48
- * the header name and the header value.
49
- * E.g. [ "content-type", "application/json" ]
62
+ * const data = await jsonPost({
63
+ * url: 'https://api.example.com/users',
64
+ * body: JSON.stringify(newUser)
65
+ * });
50
66
  *
51
- * @param {boolean} [_.withCredentials=false]
67
+ * console.log('Created user with ID:', data.id);
68
+ * } catch (error) {
69
+ * console.error('Failed to create user:', error.message);
70
+ * }
52
71
  *
53
- * @throws ResponseError
54
- * If a network error occurred or the response was not ok
55
- *
56
- * @returns {Promise<any>} parsed JSON data
72
+ * @example
73
+ * // JSON POST with authentication and timeout
74
+ * const data = await jsonPost({
75
+ * url: 'https://api.example.com/protected/resource',
76
+ * body: JSON.stringify({ action: 'update' }),
77
+ * headers: {
78
+ * 'authorization': 'Bearer ' + token
79
+ * },
80
+ * withCredentials: true,
81
+ * timeoutMs: 5000
82
+ * });
57
83
  */
58
- export function jsonPost({ url, body, urlSearchParams, headers, withCredentials }: {
59
- url: string | URL;
60
- body: any;
61
- urlSearchParams?: object;
62
- headers?: [string, string][];
63
- withCredentials?: boolean;
64
- }): Promise<any>;
84
+ export function jsonPost(options: import("./typedef").JsonPostOptions): Promise<any>;
@@ -14,161 +14,211 @@ const ACCEPT = 'accept';
14
14
 
15
15
  /**
16
16
  * Make a GET request to fetch JSON encoded data
17
- * - Expect JSON response from server
18
17
  *
19
- * @param {object} _
20
- * @param {string|URL} _.url - Url string or URL object
18
+ * This function performs a GET request and expects a JSON response from the server.
19
+ * It handles common error cases and parses the JSON response.
21
20
  *
22
- * @param {object} [_.urlSearchParams]
23
- * Parameters that should be added to the request url
21
+ * @param {import('./typedef').JsonGetOptions} options
22
+ * Request configuration options
24
23
  *
25
- * @param {[string, string][]} [_.headers]
26
- * List of custom headers. Each header is an array that contains
27
- * the header name and the header value.
28
- * E.g. [ "content-type", "application/json" ]
24
+ * @returns {Promise<any>} Parsed JSON data
29
25
  *
30
- * @param {boolean} [_.withCredentials=false]
26
+ * @example
27
+ * // Basic JSON GET request
28
+ * try {
29
+ * const data = await jsonGet({
30
+ * url: 'https://api.example.com/users/123'
31
+ * });
32
+ * console.log(data); // { id: 123, name: "John Doe", ... }
33
+ * } catch (error) {
34
+ * console.error('Failed to fetch user data:', error.message);
35
+ * }
31
36
  *
32
- * @throws ResponseError
33
- * If a network error occurred or the response was not ok
37
+ * @example
38
+ * // JSON GET request with parameters
39
+ * const data = await jsonGet({
40
+ * url: 'https://api.example.com/search',
41
+ * urlSearchParams: new URLSearchParams({ q: 'search term' }),
42
+ * withCredentials: true
43
+ * });
34
44
  *
35
- * @returns {Promise<any>} parsed JSON data
45
+ * @example
46
+ * // Using advanced options
47
+ * const data = await jsonGet({
48
+ * url: 'https://api.example.com/data',
49
+ * timeoutMs: 5000,
50
+ * requestHandler: ({ abort }) => {
51
+ * // Store abort function
52
+ * window.abortDataRequest = abort;
53
+ * }
54
+ * });
36
55
  */
37
- export async function jsonGet({
38
- url,
39
- urlSearchParams,
40
- headers,
41
- withCredentials
42
- }) {
43
- url = toURL(url);
44
-
45
- if (!headers) {
46
- headers = [];
47
- }
48
-
49
- headers[ACCEPT] = APPLICATION_JSON;
50
-
51
- const responsePromise = httpRequest({
52
- method: METHOD_GET,
53
- url,
54
- urlSearchParams,
55
- headers,
56
- withCredentials
57
- });
58
-
59
- const response = await waitForAndCheckResponse(responsePromise, url);
60
-
61
- let parsedResponse;
62
-
63
- try {
64
- //
65
- // @note when security on the client side fails, an `opaque` response
66
- // is returned by the browser (empty body) -> parsing fails
67
- // (use CORS to fix this)
68
- //
69
- parsedResponse = await response.json();
70
- } catch (e) {
71
- throw new ResponseError(
72
- `Failed to JSON decode server response from [${decodeURI(url.href)}]`,
73
- {
74
- cause: e
75
- }
76
- );
77
- }
78
-
79
- if (parsedResponse.error) {
80
- throw new ResponseError(
81
- `Server returned response error message [${parsedResponse.error}]`
82
- );
83
- }
84
-
85
- return parsedResponse;
56
+ export async function jsonGet(options) {
57
+ // Extract specific parameters needed for this function
58
+ const {
59
+ url: rawUrl,
60
+ urlSearchParams,
61
+ headers,
62
+ withCredentials,
63
+ ...otherOptions
64
+ } = options;
65
+
66
+ const url = toURL(rawUrl);
67
+
68
+ // Apply JSON-specific defaults
69
+ const jsonHeaders = headers || {};
70
+ jsonHeaders[ACCEPT] = APPLICATION_JSON;
71
+
72
+ // Create request with all options
73
+ const responsePromise = httpRequest({
74
+ method: METHOD_GET,
75
+ url,
76
+ urlSearchParams,
77
+ headers: jsonHeaders,
78
+ withCredentials,
79
+ ...otherOptions // Pass through any other options
80
+ });
81
+
82
+ const response = await waitForAndCheckResponse(responsePromise, url);
83
+
84
+ let parsedResponse;
85
+
86
+ try {
87
+ //
88
+ // @note when security on the client side fails, an `opaque` response
89
+ // is returned by the browser (empty body) -> parsing fails
90
+ // (use CORS to fix this)
91
+ //
92
+ parsedResponse = await response.json();
93
+ } catch (e) {
94
+ throw new ResponseError(
95
+ `Failed to JSON decode server response from [${decodeURI(url.href)}]`,
96
+ {
97
+ cause: e
98
+ }
99
+ );
100
+ }
101
+
102
+ if (parsedResponse.error) {
103
+ throw new ResponseError(
104
+ `Server returned response error message [${parsedResponse.error}]`
105
+ );
106
+ }
107
+
108
+ return parsedResponse;
86
109
  }
87
110
 
88
111
  /**
89
112
  * Make a POST request to fetch JSON encoded data
90
- * - Expect JSON response from server
91
113
  *
92
- * @param {object} _
93
- * @param {string|URL} _.url - Url string or URL object
114
+ * This function performs a POST request with JSON data and expects a JSON
115
+ * response from the server. It handles common error cases and parses the JSON response.
94
116
  *
95
- * @param {any} _.body
96
- * Data that will be converted to a JSON encoded string and send to the server
117
+ * @param {import('./typedef').JsonPostOptions} options
118
+ * Request configuration options
97
119
  *
98
- * @param {object} [_.urlSearchParams]
99
- * Parameters that should be added to the request url.
120
+ * @returns {Promise<any>} Parsed JSON data
100
121
  *
101
- * - Be careful when using urlSearchParams in POST requests, it can be
102
- * confusing since the parameters usually go in the body part of
103
- * the request.
122
+ * @example
123
+ * // Basic JSON POST request
124
+ * try {
125
+ * const newUser = {
126
+ * name: "Jane Smith",
127
+ * email: "jane@example.com"
128
+ * };
104
129
  *
105
- * @param {[string, string][]} [_.headers]
106
- * List of custom headers. Each header is an array that contains
107
- * the header name and the header value.
108
- * E.g. [ "content-type", "application/json" ]
130
+ * const data = await jsonPost({
131
+ * url: 'https://api.example.com/users',
132
+ * body: JSON.stringify(newUser)
133
+ * });
109
134
  *
110
- * @param {boolean} [_.withCredentials=false]
135
+ * console.log('Created user with ID:', data.id);
136
+ * } catch (error) {
137
+ * console.error('Failed to create user:', error.message);
138
+ * }
111
139
  *
112
- * @throws ResponseError
113
- * If a network error occurred or the response was not ok
114
- *
115
- * @returns {Promise<any>} parsed JSON data
140
+ * @example
141
+ * // JSON POST with authentication and timeout
142
+ * const data = await jsonPost({
143
+ * url: 'https://api.example.com/protected/resource',
144
+ * body: JSON.stringify({ action: 'update' }),
145
+ * headers: {
146
+ * 'authorization': 'Bearer ' + token
147
+ * },
148
+ * withCredentials: true,
149
+ * timeoutMs: 5000
150
+ * });
116
151
  */
117
- export async function jsonPost({
118
- url,
119
- body,
120
- urlSearchParams,
121
- headers,
122
- withCredentials
123
- }) {
124
- url = toURL(url);
125
-
126
- if (!headers) {
127
- headers = [];
128
- } else {
129
- expect.object(headers);
130
- }
131
-
132
- expect.defined(body);
133
-
134
- headers[ACCEPT] = APPLICATION_JSON;
135
- headers[CONTENT_TYPE] = APPLICATION_JSON;
136
-
137
- const responsePromise = httpRequest({
138
- method: METHOD_POST,
139
- url,
140
- body,
141
- urlSearchParams,
142
- headers
143
- });
144
-
145
- const response = await waitForAndCheckResponse(responsePromise, url);
146
-
147
- let parsedResponse;
148
-
149
- try {
150
- //
151
- // @note when security on the client side fails, an `opaque` response
152
- // is returned by the browser (empty body) -> parsing fails
153
- // (use CORS to fix this)
154
- //
155
- parsedResponse = await response.json();
156
- } catch (e) {
157
- // console.log( response );
158
- throw new ResponseError(
159
- `Failed to JSON decode server response from [${decodeURI(url.href)}]`
160
- );
161
- }
162
-
163
- if (parsedResponse.error) {
164
- //
165
- // @note this is API specific, but it's quite logical
166
- //
167
- //
168
- throw new ResponseError(
169
- `Server returned response error message [${parsedResponse.error}]`
170
- );
171
- }
172
-
173
- return parsedResponse;
152
+ export async function jsonPost(options) {
153
+ // Extract specific parameters needed for this function
154
+ const {
155
+ url: rawUrl,
156
+ body,
157
+ urlSearchParams,
158
+ headers,
159
+ withCredentials,
160
+ ...otherOptions
161
+ } = options;
162
+
163
+ const url = toURL(rawUrl);
164
+
165
+ // Apply JSON-specific defaults and validation
166
+ expect.defined(body);
167
+
168
+ const jsonHeaders = headers || {};
169
+ jsonHeaders[ACCEPT] = APPLICATION_JSON;
170
+ jsonHeaders[CONTENT_TYPE] = APPLICATION_JSON;
171
+
172
+ // Check if body is a string when using application/json
173
+ if (
174
+ jsonHeaders[CONTENT_TYPE] === APPLICATION_JSON &&
175
+ typeof body !== 'string'
176
+ ) {
177
+ throw new Error(
178
+ `Trying to send request with [content-type:${APPLICATION_JSON}], ` +
179
+ 'but body is not a (JSON encoded) string.'
180
+ );
181
+ }
182
+
183
+ // Create request with all options
184
+ const responsePromise = httpRequest({
185
+ method: METHOD_POST,
186
+ url,
187
+ body,
188
+ urlSearchParams,
189
+ headers: jsonHeaders,
190
+ withCredentials,
191
+ ...otherOptions // Pass through any other options
192
+ });
193
+
194
+ const response = await waitForAndCheckResponse(responsePromise, url);
195
+
196
+ let parsedResponse;
197
+
198
+ try {
199
+ //
200
+ // @note when security on the client side fails, an `opaque` response
201
+ // is returned by the browser (empty body) -> parsing fails
202
+ // (use CORS to fix this)
203
+ //
204
+ parsedResponse = await response.json();
205
+ } catch (e) {
206
+ throw new ResponseError(
207
+ `Failed to JSON decode server response from [${decodeURI(url.href)}]`,
208
+ {
209
+ cause: e
210
+ }
211
+ );
212
+ }
213
+
214
+ if (parsedResponse.error) {
215
+ //
216
+ // @note this is API specific, but it's quite logical
217
+ //
218
+ throw new ResponseError(
219
+ `Server returned response error message [${parsedResponse.error}]`
220
+ );
221
+ }
222
+
223
+ return parsedResponse;
174
224
  }
@@ -1,55 +1,124 @@
1
1
  /**
2
+ * Callback function that reports progress of data loading
3
+ *
2
4
  * @callback progressCallback
5
+ *
3
6
  * @param {object} _
4
- * @param {number} _.bytesLoaded
5
- * @param {number} _.size
7
+ * @param {number} _.bytesLoaded - Number of bytes loaded so far
8
+ * @param {number} _.size - Total size of the response in bytes (0 if unknown)
6
9
  */
7
10
  /**
8
- * Check if the response status is ok
11
+ * Check if the response status is ok (in 200-299 range)
12
+ * This function examines HTTP status codes and throws appropriate errors for
13
+ * non-successful responses, with special handling for 401 Unauthorized.
14
+ *
15
+ * @param {object} response - Fetch Response object to check
9
16
  *
10
- * @param {object} response
11
- * @param {string} url - used to produce useful error messages
17
+ * @param {string} url - The URL used for the request (for error messages)
12
18
  *
13
- * @throws {Error} not found
14
- * @throws {Error} internal server error
19
+ * @throws {Error} When response has 401 status with authorization details
20
+ * @throws {ResponseError} When response has other non-successful status codes
21
+ *
22
+ * @example
23
+ * // Check if response was successful
24
+ * try {
25
+ * await expectResponseOk(response, 'https://api.example.com/data');
26
+ * // Process successful response here
27
+ * } catch (error) {
28
+ * // Handle specific error types
29
+ * if (error.message.includes('401')) {
30
+ * // Handle unauthorized error
31
+ * }
32
+ * }
15
33
  */
16
34
  export function expectResponseOk(response: object, url: string): Promise<void>;
17
35
  /**
18
36
  * Get the response size from the content-length response header
19
37
  *
20
- * @param {Response} response
38
+ * @param {Response} response - Fetch Response object
21
39
  *
22
- * @returns {number} response size or 0 if unknown
40
+ * @returns {number} Response size in bytes, or 0 if content-length is not set
41
+ *
42
+ * @example
43
+ * const response = await fetch('https://example.com/large-file.zip');
44
+ * const size = getResponseSize(response);
45
+ * console.log(`Download size: ${size} bytes`);
23
46
  */
24
47
  export function getResponseSize(response: Response): number;
25
48
  /**
26
49
  * Wait for a response and check if the response is ok
50
+ * This function awaits a response promise and performs error checking,
51
+ * wrapping network errors in a standardized ResponseError format.
27
52
  *
28
- * @example
29
- * const response = await waitForAndCheckResponse( responsePromise );
53
+ * @param {Promise<Response>} responsePromise - Promise that resolves to a Response
30
54
  *
31
- * @param {Promise<Response>} responsePromise
32
- * @param {string|URL} url - An url that is used for error messages
55
+ * @param {string|URL} url - URL used for the request (for error messages)
33
56
  *
34
- * @throws ResponseError - A response error if something went wrong
57
+ * @throws {ResponseError} When a network error occurs or response is not ok
35
58
  *
36
- * @returns {Promise<Response>} response
59
+ * @returns {Promise<Response>} The response if successful
60
+ *
61
+ * @example
62
+ * // Handle a fetch promise with proper error handling
63
+ * const responsePromise = fetch('https://api.example.com/data');
64
+ * try {
65
+ * const response = await waitForAndCheckResponse(
66
+ * responsePromise,
67
+ * 'https://api.example.com/data'
68
+ * );
69
+ * // Process response
70
+ * } catch (error) {
71
+ * // Handle standardized ResponseError
72
+ * console.error(error.message);
73
+ * }
37
74
  */
38
75
  export function waitForAndCheckResponse(responsePromise: Promise<Response>, url: string | URL): Promise<Response>;
39
76
  /**
40
- * Load response body as ArrayBuffer
41
- * - Progress can be monitored by suppying an onProgress callback
42
- * - Loading can be aborted by calling the returned abort function
77
+ * Load response body as ArrayBuffer with progress monitoring and abort capability
43
78
  *
44
- * @param {Response} response - Fetch response
45
- * @param {progressCallback} onProgress
79
+ * This function reads a response body stream chunk by chunk, with optional
80
+ * progress reporting. It provides an abort mechanism to cancel an in-progress
81
+ * download.
46
82
  *
47
- * @returns {{ bufferPromise: Promise<ArrayBuffer>, abort: () => void }}
83
+ * @param {Response} response - Fetch Response object to read
84
+ *
85
+ * @param {progressCallback} [onProgress] - Optional callback for progress updates
86
+ *
87
+ * @returns {{
88
+ * bufferPromise: Promise<ArrayBuffer>,
89
+ * abort: () => void
90
+ * }} Object containing the buffer promise and abort function
91
+ *
92
+ * @example
93
+ * // Download a file with progress monitoring and abort capability
94
+ * const response = await fetch('https://example.com/large-file.zip');
95
+ *
96
+ * const { bufferPromise, abort } = loadResponseBuffer(
97
+ * response,
98
+ * ({ bytesLoaded, size }) => {
99
+ * // Update progress UI
100
+ * const percent = size ? Math.round((bytesLoaded / size) * 100) : 0;
101
+ * console.log(`Downloaded ${bytesLoaded} bytes (${percent}%)`);
102
+ * }
103
+ * );
104
+ *
105
+ * // To abort the download:
106
+ * // abort();
107
+ *
108
+ * try {
109
+ * const buffer = await bufferPromise;
110
+ * // Process the complete buffer
111
+ * } catch (error) {
112
+ * console.error('Download failed or was aborted', error);
113
+ * }
48
114
  */
49
- export function loadResponseBuffer(response: Response, onProgress: progressCallback): {
115
+ export function loadResponseBuffer(response: Response, onProgress?: progressCallback): {
50
116
  bufferPromise: Promise<ArrayBuffer>;
51
117
  abort: () => void;
52
118
  };
119
+ /**
120
+ * Callback function that reports progress of data loading
121
+ */
53
122
  export type progressCallback = (_: {
54
123
  bytesLoaded: number;
55
124
  size: number;