@fjell/client-api 4.4.44 → 4.4.45

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
@@ -17,12 +17,12 @@ var getAllOperation = (api, apiOptions, utilities) => {
17
17
  const params = queryToParams(query);
18
18
  const requestOptions = Object.assign({}, apiOptions.getOptions, { isAuthenticated: apiOptions.allAuthenticated, params });
19
19
  logger.default("all", { query, locations, requestOptions });
20
- return utilities.validatePK(await utilities.processArray(
20
+ return await utilities.processArray(
21
21
  api.httpGet(
22
22
  utilities.getPath(loc),
23
23
  requestOptions
24
24
  )
25
- ));
25
+ );
26
26
  };
27
27
  return all;
28
28
  };
@@ -30,17 +30,17 @@ var getAllOperation = (api, apiOptions, utilities) => {
30
30
  // src/ops/action.ts
31
31
  var logger2 = logger_default.get("client-api", "ops", "action");
32
32
  var getActionOperation = (api, apiOptions, utilities) => {
33
- const action = async (ik, action2, body = {}) => {
33
+ const action = async (ik, action2, params) => {
34
34
  const requestOptions = Object.assign({}, apiOptions.postOptions, { isAuthenticated: apiOptions.writeAuthenticated });
35
- logger2.default("action", { ik, action: action2, body, requestOptions });
35
+ logger2.default("action", { ik, action: action2, params, requestOptions });
36
36
  const response = await api.httpPost(
37
37
  `${utilities.getPath(ik)}/${action2}`,
38
- body,
38
+ params || {},
39
39
  requestOptions
40
40
  );
41
41
  const [item, affectedItems] = response;
42
42
  return [
43
- utilities.validatePK(await utilities.processOne(Promise.resolve(item))),
43
+ await utilities.processOne(Promise.resolve(item)),
44
44
  affectedItems
45
45
  ];
46
46
  };
@@ -50,24 +50,23 @@ var getActionOperation = (api, apiOptions, utilities) => {
50
50
  // src/ops/allAction.ts
51
51
  var logger3 = logger_default.get("client-api", "ops", "allAction");
52
52
  var getAllActionOperation = (api, apiOptions, utilities) => {
53
- const allAction = async (action, body = {}, locations = []) => {
53
+ const allAction = async (action, params, locations) => {
54
54
  const requestOptions = Object.assign({}, apiOptions.postOptions, { isAuthenticated: apiOptions.writeAuthenticated });
55
- logger3.default("allAction", { action, body, locations, requestOptions });
56
- utilities.verifyLocations(locations);
57
- const loc = locations;
55
+ const loc = locations || [];
56
+ logger3.default("allAction", { action, params, locations: loc, requestOptions });
57
+ utilities.verifyLocations(loc);
58
58
  const response = await api.httpPost(
59
59
  `${utilities.getPath(loc)}/${action}`,
60
- body,
60
+ params || {},
61
61
  requestOptions
62
62
  );
63
63
  let items = [];
64
64
  let affectedItems = [];
65
65
  if (Array.isArray(response)) {
66
- if (response[0] !== void 0 && response[1] !== void 0) {
66
+ if (response.length === 2 && Array.isArray(response[0])) {
67
67
  [items, affectedItems] = response;
68
- } else if (response[0] !== void 0) {
69
- items = response[0];
70
- affectedItems = [];
68
+ } else {
69
+ return response;
71
70
  }
72
71
  } else if (response && typeof response === "object" && Object.keys(response).length === 0) {
73
72
  items = [];
@@ -76,10 +75,12 @@ var getAllActionOperation = (api, apiOptions, utilities) => {
76
75
  items = [];
77
76
  affectedItems = [];
78
77
  }
78
+ const processedItems = await utilities.processArray(Promise.resolve(items));
79
+ if (Array.isArray(processedItems)) {
80
+ processedItems.forEach((item) => utilities.validatePK(item));
81
+ }
79
82
  return [
80
- utilities.validatePK(
81
- await utilities.processArray(Promise.resolve(items))
82
- ),
83
+ processedItems,
83
84
  affectedItems
84
85
  ];
85
86
  };
@@ -99,12 +100,12 @@ var getOneOperation = (api, apiOptions, utilities) => {
99
100
  const requestOptions = Object.assign({}, apiOptions.getOptions, { isAuthenticated: apiOptions.readAuthenticated, params });
100
101
  logger4.default("one", { query, locations, requestOptions });
101
102
  let item = null;
102
- const items = utilities.validatePK(await utilities.processArray(
103
+ const items = await utilities.processArray(
103
104
  api.httpGet(
104
105
  utilities.getPath(loc),
105
106
  requestOptions
106
107
  )
107
- ));
108
+ );
108
109
  if (items.length > 0) {
109
110
  item = items[0];
110
111
  }
@@ -114,7 +115,11 @@ var getOneOperation = (api, apiOptions, utilities) => {
114
115
  };
115
116
 
116
117
  // src/ops/errorHandling.ts
118
+ import { isFjellHttpError } from "@fjell/http-api";
117
119
  function shouldRetryError(error) {
120
+ if (isFjellHttpError(error)) {
121
+ return error.isRetryable();
122
+ }
118
123
  if (error.code === "ECONNREFUSED" || error.code === "ENOTFOUND" || error.code === "ENETUNREACH" || error.message?.includes("timeout") || error.message?.includes("network")) {
119
124
  return true;
120
125
  }
@@ -134,6 +139,9 @@ function calculateRetryDelay(attempt, config) {
134
139
  }
135
140
  function enhanceError(error, context) {
136
141
  if (!error) return new Error("Unknown error occurred");
142
+ if (isFjellHttpError(error)) {
143
+ return error;
144
+ }
137
145
  if (error.context) return error;
138
146
  const enhancedError = new Error(error.message || "HTTP operation failed");
139
147
  Object.assign(enhancedError, {
@@ -153,27 +161,27 @@ function getRetryConfig(apiOptions) {
153
161
  ...apiOptions.retryConfig
154
162
  };
155
163
  }
156
- function executeErrorHandler(errorHandler, error, context, logger21) {
164
+ function executeErrorHandler(errorHandler, error, context, logger22) {
157
165
  if (!errorHandler) return;
158
166
  try {
159
167
  errorHandler(error, context);
160
168
  } catch (handlerError) {
161
- logger21.error("Custom error handler failed", {
169
+ logger22.error("Custom error handler failed", {
162
170
  originalError: error.message,
163
171
  handlerError: handlerError?.message || String(handlerError)
164
172
  });
165
173
  }
166
174
  }
167
- async function executeWithRetry(operation, operationName, operationContext, apiOptions, logger21, specialErrorHandling) {
175
+ async function executeWithRetry(operation, operationName, operationContext, apiOptions, logger22, specialErrorHandling) {
168
176
  const retryConfig = getRetryConfig(apiOptions);
169
177
  let lastError = null;
170
178
  const startTime = Date.now();
171
179
  for (let attempt = 0; attempt <= retryConfig.maxRetries; attempt++) {
172
180
  try {
173
- logger21.debug(`Executing ${operationName} (attempt ${attempt + 1})`, operationContext);
181
+ logger22.debug(`Executing ${operationName} (attempt ${attempt + 1})`, operationContext);
174
182
  const result = await operation();
175
183
  if (attempt > 0) {
176
- logger21.info(`${operationName} operation succeeded after ${attempt} retries`, {
184
+ logger22.info(`${operationName} operation succeeded after ${attempt} retries`, {
177
185
  ...operationContext,
178
186
  totalAttempts: attempt + 1,
179
187
  duration: Date.now() - startTime
@@ -193,7 +201,7 @@ async function executeWithRetry(operation, operationName, operationContext, apiO
193
201
  }
194
202
  const isRetryable = shouldRetryError(error);
195
203
  if (!isRetryable) {
196
- logger21.debug(`Not retrying ${operationName} operation due to non-retryable error`, {
204
+ logger22.debug(`Not retrying ${operationName} operation due to non-retryable error`, {
197
205
  ...operationContext,
198
206
  errorMessage: error.message,
199
207
  errorCode: error.code || error.status,
@@ -202,7 +210,7 @@ async function executeWithRetry(operation, operationName, operationContext, apiO
202
210
  break;
203
211
  }
204
212
  const delay = calculateRetryDelay(attempt, retryConfig);
205
- logger21.warning(`Retrying ${operationName} operation (attempt ${attempt + 2}) after ${delay}ms`, {
213
+ logger22.warning(`Retrying ${operationName} operation (attempt ${attempt + 2}) after ${delay}ms`, {
206
214
  ...operationContext,
207
215
  errorMessage: error.message,
208
216
  errorCode: error.code || error.status,
@@ -213,8 +221,8 @@ async function executeWithRetry(operation, operationName, operationContext, apiO
213
221
  }
214
222
  }
215
223
  const finalError = enhanceError(lastError, operationContext);
216
- executeErrorHandler(apiOptions.errorHandler, finalError, operationContext, logger21);
217
- logger21.error(`${operationName} operation failed after ${retryConfig.maxRetries + 1} attempts`, {
224
+ executeErrorHandler(apiOptions.errorHandler, finalError, operationContext, logger22);
225
+ logger22.error(`${operationName} operation failed after ${retryConfig.maxRetries + 1} attempts`, {
218
226
  ...operationContext,
219
227
  errorMessage: finalError.message,
220
228
  errorCode: finalError.code || finalError.status,
@@ -227,10 +235,15 @@ async function executeWithRetry(operation, operationName, operationContext, apiO
227
235
  // src/ops/create.ts
228
236
  var logger5 = logger_default.get("client-api", "ops", "create");
229
237
  var getCreateOperation = (api, apiOptions, utilities) => {
230
- const create = async (item, locations = []) => {
238
+ const create = async (item, options) => {
239
+ const locations = options?.locations || [];
231
240
  const requestOptions = Object.assign({}, apiOptions.postOptions, { isAuthenticated: apiOptions.writeAuthenticated });
232
- logger5.default("create", { item, locations, requestOptions });
241
+ logger5.default("create", { item, options, locations, requestOptions });
233
242
  utilities.verifyLocations(locations);
243
+ let itemToCreate = item;
244
+ if (options?.key) {
245
+ itemToCreate = { ...item, ...options.key };
246
+ }
234
247
  const loc = locations;
235
248
  const operationContext = {
236
249
  operation: "create",
@@ -252,10 +265,10 @@ var getCreateOperation = (api, apiOptions, utilities) => {
252
265
  logger5.debug(`Creating item (attempt ${attempt + 1})`, operationContext);
253
266
  const result = await utilities.processOne(api.httpPost(
254
267
  utilities.getPath(loc),
255
- item,
268
+ itemToCreate,
256
269
  requestOptions
257
270
  ));
258
- const created = utilities.validatePK(result);
271
+ utilities.validatePK(result);
259
272
  if (attempt > 0) {
260
273
  logger5.info(`Create operation succeeded after ${attempt} retries`, {
261
274
  ...operationContext,
@@ -263,7 +276,7 @@ var getCreateOperation = (api, apiOptions, utilities) => {
263
276
  duration: Date.now() - startTime
264
277
  });
265
278
  }
266
- return created;
279
+ return result;
267
280
  } catch (error) {
268
281
  lastError = error;
269
282
  if (attempt === retryConfig.maxRetries) {
@@ -319,23 +332,42 @@ var getUpdateOperation = (api, apiOptions, utilities) => {
319
332
  const update = async (ik, item) => {
320
333
  const requestOptions = Object.assign({}, apiOptions.putOptions, { isAuthenticated: apiOptions.writeAuthenticated });
321
334
  logger6.default("update", { ik, item, requestOptions });
322
- return utilities.validatePK(await utilities.processOne(
335
+ return await utilities.processOne(
323
336
  api.httpPut(
324
337
  utilities.getPath(ik),
325
338
  item,
326
339
  requestOptions
327
340
  )
328
- ));
341
+ );
329
342
  };
330
343
  return update;
331
344
  };
332
345
 
346
+ // src/ops/upsert.ts
347
+ var logger7 = logger_default.get("client-api", "ops", "upsert");
348
+ var getUpsertOperation = (api, apiOptions, utilities) => {
349
+ const upsert = async (key, item, locations) => {
350
+ const requestOptions = Object.assign({}, apiOptions.putOptions, { isAuthenticated: apiOptions.writeAuthenticated });
351
+ logger7.default("upsert", { key, item, locations, requestOptions });
352
+ const path = utilities.getPath(key);
353
+ const url = locations && locations.length > 0 ? `${path}?locations=${encodeURIComponent(JSON.stringify(locations))}` : path;
354
+ return await utilities.processOne(
355
+ api.httpPut(
356
+ url,
357
+ { ...item, upsert: true },
358
+ requestOptions
359
+ )
360
+ );
361
+ };
362
+ return upsert;
363
+ };
364
+
333
365
  // src/ops/get.ts
334
- var logger7 = logger_default.get("client-api", "ops", "get");
366
+ var logger8 = logger_default.get("client-api", "ops", "get");
335
367
  var getGetOperation = (api, apiOptions, utilities) => {
336
368
  const get = async (ik) => {
337
369
  const requestOptions = Object.assign({}, apiOptions.getOptions, { isAuthenticated: apiOptions.readAuthenticated });
338
- logger7.default("get", { ik, requestOptions });
370
+ logger8.default("get", { ik, requestOptions });
339
371
  const operationContext = {
340
372
  operation: "get",
341
373
  path: utilities.getPath(ik),
@@ -352,26 +384,26 @@ var getGetOperation = (api, apiOptions, utilities) => {
352
384
  const startTime = Date.now();
353
385
  for (let attempt = 0; attempt <= retryConfig.maxRetries; attempt++) {
354
386
  try {
355
- logger7.debug(`Getting item (attempt ${attempt + 1})`, operationContext);
387
+ logger8.debug(`Getting item (attempt ${attempt + 1})`, operationContext);
356
388
  const result = await utilities.processOne(
357
389
  api.httpGet(
358
390
  utilities.getPath(ik),
359
391
  requestOptions
360
392
  )
361
393
  );
362
- const item = utilities.validatePK(result);
394
+ utilities.validatePK(result);
363
395
  if (attempt > 0) {
364
- logger7.info(`Get operation succeeded after ${attempt} retries`, {
396
+ logger8.info(`Get operation succeeded after ${attempt} retries`, {
365
397
  ...operationContext,
366
398
  totalAttempts: attempt + 1,
367
399
  duration: Date.now() - startTime
368
400
  });
369
401
  }
370
- return item;
402
+ return result;
371
403
  } catch (error) {
372
404
  lastError = error;
373
405
  if (error.status === 404) {
374
- logger7.debug("Item not found (404)", operationContext);
406
+ logger8.debug("Item not found (404)", operationContext);
375
407
  return null;
376
408
  }
377
409
  if (attempt === retryConfig.maxRetries) {
@@ -379,7 +411,7 @@ var getGetOperation = (api, apiOptions, utilities) => {
379
411
  }
380
412
  const isRetryable = shouldRetryError(error);
381
413
  if (!isRetryable) {
382
- logger7.debug("Not retrying get operation due to non-retryable error", {
414
+ logger8.debug("Not retrying get operation due to non-retryable error", {
383
415
  ...operationContext,
384
416
  errorMessage: error.message,
385
417
  errorCode: error.code || error.status,
@@ -388,7 +420,7 @@ var getGetOperation = (api, apiOptions, utilities) => {
388
420
  break;
389
421
  }
390
422
  const delay = calculateRetryDelay(attempt, retryConfig);
391
- logger7.warning(`Retrying get operation (attempt ${attempt + 2}) after ${delay}ms`, {
423
+ logger8.warning(`Retrying get operation (attempt ${attempt + 2}) after ${delay}ms`, {
392
424
  ...operationContext,
393
425
  errorMessage: error.message,
394
426
  errorCode: error.code || error.status,
@@ -403,13 +435,13 @@ var getGetOperation = (api, apiOptions, utilities) => {
403
435
  try {
404
436
  apiOptions.errorHandler(finalError, operationContext);
405
437
  } catch (handlerError) {
406
- logger7.error("Custom error handler failed", {
438
+ logger8.error("Custom error handler failed", {
407
439
  originalError: finalError.message,
408
440
  handlerError: handlerError?.message || String(handlerError)
409
441
  });
410
442
  }
411
443
  }
412
- logger7.error(`Get operation failed after ${retryConfig.maxRetries + 1} attempts`, {
444
+ logger8.error(`Get operation failed after ${retryConfig.maxRetries + 1} attempts`, {
413
445
  ...operationContext,
414
446
  errorMessage: finalError.message,
415
447
  errorCode: finalError.code || finalError.status,
@@ -422,37 +454,41 @@ var getGetOperation = (api, apiOptions, utilities) => {
422
454
  };
423
455
 
424
456
  // src/ops/remove.ts
425
- var logger8 = logger_default.get("client-api", "ops", "remove");
457
+ var logger9 = logger_default.get("client-api", "ops", "remove");
426
458
  var getRemoveOperation = (api, apiOptions, utilities) => {
427
459
  const remove = async (ik) => {
428
460
  const requestOptions = Object.assign({}, apiOptions.deleteOptions, { isAuthenticated: apiOptions.writeAuthenticated });
429
- logger8.default("remove", { ik, requestOptions });
430
- return api.httpDelete(utilities.getPath(ik), requestOptions);
461
+ logger9.default("remove", { ik, requestOptions });
462
+ const result = await api.httpDelete(utilities.getPath(ik), requestOptions);
463
+ if (typeof result === "boolean") {
464
+ return;
465
+ }
466
+ return result;
431
467
  };
432
468
  return remove;
433
469
  };
434
470
 
435
471
  // src/ops/find.ts
436
- var logger9 = logger_default.get("client-api", "ops", "find");
472
+ var logger10 = logger_default.get("client-api", "ops", "find");
437
473
  var getFindOperation = (api, apiOptions, utilities) => {
438
474
  const find = async (finder, finderParams = {}, locations = []) => {
439
475
  utilities.verifyLocations(locations);
440
476
  const loc = locations;
441
477
  const mergedParams = finderToParams(finder, finderParams);
442
478
  const requestOptions = Object.assign({}, apiOptions.getOptions, { isAuthenticated: apiOptions.allAuthenticated, params: mergedParams });
443
- logger9.default("find", { finder, finderParams, locations, requestOptions });
444
- return utilities.validatePK(await utilities.processArray(
479
+ logger10.default("find", { finder, finderParams, locations, requestOptions });
480
+ return await utilities.processArray(
445
481
  api.httpGet(
446
482
  utilities.getPath(loc),
447
483
  requestOptions
448
484
  )
449
- ));
485
+ );
450
486
  };
451
487
  return find;
452
488
  };
453
489
 
454
490
  // src/ops/findOne.ts
455
- var logger10 = logger_default.get("client-api", "ops", "find");
491
+ var logger11 = logger_default.get("client-api", "ops", "find");
456
492
  var getFindOneOperation = (api, apiOptions, utilities) => {
457
493
  const findOne = async (finder, finderParams = {}, locations = []) => {
458
494
  utilities.verifyLocations(locations);
@@ -460,23 +496,28 @@ var getFindOneOperation = (api, apiOptions, utilities) => {
460
496
  const params = finderToParams(finder, finderParams);
461
497
  params.one = true;
462
498
  const requestOptions = Object.assign({}, apiOptions.getOptions, { isAuthenticated: apiOptions.allAuthenticated, params });
463
- logger10.default("findOne", { finder, finderParams, locations, requestOptions });
464
- return utilities.validatePK(await utilities.processArray(
499
+ logger11.default("findOne", { finder, finderParams, locations, requestOptions });
500
+ const results = await utilities.processArray(
465
501
  api.httpGet(
466
502
  utilities.getPath(loc),
467
503
  requestOptions
468
504
  )
469
- ))[0];
505
+ );
506
+ const result = results[0];
507
+ if (result) {
508
+ utilities.validatePK(result);
509
+ }
510
+ return result;
470
511
  };
471
512
  return findOne;
472
513
  };
473
514
 
474
515
  // src/ops/facet.ts
475
- var logger11 = logger_default.get("client-api", "ops", "facet");
516
+ var logger12 = logger_default.get("client-api", "ops", "facet");
476
517
  var getFacetOperation = (api, apiOptions, utilities) => {
477
518
  const facet = async (ik, facet2, params = {}) => {
478
519
  const requestOptions = Object.assign({}, apiOptions.getOptions, { isAuthenticated: apiOptions.writeAuthenticated, params });
479
- logger11.default("facet", { ik, facet: facet2, requestOptions });
520
+ logger12.default("facet", { ik, facet: facet2, requestOptions });
480
521
  return api.httpGet(
481
522
  `${utilities.getPath(ik)}/${facet2}`,
482
523
  requestOptions
@@ -486,11 +527,11 @@ var getFacetOperation = (api, apiOptions, utilities) => {
486
527
  };
487
528
 
488
529
  // src/ops/allFacet.ts
489
- var logger12 = logger_default.get("client-api", "ops", "allFacet");
530
+ var logger13 = logger_default.get("client-api", "ops", "allFacet");
490
531
  var getAllFacetOperation = (api, apiOptions, utilities) => {
491
532
  const allFacet = async (facet, params = {}, locations = []) => {
492
533
  const requestOptions = Object.assign({}, apiOptions.getOptions, { isAuthenticated: apiOptions.writeAuthenticated, params });
493
- logger12.default("allFacet", { facet, locations, requestOptions });
534
+ logger13.default("allFacet", { facet, locations, requestOptions });
494
535
  utilities.verifyLocations(locations);
495
536
  const loc = locations;
496
537
  return api.httpGet(
@@ -563,6 +604,11 @@ var getOperations = (api, apiOptions, utilities) => {
563
604
  api,
564
605
  apiOptions,
565
606
  utilities
607
+ ),
608
+ upsert: getUpsertOperation(
609
+ api,
610
+ apiOptions,
611
+ utilities
566
612
  )
567
613
  };
568
614
  };
@@ -574,9 +620,9 @@ import {
574
620
  isPriKey
575
621
  } from "@fjell/core";
576
622
  import deepmerge from "deepmerge";
577
- var logger13 = logger_default.get("client-api", "Utility");
623
+ var logger14 = logger_default.get("client-api", "Utility");
578
624
  var createUtilities = (pkType, pathNames) => {
579
- logger13.default("createUtilities", { pkType, pathNames });
625
+ logger14.default("createUtilities", { pkType, pathNames });
580
626
  const verifyLocations = (locations) => {
581
627
  if (locations && locations.length < pathNames.length - 1) {
582
628
  throw new Error("Not enough locations for pathNames: locations:" + locations.length + " pathNames:" + pathNames.length);
@@ -584,18 +630,18 @@ var createUtilities = (pkType, pathNames) => {
584
630
  return true;
585
631
  };
586
632
  const processOne = async (apiCall) => {
587
- logger13.default("processOne", { apiCall });
633
+ logger14.default("processOne", { apiCall });
588
634
  const response = await apiCall;
589
- logger13.default("processOne response", {
635
+ logger14.default("processOne response", {
590
636
  responseType: typeof response,
591
637
  hasData: !!response
592
638
  });
593
639
  return convertDoc(response);
594
640
  };
595
641
  const processArray = async (api) => {
596
- logger13.default("processArray", { api });
642
+ logger14.default("processArray", { api });
597
643
  const response = await api;
598
- logger13.default("processArray response", {
644
+ logger14.default("processArray response", {
599
645
  responseType: typeof response,
600
646
  isArray: Array.isArray(response),
601
647
  length: Array.isArray(response) ? response.length : 0
@@ -605,12 +651,12 @@ var createUtilities = (pkType, pathNames) => {
605
651
  (subjectChat) => convertDoc(subjectChat)
606
652
  );
607
653
  } else {
608
- logger13.error("Response was not an array", { response });
654
+ logger14.error("Response was not an array", { response });
609
655
  throw new Error("Response was not an array");
610
656
  }
611
657
  };
612
658
  const convertDoc = (doc) => {
613
- logger13.default("convertDoc", { doc });
659
+ logger14.default("convertDoc", { doc });
614
660
  if (doc && doc.events) {
615
661
  const events = doc.events;
616
662
  for (const key in events) {
@@ -621,65 +667,16 @@ var createUtilities = (pkType, pathNames) => {
621
667
  return doc;
622
668
  }
623
669
  };
624
- const validateLocationKeyOrder = (keys) => {
625
- const locKeys = keys.filter((k) => !isPriKey(k));
626
- if (locKeys.length <= 1) {
627
- return;
628
- }
629
- const pathNameOrder = /* @__PURE__ */ new Map();
630
- pathNames.forEach((pathName, index) => {
631
- const pathParts = pathName.split("/");
632
- const lastPart = pathParts[pathParts.length - 1];
633
- pathNameOrder.set(pathName, index);
634
- pathNameOrder.set(pathName.toLowerCase(), index);
635
- pathNameOrder.set(lastPart, index);
636
- pathNameOrder.set(lastPart.toLowerCase(), index);
637
- const singular = lastPart.endsWith("s") ? lastPart.slice(0, -1) : lastPart;
638
- const plural = lastPart + "s";
639
- const pluralEs = lastPart + "es";
640
- pathNameOrder.set(singular, index);
641
- pathNameOrder.set(plural, index);
642
- pathNameOrder.set(pluralEs, index);
643
- pathNameOrder.set(singular.toLowerCase(), index);
644
- pathNameOrder.set(plural.toLowerCase(), index);
645
- });
646
- let lastIndex = Infinity;
647
- const keyDetails = [];
648
- for (const locKey of locKeys) {
649
- const keyType = locKey.kt;
650
- const currentIndex = pathNameOrder.get(keyType);
651
- keyDetails.push({ kt: keyType, pathNameIndex: currentIndex });
652
- if (typeof currentIndex !== "undefined") {
653
- if (currentIndex >= lastIndex) {
654
- logger13.error("Location keys are not in the correct hierarchical order", {
655
- keys: locKeys.map((k) => ({ kt: k.kt, lk: k.lk })),
656
- pathNames,
657
- keyDetails,
658
- issue: `Key type "${keyType}" (index ${currentIndex}) should come after the previous key (index ${lastIndex})`
659
- });
660
- throw new Error(
661
- `Location keys must be ordered from child to parent according to the entity hierarchy. Expected order based on pathNames: [${pathNames.join(", ")}]. Received key types in order: [${locKeys.map((k) => k.kt).join(", ")}]. Key "${keyType}" is out of order - it should appear later in the hierarchy.`
662
- );
663
- }
664
- lastIndex = currentIndex;
665
- }
666
- }
667
- logger13.default("Location key order validation passed", {
668
- locKeys: locKeys.map((k) => ({ kt: k.kt, lk: k.lk })),
669
- keyDetails
670
- });
671
- };
672
670
  const getPath = (key) => {
673
671
  const localPathNames = [...pathNames];
674
- logger13.default("getPath", { key, pathNames: localPathNames });
672
+ logger14.default("getPath", { key, pathNames: localPathNames });
675
673
  const keys = generateKeyArray(key);
676
- validateLocationKeyOrder(keys);
677
674
  if (keys.length > 1) {
678
675
  const priKeys = keys.filter((k) => isPriKey(k));
679
676
  const locKeys = keys.filter((k) => !isPriKey(k));
680
677
  const reversedLocKeys = [...locKeys].reverse();
681
678
  const reorderedKeys = [...reversedLocKeys, ...priKeys];
682
- logger13.default("Reordered keys for contained item", {
679
+ logger14.default("Reordered keys for contained item", {
683
680
  original: keys,
684
681
  locKeys,
685
682
  reversedLocKeys,
@@ -690,7 +687,7 @@ var createUtilities = (pkType, pathNames) => {
690
687
  if (localPathNames.length === 1) {
691
688
  path = `${path}/${localPathNames[0]}`;
692
689
  }
693
- logger13.default("getPath created", { key, path });
690
+ logger14.default("getPath created", { key, path });
694
691
  return path;
695
692
  } else {
696
693
  const priKeys = keys.filter((k) => isPriKey(k));
@@ -701,27 +698,27 @@ var createUtilities = (pkType, pathNames) => {
701
698
  if (localPathNames.length === 1) {
702
699
  path = `${path}/${localPathNames[0]}`;
703
700
  }
704
- logger13.default("getPath created", { key, path });
701
+ logger14.default("getPath created", { key, path });
705
702
  return path;
706
703
  }
707
704
  };
708
705
  const addPath = (base, keys, localPathNames) => {
709
- logger13.default("addPath", { base, keys, pathNames: localPathNames });
706
+ logger14.default("addPath", { base, keys, pathNames: localPathNames });
710
707
  if (keys.length < localPathNames.length - 1) {
711
- logger13.error(
708
+ logger14.error(
712
709
  "addPath should never have keys with a length less than the length of pathNames - 1",
713
710
  { keys, localPathNames }
714
711
  );
715
712
  throw new Error("addPath should never have keys with a length less than the length of pathNames - 1: " + keys.length + " " + localPathNames.length + " " + JSON.stringify(keys, localPathNames));
716
713
  } else if (keys.length > localPathNames.length) {
717
- logger13.error(
714
+ logger14.error(
718
715
  "addPath should never have keys with a length greater than the length of pathNames",
719
716
  { keys, pathNames }
720
717
  );
721
718
  throw new Error("addPath should never have keys with a length greater than the length of pathNames: " + keys.length + " " + localPathNames.length + " " + JSON.stringify(keys, localPathNames));
722
719
  }
723
720
  if (keys.length === 0) {
724
- logger13.default("addPath returning base", { base });
721
+ logger14.default("addPath returning base", { base });
725
722
  return base;
726
723
  } else {
727
724
  const currentKey = keys[0];
@@ -740,7 +737,7 @@ var createUtilities = (pkType, pathNames) => {
740
737
  const key = keys.shift();
741
738
  const id = isPriKey(key) ? key.pk : key.lk;
742
739
  const nextBase = `${base}/${pathName}/${id}`;
743
- logger13.default("Adding Path (matched)", {
740
+ logger14.default("Adding Path (matched)", {
744
741
  pathName,
745
742
  keyType,
746
743
  isPriKey: isPriKey(key),
@@ -753,7 +750,7 @@ var createUtilities = (pkType, pathNames) => {
753
750
  const key = keys.shift();
754
751
  const id = isPriKey(key) ? key.pk : key.lk;
755
752
  const nextBase = `${base}/${pathName}/${id}`;
756
- logger13.default("Adding Path (no match, using first)", {
753
+ logger14.default("Adding Path (no match, using first)", {
757
754
  pathName,
758
755
  keyType,
759
756
  isPriKey: isPriKey(key),
@@ -778,7 +775,7 @@ var createUtilities = (pkType, pathNames) => {
778
775
  };
779
776
 
780
777
  // src/AItemAPI.ts
781
- var logger14 = logger_default.get("AItemAPI");
778
+ var logger15 = logger_default.get("AItemAPI");
782
779
  var finderToParams = (finder, finderParams) => {
783
780
  return {
784
781
  finder,
@@ -786,7 +783,7 @@ var finderToParams = (finder, finderParams) => {
786
783
  };
787
784
  };
788
785
  var createAItemAPI = (api, pkType, pathNames, options) => {
789
- logger14.default("createAItemAPI", { pkType, pathNames, options });
786
+ logger15.default("createAItemAPI", { pkType, pathNames, options });
790
787
  let mergedOptions;
791
788
  const defaultOptions = {
792
789
  readAuthenticated: true,
@@ -816,14 +813,15 @@ var createAItemAPI = (api, pkType, pathNames, options) => {
816
813
  get: operations.get,
817
814
  one: operations.one,
818
815
  remove: operations.remove,
819
- update: operations.update
816
+ update: operations.update,
817
+ upsert: operations.upsert
820
818
  };
821
819
  };
822
820
 
823
821
  // src/CItemAPI.ts
824
- var logger15 = logger_default.get("CItemAPI");
822
+ var logger16 = logger_default.get("CItemAPI");
825
823
  var createCItemApi = (api, type, pathNames, options) => {
826
- logger15.default("createCItemApi", { api, type, pathNames, options });
824
+ logger16.default("createCItemApi", { api, type, pathNames, options });
827
825
  const aItemAPI = createAItemAPI(api, type, pathNames, options);
828
826
  return {
829
827
  action: aItemAPI.action,
@@ -835,6 +833,7 @@ var createCItemApi = (api, type, pathNames, options) => {
835
833
  create: aItemAPI.create,
836
834
  remove: aItemAPI.remove,
837
835
  update: aItemAPI.update,
836
+ upsert: aItemAPI.upsert,
838
837
  facet: aItemAPI.facet,
839
838
  find: aItemAPI.find,
840
839
  findOne: aItemAPI.findOne
@@ -842,24 +841,24 @@ var createCItemApi = (api, type, pathNames, options) => {
842
841
  };
843
842
 
844
843
  // src/PItemAPI.ts
845
- var logger16 = logger_default.get("PItemAPI");
844
+ var logger17 = logger_default.get("PItemAPI");
846
845
  var createPItemApi = (api, type, pathName, options) => {
847
- logger16.default("createPItemApi", { type, pathName, options });
846
+ logger17.default("createPItemApi", { type, pathName, options });
848
847
  const aItemAPI = createAItemAPI(api, type, [pathName], options);
849
- const action = async (ik, action2, body = {}) => await aItemAPI.action(ik, action2, body);
850
- const all = async (query = {}) => await aItemAPI.all(query, []);
851
- const allAction = async (action2, body = {}) => await aItemAPI.allAction(action2, body, []);
852
- const allFacet = async (facet2, params = {}) => await aItemAPI.allFacet(facet2, params);
853
- const one = async (query = {}) => await aItemAPI.one(query, []);
848
+ const action = async (ik, action2, params) => await aItemAPI.action(ik, action2, params);
849
+ const all = async (query) => await aItemAPI.all(query || {}, []);
850
+ const allAction = async (action2, params) => await aItemAPI.allAction(action2, params, []);
851
+ const allFacet = async (facet2, params) => await aItemAPI.allFacet(facet2, params);
852
+ const one = async (query) => await aItemAPI.one(query || {}, []);
854
853
  const get = async (ik) => await aItemAPI.get(ik);
855
- const create = async (item) => await aItemAPI.create(item, []);
854
+ const create = async (item, options2) => await aItemAPI.create(item, options2);
856
855
  const remove = async (ik) => await aItemAPI.remove(ik);
857
856
  const update = async (ik, item) => await aItemAPI.update(ik, item);
858
- const facet = async (ik, facet2, params = {}) => await aItemAPI.facet(ik, facet2, params);
859
- const find = async (finder, finderParams = {}) => await aItemAPI.find(finder, finderParams);
860
- const findOne = async (finder, finderParams = {}) => await aItemAPI.findOne(finder, finderParams);
857
+ const upsert = async (ik, item, locations) => await aItemAPI.upsert(ik, item, locations);
858
+ const facet = async (ik, facet2, params) => await aItemAPI.facet(ik, facet2, params);
859
+ const find = async (finder, finderParams) => await aItemAPI.find(finder, finderParams);
860
+ const findOne = async (finder, finderParams) => await aItemAPI.findOne(finder, finderParams);
861
861
  return {
862
- ...aItemAPI,
863
862
  action,
864
863
  all,
865
864
  allAction,
@@ -869,6 +868,7 @@ var createPItemApi = (api, type, pathName, options) => {
869
868
  create,
870
869
  remove,
871
870
  update,
871
+ upsert,
872
872
  facet,
873
873
  find,
874
874
  findOne
@@ -877,18 +877,18 @@ var createPItemApi = (api, type, pathName, options) => {
877
877
 
878
878
  // src/Instance.ts
879
879
  import { createInstance as createBaseInstance } from "@fjell/registry";
880
- var logger17 = logger_default.get("Instance");
880
+ var logger18 = logger_default.get("Instance");
881
881
  var createInstance = (registry, coordinate, clientApi) => {
882
- logger17.debug("createInstance", { coordinate, clientApi, registry });
882
+ logger18.debug("createInstance", { coordinate, clientApi, registry });
883
883
  const baseInstance = createBaseInstance(registry, coordinate);
884
884
  return { ...baseInstance, clientApi };
885
885
  };
886
886
 
887
887
  // src/InstanceFactory.ts
888
- var logger18 = logger_default.get("InstanceFactory");
888
+ var logger19 = logger_default.get("InstanceFactory");
889
889
  var createInstanceFactory = (clientApi) => {
890
890
  return (coordinate, context) => {
891
- logger18.debug("Creating client-api instance", { coordinate, registry: context.registry, clientApi });
891
+ logger19.debug("Creating client-api instance", { coordinate, registry: context.registry, clientApi });
892
892
  return createInstance(context.registry, coordinate, clientApi);
893
893
  };
894
894
  };
@@ -897,13 +897,13 @@ var createInstanceFactory = (clientApi) => {
897
897
  import {
898
898
  createRegistry as createBaseRegistry
899
899
  } from "@fjell/registry";
900
- var logger19 = logger_default.get("Registry");
900
+ var logger20 = logger_default.get("Registry");
901
901
  var createRegistryFactory = () => {
902
902
  return (type, registryHub) => {
903
903
  if (type !== "client-api") {
904
904
  throw new Error(`Client API registry factory can only create 'client-api' type registries, got: ${type}`);
905
905
  }
906
- logger19.debug("Creating client-api registry", { type, registryHub });
906
+ logger20.debug("Creating client-api registry", { type, registryHub });
907
907
  const baseRegistry = createBaseRegistry(type, registryHub);
908
908
  return baseRegistry;
909
909
  };
@@ -1102,8 +1102,11 @@ function isClientApiError(error) {
1102
1102
  return error instanceof ClientApiError;
1103
1103
  }
1104
1104
 
1105
+ // src/index.ts
1106
+ import { FjellHttpError, isFjellHttpError as isFjellHttpError2, extractErrorInfo } from "@fjell/http-api";
1107
+
1105
1108
  // src/http/HttpWrapper.ts
1106
- var logger20 = {
1109
+ var logger21 = {
1107
1110
  debug: (message, context) => console.debug(message, context),
1108
1111
  info: (message, context) => console.info(message, context),
1109
1112
  warning: (message, context) => console.warn(message, context),
@@ -1121,7 +1124,7 @@ var DEFAULT_RETRY_CONFIG = {
1121
1124
  return false;
1122
1125
  },
1123
1126
  onRetry: (error, attemptNumber, delay) => {
1124
- logger20.warning(`Retrying HTTP request (attempt ${attemptNumber + 1}) after ${delay}ms`, {
1127
+ logger21.warning(`Retrying HTTP request (attempt ${attemptNumber + 1}) after ${delay}ms`, {
1125
1128
  errorCode: error.code,
1126
1129
  errorMessage: error.message,
1127
1130
  delay,
@@ -1154,14 +1157,14 @@ var HttpWrapper = class {
1154
1157
  const startTime = Date.now();
1155
1158
  for (let attempt = 0; attempt <= this.retryConfig.maxRetries; attempt++) {
1156
1159
  try {
1157
- logger20.debug(`Executing ${operationName}`, {
1160
+ logger21.debug(`Executing ${operationName}`, {
1158
1161
  attempt: attempt + 1,
1159
1162
  maxRetries: this.retryConfig.maxRetries + 1,
1160
1163
  ...context
1161
1164
  });
1162
1165
  const result = await operation();
1163
1166
  if (attempt > 0) {
1164
- logger20.info(`${operationName} succeeded after ${attempt} retries`, {
1167
+ logger21.info(`${operationName} succeeded after ${attempt} retries`, {
1165
1168
  totalAttempts: attempt + 1,
1166
1169
  duration: Date.now() - startTime,
1167
1170
  ...context
@@ -1174,7 +1177,7 @@ var HttpWrapper = class {
1174
1177
  break;
1175
1178
  }
1176
1179
  if (!this.retryConfig.shouldRetry(lastError, attempt)) {
1177
- logger20.debug(`Not retrying ${operationName} due to non-retryable error`, {
1180
+ logger21.debug(`Not retrying ${operationName} due to non-retryable error`, {
1178
1181
  errorCode: lastError.code,
1179
1182
  errorMessage: lastError.message,
1180
1183
  attempt: attempt + 1,
@@ -1190,7 +1193,7 @@ var HttpWrapper = class {
1190
1193
  await sleep(delay);
1191
1194
  }
1192
1195
  }
1193
- logger20.error(`${operationName} failed after ${this.retryConfig.maxRetries + 1} attempts`, {
1196
+ logger21.error(`${operationName} failed after ${this.retryConfig.maxRetries + 1} attempts`, {
1194
1197
  errorCode: lastError?.code,
1195
1198
  errorMessage: lastError?.message,
1196
1199
  duration: Date.now() - startTime,
@@ -1282,6 +1285,7 @@ export {
1282
1285
  ClientApiError,
1283
1286
  ConfigurationError,
1284
1287
  ConflictError,
1288
+ FjellHttpError,
1285
1289
  HttpError,
1286
1290
  HttpWrapper,
1287
1291
  NetworkError,
@@ -1304,8 +1308,10 @@ export {
1304
1308
  enhanceError,
1305
1309
  executeErrorHandler,
1306
1310
  executeWithRetry,
1311
+ extractErrorInfo,
1307
1312
  getRetryConfig,
1308
1313
  isClientApiError,
1314
+ isFjellHttpError2 as isFjellHttpError,
1309
1315
  isRetryableError,
1310
1316
  shouldRetryError
1311
1317
  };