@azure-net/kit 6.0.0-next.1 → 6.0.0-next.2
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.
- package/README.md +178 -2
- package/dist/delivery/index.d.ts +2 -1
- package/dist/delivery/index.js +2 -1
- package/dist/delivery/injectable-dependencies/AsyncHelpers.d.ts +2 -4
- package/dist/delivery/injectable-dependencies/AsyncHelpers.js +96 -102
- package/dist/delivery/presenter/RegisterProvider.d.ts +9 -0
- package/dist/delivery/presenter/RegisterProvider.js +51 -0
- package/dist/delivery.d.ts +0 -1
- package/dist/delivery.js +0 -1
- package/dist/i18n/Internal.d.ts +13 -0
- package/dist/i18n/Internal.js +10 -0
- package/dist/i18n/Translations.svelte.d.ts +20 -0
- package/dist/i18n/Translations.svelte.js +254 -0
- package/dist/i18n/Types.d.ts +30 -0
- package/dist/i18n/Types.js +1 -0
- package/dist/i18n/index.d.ts +2 -0
- package/dist/i18n/index.js +1 -0
- package/dist/infra/datasource/BaseDatasource.d.ts +19 -6
- package/dist/infra/datasource/BaseDatasource.js +4 -4
- package/dist/infra/http-service/HttpServiceInstance.d.ts +26 -16
- package/dist/infra/http-service/HttpServiceInstance.js +21 -13
- package/dist/infra/index.d.ts +2 -2
- package/dist/infra/index.js +2 -2
- package/dist/infra/query/QueryBuilder.d.ts +6 -1
- package/dist/infra/query/QueryBuilder.js +14 -12
- package/dist/plugin/AzureNetPlugin.d.ts +1 -4
- package/dist/plugin/AzureNetPlugin.js +16 -64
- package/dist/plugin/index.d.ts +1 -1
- package/dist/server/Context/Runtime.d.ts +2 -0
- package/dist/server/Context/Runtime.js +18 -0
- package/dist/server/Context/index.d.ts +1 -0
- package/dist/server/Context/index.js +1 -0
- package/dist/shared/app/App.d.ts +44 -69
- package/dist/shared/app/App.js +91 -102
- package/dist/shared/app/index.d.ts +2 -1
- package/dist/shared/app/middleware/ClientMiddleware.d.ts +2 -2
- package/dist/shared/app/middleware/ClientMiddleware.js +0 -1
- package/dist/shared/app/middleware/ServerMiddleware.d.ts +1 -1
- package/dist/shared/app/middleware/ServerMiddleware.js +1 -1
- package/dist/shared/app-error/ErrorRuntime.d.ts +1 -1
- package/dist/shared/app-error/ErrorRuntime.js +4 -3
- package/dist/shared/boundary-provider/Provider.d.ts +1 -1
- package/dist/shared/boundary-provider/Provider.js +44 -29
- package/dist/shared/cookie/UniversalCookie.js +1 -1
- package/dist/shared/index.d.ts +1 -3
- package/dist/shared/index.js +1 -3
- package/dist/shared/logger/index.js +1 -1
- package/dist/shared/request-context/Internal.d.ts +16 -0
- package/dist/shared/request-context/Internal.js +24 -0
- package/dist/svelte/index.d.ts +1 -0
- package/dist/svelte/index.js +1 -0
- package/dist/svelte/query/Query.svelte.js +4 -2
- package/package.json +151 -134
- package/dist/external/edges/Dev.d.ts +0 -1
- package/dist/external/edges/Dev.js +0 -1
- package/dist/external/edges/Edges.d.ts +0 -1
- package/dist/external/edges/Edges.js +0 -1
- package/dist/external/edges/ServerContext.d.ts +0 -1
- package/dist/external/edges/ServerContext.js +0 -1
- package/dist/external/edges/_edges.d.ts +0 -1
- package/dist/external/edges/_edges.js +0 -1
- package/dist/external/i18n/index.d.ts +0 -1
- package/dist/external/i18n/index.js +0 -1
- package/dist/shared/event-bus/EventBus.d.ts +0 -12
- package/dist/shared/event-bus/EventBus.js +0 -3
- package/dist/shared/event-bus/index.d.ts +0 -1
- package/dist/shared/event-bus/index.js +0 -1
- /package/dist/{shared → svelte}/redirect/index.d.ts +0 -0
- /package/dist/{shared → svelte}/redirect/index.js +0 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { bindTranslationLifecycle } from './Internal.js';
|
|
2
|
+
import { RegisterProvider } from '../delivery/presenter/RegisterProvider.js';
|
|
3
|
+
import { Cookies, TextUtil, BROWSER } from '../external/tools/index.js';
|
|
4
|
+
import { RequestContext } from '../shared/request-context/Internal.js';
|
|
5
|
+
const PLURAL_PATTERN = /{{\s*(\w+)\s*\|\s*plural\s*:(.*?)}}/g;
|
|
6
|
+
const VARIABLE_PATTERN = /{{\s*(\w+)\s*}}/g;
|
|
7
|
+
const normalizeLocale = (locale) => locale.trim().replaceAll('_', '-').toLowerCase();
|
|
8
|
+
const parseAcceptLanguage = (value) => {
|
|
9
|
+
if (!value)
|
|
10
|
+
return [];
|
|
11
|
+
return value
|
|
12
|
+
.split(',')
|
|
13
|
+
.map((part, index) => {
|
|
14
|
+
const [locale = '', ...parameters] = part.trim().split(';');
|
|
15
|
+
const qualityParameter = parameters.find((parameter) => parameter.trim().toLowerCase().startsWith('q='));
|
|
16
|
+
const quality = qualityParameter ? Number(qualityParameter.split('=')[1]) : 1;
|
|
17
|
+
return { locale: locale.trim(), quality: Number.isFinite(quality) ? quality : 0, index };
|
|
18
|
+
})
|
|
19
|
+
.filter(({ locale, quality }) => locale.length > 0 && quality > 0)
|
|
20
|
+
.sort((left, right) => right.quality - left.quality || left.index - right.index)
|
|
21
|
+
.map(({ locale }) => locale);
|
|
22
|
+
};
|
|
23
|
+
export const createTranslations = (params) => {
|
|
24
|
+
const snapshotKey = params.prefix ?? 'default';
|
|
25
|
+
const availableLocales = Object.keys(params.messages);
|
|
26
|
+
const locales = Object.freeze(Object.fromEntries(availableLocales.map((locale) => [locale, locale])));
|
|
27
|
+
if (!Object.hasOwn(params.messages, params.initLang))
|
|
28
|
+
throw new Error('[AzureNetKit:i18n] initLang must exist in messages.');
|
|
29
|
+
const normalizedLocales = new Map();
|
|
30
|
+
const localeVariants = new Map();
|
|
31
|
+
for (const locale of availableLocales) {
|
|
32
|
+
const normalized = normalizeLocale(locale);
|
|
33
|
+
const base = normalized.split('-')[0];
|
|
34
|
+
normalizedLocales.set(normalized, locale);
|
|
35
|
+
if (base && !localeVariants.has(base))
|
|
36
|
+
localeVariants.set(base, locale);
|
|
37
|
+
}
|
|
38
|
+
const resolveLocale = (locale) => {
|
|
39
|
+
if (!locale)
|
|
40
|
+
return undefined;
|
|
41
|
+
const normalized = normalizeLocale(locale);
|
|
42
|
+
if (!normalized)
|
|
43
|
+
return undefined;
|
|
44
|
+
const exact = normalizedLocales.get(normalized);
|
|
45
|
+
if (exact)
|
|
46
|
+
return exact;
|
|
47
|
+
const base = normalized.split('-')[0];
|
|
48
|
+
return base ? (normalizedLocales.get(base) ?? localeVariants.get(base)) : undefined;
|
|
49
|
+
};
|
|
50
|
+
const factory = RegisterProvider(() => {
|
|
51
|
+
const translations = new Map();
|
|
52
|
+
const pendingLoads = new Map();
|
|
53
|
+
const localeListeners = new Set();
|
|
54
|
+
let locale = $state.raw(params.initLang);
|
|
55
|
+
let activeMessages = $state.raw({});
|
|
56
|
+
let synchronized = false;
|
|
57
|
+
let initializationPromise;
|
|
58
|
+
let switchRevision = 0;
|
|
59
|
+
const loadTranslation = (requestedLocale) => {
|
|
60
|
+
const resolvedLocale = resolveLocale(requestedLocale);
|
|
61
|
+
if (!resolvedLocale) {
|
|
62
|
+
return Promise.reject(new Error(`[AzureNetKit:i18n] Locale "${requestedLocale}" is not present in messages.`));
|
|
63
|
+
}
|
|
64
|
+
const cached = translations.get(resolvedLocale);
|
|
65
|
+
if (cached)
|
|
66
|
+
return Promise.resolve(cached);
|
|
67
|
+
const pending = pendingLoads.get(resolvedLocale);
|
|
68
|
+
if (pending)
|
|
69
|
+
return pending;
|
|
70
|
+
const request = Promise.resolve()
|
|
71
|
+
.then(() => params.messages[resolvedLocale]())
|
|
72
|
+
.then((loaded) => {
|
|
73
|
+
// Imported dictionaries are module-cached; request state must not expose that shared object.
|
|
74
|
+
const messages = BROWSER ? loaded : structuredClone(loaded);
|
|
75
|
+
translations.set(resolvedLocale, messages);
|
|
76
|
+
return messages;
|
|
77
|
+
})
|
|
78
|
+
.finally(() => {
|
|
79
|
+
if (pendingLoads.get(resolvedLocale) === request)
|
|
80
|
+
pendingLoads.delete(resolvedLocale);
|
|
81
|
+
});
|
|
82
|
+
pendingLoads.set(resolvedLocale, request);
|
|
83
|
+
return request;
|
|
84
|
+
};
|
|
85
|
+
const getLocaleFromRequest = () => {
|
|
86
|
+
const event = RequestContext.current().event;
|
|
87
|
+
if (!event)
|
|
88
|
+
throw new Error('[AzureNetKit:i18n] RequestContext has no RequestEvent.');
|
|
89
|
+
const cookieLocale = params.cookieName ? resolveLocale(event.cookies.get(params.cookieName)) : undefined;
|
|
90
|
+
if (cookieLocale)
|
|
91
|
+
return cookieLocale;
|
|
92
|
+
if (params.initLangFromAcceptLanguage) {
|
|
93
|
+
for (const requestedLocale of parseAcceptLanguage(event.request.headers.get('accept-language'))) {
|
|
94
|
+
if (requestedLocale === '*')
|
|
95
|
+
return params.initLang;
|
|
96
|
+
const resolvedLocale = resolveLocale(requestedLocale);
|
|
97
|
+
if (resolvedLocale)
|
|
98
|
+
return resolvedLocale;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return params.initLang;
|
|
102
|
+
};
|
|
103
|
+
const preloadTranslation = async (resolver) => {
|
|
104
|
+
if (BROWSER)
|
|
105
|
+
throw new Error('[AzureNetKit:i18n] preloadTranslation() is server-only.');
|
|
106
|
+
const revision = ++switchRevision;
|
|
107
|
+
const requestedLocale = resolver ? await resolver() : getLocaleFromRequest();
|
|
108
|
+
const resolvedLocale = resolveLocale(requestedLocale) ?? params.initLang;
|
|
109
|
+
const messages = await loadTranslation(resolvedLocale);
|
|
110
|
+
if (revision !== switchRevision)
|
|
111
|
+
return;
|
|
112
|
+
locale = resolvedLocale;
|
|
113
|
+
activeMessages = messages;
|
|
114
|
+
const state = RequestContext.current().state;
|
|
115
|
+
state.currLocale = resolvedLocale;
|
|
116
|
+
const snapshots = (state.i18n ??= {});
|
|
117
|
+
Object.defineProperty(snapshots, snapshotKey, { value: { locale }, enumerable: true, configurable: true, writable: true });
|
|
118
|
+
};
|
|
119
|
+
const getTranslation = (messageKey) => {
|
|
120
|
+
let current = activeMessages;
|
|
121
|
+
for (const key of messageKey.split('.')) {
|
|
122
|
+
if (typeof current === 'string' || !current || !Object.hasOwn(current, key))
|
|
123
|
+
return undefined;
|
|
124
|
+
current = current[key];
|
|
125
|
+
}
|
|
126
|
+
return typeof current === 'string' ? current : undefined;
|
|
127
|
+
};
|
|
128
|
+
const translate = (messageKey, vars = {}) => {
|
|
129
|
+
let result = getTranslation(messageKey);
|
|
130
|
+
if (result === undefined)
|
|
131
|
+
return messageKey;
|
|
132
|
+
if (!result.includes('{{'))
|
|
133
|
+
return result;
|
|
134
|
+
result = result.replace(PLURAL_PATTERN, (_, variableName, titlesString) => {
|
|
135
|
+
const count = Number(vars[variableName]);
|
|
136
|
+
if (Number.isNaN(count)) {
|
|
137
|
+
console.warn(`[AzureNetKit:i18n] Plural variable "${variableName}" is not numeric.`);
|
|
138
|
+
return '';
|
|
139
|
+
}
|
|
140
|
+
return TextUtil.pluralize(count, titlesString.split(',').map((title) => title.trim()));
|
|
141
|
+
});
|
|
142
|
+
return result.replace(VARIABLE_PATTERN, (_, key) => (vars[key] === undefined ? '' : String(vars[key])));
|
|
143
|
+
};
|
|
144
|
+
const t = (translation, vars) => {
|
|
145
|
+
if (!translation)
|
|
146
|
+
return '';
|
|
147
|
+
const extended = typeof translation === 'object' ? translation : undefined;
|
|
148
|
+
return translate(String(extended?.key ?? translation), extended?.vars ?? vars);
|
|
149
|
+
};
|
|
150
|
+
const syncFromState = (state) => {
|
|
151
|
+
if (synchronized)
|
|
152
|
+
return;
|
|
153
|
+
const snapshot = state.i18n && Object.hasOwn(state.i18n, snapshotKey) ? state.i18n[snapshotKey] : undefined;
|
|
154
|
+
const nextLocale = resolveLocale(snapshot?.locale ?? state.currLocale);
|
|
155
|
+
if (snapshot && !nextLocale)
|
|
156
|
+
throw new Error('[AzureNetKit:i18n] Unsupported boot locale.');
|
|
157
|
+
synchronized = true;
|
|
158
|
+
++switchRevision;
|
|
159
|
+
initializationPromise = undefined;
|
|
160
|
+
if (nextLocale)
|
|
161
|
+
locale = nextLocale;
|
|
162
|
+
activeMessages = translations.get(locale) ?? {};
|
|
163
|
+
};
|
|
164
|
+
const updateHtmlLocale = (currentLocale) => {
|
|
165
|
+
document.documentElement.lang = currentLocale;
|
|
166
|
+
};
|
|
167
|
+
const initializeClient = () => {
|
|
168
|
+
if (!BROWSER)
|
|
169
|
+
return Promise.resolve();
|
|
170
|
+
if (initializationPromise)
|
|
171
|
+
return initializationPromise;
|
|
172
|
+
// SSR marker is available before SvelteKit starts hydration; boot runs later.
|
|
173
|
+
const serverLocale = document.documentElement.getAttribute('data-azure-net-locale');
|
|
174
|
+
locale =
|
|
175
|
+
resolveLocale(serverLocale ?? undefined) ??
|
|
176
|
+
resolveLocale((params.cookieName ? Cookies.get(params.cookieName) : undefined) ?? undefined) ??
|
|
177
|
+
(params.initLangFromAcceptLanguage ? navigator.languages.map(resolveLocale).find(Boolean) : undefined) ??
|
|
178
|
+
locale;
|
|
179
|
+
const revision = switchRevision;
|
|
180
|
+
const request = loadTranslation(locale)
|
|
181
|
+
.then((messages) => {
|
|
182
|
+
if (revision !== switchRevision) {
|
|
183
|
+
if (initializationPromise === request)
|
|
184
|
+
initializationPromise = undefined;
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
activeMessages = messages;
|
|
188
|
+
updateHtmlLocale(locale);
|
|
189
|
+
})
|
|
190
|
+
.catch((error) => {
|
|
191
|
+
if (initializationPromise === request)
|
|
192
|
+
initializationPromise = undefined;
|
|
193
|
+
throw error;
|
|
194
|
+
});
|
|
195
|
+
initializationPromise = request;
|
|
196
|
+
return request;
|
|
197
|
+
};
|
|
198
|
+
const switchLocale = async (requestedLocale) => {
|
|
199
|
+
if (!BROWSER)
|
|
200
|
+
throw new Error('[AzureNetKit:i18n] switchLocale() is client-only.');
|
|
201
|
+
const resolvedLocale = resolveLocale(requestedLocale);
|
|
202
|
+
if (!resolvedLocale)
|
|
203
|
+
throw new Error(`[AzureNetKit:i18n] Locale "${requestedLocale}" is not present in messages.`);
|
|
204
|
+
const revision = ++switchRevision;
|
|
205
|
+
const messages = await loadTranslation(resolvedLocale);
|
|
206
|
+
if (revision !== switchRevision)
|
|
207
|
+
return;
|
|
208
|
+
locale = resolvedLocale;
|
|
209
|
+
activeMessages = messages;
|
|
210
|
+
if (params.cookieName) {
|
|
211
|
+
Cookies.set(params.cookieName, resolvedLocale, {
|
|
212
|
+
path: '/',
|
|
213
|
+
sameSite: 'Lax',
|
|
214
|
+
...params.cookieOptions
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
updateHtmlLocale(resolvedLocale);
|
|
218
|
+
for (const listener of localeListeners)
|
|
219
|
+
listener(resolvedLocale);
|
|
220
|
+
};
|
|
221
|
+
const subscribeLocaleChangeEvent = (listener) => {
|
|
222
|
+
if (!BROWSER)
|
|
223
|
+
throw new Error('[AzureNetKit:i18n] Locale change events are client-only.');
|
|
224
|
+
localeListeners.add(listener);
|
|
225
|
+
return () => localeListeners.delete(listener);
|
|
226
|
+
};
|
|
227
|
+
const applyHtmlLocaleAttr = (html) => html.replaceAll('%lang%', () => locale);
|
|
228
|
+
const manager = {
|
|
229
|
+
switchLocale,
|
|
230
|
+
applyHtmlLocaleAttr,
|
|
231
|
+
subscribeLocaleChangeEvent,
|
|
232
|
+
t,
|
|
233
|
+
get locale() {
|
|
234
|
+
return locale;
|
|
235
|
+
},
|
|
236
|
+
locales
|
|
237
|
+
};
|
|
238
|
+
const escapeAttribute = (value) => value.replaceAll('&', '&').replaceAll('"', '"').replaceAll('<', '<').replaceAll('>', '>');
|
|
239
|
+
bindTranslationLifecycle(manager, {
|
|
240
|
+
preloadTranslation,
|
|
241
|
+
initializeClient,
|
|
242
|
+
syncFromState,
|
|
243
|
+
transformHtml: (html) => applyHtmlLocaleAttr(html).replace(/<html\b([^>]*)>/i, (_, attrs) => '<html' +
|
|
244
|
+
attrs.replace(/\s+(?:data-azure-net-locale|lang)\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)/gi, '') +
|
|
245
|
+
' lang="' +
|
|
246
|
+
escapeAttribute(locale) +
|
|
247
|
+
'" data-azure-net-locale="' +
|
|
248
|
+
escapeAttribute(locale) +
|
|
249
|
+
'">')
|
|
250
|
+
});
|
|
251
|
+
return manager;
|
|
252
|
+
}, 'singleton');
|
|
253
|
+
return factory;
|
|
254
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface TranslationSnapshot {
|
|
2
|
+
locale: string;
|
|
3
|
+
}
|
|
4
|
+
declare global {
|
|
5
|
+
namespace App {
|
|
6
|
+
interface RequestContextState {
|
|
7
|
+
currLocale?: string;
|
|
8
|
+
i18n?: Record<string, TranslationSnapshot>;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export type Translation = string | {
|
|
13
|
+
[key: string]: Translation;
|
|
14
|
+
};
|
|
15
|
+
export type TranslationShape<T> = T extends string ? string : T extends Record<string, unknown> ? {
|
|
16
|
+
[K in keyof T]: TranslationShape<T[K]>;
|
|
17
|
+
} : never;
|
|
18
|
+
export type Path<T, Prefix extends string = '', Depth extends unknown[] = []> = T extends string ? never : T extends Record<string, unknown> ? {
|
|
19
|
+
[K in keyof T & string]: T[K] extends string ? `${Prefix}${K}` : Depth['length'] extends 12 ? `${Prefix}${K}.${string}` : Path<T[K], `${Prefix}${K}.`, [...Depth, unknown]>;
|
|
20
|
+
}[keyof T & string] : never;
|
|
21
|
+
export interface TranslationCookieOptions {
|
|
22
|
+
expires?: Date | number;
|
|
23
|
+
maxAge?: number;
|
|
24
|
+
path?: string;
|
|
25
|
+
domain?: string;
|
|
26
|
+
secure?: boolean;
|
|
27
|
+
sameSite?: 'Strict' | 'Lax' | 'None';
|
|
28
|
+
}
|
|
29
|
+
export type MessageLoader = () => Promise<Translation>;
|
|
30
|
+
export type TranslationVariables = Record<string, unknown>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createTranslations } from './Translations.svelte.js';
|
|
@@ -1,16 +1,29 @@
|
|
|
1
|
-
import { type IHttpServiceInstance, type IHttpServiceResponse } from '../http-service/HttpServiceInstance.js';
|
|
2
|
-
import { type IQueryBuilderInstance } from '../query/index.js';
|
|
1
|
+
import { type IHttpInstanceOptions, type IHttpServiceInstance, type IHttpServiceResponse } from '../http-service/HttpServiceInstance.js';
|
|
2
|
+
import { type IQueryBuilderInstance, type IQueryBuilderSettings } from '../query/index.js';
|
|
3
3
|
export type CreateRequestCallbackType<T> = (params: {
|
|
4
4
|
http: IHttpServiceInstance;
|
|
5
5
|
query: IQueryBuilderInstance;
|
|
6
6
|
}) => Promise<IHttpServiceResponse<T>>;
|
|
7
|
+
type HttpClientParams = {
|
|
8
|
+
http: IHttpServiceInstance;
|
|
9
|
+
httpOptions?: never;
|
|
10
|
+
} | {
|
|
11
|
+
http?: never;
|
|
12
|
+
httpOptions?: IHttpInstanceOptions;
|
|
13
|
+
};
|
|
14
|
+
type QueryBuilderParams = {
|
|
15
|
+
query: IQueryBuilderInstance;
|
|
16
|
+
queryOptions?: never;
|
|
17
|
+
} | {
|
|
18
|
+
query?: never;
|
|
19
|
+
queryOptions?: IQueryBuilderSettings;
|
|
20
|
+
};
|
|
21
|
+
type DatasourceParams = HttpClientParams & QueryBuilderParams;
|
|
7
22
|
export declare class BaseHttpDatasource {
|
|
8
23
|
protected readonly httpClient: IHttpServiceInstance;
|
|
9
24
|
protected readonly query: IQueryBuilderInstance;
|
|
10
|
-
constructor(params:
|
|
11
|
-
http?: IHttpServiceInstance;
|
|
12
|
-
query?: IQueryBuilderInstance;
|
|
13
|
-
});
|
|
25
|
+
constructor(params: DatasourceParams);
|
|
14
26
|
private _createRawRequest;
|
|
15
27
|
readonly createRawRequest: <T>(callback: CreateRequestCallbackType<T>) => Promise<IHttpServiceResponse<T>>;
|
|
16
28
|
}
|
|
29
|
+
export {};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { HttpServiceInstance } from '../http-service/HttpServiceInstance.js';
|
|
2
|
+
import { QueryBuilder } from '../query/index.js';
|
|
3
3
|
export class BaseHttpDatasource {
|
|
4
4
|
httpClient;
|
|
5
5
|
query;
|
|
6
6
|
constructor(params) {
|
|
7
|
-
this.httpClient = params.http ??
|
|
8
|
-
this.query = params.query ??
|
|
7
|
+
this.httpClient = params.http ?? new HttpServiceInstance(params?.httpOptions);
|
|
8
|
+
this.query = params.query ?? new QueryBuilder(params?.queryOptions);
|
|
9
9
|
}
|
|
10
10
|
_createRawRequest(callback) {
|
|
11
11
|
return callback({ http: this.httpClient, query: this.query });
|
|
@@ -47,7 +47,7 @@ export declare class HttpServiceError<T> extends Error implements IHttpServiceEr
|
|
|
47
47
|
response?: Response;
|
|
48
48
|
constructor({ status, data, message, original, type, response }: Partial<IHttpServiceError<T>>);
|
|
49
49
|
}
|
|
50
|
-
export interface
|
|
50
|
+
export interface IHttpInstanceNormalizedRequest {
|
|
51
51
|
url: string | URL;
|
|
52
52
|
method: HttpInstanceFetchMethods;
|
|
53
53
|
headers: Headers;
|
|
@@ -60,9 +60,9 @@ export interface HttpInstanceNormalizedRequest {
|
|
|
60
60
|
fetch: typeof fetch;
|
|
61
61
|
requestInit: Omit<RequestInit, 'method' | 'headers' | 'body'>;
|
|
62
62
|
}
|
|
63
|
-
export type
|
|
64
|
-
export type
|
|
65
|
-
export type
|
|
63
|
+
export type IHttpInstanceOnRequest = (request: IHttpInstanceNormalizedRequest) => void | Promise<void>;
|
|
64
|
+
export type IHttpInstanceOnError = (error: HttpServiceError<unknown>, request: IHttpInstanceNormalizedRequest) => void | Promise<void>;
|
|
65
|
+
export type IHttpInstanceDoFetch = <T = unknown>(request: IHttpInstanceNormalizedRequest) => Promise<IHttpServiceResponse<T>>;
|
|
66
66
|
export interface IHttpInstanceOptions<T = unknown> extends Omit<RequestInit, 'headers' | 'method'> {
|
|
67
67
|
headers?: NonNullable<RequestInit['headers']> | Record<string, string | undefined>;
|
|
68
68
|
json?: unknown;
|
|
@@ -73,19 +73,29 @@ export interface IHttpInstanceOptions<T = unknown> extends Omit<RequestInit, 'he
|
|
|
73
73
|
retry?: number;
|
|
74
74
|
includeRaw?: boolean;
|
|
75
75
|
responseFormat?: 'json' | 'blob' | 'text' | 'arrayBuffer' | 'body';
|
|
76
|
-
onRequest?:
|
|
77
|
-
onError?:
|
|
76
|
+
onRequest?: IHttpInstanceOnRequest;
|
|
77
|
+
onError?: IHttpInstanceOnError;
|
|
78
78
|
onResponse?: (response: IHttpServiceResponse<T>) => void | Promise<void>;
|
|
79
|
-
doFetch?:
|
|
79
|
+
doFetch?: IHttpInstanceDoFetch;
|
|
80
80
|
}
|
|
81
|
-
export type
|
|
81
|
+
export type IHttpInstanceRequestMethod = <T = unknown>(url: string | URL, options?: IHttpInstanceOptions<T>) => Promise<IHttpServiceResponse<T>>;
|
|
82
82
|
export interface IHttpServiceInstance {
|
|
83
|
-
get:
|
|
84
|
-
post:
|
|
85
|
-
put:
|
|
86
|
-
delete:
|
|
87
|
-
patch:
|
|
88
|
-
head:
|
|
89
|
-
options:
|
|
83
|
+
get: IHttpInstanceRequestMethod;
|
|
84
|
+
post: IHttpInstanceRequestMethod;
|
|
85
|
+
put: IHttpInstanceRequestMethod;
|
|
86
|
+
delete: IHttpInstanceRequestMethod;
|
|
87
|
+
patch: IHttpInstanceRequestMethod;
|
|
88
|
+
head: IHttpInstanceRequestMethod;
|
|
89
|
+
options: IHttpInstanceRequestMethod;
|
|
90
|
+
}
|
|
91
|
+
export declare class HttpServiceInstance implements IHttpServiceInstance {
|
|
92
|
+
private readonly defaults;
|
|
93
|
+
readonly get: IHttpInstanceRequestMethod;
|
|
94
|
+
readonly post: IHttpInstanceRequestMethod;
|
|
95
|
+
readonly put: IHttpInstanceRequestMethod;
|
|
96
|
+
readonly delete: IHttpInstanceRequestMethod;
|
|
97
|
+
readonly patch: IHttpInstanceRequestMethod;
|
|
98
|
+
readonly head: IHttpInstanceRequestMethod;
|
|
99
|
+
readonly options: IHttpInstanceRequestMethod;
|
|
100
|
+
constructor(config?: IHttpInstanceOptions);
|
|
90
101
|
}
|
|
91
|
-
export declare const createHttpServiceInstance: (config?: IHttpInstanceOptions) => IHttpServiceInstance;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BROWSER } from '../../external/tools/index.js';
|
|
2
|
-
import { RequestContext } from '../../
|
|
2
|
+
import { RequestContext } from '../../shared/request-context/Internal.js';
|
|
3
3
|
export var HttpInstanceFetchMethods;
|
|
4
4
|
(function (HttpInstanceFetchMethods) {
|
|
5
5
|
HttpInstanceFetchMethods["GET"] = "GET";
|
|
@@ -344,15 +344,23 @@ const makeMethod = (method, defaults) => {
|
|
|
344
344
|
}
|
|
345
345
|
};
|
|
346
346
|
};
|
|
347
|
-
export
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
347
|
+
export class HttpServiceInstance {
|
|
348
|
+
defaults;
|
|
349
|
+
get;
|
|
350
|
+
post;
|
|
351
|
+
put;
|
|
352
|
+
delete;
|
|
353
|
+
patch;
|
|
354
|
+
head;
|
|
355
|
+
options;
|
|
356
|
+
constructor(config = {}) {
|
|
357
|
+
this.defaults = { ...config };
|
|
358
|
+
this.get = makeMethod(HttpInstanceFetchMethods.GET, this.defaults);
|
|
359
|
+
this.post = makeMethod(HttpInstanceFetchMethods.POST, this.defaults);
|
|
360
|
+
this.put = makeMethod(HttpInstanceFetchMethods.PUT, this.defaults);
|
|
361
|
+
this.delete = makeMethod(HttpInstanceFetchMethods.DELETE, this.defaults);
|
|
362
|
+
this.patch = makeMethod(HttpInstanceFetchMethods.PATCH, this.defaults);
|
|
363
|
+
this.head = makeMethod(HttpInstanceFetchMethods.HEAD, this.defaults);
|
|
364
|
+
this.options = makeMethod(HttpInstanceFetchMethods.OPTIONS, this.defaults);
|
|
365
|
+
}
|
|
366
|
+
}
|
package/dist/infra/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { BaseHttpDatasource, type CreateRequestCallbackType } from './datasource/index.js';
|
|
2
2
|
export { DTOMapper, type IDTOMapper } from './resource/index.js';
|
|
3
|
-
export { HttpStatusCode,
|
|
3
|
+
export { HttpStatusCode, HttpServiceInstance, HttpInstanceFetchMethods, HttpErrorTypes, HttpServiceResponse, HttpServiceError, type IHttpServiceError, type IHttpServiceResponse, type IHttpServiceInstance, type IHttpInstanceOptions, type IHttpInstanceNormalizedRequest, type IHttpInstanceOnRequest, type IHttpInstanceOnError, type IHttpInstanceDoFetch, type IHttpInstanceRequestMethod } from './http-service/index.js';
|
|
4
4
|
export { ResponseBuilder } from './response/index.js';
|
|
5
|
-
export {
|
|
5
|
+
export { QueryBuilder, type IQueryBuilderInstance, type ArrayFormat, type ObjectFormat, type IQueryBuilderSettings } from './query/QueryBuilder.js';
|
package/dist/infra/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { BaseHttpDatasource } from './datasource/index.js';
|
|
2
2
|
export { DTOMapper } from './resource/index.js';
|
|
3
|
-
export { HttpStatusCode,
|
|
3
|
+
export { HttpStatusCode, HttpServiceInstance, HttpInstanceFetchMethods, HttpErrorTypes, HttpServiceResponse, HttpServiceError } from './http-service/index.js';
|
|
4
4
|
export { ResponseBuilder } from './response/index.js';
|
|
5
|
-
export {
|
|
5
|
+
export { QueryBuilder } from './query/QueryBuilder.js';
|
|
@@ -10,4 +10,9 @@ export interface IQueryBuilderInstance<TTransformInput extends object = object>
|
|
|
10
10
|
toString: (query: object, settings?: IQueryBuilderSettings<TTransformInput>) => string;
|
|
11
11
|
toSearchParams: (query: object, settings?: Omit<IQueryBuilderSettings<TTransformInput>, 'delimiter'>) => URLSearchParams;
|
|
12
12
|
}
|
|
13
|
-
export declare
|
|
13
|
+
export declare class QueryBuilder<TTransformInputGlobal extends object = object> implements IQueryBuilderInstance<TTransformInputGlobal> {
|
|
14
|
+
private readonly defaults;
|
|
15
|
+
constructor(config?: IQueryBuilderSettings<TTransformInputGlobal>);
|
|
16
|
+
readonly toSearchParams: <TTransformInput extends TTransformInputGlobal = TTransformInputGlobal>(query: object, settings?: Omit<IQueryBuilderSettings<TTransformInput>, "delimiter">) => URLSearchParams;
|
|
17
|
+
readonly toString: <TTransformInput extends TTransformInputGlobal = TTransformInputGlobal>(query: object, settings?: IQueryBuilderSettings<TTransformInput>) => string;
|
|
18
|
+
}
|
|
@@ -75,16 +75,18 @@ const toSearchParamsWithSettings = (query, settings) => {
|
|
|
75
75
|
}
|
|
76
76
|
return params;
|
|
77
77
|
};
|
|
78
|
-
export
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const serialized = encodeQuery(Array.from(toSearchParamsWithSettings(query, resolved).entries()));
|
|
87
|
-
return resolved.delimiter && serialized ? `?${serialized}` : serialized;
|
|
88
|
-
}
|
|
78
|
+
export class QueryBuilder {
|
|
79
|
+
defaults;
|
|
80
|
+
constructor(config) {
|
|
81
|
+
this.defaults = { ...config };
|
|
82
|
+
}
|
|
83
|
+
toSearchParams = (query, settings) => {
|
|
84
|
+
const resolved = normalizeSettings(this.defaults, settings);
|
|
85
|
+
return toSearchParamsWithSettings(query, resolved);
|
|
89
86
|
};
|
|
90
|
-
|
|
87
|
+
toString = (query, settings) => {
|
|
88
|
+
const resolved = normalizeSettings(this.defaults, settings);
|
|
89
|
+
const serialized = encodeQuery(Array.from(toSearchParamsWithSettings(query, resolved).entries()));
|
|
90
|
+
return resolved.delimiter && serialized ? `?${serialized}` : serialized;
|
|
91
|
+
};
|
|
92
|
+
}
|