@azure-net/kit 3.1.0 → 3.9.1

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 (48) hide show
  1. package/README.md +2 -2
  2. package/dist/core/delivery/injectableDependencies/AsyncHelpers.d.ts +8 -2
  3. package/dist/core/delivery/injectableDependencies/AsyncHelpers.js +32 -10
  4. package/dist/core/delivery/schema/Schema.js +1 -1
  5. package/dist/core/delivery/serverAction/CreateServerAction.js +1 -1
  6. package/dist/core/infra/datasource/BaseDatasource.d.ts +11 -11
  7. package/dist/core/infra/datasource/BaseDatasource.js +4 -4
  8. package/dist/core/infra/httpService/HttpServiceInstance.d.ts +82 -0
  9. package/dist/core/infra/httpService/HttpServiceInstance.js +342 -0
  10. package/dist/core/infra/httpService/index.d.ts +1 -1
  11. package/dist/core/infra/httpService/index.js +1 -1
  12. package/dist/core/infra/query/QueryBuilder.d.ts +9 -21
  13. package/dist/core/infra/query/QueryBuilder.js +62 -50
  14. package/dist/core/shared/appEventBus/EventBus.d.ts +1 -1
  15. package/dist/core/shared/appEventBus/EventBus.js +2 -2
  16. package/dist/core/shared/boundaryProvider/Provider.d.ts +2 -2
  17. package/dist/core/shared/boundaryProvider/Provider.js +14 -8
  18. package/dist/core/shared/cookie/UniversalCookie.js +2 -2
  19. package/dist/core/shared/middleware/Middleware.js +12 -8
  20. package/dist/core/svelte/ActiveForm/ActiveForm.svelte.d.ts +4 -1
  21. package/dist/core/svelte/ActiveForm/ActiveForm.svelte.js +19 -18
  22. package/dist/core/svelte/AsyncSignal/AsyncSignal.svelte.js +1 -1
  23. package/dist/core/svelte/Query/Query.svelte.js +1 -1
  24. package/dist/core/ui/onClickOutside/OnClickOutside.js +1 -1
  25. package/dist/core/ui/scrollTo/index.js +1 -1
  26. package/dist/edges/context/index.d.ts +1 -1
  27. package/dist/edges/context/index.js +1 -1
  28. package/dist/edges/dev/index.d.ts +1 -1
  29. package/dist/edges/dev/index.js +1 -1
  30. package/dist/edges/index.d.ts +1 -1
  31. package/dist/edges/index.js +1 -1
  32. package/dist/edges/plugin/index.d.ts +1 -1
  33. package/dist/edges/plugin/index.js +1 -1
  34. package/dist/edges/server/index.d.ts +1 -1
  35. package/dist/edges/server/index.js +1 -1
  36. package/dist/edges/state/index.d.ts +1 -1
  37. package/dist/edges/state/index.js +1 -1
  38. package/dist/i18n/index.d.ts +1 -1
  39. package/dist/i18n/index.js +1 -1
  40. package/dist/tools/index.d.ts +2 -1
  41. package/dist/tools/index.js +2 -1
  42. package/package.json +36 -42
  43. package/dist/core/infra/httpService/HttpService.d.ts +0 -74
  44. package/dist/core/infra/httpService/HttpService.js +0 -164
  45. package/dist/core/shared/eventBus/EventBus.d.ts +0 -87
  46. package/dist/core/shared/eventBus/EventBus.js +0 -227
  47. package/dist/core/shared/eventBus/index.d.ts +0 -1
  48. package/dist/core/shared/eventBus/index.js +0 -1
package/README.md CHANGED
@@ -10,8 +10,8 @@
10
10
 
11
11
  ## 🚀 What's included?
12
12
 
13
- - **Built-in store** — flexible and SSR-friendly state management powered by [edges-svelte](https://github.com/Pixel1917/edge-s).
14
- - **Localization and translation** — ready-to-use i18n solution ([edges-svelte-translations](https://github.com/Pixel1917/edges-svelte-translations)) for multilingual applications.
13
+ - **Built-in store** — flexible and SSR-friendly state management powered by [@azure-net/edges](https://github.com/Pixel1917/edge-s).
14
+ - **Localization and translation** — ready-to-use i18n solution ([@azure-net/edges-translations](https://github.com/Pixel1917/edges-svelte-translations)) for multilingual applications.
15
15
  - **Extensive utilities** — for working with text, objects, dates, and common tasks.
16
16
  - **Data validation** — handy rules and validators.
17
17
  - **Reusable base abstractions** — `Repositories`, `Services`, `Providers`, and `Datasources` for quick setup and reuse.
@@ -9,7 +9,10 @@ export declare const createAsyncHelpers: <BaseError = unknown, Custom = unknown>
9
9
  parseError?: ReturnType<typeof createErrorParser<BaseError, Custom>>;
10
10
  }) => {
11
11
  createAsyncAction: <Res = unknown, Req = unknown>(action: ActionOrThunk<Res>, args?: {
12
- beforeSend?: (next: () => void, abort: () => void) => void | Promise<void>;
12
+ beforeSend?: (actions: {
13
+ next: () => void;
14
+ abort: () => void;
15
+ }) => void | Promise<void>;
13
16
  onSuccess?: (result: AsyncActionResponse<Res, undefined, Custom>) => Promise<unknown> | unknown;
14
17
  onError?: (result: AsyncActionResponse<never, Req, Custom>) => Promise<unknown> | unknown;
15
18
  reject?: boolean;
@@ -21,7 +24,10 @@ export declare const createAsyncHelpers: <BaseError = unknown, Custom = unknown>
21
24
  maxRetries?: number;
22
25
  }) => Promise<AsyncActionResponse<Res, Req, Custom>>;
23
26
  createAsyncResource: <Res, Req_1 = unknown>(action: ActionOrThunk<Res>, args?: {
24
- beforeSend?: (next: () => void, abort: () => void) => void | Promise<void>;
27
+ beforeSend?: (actions: {
28
+ next: () => void;
29
+ abort: () => void;
30
+ }) => void | Promise<void>;
25
31
  onSuccess?: (result: Res) => Promise<unknown> | unknown;
26
32
  onError?: (error: AppError<Req_1, Custom>) => Promise<unknown> | unknown;
27
33
  reject?: boolean;
@@ -20,11 +20,22 @@ export const createAsyncHelpers = (opts) => {
20
20
  }
21
21
  if (args?.beforeSend) {
22
22
  const beforeSendResult = await new Promise((resolve) => {
23
- const next = () => resolve('next');
24
- const abort = () => resolve('abort');
25
- Promise.resolve(args.beforeSend(next, abort)).catch((err) => {
23
+ let settled = false;
24
+ const settle = (value) => {
25
+ if (settled)
26
+ return;
27
+ settled = true;
28
+ resolve(value);
29
+ };
30
+ const next = () => settle('next');
31
+ const abort = () => settle('abort');
32
+ Promise.resolve(args.beforeSend({ next, abort }))
33
+ .then(() => {
34
+ settle('next');
35
+ })
36
+ .catch((err) => {
26
37
  console.error('Error in beforeSend:', err);
27
- resolve('abort');
38
+ settle('abort');
28
39
  });
29
40
  });
30
41
  if (beforeSendResult === 'abort') {
@@ -69,7 +80,7 @@ export const createAsyncHelpers = (opts) => {
69
80
  return retryResult;
70
81
  }
71
82
  const { bus } = AppEvents();
72
- bus.publish('OnAsyncHelperError', error);
83
+ bus.publish('OnAsyncHelperError', () => error);
73
84
  const result = { error, response: args?.fallbackResponse, success: false };
74
85
  await args?.onError?.(result);
75
86
  if (args?.reject)
@@ -84,11 +95,22 @@ export const createAsyncHelpers = (opts) => {
84
95
  }
85
96
  if (args?.beforeSend) {
86
97
  const beforeSendResult = await new Promise((resolve) => {
87
- const next = () => resolve('next');
88
- const abort = () => resolve('abort');
89
- Promise.resolve(args.beforeSend(next, abort)).catch((err) => {
98
+ let settled = false;
99
+ const settle = (value) => {
100
+ if (settled)
101
+ return;
102
+ settled = true;
103
+ resolve(value);
104
+ };
105
+ const next = () => settle('next');
106
+ const abort = () => settle('abort');
107
+ Promise.resolve(args.beforeSend({ next, abort }))
108
+ .then(() => {
109
+ settle('next');
110
+ })
111
+ .catch((err) => {
90
112
  console.error('Error in beforeSend:', err);
91
- resolve('abort');
113
+ settle('abort');
92
114
  });
93
115
  });
94
116
  if (beforeSendResult === 'abort') {
@@ -128,7 +150,7 @@ export const createAsyncHelpers = (opts) => {
128
150
  return retryResult;
129
151
  }
130
152
  const { bus } = AppEvents();
131
- bus.publish('OnAsyncHelperError', error);
153
+ bus.publish('OnAsyncHelperError', () => error);
132
154
  await args?.onError?.(error);
133
155
  if (args?.reject)
134
156
  throw error;
@@ -1,4 +1,4 @@
1
- import { FormDataUtil } from 'azure-net-tools';
1
+ import { FormDataUtil } from '@azure-net/tools';
2
2
  export class SchemaFail {
3
3
  _errors;
4
4
  constructor(_errors) {
@@ -1,6 +1,6 @@
1
1
  import { RequestContext } from '../../../edges/context/index.js';
2
2
  import { error, fail, redirect } from '@sveltejs/kit';
3
- import { EnvironmentUtil } from 'azure-net-tools';
3
+ import { EnvironmentUtil } from '@azure-net/tools';
4
4
  export const createServerAction = (factory, inject) => {
5
5
  return () => {
6
6
  if (EnvironmentUtil.isBrowser) {
@@ -1,16 +1,16 @@
1
- import { HttpService, HttpServiceResponse } from '../httpService/HttpService.js';
2
- import { QueryBuilder } from '../query/index.js';
1
+ import { type IHttpServiceInstance, type IHttpServiceResponse } from '../httpService/HttpServiceInstance.js';
2
+ import { type IQueryBuilderInstance } from '../query/index.js';
3
3
  export type CreateRequestCallbackType<T> = (params: {
4
- http: HttpService;
5
- query: QueryBuilder;
6
- }) => Promise<HttpServiceResponse<T>>;
7
- export declare class BaseHttpDatasource<TQueryBuilder extends QueryBuilder = QueryBuilder> {
8
- protected readonly httpClient: HttpService;
9
- protected readonly query: QueryBuilder;
4
+ http: IHttpServiceInstance;
5
+ query: IQueryBuilderInstance;
6
+ }) => Promise<IHttpServiceResponse<T>>;
7
+ export declare class BaseHttpDatasource {
8
+ protected readonly httpClient: IHttpServiceInstance;
9
+ protected readonly query: IQueryBuilderInstance;
10
10
  constructor(params: {
11
- http?: HttpService;
12
- query?: TQueryBuilder;
11
+ http?: IHttpServiceInstance;
12
+ query?: IQueryBuilderInstance;
13
13
  });
14
14
  private _createRawRequest;
15
- readonly createRawRequest: <T>(callback: CreateRequestCallbackType<T>) => Promise<HttpServiceResponse<T>>;
15
+ readonly createRawRequest: <T>(callback: CreateRequestCallbackType<T>) => Promise<IHttpServiceResponse<T>>;
16
16
  }
@@ -1,11 +1,11 @@
1
- import { HttpService, HttpServiceError, HttpServiceResponse } from '../httpService/HttpService.js';
2
- import { QueryBuilder } from '../query/index.js';
1
+ import { createHttpServiceInstance } from '../httpService/HttpServiceInstance.js';
2
+ import { createQueryInstance } from '../query/index.js';
3
3
  export class BaseHttpDatasource {
4
4
  httpClient;
5
5
  query;
6
6
  constructor(params) {
7
- this.httpClient = params.http ?? new HttpService({ baseUrl: '' });
8
- this.query = params.query ?? new QueryBuilder();
7
+ this.httpClient = params.http ?? createHttpServiceInstance();
8
+ this.query = params.query ?? createQueryInstance();
9
9
  }
10
10
  async _createRawRequest(callback) {
11
11
  return await callback({ http: this.httpClient, query: this.query }).catch((err) => {
@@ -0,0 +1,82 @@
1
+ export type SearchParamsInit = string | string[][] | Record<string, string> | URLSearchParams | undefined;
2
+ export type SearchParamsOption = SearchParamsInit | Record<string, string | number | boolean | undefined> | Array<Array<string | number | boolean>>;
3
+ export declare enum HttpInstanceFetchMethods {
4
+ GET = "GET",
5
+ POST = "POST",
6
+ PUT = "PUT",
7
+ PATCH = "PATCH",
8
+ DELETE = "DELETE",
9
+ HEAD = "HEAD",
10
+ OPTIONS = "OPTIONS"
11
+ }
12
+ export interface IHttpServiceResponse<T = unknown> {
13
+ headers: Record<string, string>;
14
+ status: number;
15
+ success: boolean;
16
+ data: T;
17
+ message: string;
18
+ raw?: Response;
19
+ }
20
+ export interface IHttpServiceError<T = unknown> extends IHttpServiceResponse<T> {
21
+ original?: Error;
22
+ }
23
+ export declare class HttpServiceResponse<T> implements IHttpServiceResponse<T> {
24
+ headers: Record<string, string>;
25
+ status: number;
26
+ success: boolean;
27
+ data: T;
28
+ message: string;
29
+ raw?: Response;
30
+ constructor({ headers, status, success, data, message, raw }: IHttpServiceResponse<T>);
31
+ }
32
+ export declare class HttpServiceError<T> implements IHttpServiceError<T> {
33
+ headers: Record<string, string>;
34
+ status: number;
35
+ success: boolean;
36
+ data: T;
37
+ message: string;
38
+ original?: Error;
39
+ raw?: Response;
40
+ constructor({ headers, status, success, data, message, original, raw }: IHttpServiceError<T>);
41
+ }
42
+ export interface HttpInstanceNormalizedRequest {
43
+ url: string | URL;
44
+ method: HttpInstanceFetchMethods;
45
+ headers: Headers;
46
+ body: BodyInit | null | undefined;
47
+ responseFormat: 'json' | 'blob' | 'text' | 'arrayBuffer' | 'body';
48
+ includeRaw: boolean;
49
+ timeout: number | false;
50
+ retry: number;
51
+ stringifyJson: (data: unknown) => string | undefined;
52
+ fetch: typeof fetch;
53
+ requestInit: Omit<RequestInit, 'method' | 'headers' | 'body'>;
54
+ }
55
+ export type HttpInstanceOnRequest = (request: HttpInstanceNormalizedRequest) => void | Promise<void>;
56
+ export type HttpInstanceOnError = (error: HttpServiceError<unknown>, request: HttpInstanceNormalizedRequest) => HttpServiceError<unknown> | Promise<HttpServiceError<unknown>>;
57
+ export type HttpInstanceDoFetch = <T = unknown>(request: HttpInstanceNormalizedRequest) => Promise<IHttpServiceResponse<T>>;
58
+ export interface IHttpInstanceOptions extends Omit<RequestInit, 'headers' | 'method'> {
59
+ headers?: NonNullable<RequestInit['headers']> | Record<string, string | undefined>;
60
+ json?: unknown;
61
+ stringifyJson?: (data: unknown) => string | undefined;
62
+ searchParams?: SearchParamsOption;
63
+ prefixUrl?: URL | string;
64
+ timeout?: number | false;
65
+ retry?: number;
66
+ includeRaw?: boolean;
67
+ responseFormat?: 'json' | 'blob' | 'text' | 'arrayBuffer' | 'body';
68
+ onRequest?: HttpInstanceOnRequest;
69
+ onError?: HttpInstanceOnError;
70
+ doFetch?: HttpInstanceDoFetch;
71
+ }
72
+ export type HttpInstanceRequestMethod = <T = unknown>(url: string | URL, options?: IHttpInstanceOptions) => Promise<IHttpServiceResponse<T>>;
73
+ export interface IHttpServiceInstance {
74
+ get: HttpInstanceRequestMethod;
75
+ post: HttpInstanceRequestMethod;
76
+ put: HttpInstanceRequestMethod;
77
+ delete: HttpInstanceRequestMethod;
78
+ patch: HttpInstanceRequestMethod;
79
+ head: HttpInstanceRequestMethod;
80
+ options: HttpInstanceRequestMethod;
81
+ }
82
+ export declare const createHttpServiceInstance: (config?: IHttpInstanceOptions) => IHttpServiceInstance;
@@ -0,0 +1,342 @@
1
+ import { BROWSER } from '@azure-net/tools/environment';
2
+ import { RequestContext } from '@azure-net/edges/context';
3
+ export var HttpInstanceFetchMethods;
4
+ (function (HttpInstanceFetchMethods) {
5
+ HttpInstanceFetchMethods["GET"] = "GET";
6
+ HttpInstanceFetchMethods["POST"] = "POST";
7
+ HttpInstanceFetchMethods["PUT"] = "PUT";
8
+ HttpInstanceFetchMethods["PATCH"] = "PATCH";
9
+ HttpInstanceFetchMethods["DELETE"] = "DELETE";
10
+ HttpInstanceFetchMethods["HEAD"] = "HEAD";
11
+ HttpInstanceFetchMethods["OPTIONS"] = "OPTIONS";
12
+ })(HttpInstanceFetchMethods || (HttpInstanceFetchMethods = {}));
13
+ export class HttpServiceResponse {
14
+ headers;
15
+ status;
16
+ success;
17
+ data;
18
+ message;
19
+ raw;
20
+ constructor({ headers, status, success, data, message, raw }) {
21
+ this.headers = headers;
22
+ this.status = status;
23
+ this.success = success;
24
+ this.data = data;
25
+ this.message = message;
26
+ this.raw = raw;
27
+ }
28
+ }
29
+ export class HttpServiceError {
30
+ headers;
31
+ status;
32
+ success;
33
+ data;
34
+ message;
35
+ original;
36
+ raw;
37
+ constructor({ headers, status, success, data, message, original, raw }) {
38
+ this.headers = headers;
39
+ this.status = status;
40
+ this.success = success;
41
+ this.data = data;
42
+ this.message = message;
43
+ this.original = original;
44
+ this.raw = raw;
45
+ }
46
+ }
47
+ const stringifyJsonFunc = (data) => {
48
+ try {
49
+ return JSON.stringify(data);
50
+ }
51
+ catch {
52
+ return undefined;
53
+ }
54
+ };
55
+ const isAbsoluteUrl = (value) => /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(value);
56
+ const normalizeHeaders = (headers) => {
57
+ if (!headers)
58
+ return new Headers();
59
+ if (headers instanceof Headers)
60
+ return new Headers(headers);
61
+ if (Array.isArray(headers))
62
+ return new Headers(headers);
63
+ return new Headers(Object.entries(headers).filter(([, value]) => value !== undefined));
64
+ };
65
+ const normalizeSearchParams = (value) => {
66
+ if (!value)
67
+ return new URLSearchParams();
68
+ if (value instanceof URLSearchParams)
69
+ return new URLSearchParams(value);
70
+ if (typeof value === 'string')
71
+ return new URLSearchParams(value);
72
+ if (Array.isArray(value)) {
73
+ const params = new URLSearchParams();
74
+ for (const [key, rawValue] of value) {
75
+ params.append(String(key), String(rawValue));
76
+ }
77
+ return params;
78
+ }
79
+ const params = new URLSearchParams();
80
+ for (const [key, rawValue] of Object.entries(value)) {
81
+ if (rawValue === undefined)
82
+ continue;
83
+ params.append(key, String(rawValue));
84
+ }
85
+ return params;
86
+ };
87
+ const mergeSearchParams = (base, extra) => {
88
+ if (!base && !extra)
89
+ return undefined;
90
+ const result = normalizeSearchParams(base);
91
+ const next = normalizeSearchParams(extra);
92
+ for (const [key, value] of next.entries()) {
93
+ result.append(key, value);
94
+ }
95
+ return result;
96
+ };
97
+ const mergeOptions = (base = {}, extra = {}) => {
98
+ const mergedHeaders = new Headers(normalizeHeaders(base.headers));
99
+ for (const [key, value] of normalizeHeaders(extra.headers).entries()) {
100
+ mergedHeaders.set(key, value);
101
+ }
102
+ const mergedSearchParams = mergeSearchParams(base.searchParams, extra.searchParams);
103
+ return {
104
+ ...base,
105
+ ...extra,
106
+ headers: mergedHeaders,
107
+ searchParams: mergedSearchParams,
108
+ stringifyJson: extra.stringifyJson ?? base.stringifyJson,
109
+ onRequest: extra.onRequest ?? base.onRequest,
110
+ onError: extra.onError ?? base.onError,
111
+ doFetch: extra.doFetch ?? base.doFetch
112
+ };
113
+ };
114
+ const mergeQueryToRelativeUrl = (url, searchParams) => {
115
+ const hashIndex = url.indexOf('#');
116
+ const hash = hashIndex >= 0 ? url.slice(hashIndex) : '';
117
+ const urlWithoutHash = hashIndex >= 0 ? url.slice(0, hashIndex) : url;
118
+ const queryIndex = urlWithoutHash.indexOf('?');
119
+ const path = queryIndex >= 0 ? urlWithoutHash.slice(0, queryIndex) : urlWithoutHash;
120
+ const query = queryIndex >= 0 ? urlWithoutHash.slice(queryIndex + 1) : '';
121
+ const merged = new URLSearchParams(query);
122
+ for (const [key, value] of searchParams.entries()) {
123
+ merged.append(key, value);
124
+ }
125
+ const nextQuery = merged.toString();
126
+ return `${path}${nextQuery ? `?${nextQuery}` : ''}${hash}`;
127
+ };
128
+ const resolveUrl = (target, baseUrl, searchParams) => {
129
+ if (!baseUrl && !searchParams)
130
+ return target;
131
+ let rawUrl = String(target);
132
+ if (baseUrl) {
133
+ const base = String(baseUrl);
134
+ rawUrl = isAbsoluteUrl(rawUrl) ? rawUrl : new URL(rawUrl, base).toString();
135
+ }
136
+ if (!searchParams)
137
+ return rawUrl;
138
+ const normalizedSearchParams = normalizeSearchParams(searchParams);
139
+ if (!normalizedSearchParams.size)
140
+ return rawUrl;
141
+ if (isAbsoluteUrl(rawUrl)) {
142
+ const absoluteUrl = new URL(rawUrl);
143
+ for (const [key, value] of normalizedSearchParams.entries()) {
144
+ absoluteUrl.searchParams.append(key, value);
145
+ }
146
+ return absoluteUrl.toString();
147
+ }
148
+ return mergeQueryToRelativeUrl(rawUrl, normalizedSearchParams);
149
+ };
150
+ const parseBodyByFormat = async (response, format) => {
151
+ switch (format) {
152
+ case 'blob':
153
+ return (await response.blob());
154
+ case 'text':
155
+ return (await response.text());
156
+ case 'arrayBuffer':
157
+ return (await response.arrayBuffer());
158
+ case 'body':
159
+ return response.body;
160
+ case 'json':
161
+ return (await response.json());
162
+ default:
163
+ return (await response.json());
164
+ }
165
+ };
166
+ const withTimeout = (signal, timeout) => {
167
+ if (!timeout || timeout <= 0) {
168
+ return { signal, clear: () => undefined };
169
+ }
170
+ const controller = new AbortController();
171
+ const timer = setTimeout(() => controller.abort(new Error('Request timeout exceeded')), timeout);
172
+ const abortBySource = () => controller.abort(signal?.reason);
173
+ if (signal) {
174
+ if (signal.aborted) {
175
+ abortBySource();
176
+ }
177
+ else {
178
+ signal.addEventListener('abort', abortBySource, { once: true });
179
+ }
180
+ }
181
+ return {
182
+ signal: controller.signal,
183
+ clear: () => {
184
+ clearTimeout(timer);
185
+ if (signal)
186
+ signal.removeEventListener('abort', abortBySource);
187
+ }
188
+ };
189
+ };
190
+ const shouldRetryError = (error) => {
191
+ if (error instanceof HttpServiceError) {
192
+ return [408, 425, 429, 500, 502, 503, 504].includes(error.status);
193
+ }
194
+ return !(error instanceof Error && error.name === 'AbortError');
195
+ };
196
+ const normalizeUnknownError = (error) => {
197
+ if (error instanceof Error)
198
+ return error;
199
+ return new Error(String(error));
200
+ };
201
+ const defaultDoFetch = async (request) => {
202
+ const maxAttempts = Math.max(1, Math.floor(request.retry) + 1);
203
+ let lastError;
204
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
205
+ const timeoutState = withTimeout(request.requestInit.signal ?? null, request.timeout);
206
+ try {
207
+ const response = await request.fetch(request.url, {
208
+ ...request.requestInit,
209
+ method: request.method,
210
+ headers: request.headers,
211
+ body: request.body,
212
+ signal: timeoutState.signal ?? undefined
213
+ });
214
+ const rawResponse = request.includeRaw ? response.clone() : undefined;
215
+ const data = await parseBodyByFormat(response, request.responseFormat);
216
+ if (!response.ok) {
217
+ const httpError = new HttpServiceError({
218
+ headers: Object.fromEntries(response.headers.entries()),
219
+ status: response.status,
220
+ success: false,
221
+ data,
222
+ message: `Request failed with status code ${response.status}`,
223
+ raw: rawResponse
224
+ });
225
+ lastError = httpError;
226
+ if (attempt >= maxAttempts || !shouldRetryError(httpError)) {
227
+ throw httpError;
228
+ }
229
+ continue;
230
+ }
231
+ return new HttpServiceResponse({
232
+ headers: Object.fromEntries(response.headers.entries()),
233
+ status: response.status,
234
+ success: true,
235
+ data,
236
+ message: 'Request completed',
237
+ raw: rawResponse
238
+ });
239
+ }
240
+ catch (error) {
241
+ lastError = error;
242
+ if (attempt >= maxAttempts || !shouldRetryError(error)) {
243
+ throw error;
244
+ }
245
+ }
246
+ finally {
247
+ timeoutState.clear();
248
+ }
249
+ }
250
+ throw lastError;
251
+ };
252
+ const makeMethod = (method, defaults) => {
253
+ return async (url, options = {}) => {
254
+ const merged = mergeOptions(defaults, options);
255
+ const stringifyJson = merged.stringifyJson ?? stringifyJsonFunc;
256
+ const fetcher = !BROWSER ? (RequestContext.current()?.event?.fetch ?? fetch) : fetch;
257
+ const headers = normalizeHeaders(merged.headers);
258
+ let body = merged.body;
259
+ if (merged.json !== undefined && body === undefined) {
260
+ body = stringifyJson(merged.json);
261
+ if (!headers.has('content-type')) {
262
+ headers.set('content-type', 'application/json');
263
+ }
264
+ }
265
+ const responseFormat = merged.responseFormat ?? 'json';
266
+ if (responseFormat === 'json' && !headers.has('accept')) {
267
+ headers.set('accept', 'application/json');
268
+ }
269
+ const normalizedRequest = {
270
+ url: resolveUrl(url, merged.prefixUrl, merged.searchParams),
271
+ method,
272
+ headers,
273
+ body,
274
+ responseFormat,
275
+ includeRaw: merged.includeRaw ?? false,
276
+ timeout: merged.timeout ?? 20000,
277
+ retry: merged.retry ?? 0,
278
+ stringifyJson,
279
+ fetch: fetcher,
280
+ requestInit: {
281
+ cache: merged.cache,
282
+ credentials: merged.credentials,
283
+ integrity: merged.integrity,
284
+ keepalive: merged.keepalive,
285
+ mode: merged.mode,
286
+ priority: merged.priority,
287
+ redirect: merged.redirect,
288
+ referrer: merged.referrer,
289
+ referrerPolicy: merged.referrerPolicy,
290
+ signal: merged.signal,
291
+ window: merged.window
292
+ }
293
+ };
294
+ const onRequest = options.onRequest ?? defaults.onRequest;
295
+ if (onRequest) {
296
+ await onRequest(normalizedRequest);
297
+ }
298
+ const doFetch = merged.doFetch ?? defaults.doFetch ?? defaultDoFetch;
299
+ try {
300
+ return await doFetch(normalizedRequest);
301
+ }
302
+ catch (error) {
303
+ const normalizedError = error instanceof HttpServiceError
304
+ ? error
305
+ : new HttpServiceError({
306
+ headers: {},
307
+ status: 500,
308
+ success: false,
309
+ data: undefined,
310
+ message: normalizeUnknownError(error).message,
311
+ original: normalizeUnknownError(error)
312
+ });
313
+ const onError = options.onError ?? defaults.onError;
314
+ if (!onError)
315
+ throw normalizedError;
316
+ const handledError = await onError(normalizedError, normalizedRequest);
317
+ if (!(handledError instanceof HttpServiceError)) {
318
+ throw new HttpServiceError({
319
+ headers: normalizedError.headers,
320
+ status: normalizedError.status,
321
+ success: false,
322
+ data: normalizedError.data,
323
+ message: 'onError hook must return HttpServiceError',
324
+ original: new Error(normalizedError.message)
325
+ });
326
+ }
327
+ throw handledError;
328
+ }
329
+ };
330
+ };
331
+ export const createHttpServiceInstance = (config = {}) => {
332
+ const defaults = { ...config };
333
+ return {
334
+ get: makeMethod(HttpInstanceFetchMethods.GET, defaults),
335
+ post: makeMethod(HttpInstanceFetchMethods.POST, defaults),
336
+ put: makeMethod(HttpInstanceFetchMethods.PUT, defaults),
337
+ delete: makeMethod(HttpInstanceFetchMethods.DELETE, defaults),
338
+ patch: makeMethod(HttpInstanceFetchMethods.PATCH, defaults),
339
+ head: makeMethod(HttpInstanceFetchMethods.HEAD, defaults),
340
+ options: makeMethod(HttpInstanceFetchMethods.OPTIONS, defaults)
341
+ };
342
+ };
@@ -1,2 +1,2 @@
1
- export * from './HttpService.js';
2
1
  export * from './Statuses.js';
2
+ export * from './HttpServiceInstance.js';
@@ -1,2 +1,2 @@
1
- export * from './HttpService.js';
2
1
  export * from './Statuses.js';
2
+ export * from './HttpServiceInstance.js';
@@ -1,25 +1,13 @@
1
1
  export type ArrayFormat = 'repeat' | 'brackets' | 'comma' | 'json';
2
2
  export type ObjectFormat = 'default' | 'nested-brackets';
3
- export interface IQueryBuilder {
4
- build(query: Record<string, unknown>, opts?: {
5
- arrayFormat?: ArrayFormat;
6
- objectFormat?: ObjectFormat;
7
- }): string;
8
- transform(object: object): object;
3
+ export interface IQueryBuilderSettings<TTransformInput extends object = object> {
4
+ delimiter?: boolean;
5
+ arrayFormat?: ArrayFormat;
6
+ objectFormat?: ObjectFormat;
7
+ transform?: (obj: TTransformInput) => object;
9
8
  }
10
- export declare class QueryBuilder implements IQueryBuilder {
11
- private readonly defaultArrayFormat;
12
- private readonly defaultObjectFormat;
13
- constructor(options?: {
14
- arrayFormat?: ArrayFormat;
15
- objectFormat?: ObjectFormat;
16
- });
17
- transform(object: object): object;
18
- build(query?: object, opts?: {
19
- delimiter?: boolean;
20
- arrayFormat?: ArrayFormat;
21
- objectFormat?: ObjectFormat;
22
- }): string;
23
- private serialize;
24
- private encodeArray;
9
+ export interface IQueryBuilderInstance<TTransformInput extends object = object> {
10
+ toString: (query: object, settings?: IQueryBuilderSettings<TTransformInput>) => string;
11
+ toSearchParams: (query: object, settings?: Omit<IQueryBuilderSettings<TTransformInput>, 'delimiter'>) => URLSearchParams;
25
12
  }
13
+ export declare const createQueryInstance: <TTransformInput extends object = object>(defaults?: IQueryBuilderSettings<TTransformInput>) => IQueryBuilderInstance<TTransformInput>;