@c-rex/services 0.1.2 → 0.1.4

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.js CHANGED
@@ -42,6 +42,14 @@ module.exports = __toCommonJS(index_exports);
42
42
  var import_axios = __toESM(require("axios"));
43
43
 
44
44
  // ../constants/src/index.ts
45
+ var ALL = "*";
46
+ var LOG_LEVELS = {
47
+ critical: 2,
48
+ error: 3,
49
+ warning: 4,
50
+ info: 6,
51
+ debug: 7
52
+ };
45
53
  var API = {
46
54
  MAX_RETRY: 3,
47
55
  API_TIMEOUT: 1e4,
@@ -49,140 +57,241 @@ var API = {
49
57
  "content-Type": "application/json"
50
58
  }
51
59
  };
60
+ var SDK_CONFIG_KEY = "crex-sdk-config";
52
61
  var FLAGS_BY_LANG = {
53
62
  "en": "US",
54
63
  "de": "DE"
55
64
  };
56
65
  var EN_LANG = "en";
66
+ var TOPIC = "TOPIC";
67
+ var DOCUMENT = "DOCUMENT";
68
+ var PACKAGE = "PACKAGE";
57
69
  var RESULT_TYPES = {
58
- TOPIC: "TOPIC",
59
- DOCUMENT: "DOCUMENT",
60
- PACKAGE: "PACKAGE"
70
+ TOPIC,
71
+ DOCUMENT,
72
+ PACKAGE
61
73
  };
62
74
  var DEFAULT_COOKIE_LIMIT = 7 * 24 * 60 * 60 * 1e3;
75
+ var CREX_TOKEN_HEADER_KEY = "crex-token";
63
76
 
64
77
  // ../core/src/requests.ts
65
- var import_openid_client = require("openid-client");
78
+ var import_headers = require("next/headers");
66
79
 
67
- // ../utils/src/utils.ts
68
- var call = async (method, params) => {
69
- try {
70
- const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/rpc`, {
71
- method: "POST",
72
- headers: { "Content-Type": "application/json" },
73
- body: JSON.stringify({ method, params })
80
+ // ../core/src/logger.ts
81
+ var import_winston = __toESM(require("winston"));
82
+
83
+ // ../core/src/transports/matomo.ts
84
+ var import_winston_transport = __toESM(require("winston-transport"));
85
+ var MatomoTransport = class extends import_winston_transport.default {
86
+ matomoTransport;
87
+ configs;
88
+ /**
89
+ * Creates a new instance of MatomoTransport.
90
+ *
91
+ * @param configs - The application configuration containing logging settings
92
+ */
93
+ constructor(configs) {
94
+ super({
95
+ level: configs.logs.matomo.minimumLevel,
96
+ silent: configs.logs.matomo.silent
74
97
  });
75
- const json = await res.json();
76
- if (!res.ok) throw new Error(json.error || "Unknown error");
77
- return json.data;
78
- } catch (error) {
79
- console.error(error);
80
- return null;
98
+ this.matomoTransport = new import_winston_transport.default();
99
+ this.configs = configs;
81
100
  }
82
- };
83
- var getCountryCodeByLang = (lang) => {
84
- const mappedKeys = Object.keys(FLAGS_BY_LANG);
85
- if (!mappedKeys.includes(lang)) {
86
- return lang;
101
+ /**
102
+ * Logs a message to Matomo if the message category is included in the configured categories.
103
+ *
104
+ * @param info - The log information including level, message, and category
105
+ * @param callback - Callback function to execute after logging
106
+ */
107
+ log(info, callback) {
108
+ const matomoCategory = this.configs.logs.matomo.categoriesLevel;
109
+ if (matomoCategory.includes(info.category) || matomoCategory.includes(ALL)) {
110
+ this.matomoTransport.log(info, callback);
111
+ }
87
112
  }
88
- const country = FLAGS_BY_LANG[lang];
89
- return country;
90
113
  };
91
114
 
92
- // ../utils/src/memory.ts
93
- function isBrowser() {
94
- return typeof window !== "undefined" && typeof document !== "undefined";
95
- }
96
- function saveInMemory(value, key) {
97
- if (isBrowser()) throw new Error("saveInMemory is not supported in browser");
98
- if (typeof global !== "undefined" && !(key in global)) {
99
- global[key] = null;
100
- }
101
- const globalConfig = global[key];
102
- if (globalConfig === null) {
103
- global[key] = value;
104
- }
105
- }
106
- function getFromMemory(key) {
107
- if (isBrowser()) throw new Error("getFromMemory is not supported in browser");
108
- return global[key];
109
- }
110
-
111
- // ../utils/src/classMerge.ts
112
- var import_clsx = require("clsx");
113
- var import_tailwind_merge = require("tailwind-merge");
115
+ // ../core/src/transports/graylog.ts
116
+ var import_winston_transport2 = __toESM(require("winston-transport"));
117
+ var import_winston_graylog2 = __toESM(require("winston-graylog2"));
118
+ var GraylogTransport = class extends import_winston_transport2.default {
119
+ graylogTransport;
120
+ configs;
121
+ /**
122
+ * Creates a new instance of GraylogTransport.
123
+ *
124
+ * @param configs - The application configuration containing logging settings
125
+ */
126
+ constructor(configs) {
127
+ super({
128
+ level: configs.logs.graylog.minimumLevel,
129
+ silent: configs.logs.graylog.silent
130
+ });
131
+ this.configs = configs;
132
+ this.graylogTransport = new import_winston_graylog2.default({
133
+ name: "crex.net.documentation",
134
+ //name: "crex.net.blog",
135
+ silent: false,
136
+ handleExceptions: false,
137
+ graylog: {
138
+ servers: [
139
+ { host: "localhost", port: 12201 },
140
+ { host: "https://log.c-rex.net", port: 12202 }
141
+ //TODO: check the URL => https://log.c-rex.net:12202/gelf" GELF??
142
+ ]
143
+ }
144
+ });
145
+ }
146
+ /**
147
+ * Logs a message to Graylog if the message category is included in the configured categories.
148
+ *
149
+ * @param info - The log information including level, message, and category
150
+ * @param callback - Callback function to execute after logging
151
+ */
152
+ log(info, callback) {
153
+ const graylogCategory = this.configs.logs.graylog.categoriesLevel;
154
+ if (graylogCategory.includes(info.category) || graylogCategory.includes(ALL)) {
155
+ this.graylogTransport.log(info, callback);
156
+ }
157
+ }
158
+ };
114
159
 
115
- // ../utils/src/params.ts
116
- var createParams = (fieldsList, key = "Fields") => fieldsList.map((item) => ({
117
- key,
118
- value: item
119
- }));
120
- var generateQueryParams = (params) => {
121
- const queryParams = params.map(
122
- (param) => `${encodeURIComponent(param.key)}=${encodeURIComponent(param.value)}`
123
- ).join("&");
124
- return queryParams;
160
+ // ../core/src/logger.ts
161
+ var import_next_cookies = require("@c-rex/utils/next-cookies");
162
+ var CrexLogger = class {
163
+ customerConfig;
164
+ logger;
165
+ /**
166
+ * Initializes the logger instance if it hasn't been initialized yet.
167
+ * Loads customer configuration and creates the logger with appropriate transports.
168
+ *
169
+ * @private
170
+ */
171
+ async initLogger() {
172
+ try {
173
+ if (!this.customerConfig) {
174
+ this.customerConfig = await (0, import_next_cookies.getConfigs)();
175
+ }
176
+ if (!this.logger) {
177
+ this.logger = this.createLogger();
178
+ }
179
+ } catch (error) {
180
+ console.error("Error initializing logger:", error);
181
+ }
182
+ }
183
+ /**
184
+ * Logs a message with the specified level and optional category.
185
+ *
186
+ * @param options - Logging options
187
+ * @param options.level - The log level (error, warn, info, etc.)
188
+ * @param options.message - The message to log
189
+ * @param options.category - Optional category for the log message
190
+ */
191
+ async log({ level, message, category }) {
192
+ await this.initLogger();
193
+ this.logger.log(level, message, category);
194
+ }
195
+ /**
196
+ * Creates a new Winston logger instance with configured transports.
197
+ *
198
+ * @private
199
+ * @returns A configured Winston logger instance
200
+ */
201
+ createLogger() {
202
+ return import_winston.default.createLogger({
203
+ levels: LOG_LEVELS,
204
+ transports: [
205
+ new import_winston.default.transports.Console({
206
+ level: this.customerConfig.logs.console.minimumLevel,
207
+ silent: this.customerConfig.logs.console.silent
208
+ }),
209
+ new MatomoTransport(this.customerConfig),
210
+ new GraylogTransport(this.customerConfig)
211
+ ]
212
+ });
213
+ }
125
214
  };
126
215
 
127
216
  // ../core/src/requests.ts
128
- var import_next_cookies = require("@c-rex/utils/next-cookies");
129
- var CREX_TOKEN_HEADER_KEY = "crex-token";
130
- var CREX_TOKEN_EXPIRY_HEADER_KEY = "crex-token-expiry";
131
217
  var CrexApi = class {
132
218
  customerConfig;
133
219
  apiClient;
134
- async manageToken() {
135
- const headersAux = {};
136
- if (this.customerConfig.OIDC.client.enabled) {
137
- let token = getFromMemory(CREX_TOKEN_HEADER_KEY);
138
- const tokenExpiry = Number(
139
- getFromMemory(CREX_TOKEN_EXPIRY_HEADER_KEY)
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);
220
+ logger;
221
+ /**
222
+ * Initializes the API client if it hasn't been initialized yet.
223
+ * Loads customer configuration, creates the axios instance, and initializes the logger.
224
+ *
225
+ * @private
226
+ */
227
+ async initAPI() {
228
+ this.logger = new CrexLogger();
229
+ if (!this.customerConfig) {
230
+ const aux = (0, import_headers.cookies)().get(SDK_CONFIG_KEY);
231
+ if (aux != void 0) {
232
+ this.customerConfig = JSON.parse(aux.value);
233
+ } else {
234
+ this.logger.log({
235
+ level: "error",
236
+ message: `utils.initAPI error: Config cookie not available`
237
+ });
238
+ throw new Error("Config cookie not available");
147
239
  }
148
- headersAux["Authorization"] = `Bearer ${token}`;
149
240
  }
150
- return headersAux;
241
+ if (!this.apiClient) {
242
+ this.apiClient = import_axios.default.create({
243
+ baseURL: this.customerConfig.baseUrl
244
+ });
245
+ }
151
246
  }
152
247
  async getToken() {
153
- let token = "";
154
- let tokenExpiry = 0;
155
248
  try {
156
- const now = Math.floor(Date.now() / 1e3);
157
- const issuer = await import_openid_client.Issuer.discover(this.customerConfig.OIDC.client.issuer);
158
- const client = new issuer.Client({
159
- client_id: this.customerConfig.OIDC.client.id,
160
- client_secret: this.customerConfig.OIDC.client.secret
249
+ const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/token`, {
250
+ method: "POST",
251
+ credentials: "include"
161
252
  });
162
- const tokenSet = await client.grant({ grant_type: "client_credentials" });
163
- token = tokenSet.access_token;
164
- tokenExpiry = now + tokenSet.expires_at;
253
+ const { token } = await response.json();
254
+ return token;
165
255
  } catch (error) {
166
- call("CrexLogger.log", {
256
+ this.logger.log({
167
257
  level: "error",
168
- message: `API.getToken error when request ${this.customerConfig.OIDC.client.issuer}. Error: ${error}`
258
+ message: `utils.getToken error: ${error}`
169
259
  });
260
+ throw error;
170
261
  }
171
- return {
172
- token,
173
- tokenExpiry
174
- };
175
262
  }
176
- async initAPI() {
177
- if (!this.customerConfig) {
178
- this.customerConfig = await (0, import_next_cookies.getConfigs)();
179
- }
180
- if (!this.apiClient) {
181
- this.apiClient = import_axios.default.create({
182
- baseURL: this.customerConfig.baseUrl
263
+ async manageToken() {
264
+ try {
265
+ let token = "";
266
+ const hasToken = (0, import_headers.cookies)().get(CREX_TOKEN_HEADER_KEY);
267
+ if (hasToken == void 0 || hasToken.value === null) {
268
+ const tokenResult = await this.getToken();
269
+ if (tokenResult === null) throw new Error("Token is undefined");
270
+ token = tokenResult;
271
+ } else {
272
+ token = hasToken.value;
273
+ }
274
+ return token;
275
+ } catch (error) {
276
+ this.logger.log({
277
+ level: "error",
278
+ message: `utils.manageToken error: ${error}`
183
279
  });
280
+ throw error;
184
281
  }
185
282
  }
283
+ /**
284
+ * Executes an API request with caching, authentication, and retry logic.
285
+ *
286
+ * @param options - Request options
287
+ * @param options.url - The URL to request
288
+ * @param options.method - The HTTP method to use
289
+ * @param options.params - Optional query parameters
290
+ * @param options.body - Optional request body
291
+ * @param options.headers - Optional request headers
292
+ * @returns The response data
293
+ * @throws Error if the request fails after maximum retries
294
+ */
186
295
  async execute({
187
296
  url,
188
297
  method,
@@ -192,10 +301,14 @@ var CrexApi = class {
192
301
  }) {
193
302
  await this.initAPI();
194
303
  let response = void 0;
195
- headers = {
196
- ...headers,
197
- ...await this.manageToken()
198
- };
304
+ if (this.customerConfig.OIDC.client.enabled) {
305
+ const token = await this.manageToken();
306
+ headers = {
307
+ ...headers,
308
+ Authorization: `Bearer ${token}`
309
+ };
310
+ this.apiClient.defaults.headers.common["Authorization"] = `Bearer ${token}`;
311
+ }
199
312
  for (let retry = 0; retry < API.MAX_RETRY; retry++) {
200
313
  try {
201
314
  response = await this.apiClient.request({
@@ -207,7 +320,7 @@ var CrexApi = class {
207
320
  });
208
321
  break;
209
322
  } catch (error) {
210
- call("CrexLogger.log", {
323
+ this.logger.log({
211
324
  level: "error",
212
325
  message: `API.execute ${retry + 1}\xBA error when request ${url}. Error: ${error}`
213
326
  });
@@ -223,6 +336,106 @@ var CrexApi = class {
223
336
  }
224
337
  };
225
338
 
339
+ // ../utils/src/utils.ts
340
+ var _generateShaKey = async (input) => {
341
+ const encoder = new TextEncoder();
342
+ const data = encoder.encode(input);
343
+ const hashBuffer = await crypto.subtle.digest("SHA-1", data);
344
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
345
+ const base64url = btoa(String.fromCharCode(...hashArray)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
346
+ return base64url.slice(0, 12);
347
+ };
348
+ var getCountryCodeByLang = (lang) => {
349
+ const mappedKeys = Object.keys(FLAGS_BY_LANG);
350
+ if (!mappedKeys.includes(lang)) {
351
+ return lang;
352
+ }
353
+ const country = FLAGS_BY_LANG[lang];
354
+ return country;
355
+ };
356
+
357
+ // ../utils/src/call.ts
358
+ var call = async (method, params) => {
359
+ const shaKey = await _generateShaKey(JSON.stringify({ method, params }));
360
+ const cache = localStorage.getItem(shaKey);
361
+ if (cache !== null) {
362
+ const { data, expireDate } = JSON.parse(cache);
363
+ if (new Date(expireDate) > /* @__PURE__ */ new Date()) {
364
+ return JSON.parse(data);
365
+ } else {
366
+ localStorage.removeItem(shaKey);
367
+ }
368
+ }
369
+ const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/rpc`, {
370
+ method: "POST",
371
+ headers: { "Content-Type": "application/json" },
372
+ body: JSON.stringify({ method, params }),
373
+ credentials: "include"
374
+ });
375
+ const json = await res.json();
376
+ if (!res.ok) throw new Error(json.error || "Unknown error");
377
+ const today = /* @__PURE__ */ new Date();
378
+ const result = {
379
+ data: JSON.stringify(json.data),
380
+ expireDate: new Date(today.getTime() + 1e3 * 60 * 60)
381
+ };
382
+ localStorage.setItem(shaKey, JSON.stringify(result));
383
+ return json.data;
384
+ };
385
+
386
+ // ../utils/src/classMerge.ts
387
+ var import_clsx = require("clsx");
388
+ var import_tailwind_merge = require("tailwind-merge");
389
+
390
+ // ../utils/src/params.ts
391
+ var createParams = (fieldsList, key = "Fields") => fieldsList.map((item) => ({
392
+ key,
393
+ value: item
394
+ }));
395
+ var generateQueryParams = (params) => {
396
+ const queryParams = params.map(
397
+ (param) => `${encodeURIComponent(param.key)}=${encodeURIComponent(param.value)}`
398
+ ).join("&");
399
+ return queryParams;
400
+ };
401
+
402
+ // ../utils/src/renditions.ts
403
+ var getFileRenditions = ({ renditions }) => {
404
+ if (renditions == void 0 || renditions.length == 0) {
405
+ return {
406
+ filesToDownload: [],
407
+ filesToOpen: []
408
+ };
409
+ }
410
+ const filteredRenditions = renditions.filter(
411
+ (item) => item.format != "application/xhtml+xml" && item.format != "application/json" && item.format != "application/llm+xml"
412
+ );
413
+ if (filteredRenditions.length == 0 || filteredRenditions[0] == void 0) {
414
+ return {
415
+ filesToDownload: [],
416
+ filesToOpen: []
417
+ };
418
+ }
419
+ const filesToDownload = filteredRenditions.map((item) => {
420
+ const filteredLinks = item.links.filter((item2) => item2.rel == "download");
421
+ return {
422
+ format: item.format,
423
+ link: filteredLinks[0].href
424
+ };
425
+ });
426
+ const filesToOpen = filteredRenditions.map((item) => {
427
+ const filteredLinks = item.links.filter((item2) => item2.rel == "view");
428
+ return {
429
+ format: item.format,
430
+ link: filteredLinks[0].href
431
+ };
432
+ });
433
+ return {
434
+ filesToDownload,
435
+ filesToOpen
436
+ };
437
+ };
438
+
226
439
  // src/baseService.ts
227
440
  var BaseService = class {
228
441
  api;
@@ -281,7 +494,15 @@ var RenditionsService = class extends BaseService {
281
494
  constructor() {
282
495
  super("Renditions/");
283
496
  }
284
- async getHTMLRendition(renditions) {
497
+ /**
498
+ * Retrieves the HTML rendition from a list of renditions.
499
+ * Filters for renditions with format 'application/xhtml+xml' and rel 'view'.
500
+ *
501
+ * @param renditions - Array of rendition objects to process
502
+ * @returns A promise that resolves to the HTML content as a string, or empty string if no suitable rendition is found
503
+ * @throws Error if the API request fails
504
+ */
505
+ async getHTMLRendition({ renditions }) {
285
506
  const filteredRenditions = renditions.filter(
286
507
  (item2) => item2.format == "application/xhtml+xml"
287
508
  );
@@ -299,41 +520,6 @@ var RenditionsService = class extends BaseService {
299
520
  });
300
521
  return response;
301
522
  }
302
- getFileRenditions = (renditions) => {
303
- if (renditions == void 0 || renditions.length == 0) {
304
- return {
305
- filesToDownload: [],
306
- filesToOpen: []
307
- };
308
- }
309
- const filteredRenditions = renditions.filter(
310
- (item) => item.format != "application/xhtml+xml" && item.format != "application/json" && item.format != "application/llm+xml"
311
- );
312
- if (filteredRenditions.length == 0 || filteredRenditions[0] == void 0) {
313
- return {
314
- filesToDownload: [],
315
- filesToOpen: []
316
- };
317
- }
318
- const filesToDownload = filteredRenditions.map((item) => {
319
- const filteredLinks = item.links.filter((item2) => item2.rel == "download");
320
- return {
321
- format: item.format,
322
- link: filteredLinks[0].href
323
- };
324
- });
325
- const filesToOpen = filteredRenditions.map((item) => {
326
- const filteredLinks = item.links.filter((item2) => item2.rel == "view");
327
- return {
328
- format: item.format,
329
- link: filteredLinks[0].href
330
- };
331
- });
332
- return {
333
- filesToDownload,
334
- filesToOpen
335
- };
336
- };
337
523
  };
338
524
 
339
525
  // src/directoryNodes.ts
@@ -341,11 +527,26 @@ var DirectoryNodesService = class extends BaseService {
341
527
  constructor() {
342
528
  super("DirectoryNodes/");
343
529
  }
530
+ /**
531
+ * Retrieves a specific directory node by its ID.
532
+ *
533
+ * @param id - The unique identifier of the directory node
534
+ * @returns A promise that resolves to the directory node data
535
+ * @throws Error if the API request fails
536
+ */
344
537
  async getItem(id) {
345
538
  return await this.request({
346
539
  path: id
347
540
  });
348
541
  }
542
+ /**
543
+ * Retrieves a list of directory nodes based on specified filters.
544
+ *
545
+ * @param options - Options for filtering the directory nodes list
546
+ * @param options.filters - Optional array of filter strings to apply
547
+ * @returns A promise that resolves to the directory nodes response
548
+ * @throws Error if the API request fails
549
+ */
349
550
  async getList({
350
551
  filters = []
351
552
  }) {
@@ -375,6 +576,14 @@ var DocumentTypesService = class extends BaseService {
375
576
  constructor() {
376
577
  super("DocumentTypes/");
377
578
  }
579
+ /**
580
+ * Retrieves document type labels for the specified fields.
581
+ * The labels are restricted to English language (EN-us).
582
+ *
583
+ * @param fields - Array of field names to retrieve labels for
584
+ * @returns A promise that resolves to an array of label strings
585
+ * @throws Error if the API request fails
586
+ */
378
587
  async getLabels(fields) {
379
588
  const params = [
380
589
  {
@@ -395,11 +604,12 @@ var import_next_cookies2 = require("@c-rex/utils/next-cookies");
395
604
  var transformInformationUnits = async (data) => {
396
605
  const config = await (0, import_next_cookies2.getConfigs)();
397
606
  const items = await Promise.all(data.items.map(async (item) => {
398
- let link = `/topics/${item.shortId}`;
399
607
  const type = item.class.labels.filter((item2) => item2.language === EN_LANG)[0].value.toUpperCase();
400
- const service = new RenditionsService();
401
- const { filesToOpen, filesToDownload } = service.getFileRenditions(item?.renditions);
402
- if (type == RESULT_TYPES.DOCUMENT) {
608
+ const { filesToOpen, filesToDownload } = getFileRenditions({ renditions: item?.renditions });
609
+ let link = `/topics/${item.shortId}`;
610
+ if (config.results.articlePageLayout == "BLOG") {
611
+ link = `/blog/${item.shortId}`;
612
+ } else if (type == RESULT_TYPES.DOCUMENT) {
403
613
  link = `/documents/${item.shortId}`;
404
614
  }
405
615
  return {
@@ -425,6 +635,18 @@ var InformationUnitsService = class extends BaseService {
425
635
  constructor() {
426
636
  super("InformationUnits/");
427
637
  }
638
+ /**
639
+ * Retrieves a list of information units based on specified criteria.
640
+ *
641
+ * @param options - Options for filtering and paginating the information units list
642
+ * @param options.queries - Optional search query string
643
+ * @param options.page - Optional page number for pagination (defaults to 1)
644
+ * @param options.fields - Optional array of fields to include in the response
645
+ * @param options.filters - Optional array of filter strings to apply
646
+ * @param options.languages - Optional array of language codes to filter by
647
+ * @returns A promise that resolves to the information units response
648
+ * @throws Error if the API request fails
649
+ */
428
650
  async getList({
429
651
  queries = "",
430
652
  page = 1,
@@ -455,6 +677,15 @@ var InformationUnitsService = class extends BaseService {
455
677
  transformer: transformInformationUnits
456
678
  });
457
679
  }
680
+ /**
681
+ * Retrieves a specific information unit by its ID.
682
+ * Includes renditions, directory nodes, version information, titles, languages, and labels.
683
+ *
684
+ * @param options - Options for retrieving the information unit
685
+ * @param options.id - The unique identifier of the information unit
686
+ * @returns A promise that resolves to the information unit data
687
+ * @throws Error if the API request fails
688
+ */
458
689
  async getItem({ id }) {
459
690
  const params = [
460
691
  { key: "Fields", value: "renditions" },
@@ -469,32 +700,52 @@ var InformationUnitsService = class extends BaseService {
469
700
  params
470
701
  });
471
702
  }
472
- async getSuggestions({ query }) {
703
+ /**
704
+ * Retrieves autocomplete suggestions based on a query prefix.
705
+ *
706
+ * @param options - Options for retrieving suggestions
707
+ * @param options.query - The query prefix to get suggestions for
708
+ * @param options.language - The language of the suggestions
709
+ * @returns A promise that resolves to an array of suggestion strings
710
+ * @throws Error if the API request fails
711
+ */
712
+ async getSuggestions({ query, language }) {
473
713
  return await this.request({
474
714
  path: `Suggestions`,
475
- params: [{ key: "prefix", value: query }],
715
+ params: [
716
+ { key: "prefix", value: query },
717
+ { key: "lang", value: language }
718
+ ],
476
719
  transformer: (data) => {
477
- return data.suggestions.map((item) => item.value);
720
+ const suggestions = [];
721
+ const comparableList = [];
722
+ data.suggestions.forEach((item) => {
723
+ suggestions.push(item.value);
724
+ comparableList.push(item.value.toLowerCase());
725
+ });
726
+ if (!comparableList.includes(query.toLowerCase())) {
727
+ return [query, ...suggestions];
728
+ }
729
+ return suggestions;
478
730
  }
479
731
  });
480
732
  }
481
733
  };
482
734
 
483
735
  // src/language.ts
736
+ var import_next_cookies3 = require("@c-rex/utils/next-cookies");
484
737
  var LanguageService = class extends BaseService {
485
- constructor(endpoint) {
486
- super(endpoint);
487
- }
488
- /*
489
- public static async getInstance(): Promise<LanguageService> {
490
- const customerConfig = await getConfigs()
491
-
492
- if (!LanguageService.instance) {
493
- LanguageService.instance = new LanguageService(customerConfig.languageSwitcher.endpoint);
494
- }
495
- return LanguageService.instance;
496
- }
497
- */
738
+ constructor() {
739
+ const configs = (0, import_next_cookies3.getConfigs)();
740
+ super(configs.languageSwitcher.endpoint);
741
+ }
742
+ /**
743
+ * Retrieves a list of available languages and their associated countries.
744
+ * Transforms the API response to include language code, country code, and original value.
745
+ *
746
+ * @returns A promise that resolves to an array of language and country objects
747
+ * @throws Error if the API request fails
748
+ */
498
749
  async getLanguagesAndCountries() {
499
750
  return await this.request({
500
751
  transformer: (data) => {