@vahidkaargar/customized-api-client 0.3.0 → 0.4.0
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 +26 -1
- package/dist/index.cjs +113 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -2
- package/dist/index.d.ts +38 -2
- package/dist/index.js +105 -27
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// package.json
|
|
2
2
|
var package_default = {
|
|
3
3
|
name: "@vahidkaargar/customized-api-client",
|
|
4
|
-
version: "0.
|
|
4
|
+
version: "0.4.0",
|
|
5
5
|
description: "TypeScript Axios client for JSON:API v1.1 with idempotency, retries, and normalized results",
|
|
6
6
|
type: "module",
|
|
7
7
|
engines: {
|
|
@@ -125,11 +125,85 @@ async function resolveAuthorizationHeader(auth) {
|
|
|
125
125
|
return `Bearer ${s}`;
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
// src/http/header-utils.ts
|
|
129
|
+
function flattenAxiosHeaders(headers) {
|
|
130
|
+
if (!headers) return {};
|
|
131
|
+
if (typeof headers.forEach === "function") {
|
|
132
|
+
const out2 = {};
|
|
133
|
+
headers.forEach((value, key) => {
|
|
134
|
+
out2[key.toLowerCase()] = value;
|
|
135
|
+
});
|
|
136
|
+
return out2;
|
|
137
|
+
}
|
|
138
|
+
const o = headers;
|
|
139
|
+
const out = {};
|
|
140
|
+
for (const [k, v] of Object.entries(o)) {
|
|
141
|
+
if (typeof v === "string") out[k.toLowerCase()] = v;
|
|
142
|
+
else if (Array.isArray(v) && v[0]) out[k.toLowerCase()] = v[0];
|
|
143
|
+
}
|
|
144
|
+
return out;
|
|
145
|
+
}
|
|
146
|
+
function getHeader(headers, name) {
|
|
147
|
+
return headers[name.toLowerCase()];
|
|
148
|
+
}
|
|
149
|
+
|
|
128
150
|
// src/headers/locale.ts
|
|
151
|
+
function normalizeLocaleCode(tag) {
|
|
152
|
+
if (tag === void 0) return void 0;
|
|
153
|
+
const trimmed = tag.trim();
|
|
154
|
+
if (!trimmed) return void 0;
|
|
155
|
+
const base = trimmed.split(/[-_]/)[0]?.trim();
|
|
156
|
+
return base ? base.toLowerCase() : void 0;
|
|
157
|
+
}
|
|
158
|
+
function parseContentLanguage(header) {
|
|
159
|
+
if (header === void 0) return void 0;
|
|
160
|
+
const first = header.split(",")[0]?.trim();
|
|
161
|
+
if (!first) return void 0;
|
|
162
|
+
const tag = first.split(";")[0]?.trim();
|
|
163
|
+
return tag && tag.length > 0 ? tag : void 0;
|
|
164
|
+
}
|
|
165
|
+
function localesMatch(a, b) {
|
|
166
|
+
const na = normalizeLocaleCode(a);
|
|
167
|
+
const nb = normalizeLocaleCode(b);
|
|
168
|
+
if (na === void 0 || nb === void 0) return false;
|
|
169
|
+
return na === nb;
|
|
170
|
+
}
|
|
171
|
+
function resolveLocaleProvider(getAcceptLanguage, locale) {
|
|
172
|
+
return locale?.getLocale ?? getAcceptLanguage;
|
|
173
|
+
}
|
|
174
|
+
async function resolveRequestLocale(getAcceptLanguage, locale) {
|
|
175
|
+
return resolveAcceptLanguage(resolveLocaleProvider(getAcceptLanguage, locale));
|
|
176
|
+
}
|
|
177
|
+
function acceptLanguageForRequest(resolved, defaultLocale) {
|
|
178
|
+
if (resolved === void 0) return void 0;
|
|
179
|
+
if (defaultLocale !== void 0 && localesMatch(resolved, defaultLocale)) {
|
|
180
|
+
return void 0;
|
|
181
|
+
}
|
|
182
|
+
return resolved;
|
|
183
|
+
}
|
|
129
184
|
async function resolveAcceptLanguage(provider) {
|
|
130
185
|
if (!provider) return void 0;
|
|
131
186
|
const v = await provider();
|
|
132
|
-
|
|
187
|
+
if (v === null || v === void 0) return void 0;
|
|
188
|
+
const trimmed = v.trim();
|
|
189
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
190
|
+
}
|
|
191
|
+
function readResponseContentLanguage(flatHeaders) {
|
|
192
|
+
return parseContentLanguage(getHeader(flatHeaders, "content-language"));
|
|
193
|
+
}
|
|
194
|
+
function notifyLocaleMismatch(locale, ctx) {
|
|
195
|
+
const handler = locale?.onLocaleMismatch;
|
|
196
|
+
if (!handler) return;
|
|
197
|
+
if (ctx.requested === void 0) return;
|
|
198
|
+
if (localesMatch(ctx.requested, ctx.resolved)) return;
|
|
199
|
+
if (handler === "warn") {
|
|
200
|
+
console.warn(
|
|
201
|
+
"[@vahidkaargar/customized-api-client] Content-Language mismatch",
|
|
202
|
+
ctx
|
|
203
|
+
);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
handler(ctx);
|
|
133
207
|
}
|
|
134
208
|
|
|
135
209
|
// src/headers/idempotency.ts
|
|
@@ -217,28 +291,6 @@ function parseRetryAfterSeconds(value) {
|
|
|
217
291
|
return void 0;
|
|
218
292
|
}
|
|
219
293
|
|
|
220
|
-
// src/http/header-utils.ts
|
|
221
|
-
function flattenAxiosHeaders(headers) {
|
|
222
|
-
if (!headers) return {};
|
|
223
|
-
if (typeof headers.forEach === "function") {
|
|
224
|
-
const out2 = {};
|
|
225
|
-
headers.forEach((value, key) => {
|
|
226
|
-
out2[key.toLowerCase()] = value;
|
|
227
|
-
});
|
|
228
|
-
return out2;
|
|
229
|
-
}
|
|
230
|
-
const o = headers;
|
|
231
|
-
const out = {};
|
|
232
|
-
for (const [k, v] of Object.entries(o)) {
|
|
233
|
-
if (typeof v === "string") out[k.toLowerCase()] = v;
|
|
234
|
-
else if (Array.isArray(v) && v[0]) out[k.toLowerCase()] = v[0];
|
|
235
|
-
}
|
|
236
|
-
return out;
|
|
237
|
-
}
|
|
238
|
-
function getHeader(headers, name) {
|
|
239
|
-
return headers[name.toLowerCase()];
|
|
240
|
-
}
|
|
241
|
-
|
|
242
294
|
// src/retry/execute-with-retry.ts
|
|
243
295
|
var DEFAULT_MAX_ATTEMPTS = 4;
|
|
244
296
|
var DEFAULT_BASE_MS = 200;
|
|
@@ -662,6 +714,7 @@ function createApiClient(config) {
|
|
|
662
714
|
const mode = config.baseUrlMode ?? "modeB";
|
|
663
715
|
const genKey = config.generateIdempotencyKey ?? defaultIdempotencyKey;
|
|
664
716
|
warnInsecureBaseUrl(config.baseURL);
|
|
717
|
+
const localeByRequest = /* @__PURE__ */ new WeakMap();
|
|
665
718
|
const instance = axios.create({
|
|
666
719
|
baseURL: config.baseURL,
|
|
667
720
|
timeout: config.timeout ?? DEFAULT_TIMEOUT_MS,
|
|
@@ -678,9 +731,15 @@ function createApiClient(config) {
|
|
|
678
731
|
if (authHeader) {
|
|
679
732
|
next.headers.Authorization = authHeader;
|
|
680
733
|
}
|
|
681
|
-
const
|
|
682
|
-
|
|
683
|
-
|
|
734
|
+
const resolved = await resolveRequestLocale(
|
|
735
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated -- legacy `getAcceptLanguage` fallback
|
|
736
|
+
config.getAcceptLanguage,
|
|
737
|
+
config.locale
|
|
738
|
+
);
|
|
739
|
+
localeByRequest.set(next, resolved);
|
|
740
|
+
const toSend = acceptLanguageForRequest(resolved, config.locale?.defaultLocale);
|
|
741
|
+
if (toSend) {
|
|
742
|
+
next.headers["Accept-Language"] = toSend;
|
|
684
743
|
}
|
|
685
744
|
if (isMutationMethod(method)) {
|
|
686
745
|
const h = next.headers;
|
|
@@ -706,6 +765,17 @@ function createApiClient(config) {
|
|
|
706
765
|
if (dep && config.onDeprecated) {
|
|
707
766
|
config.onDeprecated(dep);
|
|
708
767
|
}
|
|
768
|
+
const contentLang = readResponseContentLanguage(flat);
|
|
769
|
+
if (contentLang) {
|
|
770
|
+
notifyLocaleMismatch(config.locale, {
|
|
771
|
+
requested: localeByRequest.get(res.config),
|
|
772
|
+
resolved: contentLang,
|
|
773
|
+
/* v8 ignore start -- @preserve axios config url/method are strings */
|
|
774
|
+
url: typeof res.config.url === "string" ? res.config.url : void 0,
|
|
775
|
+
method: typeof res.config.method === "string" ? res.config.method : void 0
|
|
776
|
+
/* v8 ignore stop -- @preserve */
|
|
777
|
+
});
|
|
778
|
+
}
|
|
709
779
|
return res;
|
|
710
780
|
},
|
|
711
781
|
(err) => Promise.reject(
|
|
@@ -1089,6 +1159,7 @@ export {
|
|
|
1089
1159
|
DEFAULT_TIMEOUT_MS,
|
|
1090
1160
|
IDEMPOTENCY_MAX_LENGTH,
|
|
1091
1161
|
PACKAGE_VERSION,
|
|
1162
|
+
acceptLanguageForRequest,
|
|
1092
1163
|
applyJsonApiHeaders,
|
|
1093
1164
|
applyTransformKeys,
|
|
1094
1165
|
assertValidIdempotencyKey,
|
|
@@ -1121,8 +1192,12 @@ export {
|
|
|
1121
1192
|
isPreconditionRequiredError,
|
|
1122
1193
|
isRetryablePerPolicy,
|
|
1123
1194
|
isValidationError,
|
|
1195
|
+
localesMatch,
|
|
1124
1196
|
normalizeAxiosResponse,
|
|
1125
1197
|
normalizeHttpUrl,
|
|
1198
|
+
normalizeLocaleCode,
|
|
1199
|
+
notifyLocaleMismatch,
|
|
1200
|
+
parseContentLanguage,
|
|
1126
1201
|
parseDeprecationHeaders,
|
|
1127
1202
|
parseJsonApiDocument,
|
|
1128
1203
|
parseJsonApiErrorBody,
|
|
@@ -1131,11 +1206,14 @@ export {
|
|
|
1131
1206
|
parseRetryAfterSeconds,
|
|
1132
1207
|
pollAsyncResult,
|
|
1133
1208
|
readResourceVersion,
|
|
1209
|
+
readResponseContentLanguage,
|
|
1134
1210
|
redactHeaderRecord,
|
|
1135
1211
|
resolveAcceptLanguage,
|
|
1136
1212
|
resolveAcceptedLocation,
|
|
1137
1213
|
resolveAuthorizationHeader,
|
|
1138
1214
|
resolveIncluded,
|
|
1215
|
+
resolveLocaleProvider,
|
|
1216
|
+
resolveRequestLocale,
|
|
1139
1217
|
resolveResourcePath,
|
|
1140
1218
|
retryAllowed,
|
|
1141
1219
|
truncateForLog
|