@c-rex/services 0.1.2 → 0.1.3
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/dist/index.d.mts +104 -4
- package/dist/index.d.ts +104 -4
- package/dist/index.js +273 -76
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +273 -76
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -54,15 +54,16 @@ var FLAGS_BY_LANG = {
|
|
|
54
54
|
"de": "DE"
|
|
55
55
|
};
|
|
56
56
|
var EN_LANG = "en";
|
|
57
|
+
var TOPIC = "TOPIC";
|
|
58
|
+
var DOCUMENT = "DOCUMENT";
|
|
59
|
+
var PACKAGE = "PACKAGE";
|
|
57
60
|
var RESULT_TYPES = {
|
|
58
|
-
TOPIC
|
|
59
|
-
DOCUMENT
|
|
60
|
-
PACKAGE
|
|
61
|
+
TOPIC,
|
|
62
|
+
DOCUMENT,
|
|
63
|
+
PACKAGE
|
|
61
64
|
};
|
|
62
65
|
var DEFAULT_COOKIE_LIMIT = 7 * 24 * 60 * 60 * 1e3;
|
|
63
|
-
|
|
64
|
-
// ../core/src/requests.ts
|
|
65
|
-
var import_openid_client = require("openid-client");
|
|
66
|
+
var CREX_TOKEN_HEADER_KEY = "crex-token";
|
|
66
67
|
|
|
67
68
|
// ../utils/src/utils.ts
|
|
68
69
|
var call = async (method, params) => {
|
|
@@ -70,7 +71,8 @@ var call = async (method, params) => {
|
|
|
70
71
|
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/rpc`, {
|
|
71
72
|
method: "POST",
|
|
72
73
|
headers: { "Content-Type": "application/json" },
|
|
73
|
-
body: JSON.stringify({ method, params })
|
|
74
|
+
body: JSON.stringify({ method, params }),
|
|
75
|
+
credentials: "include"
|
|
74
76
|
});
|
|
75
77
|
const json = await res.json();
|
|
76
78
|
if (!res.ok) throw new Error(json.error || "Unknown error");
|
|
@@ -90,23 +92,35 @@ var getCountryCodeByLang = (lang) => {
|
|
|
90
92
|
};
|
|
91
93
|
|
|
92
94
|
// ../utils/src/memory.ts
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
if (isBrowser()) throw new Error("saveInMemory is not supported in browser");
|
|
98
|
-
if (typeof global !== "undefined" && !(key in global)) {
|
|
99
|
-
global[key] = null;
|
|
95
|
+
var getCookie = async (key) => {
|
|
96
|
+
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/cookies?key=${key}`);
|
|
97
|
+
if (!res.ok) {
|
|
98
|
+
return { key, value: null };
|
|
100
99
|
}
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
const json = await res.json();
|
|
101
|
+
return json;
|
|
102
|
+
};
|
|
103
|
+
var setCookie = async (key, value, maxAge) => {
|
|
104
|
+
try {
|
|
105
|
+
if (maxAge === void 0) {
|
|
106
|
+
maxAge = DEFAULT_COOKIE_LIMIT;
|
|
107
|
+
}
|
|
108
|
+
await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/cookies`, {
|
|
109
|
+
method: "POST",
|
|
110
|
+
credentials: "include",
|
|
111
|
+
body: JSON.stringify({
|
|
112
|
+
key,
|
|
113
|
+
value,
|
|
114
|
+
maxAge
|
|
115
|
+
})
|
|
116
|
+
});
|
|
117
|
+
} catch (error) {
|
|
118
|
+
call("CrexLogger.log", {
|
|
119
|
+
level: "error",
|
|
120
|
+
message: `utils.setCookie error: ${error}`
|
|
121
|
+
});
|
|
104
122
|
}
|
|
105
|
-
}
|
|
106
|
-
function getFromMemory(key) {
|
|
107
|
-
if (isBrowser()) throw new Error("getFromMemory is not supported in browser");
|
|
108
|
-
return global[key];
|
|
109
|
-
}
|
|
123
|
+
};
|
|
110
124
|
|
|
111
125
|
// ../utils/src/classMerge.ts
|
|
112
126
|
var import_clsx = require("clsx");
|
|
@@ -124,55 +138,128 @@ var generateQueryParams = (params) => {
|
|
|
124
138
|
return queryParams;
|
|
125
139
|
};
|
|
126
140
|
|
|
141
|
+
// ../utils/src/token.ts
|
|
142
|
+
var updateToken = async () => {
|
|
143
|
+
try {
|
|
144
|
+
const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/token`, {
|
|
145
|
+
method: "POST",
|
|
146
|
+
credentials: "include"
|
|
147
|
+
});
|
|
148
|
+
const cookies = response.headers.get("set-cookie");
|
|
149
|
+
if (cookies === null) return null;
|
|
150
|
+
const aux = cookies.split(`${CREX_TOKEN_HEADER_KEY}=`);
|
|
151
|
+
if (aux.length == 0) return null;
|
|
152
|
+
const token = aux[1].split(";")[0];
|
|
153
|
+
if (token === void 0) throw new Error("Token is undefined");
|
|
154
|
+
return token;
|
|
155
|
+
} catch (error) {
|
|
156
|
+
call("CrexLogger.log", {
|
|
157
|
+
level: "error",
|
|
158
|
+
message: `utils.updateToken error: ${error}`
|
|
159
|
+
});
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
var manageToken = async () => {
|
|
164
|
+
try {
|
|
165
|
+
const hasToken = await getCookie(CREX_TOKEN_HEADER_KEY);
|
|
166
|
+
let token = hasToken.value;
|
|
167
|
+
if (hasToken.value === null) {
|
|
168
|
+
const tokenResult = await updateToken();
|
|
169
|
+
if (tokenResult === null) throw new Error("Token is undefined");
|
|
170
|
+
token = tokenResult;
|
|
171
|
+
}
|
|
172
|
+
return token;
|
|
173
|
+
} catch (error) {
|
|
174
|
+
call("CrexLogger.log", {
|
|
175
|
+
level: "error",
|
|
176
|
+
message: `utils.manageToken error: ${error}`
|
|
177
|
+
});
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
127
182
|
// ../core/src/requests.ts
|
|
128
183
|
var import_next_cookies = require("@c-rex/utils/next-cookies");
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
var
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
142
|
-
if (!(token && tokenExpiry > now + 60)) {
|
|
143
|
-
const { token: tokenAux, tokenExpiry: tokenExpiryAux } = await this.getToken();
|
|
144
|
-
token = tokenAux;
|
|
145
|
-
saveInMemory(token, CREX_TOKEN_HEADER_KEY);
|
|
146
|
-
saveInMemory(tokenExpiryAux.toString(), CREX_TOKEN_EXPIRY_HEADER_KEY);
|
|
147
|
-
}
|
|
148
|
-
headersAux["Authorization"] = `Bearer ${token}`;
|
|
149
|
-
}
|
|
150
|
-
return headersAux;
|
|
184
|
+
|
|
185
|
+
// ../core/src/cache.ts
|
|
186
|
+
var CrexCache = class {
|
|
187
|
+
/**
|
|
188
|
+
* Retrieves a value from the cache by key.
|
|
189
|
+
*
|
|
190
|
+
* @param key - The cache key to retrieve
|
|
191
|
+
* @returns The cached value as a string, or null if not found
|
|
192
|
+
*/
|
|
193
|
+
async get(key) {
|
|
194
|
+
const cookie = await getCookie(key);
|
|
195
|
+
return cookie.value;
|
|
151
196
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
197
|
+
/**
|
|
198
|
+
* Stores a value in the cache with the specified key.
|
|
199
|
+
* Checks if the value size is within cookie size limits (4KB).
|
|
200
|
+
*
|
|
201
|
+
* @param key - The cache key
|
|
202
|
+
* @param value - The value to store
|
|
203
|
+
*/
|
|
204
|
+
async set(key, value) {
|
|
155
205
|
try {
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
const tokenSet = await client.grant({ grant_type: "client_credentials" });
|
|
163
|
-
token = tokenSet.access_token;
|
|
164
|
-
tokenExpiry = now + tokenSet.expires_at;
|
|
206
|
+
const byteLength = new TextEncoder().encode(value).length;
|
|
207
|
+
if (byteLength <= 4096) {
|
|
208
|
+
await setCookie(key, value);
|
|
209
|
+
} else {
|
|
210
|
+
console.warn(`Cookie ${key} value is too large to be stored in a single cookie`);
|
|
211
|
+
}
|
|
165
212
|
} catch (error) {
|
|
166
213
|
call("CrexLogger.log", {
|
|
167
214
|
level: "error",
|
|
168
|
-
message: `
|
|
215
|
+
message: `CrexCache.set error: ${error}`
|
|
169
216
|
});
|
|
170
217
|
}
|
|
171
|
-
return {
|
|
172
|
-
token,
|
|
173
|
-
tokenExpiry
|
|
174
|
-
};
|
|
175
218
|
}
|
|
219
|
+
/**
|
|
220
|
+
* Generates a cache key based on request parameters.
|
|
221
|
+
* Combines URL, method, and optionally params, body, and headers into a single string key.
|
|
222
|
+
*
|
|
223
|
+
* @param options - Request options to generate key from
|
|
224
|
+
* @param options.url - The request URL
|
|
225
|
+
* @param options.method - The HTTP method
|
|
226
|
+
* @param options.body - Optional request body
|
|
227
|
+
* @param options.params - Optional query parameters
|
|
228
|
+
* @param options.headers - Optional request headers
|
|
229
|
+
* @returns A string cache key
|
|
230
|
+
*/
|
|
231
|
+
generateCacheKey({
|
|
232
|
+
url,
|
|
233
|
+
method,
|
|
234
|
+
body,
|
|
235
|
+
params,
|
|
236
|
+
headers
|
|
237
|
+
}) {
|
|
238
|
+
let cacheKey = `${url}-${method}`;
|
|
239
|
+
if (params !== void 0 && Object.keys(params).length > 0) {
|
|
240
|
+
cacheKey += `-${JSON.stringify(params)}`;
|
|
241
|
+
}
|
|
242
|
+
if (body !== void 0 && Object.keys(body).length > 0) {
|
|
243
|
+
cacheKey += `-${JSON.stringify(body)}`;
|
|
244
|
+
}
|
|
245
|
+
if (headers !== void 0 && Object.keys(headers).length > 0) {
|
|
246
|
+
cacheKey += `-${JSON.stringify(headers)}`;
|
|
247
|
+
}
|
|
248
|
+
return cacheKey;
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
// ../core/src/requests.ts
|
|
253
|
+
var CrexApi = class {
|
|
254
|
+
customerConfig;
|
|
255
|
+
apiClient;
|
|
256
|
+
cache;
|
|
257
|
+
/**
|
|
258
|
+
* Initializes the API client if it hasn't been initialized yet.
|
|
259
|
+
* Loads customer configuration, creates the axios instance, and initializes the cache.
|
|
260
|
+
*
|
|
261
|
+
* @private
|
|
262
|
+
*/
|
|
176
263
|
async initAPI() {
|
|
177
264
|
if (!this.customerConfig) {
|
|
178
265
|
this.customerConfig = await (0, import_next_cookies.getConfigs)();
|
|
@@ -182,7 +269,22 @@ var CrexApi = class {
|
|
|
182
269
|
baseURL: this.customerConfig.baseUrl
|
|
183
270
|
});
|
|
184
271
|
}
|
|
272
|
+
if (!this.cache) {
|
|
273
|
+
this.cache = new CrexCache();
|
|
274
|
+
}
|
|
185
275
|
}
|
|
276
|
+
/**
|
|
277
|
+
* Executes an API request with caching, authentication, and retry logic.
|
|
278
|
+
*
|
|
279
|
+
* @param options - Request options
|
|
280
|
+
* @param options.url - The URL to request
|
|
281
|
+
* @param options.method - The HTTP method to use
|
|
282
|
+
* @param options.params - Optional query parameters
|
|
283
|
+
* @param options.body - Optional request body
|
|
284
|
+
* @param options.headers - Optional request headers
|
|
285
|
+
* @returns The response data
|
|
286
|
+
* @throws Error if the request fails after maximum retries
|
|
287
|
+
*/
|
|
186
288
|
async execute({
|
|
187
289
|
url,
|
|
188
290
|
method,
|
|
@@ -192,10 +294,14 @@ var CrexApi = class {
|
|
|
192
294
|
}) {
|
|
193
295
|
await this.initAPI();
|
|
194
296
|
let response = void 0;
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
297
|
+
if (this.customerConfig.OIDC.client.enabled) {
|
|
298
|
+
const token = await manageToken();
|
|
299
|
+
headers = {
|
|
300
|
+
...headers,
|
|
301
|
+
Authorization: `Bearer ${token}`
|
|
302
|
+
};
|
|
303
|
+
this.apiClient.defaults.headers.common["Authorization"] = `Bearer ${token}`;
|
|
304
|
+
}
|
|
199
305
|
for (let retry = 0; retry < API.MAX_RETRY; retry++) {
|
|
200
306
|
try {
|
|
201
307
|
response = await this.apiClient.request({
|
|
@@ -281,7 +387,15 @@ var RenditionsService = class extends BaseService {
|
|
|
281
387
|
constructor() {
|
|
282
388
|
super("Renditions/");
|
|
283
389
|
}
|
|
284
|
-
|
|
390
|
+
/**
|
|
391
|
+
* Retrieves the HTML rendition from a list of renditions.
|
|
392
|
+
* Filters for renditions with format 'application/xhtml+xml' and rel 'view'.
|
|
393
|
+
*
|
|
394
|
+
* @param renditions - Array of rendition objects to process
|
|
395
|
+
* @returns A promise that resolves to the HTML content as a string, or empty string if no suitable rendition is found
|
|
396
|
+
* @throws Error if the API request fails
|
|
397
|
+
*/
|
|
398
|
+
async getHTMLRendition({ renditions }) {
|
|
285
399
|
const filteredRenditions = renditions.filter(
|
|
286
400
|
(item2) => item2.format == "application/xhtml+xml"
|
|
287
401
|
);
|
|
@@ -299,7 +413,14 @@ var RenditionsService = class extends BaseService {
|
|
|
299
413
|
});
|
|
300
414
|
return response;
|
|
301
415
|
}
|
|
302
|
-
|
|
416
|
+
/**
|
|
417
|
+
* Processes a list of renditions and categorizes them into files to download and files to open.
|
|
418
|
+
* Excludes renditions with formats 'application/xhtml+xml', 'application/json', and 'application/llm+xml'.
|
|
419
|
+
*
|
|
420
|
+
* @param renditions - Array of rendition objects to process
|
|
421
|
+
* @returns An object containing arrays of file renditions categorized as 'filesToDownload' and 'filesToOpen'
|
|
422
|
+
*/
|
|
423
|
+
getFileRenditions = ({ renditions }) => {
|
|
303
424
|
if (renditions == void 0 || renditions.length == 0) {
|
|
304
425
|
return {
|
|
305
426
|
filesToDownload: [],
|
|
@@ -341,11 +462,26 @@ var DirectoryNodesService = class extends BaseService {
|
|
|
341
462
|
constructor() {
|
|
342
463
|
super("DirectoryNodes/");
|
|
343
464
|
}
|
|
465
|
+
/**
|
|
466
|
+
* Retrieves a specific directory node by its ID.
|
|
467
|
+
*
|
|
468
|
+
* @param id - The unique identifier of the directory node
|
|
469
|
+
* @returns A promise that resolves to the directory node data
|
|
470
|
+
* @throws Error if the API request fails
|
|
471
|
+
*/
|
|
344
472
|
async getItem(id) {
|
|
345
473
|
return await this.request({
|
|
346
474
|
path: id
|
|
347
475
|
});
|
|
348
476
|
}
|
|
477
|
+
/**
|
|
478
|
+
* Retrieves a list of directory nodes based on specified filters.
|
|
479
|
+
*
|
|
480
|
+
* @param options - Options for filtering the directory nodes list
|
|
481
|
+
* @param options.filters - Optional array of filter strings to apply
|
|
482
|
+
* @returns A promise that resolves to the directory nodes response
|
|
483
|
+
* @throws Error if the API request fails
|
|
484
|
+
*/
|
|
349
485
|
async getList({
|
|
350
486
|
filters = []
|
|
351
487
|
}) {
|
|
@@ -375,6 +511,14 @@ var DocumentTypesService = class extends BaseService {
|
|
|
375
511
|
constructor() {
|
|
376
512
|
super("DocumentTypes/");
|
|
377
513
|
}
|
|
514
|
+
/**
|
|
515
|
+
* Retrieves document type labels for the specified fields.
|
|
516
|
+
* The labels are restricted to English language (EN-us).
|
|
517
|
+
*
|
|
518
|
+
* @param fields - Array of field names to retrieve labels for
|
|
519
|
+
* @returns A promise that resolves to an array of label strings
|
|
520
|
+
* @throws Error if the API request fails
|
|
521
|
+
*/
|
|
378
522
|
async getLabels(fields) {
|
|
379
523
|
const params = [
|
|
380
524
|
{
|
|
@@ -393,13 +537,15 @@ var DocumentTypesService = class extends BaseService {
|
|
|
393
537
|
// src/transforms/information.ts
|
|
394
538
|
var import_next_cookies2 = require("@c-rex/utils/next-cookies");
|
|
395
539
|
var transformInformationUnits = async (data) => {
|
|
396
|
-
const config =
|
|
540
|
+
const config = (0, import_next_cookies2.getConfigs)();
|
|
397
541
|
const items = await Promise.all(data.items.map(async (item) => {
|
|
398
|
-
let link = `/topics/${item.shortId}`;
|
|
399
542
|
const type = item.class.labels.filter((item2) => item2.language === EN_LANG)[0].value.toUpperCase();
|
|
400
543
|
const service = new RenditionsService();
|
|
401
|
-
const { filesToOpen, filesToDownload } = service.getFileRenditions(item?.renditions);
|
|
402
|
-
|
|
544
|
+
const { filesToOpen, filesToDownload } = service.getFileRenditions({ renditions: item?.renditions });
|
|
545
|
+
let link = `/topics/${item.shortId}`;
|
|
546
|
+
if (config.results.articlePageLayout == "BLOG") {
|
|
547
|
+
link = `/blog/${item.shortId}`;
|
|
548
|
+
} else if (type == RESULT_TYPES.DOCUMENT) {
|
|
403
549
|
link = `/documents/${item.shortId}`;
|
|
404
550
|
}
|
|
405
551
|
return {
|
|
@@ -425,6 +571,18 @@ var InformationUnitsService = class extends BaseService {
|
|
|
425
571
|
constructor() {
|
|
426
572
|
super("InformationUnits/");
|
|
427
573
|
}
|
|
574
|
+
/**
|
|
575
|
+
* Retrieves a list of information units based on specified criteria.
|
|
576
|
+
*
|
|
577
|
+
* @param options - Options for filtering and paginating the information units list
|
|
578
|
+
* @param options.queries - Optional search query string
|
|
579
|
+
* @param options.page - Optional page number for pagination (defaults to 1)
|
|
580
|
+
* @param options.fields - Optional array of fields to include in the response
|
|
581
|
+
* @param options.filters - Optional array of filter strings to apply
|
|
582
|
+
* @param options.languages - Optional array of language codes to filter by
|
|
583
|
+
* @returns A promise that resolves to the information units response
|
|
584
|
+
* @throws Error if the API request fails
|
|
585
|
+
*/
|
|
428
586
|
async getList({
|
|
429
587
|
queries = "",
|
|
430
588
|
page = 1,
|
|
@@ -455,6 +613,15 @@ var InformationUnitsService = class extends BaseService {
|
|
|
455
613
|
transformer: transformInformationUnits
|
|
456
614
|
});
|
|
457
615
|
}
|
|
616
|
+
/**
|
|
617
|
+
* Retrieves a specific information unit by its ID.
|
|
618
|
+
* Includes renditions, directory nodes, version information, titles, languages, and labels.
|
|
619
|
+
*
|
|
620
|
+
* @param options - Options for retrieving the information unit
|
|
621
|
+
* @param options.id - The unique identifier of the information unit
|
|
622
|
+
* @returns A promise that resolves to the information unit data
|
|
623
|
+
* @throws Error if the API request fails
|
|
624
|
+
*/
|
|
458
625
|
async getItem({ id }) {
|
|
459
626
|
const params = [
|
|
460
627
|
{ key: "Fields", value: "renditions" },
|
|
@@ -469,21 +636,44 @@ var InformationUnitsService = class extends BaseService {
|
|
|
469
636
|
params
|
|
470
637
|
});
|
|
471
638
|
}
|
|
472
|
-
|
|
639
|
+
/**
|
|
640
|
+
* Retrieves autocomplete suggestions based on a query prefix.
|
|
641
|
+
*
|
|
642
|
+
* @param options - Options for retrieving suggestions
|
|
643
|
+
* @param options.query - The query prefix to get suggestions for
|
|
644
|
+
* @param options.language - The language of the suggestions
|
|
645
|
+
* @returns A promise that resolves to an array of suggestion strings
|
|
646
|
+
* @throws Error if the API request fails
|
|
647
|
+
*/
|
|
648
|
+
async getSuggestions({ query, language }) {
|
|
473
649
|
return await this.request({
|
|
474
650
|
path: `Suggestions`,
|
|
475
|
-
params: [
|
|
651
|
+
params: [
|
|
652
|
+
{ key: "prefix", value: query },
|
|
653
|
+
{ key: "lang", value: language }
|
|
654
|
+
],
|
|
476
655
|
transformer: (data) => {
|
|
477
|
-
|
|
656
|
+
const suggestions = [];
|
|
657
|
+
const comparableList = [];
|
|
658
|
+
data.suggestions.forEach((item) => {
|
|
659
|
+
suggestions.push(item.value);
|
|
660
|
+
comparableList.push(item.value.toLowerCase());
|
|
661
|
+
});
|
|
662
|
+
if (!comparableList.includes(query.toLowerCase())) {
|
|
663
|
+
return [query, ...suggestions];
|
|
664
|
+
}
|
|
665
|
+
return suggestions;
|
|
478
666
|
}
|
|
479
667
|
});
|
|
480
668
|
}
|
|
481
669
|
};
|
|
482
670
|
|
|
483
671
|
// src/language.ts
|
|
672
|
+
var import_next_cookies3 = require("@c-rex/utils/next-cookies");
|
|
484
673
|
var LanguageService = class extends BaseService {
|
|
485
|
-
constructor(
|
|
486
|
-
|
|
674
|
+
constructor() {
|
|
675
|
+
const configs = (0, import_next_cookies3.getConfigs)();
|
|
676
|
+
super(configs.languageSwitcher.endpoint);
|
|
487
677
|
}
|
|
488
678
|
/*
|
|
489
679
|
public static async getInstance(): Promise<LanguageService> {
|
|
@@ -495,6 +685,13 @@ var LanguageService = class extends BaseService {
|
|
|
495
685
|
return LanguageService.instance;
|
|
496
686
|
}
|
|
497
687
|
*/
|
|
688
|
+
/**
|
|
689
|
+
* Retrieves a list of available languages and their associated countries.
|
|
690
|
+
* Transforms the API response to include language code, country code, and original value.
|
|
691
|
+
*
|
|
692
|
+
* @returns A promise that resolves to an array of language and country objects
|
|
693
|
+
* @throws Error if the API request fails
|
|
694
|
+
*/
|
|
498
695
|
async getLanguagesAndCountries() {
|
|
499
696
|
return await this.request({
|
|
500
697
|
transformer: (data) => {
|