@viu/emporix-sdk 2.13.1 → 2.15.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.
Files changed (136) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +1 -1
  3. package/dist/availability.cjs +4 -1
  4. package/dist/availability.cjs.map +1 -1
  5. package/dist/availability.d.cts +2 -1
  6. package/dist/availability.d.ts +2 -1
  7. package/dist/availability.js +2 -2
  8. package/dist/cart.cjs +1 -0
  9. package/dist/cart.cjs.map +1 -1
  10. package/dist/cart.d.cts +2 -1
  11. package/dist/cart.d.ts +2 -1
  12. package/dist/cart.js +2 -2
  13. package/dist/category.cjs +4 -1
  14. package/dist/category.cjs.map +1 -1
  15. package/dist/category.d.cts +2 -1
  16. package/dist/category.d.ts +2 -1
  17. package/dist/category.js +1 -1
  18. package/dist/checkout.cjs +1 -0
  19. package/dist/checkout.cjs.map +1 -1
  20. package/dist/checkout.d.cts +2 -1
  21. package/dist/checkout.d.ts +2 -1
  22. package/dist/checkout.js +2 -2
  23. package/dist/{chunk-BFQ732VZ.js → chunk-3BDDYX3V.js} +3 -3
  24. package/dist/{chunk-BFQ732VZ.js.map → chunk-3BDDYX3V.js.map} +1 -1
  25. package/dist/{chunk-LGOC5XOI.js → chunk-3BTPX7IJ.js} +3 -2
  26. package/dist/chunk-3BTPX7IJ.js.map +1 -0
  27. package/dist/{chunk-B4UOYJKW.js → chunk-5VTBLBXJ.js} +9 -4
  28. package/dist/chunk-5VTBLBXJ.js.map +1 -0
  29. package/dist/{chunk-WW3H7VJ5.js → chunk-62PCCHZ2.js} +4 -2
  30. package/dist/chunk-62PCCHZ2.js.map +1 -0
  31. package/dist/{chunk-BK25FDTH.js → chunk-A3LYJUD4.js} +10 -5
  32. package/dist/chunk-A3LYJUD4.js.map +1 -0
  33. package/dist/{chunk-MM6JF3Z7.js → chunk-BNX3JULF.js} +3 -2
  34. package/dist/chunk-BNX3JULF.js.map +1 -0
  35. package/dist/{chunk-LGLFJL3S.js → chunk-DUVIIWFG.js} +3 -2
  36. package/dist/chunk-DUVIIWFG.js.map +1 -0
  37. package/dist/{chunk-HAEVK6IS.js → chunk-EAWGUZHS.js} +3 -2
  38. package/dist/chunk-EAWGUZHS.js.map +1 -0
  39. package/dist/{chunk-AUVJ5V47.js → chunk-GIZS4BY3.js} +6 -3
  40. package/dist/chunk-GIZS4BY3.js.map +1 -0
  41. package/dist/{chunk-XMEP74BU.js → chunk-K3VQLW3P.js} +7 -4
  42. package/dist/chunk-K3VQLW3P.js.map +1 -0
  43. package/dist/{chunk-Z6PNI5VT.js → chunk-NE7MIZPR.js} +5 -3
  44. package/dist/chunk-NE7MIZPR.js.map +1 -0
  45. package/dist/{chunk-TLH6SLAF.js → chunk-NEXUWPHW.js} +28 -34
  46. package/dist/chunk-NEXUWPHW.js.map +1 -0
  47. package/dist/{chunk-WSXRUYBE.js → chunk-OTG2S2L4.js} +4 -3
  48. package/dist/chunk-OTG2S2L4.js.map +1 -0
  49. package/dist/{chunk-I3YYGSN2.js → chunk-PAT4CS36.js} +4 -3
  50. package/dist/chunk-PAT4CS36.js.map +1 -0
  51. package/dist/{chunk-OMYVOOSX.js → chunk-RYQVMR26.js} +4 -3
  52. package/dist/chunk-RYQVMR26.js.map +1 -0
  53. package/dist/{chunk-KTODT6DV.js → chunk-UWGGF4MC.js} +7 -3
  54. package/dist/chunk-UWGGF4MC.js.map +1 -0
  55. package/dist/{chunk-HKPZI7Y5.js → chunk-XEJPH6UN.js} +4 -3
  56. package/dist/chunk-XEJPH6UN.js.map +1 -0
  57. package/dist/companies.cjs +1 -0
  58. package/dist/companies.cjs.map +1 -1
  59. package/dist/companies.d.cts +2 -1
  60. package/dist/companies.d.ts +2 -1
  61. package/dist/companies.js +1 -1
  62. package/dist/contacts.cjs +1 -0
  63. package/dist/contacts.cjs.map +1 -1
  64. package/dist/contacts.d.cts +2 -1
  65. package/dist/contacts.d.ts +2 -1
  66. package/dist/contacts.js +1 -1
  67. package/dist/{context-CD7F_LHT.d.cts → context-DhoFgoKf.d.cts} +13 -0
  68. package/dist/{context-CD7F_LHT.d.ts → context-DhoFgoKf.d.ts} +13 -0
  69. package/dist/customer-groups.cjs +1 -0
  70. package/dist/customer-groups.cjs.map +1 -1
  71. package/dist/customer-groups.d.cts +2 -1
  72. package/dist/customer-groups.d.ts +2 -1
  73. package/dist/customer-groups.js +1 -1
  74. package/dist/customer.cjs +24 -31
  75. package/dist/customer.cjs.map +1 -1
  76. package/dist/customer.d.cts +2 -1
  77. package/dist/customer.d.ts +2 -1
  78. package/dist/customer.js +3 -3
  79. package/dist/index.cjs +310 -151
  80. package/dist/index.cjs.map +1 -1
  81. package/dist/index.d.cts +84 -6
  82. package/dist/index.d.ts +84 -6
  83. package/dist/index.js +278 -148
  84. package/dist/index.js.map +1 -1
  85. package/dist/locations.cjs +1 -0
  86. package/dist/locations.cjs.map +1 -1
  87. package/dist/locations.d.cts +2 -1
  88. package/dist/locations.d.ts +2 -1
  89. package/dist/locations.js +1 -1
  90. package/dist/media.cjs +1 -0
  91. package/dist/media.cjs.map +1 -1
  92. package/dist/media.d.cts +2 -1
  93. package/dist/media.d.ts +2 -1
  94. package/dist/media.js +2 -2
  95. package/dist/orders.cjs +2 -0
  96. package/dist/orders.cjs.map +1 -1
  97. package/dist/orders.d.cts +3 -1
  98. package/dist/orders.d.ts +3 -1
  99. package/dist/orders.js +1 -1
  100. package/dist/payment.cjs +1 -0
  101. package/dist/payment.cjs.map +1 -1
  102. package/dist/payment.d.cts +2 -1
  103. package/dist/payment.d.ts +2 -1
  104. package/dist/payment.js +3 -3
  105. package/dist/price.cjs +7 -2
  106. package/dist/price.cjs.map +1 -1
  107. package/dist/price.d.cts +2 -1
  108. package/dist/price.d.ts +2 -1
  109. package/dist/price.js +2 -2
  110. package/dist/product.cjs +7 -2
  111. package/dist/product.cjs.map +1 -1
  112. package/dist/product.d.cts +2 -1
  113. package/dist/product.d.ts +2 -1
  114. package/dist/product.js +1 -1
  115. package/dist/segment.cjs +2 -0
  116. package/dist/segment.cjs.map +1 -1
  117. package/dist/segment.d.cts +3 -1
  118. package/dist/segment.d.ts +3 -1
  119. package/dist/segment.js +3 -3
  120. package/package.json +2 -1
  121. package/dist/chunk-AUVJ5V47.js.map +0 -1
  122. package/dist/chunk-B4UOYJKW.js.map +0 -1
  123. package/dist/chunk-BK25FDTH.js.map +0 -1
  124. package/dist/chunk-HAEVK6IS.js.map +0 -1
  125. package/dist/chunk-HKPZI7Y5.js.map +0 -1
  126. package/dist/chunk-I3YYGSN2.js.map +0 -1
  127. package/dist/chunk-KTODT6DV.js.map +0 -1
  128. package/dist/chunk-LGLFJL3S.js.map +0 -1
  129. package/dist/chunk-LGOC5XOI.js.map +0 -1
  130. package/dist/chunk-MM6JF3Z7.js.map +0 -1
  131. package/dist/chunk-OMYVOOSX.js.map +0 -1
  132. package/dist/chunk-TLH6SLAF.js.map +0 -1
  133. package/dist/chunk-WSXRUYBE.js.map +0 -1
  134. package/dist/chunk-WW3H7VJ5.js.map +0 -1
  135. package/dist/chunk-XMEP74BU.js.map +0 -1
  136. package/dist/chunk-Z6PNI5VT.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -48,6 +48,10 @@ var EmporixValidationError = class extends EmporixError {
48
48
  };
49
49
  var EmporixServerError = class extends EmporixError {
50
50
  };
51
+ var EmporixTimeoutError = class extends EmporixError {
52
+ };
53
+ var EmporixNetworkError = class extends EmporixError {
54
+ };
51
55
  var EmporixInsufficientScopeError = class extends EmporixForbiddenError {
52
56
  requiredScope;
53
57
  constructor(message, status, body, requiredScope) {
@@ -457,6 +461,26 @@ var DefaultTokenProvider = class {
457
461
  this.serviceLocks.set(set, p);
458
462
  return p;
459
463
  }
464
+ /**
465
+ * fetch with the configured read timeout. Token endpoints sit in front of
466
+ * single-flight locks — one hung call would otherwise block every request
467
+ * on this credential set forever.
468
+ */
469
+ async boundedFetch(url, init = {}) {
470
+ const ms = this.cfg.timeouts?.readMs ?? 6e4;
471
+ const controller = new AbortController();
472
+ const timer = setTimeout(() => controller.abort(), ms);
473
+ try {
474
+ return await fetch(url, { ...init, signal: controller.signal });
475
+ } catch (err) {
476
+ if (err.name === "AbortError") {
477
+ throw new EmporixTimeoutError(`token request timed out after ${ms}ms`);
478
+ }
479
+ throw new EmporixNetworkError(`token request network failure: ${err.message}`);
480
+ } finally {
481
+ clearTimeout(timer);
482
+ }
483
+ }
460
484
  async requestServiceToken(set) {
461
485
  const c = this.creds(set);
462
486
  const body = new URLSearchParams({
@@ -465,7 +489,7 @@ var DefaultTokenProvider = class {
465
489
  client_secret: c.secret
466
490
  });
467
491
  if (c.scope) body.set("scope", c.scope);
468
- const res = await fetch(`${this.cfg.host}/oauth/token`, {
492
+ const res = await this.boundedFetch(`${this.cfg.host}/oauth/token`, {
469
493
  method: "POST",
470
494
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
471
495
  body
@@ -538,7 +562,7 @@ var DefaultTokenProvider = class {
538
562
  url.searchParams.set("refresh_token", this.anon.refreshToken);
539
563
  }
540
564
  try {
541
- const res = await fetch(url, { method: "GET" });
565
+ const res = await this.boundedFetch(url, { method: "GET" });
542
566
  const json = await res.json().catch(() => ({}));
543
567
  if (!res.ok) {
544
568
  this.notifyRefresh("anonymous", false);
@@ -614,10 +638,18 @@ var HttpClient = class {
614
638
  attempt
615
639
  });
616
640
  const controller = new AbortController();
617
- const timer = setTimeout(
618
- () => controller.abort(),
619
- o.timeoutMs ?? this.opts.timeouts.readMs
620
- );
641
+ const overallMs = o.timeoutMs ?? this.opts.timeouts.readMs;
642
+ const connectMs = Math.min(this.opts.timeouts.connectMs, overallMs);
643
+ const timeoutMsg = `${o.method} ${o.path} timed out after ${overallMs}ms (connect budget ${connectMs}ms)`;
644
+ let connectTimer;
645
+ let overallTimer;
646
+ const overallBudget = new Promise((_, reject) => {
647
+ overallTimer = setTimeout(() => {
648
+ controller.abort();
649
+ reject(new EmporixTimeoutError(timeoutMsg));
650
+ }, overallMs);
651
+ });
652
+ connectTimer = setTimeout(() => controller.abort(), connectMs);
621
653
  const isFormData = typeof FormData !== "undefined" && o.body instanceof FormData;
622
654
  const init = {
623
655
  method: o.method,
@@ -628,12 +660,27 @@ var HttpClient = class {
628
660
  init.body = isFormData ? o.body : JSON.stringify(o.body);
629
661
  }
630
662
  let res;
663
+ let text;
631
664
  try {
632
- res = await fetch(url, init);
665
+ res = await Promise.race([fetch(url, init), overallBudget]);
666
+ clearTimeout(connectTimer);
667
+ connectTimer = void 0;
668
+ const body = res.text();
669
+ body.catch(() => {
670
+ });
671
+ text = await Promise.race([body, overallBudget]);
672
+ } catch (err) {
673
+ if (err instanceof EmporixTimeoutError) throw err;
674
+ if (err.name === "AbortError") {
675
+ throw new EmporixTimeoutError(timeoutMsg);
676
+ }
677
+ throw new EmporixNetworkError(
678
+ `${o.method} ${o.path} network failure: ${err.message}`
679
+ );
633
680
  } finally {
634
- clearTimeout(timer);
681
+ if (connectTimer !== void 0) clearTimeout(connectTimer);
682
+ if (overallTimer !== void 0) clearTimeout(overallTimer);
635
683
  }
636
- const text = await res.text();
637
684
  const parsed = text ? safeJson(text) : void 0;
638
685
  if (res.ok) {
639
686
  log.debug("http ok", { status: res.status });
@@ -663,10 +710,12 @@ var HttpClient = class {
663
710
  }
664
711
  throw errorFromResponse(res.status, `${o.method} ${o.path} \u2192 401`, parsed);
665
712
  }
666
- const retryable = res.status >= 500 || res.status === 429;
713
+ const idempotent = o.method === "GET" || o.method === "PUT" || o.method === "DELETE" || o.idempotent === true;
714
+ const retryable = idempotent && (res.status >= 500 || res.status === 429);
667
715
  if (retryable && attempt < maxAttempts) {
668
- const retryAfter = Number(res.headers.get("Retry-After"));
669
- const backoff = Number.isFinite(retryAfter) && retryAfter >= 0 ? retryAfter * 1e3 : Math.min(1e3 * 2 ** (attempt - 1), 8e3) + Math.random() * 100;
716
+ const retryAfterHeader = res.headers.get("Retry-After");
717
+ const retryAfter = retryAfterHeader ? Number(retryAfterHeader) : Number.NaN;
718
+ const backoff = Number.isFinite(retryAfter) && retryAfter >= 0 ? Math.min(retryAfter * 1e3, 8e3) : Math.min(1e3 * 2 ** (attempt - 1), 8e3) + Math.random() * 100;
670
719
  log.warn("retryable failure", { status: res.status, attempt, backoffMs: backoff });
671
720
  await this.sleep(backoff);
672
721
  continue;
@@ -718,12 +767,90 @@ var HttpClient = class {
718
767
  }
719
768
  try {
720
769
  return await fetch(url, init);
770
+ } catch (err) {
771
+ if (err.name === "AbortError") {
772
+ throw new EmporixTimeoutError(
773
+ `${o.method} ${o.path} timed out after ${o.timeoutMs ?? this.opts.timeouts.readMs}ms`
774
+ );
775
+ }
776
+ throw new EmporixNetworkError(
777
+ `${o.method} ${o.path} network failure: ${err.message}`
778
+ );
721
779
  } finally {
722
780
  clearTimeout(timer);
723
781
  }
724
782
  }
725
783
  };
726
784
 
785
+ // package.json
786
+ var version = "2.15.0";
787
+
788
+ // src/version.ts
789
+ var SDK_VERSION = version;
790
+
791
+ // src/core/create-core.ts
792
+ function createCore(config) {
793
+ const cfg = validateConfig(config);
794
+ let loggerObj = {};
795
+ let baseLogger;
796
+ if (cfg.logger === false) {
797
+ baseLogger = createNoopLogger();
798
+ } else if (cfg.logger && typeof cfg.logger.child === "function") {
799
+ baseLogger = cfg.logger;
800
+ } else if (cfg.logger) {
801
+ loggerObj = cfg.logger;
802
+ }
803
+ const resolver = new LevelResolver(loggerObj);
804
+ const root = baseLogger ?? createConsoleLogger(resolver, {
805
+ sdk: "emporix",
806
+ sdkVersion: SDK_VERSION,
807
+ tenant: cfg.tenant
808
+ });
809
+ const tokenProvider = cfg.tokenProvider ?? new DefaultTokenProvider(cfg);
810
+ const customerRefresh = new CustomerRefreshRegistry();
811
+ const requestContext = {
812
+ language: cfg.credentials.storefront?.context?.language
813
+ };
814
+ const mk = (service) => ({
815
+ tenant: cfg.tenant,
816
+ tokenProvider,
817
+ logger: root.child({ service }),
818
+ http: new HttpClient({
819
+ host: cfg.host,
820
+ provider: tokenProvider,
821
+ logger: root.child({ service: "http" }),
822
+ retry: cfg.retry,
823
+ timeouts: cfg.timeouts,
824
+ customerRefresh,
825
+ requestContext
826
+ })
827
+ });
828
+ return {
829
+ tenant: cfg.tenant,
830
+ config: cfg,
831
+ tokenProvider,
832
+ mk,
833
+ setStorefrontContext(ctx) {
834
+ if (ctx.language !== void 0) {
835
+ requestContext.language = ctx.language || void 0;
836
+ }
837
+ const { language: _language, ...priceContext } = ctx;
838
+ if (Object.keys(priceContext).length > 0) {
839
+ tokenProvider.setAnonymousContext?.(priceContext);
840
+ }
841
+ },
842
+ setLogLevel(level, opts = {}) {
843
+ resolver.set(level, opts.service, opts.force ?? false);
844
+ },
845
+ getLogLevel(service) {
846
+ return resolver.get(service);
847
+ },
848
+ setCustomerTokenRefresher(refresher) {
849
+ customerRefresh.set(refresher);
850
+ }
851
+ };
852
+ }
853
+
727
854
  // src/core/require-customer.ts
728
855
  function requireCustomer(auth2) {
729
856
  if (auth2 && (auth2.kind === "customer" || auth2.kind === "raw")) return auth2;
@@ -731,11 +858,27 @@ function requireCustomer(auth2) {
731
858
  }
732
859
 
733
860
  // src/services/customer.ts
861
+ function toSession(endpoint, wire, opts = {}) {
862
+ const customerToken = wire.access_token ?? wire.accessToken;
863
+ if (!customerToken) {
864
+ throw new EmporixAuthError(`${endpoint}: response missing access_token`, void 0, wire);
865
+ }
866
+ return {
867
+ customerToken,
868
+ saasToken: wire.saas_token ?? wire.saasToken ?? opts.carrySaasToken ?? "",
869
+ refreshToken: wire.refresh_token ?? wire.refreshToken ?? "",
870
+ sessionId: wire.session_id,
871
+ expiresIn: wire.expires_in != null ? Number(wire.expires_in) : void 0,
872
+ ...wire.social_access_token ? { socialAccessToken: wire.social_access_token } : {},
873
+ ...wire.social_id_token ? { socialIdToken: wire.social_id_token } : {}
874
+ };
875
+ }
734
876
  var CustomerService = class {
735
877
  constructor(ctx) {
736
878
  this.ctx = ctx;
737
879
  }
738
880
  ctx;
881
+ static channel = "customer";
739
882
  /** Obtains an anonymous storefront session (accessToken + sessionId + refreshToken). */
740
883
  async anonymous() {
741
884
  return this.ctx.tokenProvider.getAnonymousToken();
@@ -762,13 +905,7 @@ var CustomerService = class {
762
905
  auth: effective,
763
906
  body: creds
764
907
  });
765
- return {
766
- customerToken: wire.access_token ?? wire.accessToken ?? "",
767
- saasToken: wire.saas_token ?? wire.saasToken ?? "",
768
- refreshToken: wire.refresh_token ?? wire.refreshToken ?? "",
769
- sessionId: wire.session_id,
770
- expiresIn: wire.expires_in
771
- };
908
+ return toSession("login", wire);
772
909
  }
773
910
  /**
774
911
  * Refreshes an authenticated customer session via its refresh token,
@@ -788,14 +925,11 @@ var CustomerService = class {
788
925
  query,
789
926
  auth: auth2
790
927
  });
791
- return {
792
- customerToken: wire.access_token ?? wire.accessToken ?? "",
793
- // Refresh does not return a saas_token — carry the original forward.
794
- saasToken: input.saasToken ?? "",
795
- refreshToken: wire.refresh_token ?? wire.refreshToken ?? "",
796
- sessionId: wire.session_id,
797
- expiresIn: wire.expires_in
798
- };
928
+ return toSession(
929
+ "refresh",
930
+ wire,
931
+ input.saasToken !== void 0 ? { carrySaasToken: input.saasToken } : {}
932
+ );
799
933
  }
800
934
  /**
801
935
  * Logs the customer out server-side: `GET /customer/{tenant}/logout?
@@ -834,15 +968,7 @@ var CustomerService = class {
834
968
  auth: auth2,
835
969
  ...input.sessionId ? { headers: { "session-id": input.sessionId } } : {}
836
970
  });
837
- return {
838
- customerToken: wire.access_token ?? wire.accessToken ?? "",
839
- saasToken: wire.saas_token ?? wire.saasToken ?? "",
840
- refreshToken: wire.refresh_token ?? wire.refreshToken ?? "",
841
- sessionId: wire.session_id,
842
- expiresIn: wire.expires_in != null ? Number(wire.expires_in) : void 0,
843
- ...wire.social_access_token ? { socialAccessToken: wire.social_access_token } : {},
844
- ...wire.social_id_token ? { socialIdToken: wire.social_id_token } : {}
845
- };
971
+ return toSession("socialLogin", wire);
846
972
  }
847
973
  /**
848
974
  * RFC 8693 token exchange: exchanges an external IdP JWT for an Emporix
@@ -861,13 +987,7 @@ var CustomerService = class {
861
987
  query,
862
988
  auth: auth2
863
989
  });
864
- return {
865
- customerToken: wire.access_token ?? wire.accessToken ?? "",
866
- saasToken: wire.saas_token ?? wire.saasToken ?? "",
867
- refreshToken: wire.refresh_token ?? wire.refreshToken ?? "",
868
- sessionId: wire.session_id,
869
- expiresIn: wire.expires_in != null ? Number(wire.expires_in) : void 0
870
- };
990
+ return toSession("exchangeToken", wire);
871
991
  }
872
992
  /** Returns the authenticated customer. Requires customer/raw auth. */
873
993
  async me(auth2) {
@@ -958,6 +1078,7 @@ var ProductService = class {
958
1078
  this.ctx = ctx;
959
1079
  }
960
1080
  ctx;
1081
+ static channel = "product";
961
1082
  /** Fetches one product by id. */
962
1083
  async get(productId, _opts, auth2 = ANON) {
963
1084
  return this.ctx.http.request({
@@ -1037,7 +1158,9 @@ var ProductService = class {
1037
1158
  path: `/product/${this.ctx.tenant}/products/search`,
1038
1159
  query: { pageSize: chunk.length },
1039
1160
  auth: auth2,
1040
- body: { q: `id:(${chunk.join(",")})` }
1161
+ body: { q: `id:(${chunk.join(",")})` },
1162
+ idempotent: true
1163
+ // pure read over POST — safe to replay on 5xx/429
1041
1164
  })
1042
1165
  )
1043
1166
  );
@@ -1077,7 +1200,9 @@ var ProductService = class {
1077
1200
  path: `/product/${this.ctx.tenant}/products/search`,
1078
1201
  query: { pageSize: chunk.length },
1079
1202
  auth: auth2,
1080
- body: { q: `code:(${chunk.join(",")})` }
1203
+ body: { q: `code:(${chunk.join(",")})` },
1204
+ idempotent: true
1205
+ // pure read over POST — safe to replay on 5xx/429
1081
1206
  })
1082
1207
  )
1083
1208
  );
@@ -1115,6 +1240,7 @@ var CategoryService = class {
1115
1240
  this.ctx = ctx;
1116
1241
  }
1117
1242
  ctx;
1243
+ static channel = "category";
1118
1244
  /** Fetches one category by id. */
1119
1245
  async get(categoryId, auth2 = ANON2) {
1120
1246
  return this.ctx.http.request({
@@ -1198,7 +1324,9 @@ var CategoryService = class {
1198
1324
  path: `/product/${this.ctx.tenant}/products/search`,
1199
1325
  query: { pageSize: productIds.length },
1200
1326
  auth: auth2,
1201
- body: { q: `id:(${productIds.join(",")})` }
1327
+ body: { q: `id:(${productIds.join(",")})` },
1328
+ idempotent: true
1329
+ // pure read over POST — safe to replay on 5xx/429
1202
1330
  });
1203
1331
  return { items, pageNumber, pageSize, hasNextPage };
1204
1332
  }
@@ -1246,6 +1374,7 @@ var CartService = class {
1246
1374
  this.ctx = ctx;
1247
1375
  }
1248
1376
  ctx;
1377
+ static channel = "cart";
1249
1378
  base() {
1250
1379
  return `/cart/${this.ctx.tenant}/carts`;
1251
1380
  }
@@ -1418,6 +1547,7 @@ var CheckoutService = class {
1418
1547
  this.ctx = ctx;
1419
1548
  }
1420
1549
  ctx;
1550
+ static channel = "checkout";
1421
1551
  headers(opts, guest) {
1422
1552
  if (guest || !opts.saasToken) return void 0;
1423
1553
  return { "saas-token": opts.saasToken };
@@ -1460,6 +1590,7 @@ var PaymentGatewayService = class {
1460
1590
  this.ctx = ctx;
1461
1591
  }
1462
1592
  ctx;
1593
+ static channel = "payment";
1463
1594
  /** Lists configured frontend payment modes. */
1464
1595
  async listPaymentModes(auth2) {
1465
1596
  return this.ctx.http.request({
@@ -1504,6 +1635,7 @@ var PriceService = class {
1504
1635
  this.ctx = ctx;
1505
1636
  }
1506
1637
  ctx;
1638
+ static channel = "price";
1507
1639
  /**
1508
1640
  * Resolves prices using the session context bound to the bearer token
1509
1641
  * (currency/site/country were set at anonymous-login time). Default auth:
@@ -1514,7 +1646,9 @@ var PriceService = class {
1514
1646
  method: "POST",
1515
1647
  path: `/price/${this.ctx.tenant}/match-prices-by-context`,
1516
1648
  auth: requireContextAuth(auth2),
1517
- body: input
1649
+ body: input,
1650
+ idempotent: true
1651
+ // pure read over POST — safe to replay on 5xx/429
1518
1652
  });
1519
1653
  return rows.map(normalizeMatch);
1520
1654
  }
@@ -1527,7 +1661,9 @@ var PriceService = class {
1527
1661
  method: "POST",
1528
1662
  path: `/price/${this.ctx.tenant}/match-prices`,
1529
1663
  auth: auth2,
1530
- body: input
1664
+ body: input,
1665
+ idempotent: true
1666
+ // pure read over POST — safe to replay on 5xx/429
1531
1667
  });
1532
1668
  return rows.map(normalizeMatch);
1533
1669
  }
@@ -1587,6 +1723,7 @@ var MediaService = class {
1587
1723
  this.ctx = ctx;
1588
1724
  }
1589
1725
  ctx;
1726
+ static channel = "media";
1590
1727
  base() {
1591
1728
  return `/media/${this.ctx.tenant}/assets`;
1592
1729
  }
@@ -1832,6 +1969,8 @@ var SegmentService = class {
1832
1969
  }
1833
1970
  ctx;
1834
1971
  deps;
1972
+ static channel = "segment";
1973
+ static deps = ["products", "categories"];
1835
1974
  base() {
1836
1975
  return `/customer-segment/${this.ctx.tenant}/segments`;
1837
1976
  }
@@ -1963,6 +2102,7 @@ var SiteService = class {
1963
2102
  this.ctx = ctx;
1964
2103
  }
1965
2104
  ctx;
2105
+ static channel = "site";
1966
2106
  /** Lists active sites. */
1967
2107
  async list(authCtx = ANON4) {
1968
2108
  return this.ctx.http.request({
@@ -2002,6 +2142,7 @@ var SessionContextService = class {
2002
2142
  this.ctx = ctx;
2003
2143
  }
2004
2144
  ctx;
2145
+ static channel = "session-context";
2005
2146
  /**
2006
2147
  * Retrieves the current session context, or `null` when the server returns
2007
2148
  * 404 (no session exists yet — the session-context is created server-side
@@ -2064,6 +2205,7 @@ var CompaniesService = class {
2064
2205
  this.ctx = ctx;
2065
2206
  }
2066
2207
  ctx;
2208
+ static channel = "customer-management";
2067
2209
  base() {
2068
2210
  return `/customer-management/${this.ctx.tenant}/legal-entities`;
2069
2211
  }
@@ -2120,6 +2262,7 @@ var ContactsService = class {
2120
2262
  this.ctx = ctx;
2121
2263
  }
2122
2264
  ctx;
2265
+ static channel = "customer-management";
2123
2266
  base() {
2124
2267
  return `/customer-management/${this.ctx.tenant}/contact-assignments`;
2125
2268
  }
@@ -2169,6 +2312,7 @@ var LocationsService = class {
2169
2312
  this.ctx = ctx;
2170
2313
  }
2171
2314
  ctx;
2315
+ static channel = "customer-management";
2172
2316
  base() {
2173
2317
  return `/customer-management/${this.ctx.tenant}/locations`;
2174
2318
  }
@@ -2226,6 +2370,7 @@ var CustomerGroupsService = class {
2226
2370
  this.ctx = ctx;
2227
2371
  }
2228
2372
  ctx;
2373
+ static channel = "iam";
2229
2374
  base() {
2230
2375
  return `/iam/${this.ctx.tenant}/groups`;
2231
2376
  }
@@ -2268,6 +2413,7 @@ var OrdersService = class {
2268
2413
  this.ctx = ctx;
2269
2414
  }
2270
2415
  ctx;
2416
+ static channel = "orders";
2271
2417
  base() {
2272
2418
  return `/order-v2/${this.ctx.tenant}/orders`;
2273
2419
  }
@@ -2328,6 +2474,7 @@ var SalesOrdersService = class {
2328
2474
  this.ctx = ctx;
2329
2475
  }
2330
2476
  ctx;
2477
+ static channel = "sales-orders";
2331
2478
  base() {
2332
2479
  return `/order-v2/${this.ctx.tenant}/salesorders`;
2333
2480
  }
@@ -2360,6 +2507,7 @@ var AvailabilityService = class {
2360
2507
  this.ctx = ctx;
2361
2508
  }
2362
2509
  ctx;
2510
+ static channel = "availability";
2363
2511
  /**
2364
2512
  * Single product. Resolves the availability record, or — when
2365
2513
  * `opts.defaultAvailableOnNotFound` is set — a default available record on 404.
@@ -2394,7 +2542,9 @@ var AvailabilityService = class {
2394
2542
  path: `/availability/${this.ctx.tenant}/availability/search`,
2395
2543
  auth: auth2,
2396
2544
  query: { site: siteCode, pageSize: productIds.length },
2397
- body: productIds
2545
+ body: productIds,
2546
+ idempotent: true
2547
+ // pure read over POST — safe to replay on 5xx/429
2398
2548
  });
2399
2549
  const byId = /* @__PURE__ */ new Map();
2400
2550
  for (const a of found) if (a.productId) byId.set(a.productId, a);
@@ -2415,6 +2565,7 @@ var TenantConfigService = class {
2415
2565
  this.ctx = ctx;
2416
2566
  }
2417
2567
  ctx;
2568
+ static channel = "configuration";
2418
2569
  base() {
2419
2570
  return `/configuration/${this.ctx.tenant}/configurations`;
2420
2571
  }
@@ -2471,6 +2622,7 @@ var ClientConfigService = class {
2471
2622
  this.ctx = ctx;
2472
2623
  }
2473
2624
  ctx;
2625
+ static channel = "configuration";
2474
2626
  base(client) {
2475
2627
  return `/configuration/${this.ctx.tenant}/clients/${encodeURIComponent(client)}/configurations`;
2476
2628
  }
@@ -2528,6 +2680,7 @@ var ShoppingListService = class {
2528
2680
  this.ctx = ctx;
2529
2681
  }
2530
2682
  ctx;
2683
+ static channel = "shopping-list";
2531
2684
  base() {
2532
2685
  return `/shoppinglist/${this.ctx.tenant}/shopping-lists`;
2533
2686
  }
@@ -2624,6 +2777,7 @@ var RagIndexerService = class {
2624
2777
  this.ctx = ctx;
2625
2778
  }
2626
2779
  ctx;
2780
+ static channel = "ai-rag-indexer";
2627
2781
  base(type) {
2628
2782
  return `/ai-rag-indexer/${this.ctx.tenant}/${encodeURIComponent(type)}`;
2629
2783
  }
@@ -2664,6 +2818,7 @@ var SequentialIdService = class {
2664
2818
  this.ctx = ctx;
2665
2819
  }
2666
2820
  ctx;
2821
+ static channel = "sequential-id";
2667
2822
  base() {
2668
2823
  return `/sequential-id/${this.ctx.tenant}/schemas`;
2669
2824
  }
@@ -2753,6 +2908,7 @@ var FeeService = class {
2753
2908
  this.ctx = ctx;
2754
2909
  }
2755
2910
  ctx;
2911
+ static channel = "fee";
2756
2912
  feesBase() {
2757
2913
  return `/fee/${this.ctx.tenant}/fees`;
2758
2914
  }
@@ -2912,6 +3068,7 @@ var CloudFunctionsService = class {
2912
3068
  this.ctx = ctx;
2913
3069
  }
2914
3070
  ctx;
3071
+ static channel = "cloud-functions";
2915
3072
  base() {
2916
3073
  return `/cloud-functions/${this.ctx.tenant}/functions`;
2917
3074
  }
@@ -2935,6 +3092,7 @@ var WebhookService = class {
2935
3092
  this.ctx = ctx;
2936
3093
  }
2937
3094
  ctx;
3095
+ static channel = "webhook";
2938
3096
  base() {
2939
3097
  return `/webhook/${this.ctx.tenant}`;
2940
3098
  }
@@ -3047,6 +3205,7 @@ var SchemaService = class {
3047
3205
  this.ctx = ctx;
3048
3206
  }
3049
3207
  ctx;
3208
+ static channel = "schema";
3050
3209
  schemasBase() {
3051
3210
  return `/schema/${this.ctx.tenant}/schemas`;
3052
3211
  }
@@ -3274,6 +3433,7 @@ var AiService = class {
3274
3433
  this.ctx = ctx;
3275
3434
  }
3276
3435
  ctx;
3436
+ static channel = "ai";
3277
3437
  base() {
3278
3438
  return `/ai-service/${this.ctx.tenant}`;
3279
3439
  }
@@ -3387,6 +3547,7 @@ var TaxService = class {
3387
3547
  this.ctx = ctx;
3388
3548
  }
3389
3549
  ctx;
3550
+ static channel = "tax";
3390
3551
  base() {
3391
3552
  return `/tax/${this.ctx.tenant}`;
3392
3553
  }
@@ -3456,6 +3617,7 @@ var CouponService = class {
3456
3617
  this.ctx = ctx;
3457
3618
  }
3458
3619
  ctx;
3620
+ static channel = "coupon";
3459
3621
  base() {
3460
3622
  return `/coupon/${this.ctx.tenant}`;
3461
3623
  }
@@ -3582,6 +3744,7 @@ var RewardPointsService = class {
3582
3744
  this.ctx = ctx;
3583
3745
  }
3584
3746
  ctx;
3747
+ static channel = "reward-points";
3585
3748
  /** Base without tenant (customer / public / batch endpoints). */
3586
3749
  base() {
3587
3750
  return `/reward-points`;
@@ -3736,6 +3899,7 @@ var BrandService = class {
3736
3899
  this.ctx = ctx;
3737
3900
  }
3738
3901
  ctx;
3902
+ static channel = "brand";
3739
3903
  base() {
3740
3904
  return `/brand/brands`;
3741
3905
  }
@@ -3800,6 +3964,7 @@ var LabelService = class {
3800
3964
  this.ctx = ctx;
3801
3965
  }
3802
3966
  ctx;
3967
+ static channel = "label";
3803
3968
  base() {
3804
3969
  return `/label/labels`;
3805
3970
  }
@@ -3864,6 +4029,7 @@ var CountryService = class {
3864
4029
  this.ctx = ctx;
3865
4030
  }
3866
4031
  ctx;
4032
+ static channel = "country";
3867
4033
  base() {
3868
4034
  return `/country/${this.ctx.tenant}`;
3869
4035
  }
@@ -3919,6 +4085,7 @@ var CurrencyService = class {
3919
4085
  this.ctx = ctx;
3920
4086
  }
3921
4087
  ctx;
4088
+ static channel = "currency";
3922
4089
  base() {
3923
4090
  return `/currency/${this.ctx.tenant}`;
3924
4091
  }
@@ -4019,6 +4186,7 @@ var ShippingService = class {
4019
4186
  this.ctx = ctx;
4020
4187
  }
4021
4188
  ctx;
4189
+ static channel = "shipping";
4022
4190
  base() {
4023
4191
  return `/shipping/${this.ctx.tenant}`;
4024
4192
  }
@@ -4433,6 +4601,7 @@ var ReturnsService = class {
4433
4601
  this.ctx = ctx;
4434
4602
  }
4435
4603
  ctx;
4604
+ static channel = "returns";
4436
4605
  base() {
4437
4606
  return `/return/${this.ctx.tenant}/returns`;
4438
4607
  }
@@ -4497,6 +4666,7 @@ var SepaExportService = class {
4497
4666
  this.ctx = ctx;
4498
4667
  }
4499
4668
  ctx;
4669
+ static channel = "sepa-export";
4500
4670
  base() {
4501
4671
  return `/sepa-export/${this.ctx.tenant}`;
4502
4672
  }
@@ -4537,6 +4707,7 @@ var IndexingService = class {
4537
4707
  this.ctx = ctx;
4538
4708
  }
4539
4709
  ctx;
4710
+ static channel = "indexing";
4540
4711
  base() {
4541
4712
  return `/indexing/${this.ctx.tenant}`;
4542
4713
  }
@@ -4603,6 +4774,7 @@ var UnitHandlingService = class {
4603
4774
  this.ctx = ctx;
4604
4775
  }
4605
4776
  ctx;
4777
+ static channel = "unit-handling";
4606
4778
  base() {
4607
4779
  return `/unit-handling/${this.ctx.tenant}`;
4608
4780
  }
@@ -4684,6 +4856,7 @@ var CatalogService = class {
4684
4856
  this.ctx = ctx;
4685
4857
  }
4686
4858
  ctx;
4859
+ static channel = "catalog";
4687
4860
  base() {
4688
4861
  return `/catalog/${this.ctx.tenant}/catalogs`;
4689
4862
  }
@@ -4751,6 +4924,7 @@ var VendorService = class {
4751
4924
  this.ctx = ctx;
4752
4925
  }
4753
4926
  ctx;
4927
+ static channel = "vendor";
4754
4928
  base() {
4755
4929
  return `/vendor/${this.ctx.tenant}`;
4756
4930
  }
@@ -4850,6 +5024,7 @@ var PickPackService = class {
4850
5024
  this.ctx = ctx;
4851
5025
  }
4852
5026
  ctx;
5027
+ static channel = "pick-pack";
4853
5028
  base() {
4854
5029
  return `/pick-pack/${this.ctx.tenant}`;
4855
5030
  }
@@ -4941,6 +5116,7 @@ var CustomerAdminService = class {
4941
5116
  this.ctx = ctx;
4942
5117
  }
4943
5118
  ctx;
5119
+ static channel = "customer-admin";
4944
5120
  base() {
4945
5121
  return `/customer/${this.ctx.tenant}/customers`;
4946
5122
  }
@@ -5045,6 +5221,7 @@ var ApprovalService = class {
5045
5221
  this.ctx = ctx;
5046
5222
  }
5047
5223
  ctx;
5224
+ static channel = "approval";
5048
5225
  base() {
5049
5226
  return `/approval/${this.ctx.tenant}`;
5050
5227
  }
@@ -5111,12 +5288,6 @@ var ApprovalService = class {
5111
5288
  }
5112
5289
  };
5113
5290
 
5114
- // package.json
5115
- var version = "2.13.1";
5116
-
5117
- // src/version.ts
5118
- var SDK_VERSION = version;
5119
-
5120
5291
  // src/client.ts
5121
5292
  var EmporixClient = class {
5122
5293
  customers;
@@ -5179,96 +5350,62 @@ var EmporixClient = class {
5179
5350
  * Provider tree. Treat as read-only.
5180
5351
  */
5181
5352
  config;
5182
- resolver;
5183
- customerRefresh;
5184
- requestContext;
5353
+ core;
5185
5354
  constructor(config) {
5186
- const cfg = validateConfig(config);
5187
- this.tenant = cfg.tenant;
5188
- this.config = cfg;
5189
- let loggerObj = {};
5190
- let baseLogger;
5191
- if (cfg.logger === false) {
5192
- baseLogger = createNoopLogger();
5193
- } else if (cfg.logger && typeof cfg.logger.child === "function") {
5194
- baseLogger = cfg.logger;
5195
- } else if (cfg.logger) {
5196
- loggerObj = cfg.logger;
5197
- }
5198
- this.resolver = new LevelResolver(loggerObj);
5199
- const root = baseLogger ?? createConsoleLogger(this.resolver, {
5200
- sdk: "emporix",
5201
- sdkVersion: SDK_VERSION,
5202
- tenant: cfg.tenant
5203
- });
5204
- const tokenProvider = cfg.tokenProvider ?? new DefaultTokenProvider(cfg);
5205
- this.tokenProvider = tokenProvider;
5206
- const customerRefresh = new CustomerRefreshRegistry();
5207
- this.customerRefresh = customerRefresh;
5208
- this.requestContext = { language: cfg.credentials.storefront?.context?.language };
5209
- const requestContext = this.requestContext;
5210
- const mk = (service) => ({
5211
- tenant: cfg.tenant,
5212
- tokenProvider,
5213
- logger: root.child({ service }),
5214
- http: new HttpClient({
5215
- host: cfg.host,
5216
- provider: tokenProvider,
5217
- logger: root.child({ service: "http" }),
5218
- retry: cfg.retry,
5219
- timeouts: cfg.timeouts,
5220
- customerRefresh,
5221
- requestContext
5222
- })
5223
- });
5224
- this.customers = new CustomerService(mk("customer"));
5225
- this.products = new ProductService(mk("product"));
5226
- this.categories = new CategoryService(mk("category"));
5227
- this.carts = new CartService(mk("cart"));
5228
- this.checkout = new CheckoutService(mk("checkout"));
5229
- this.payments = new PaymentGatewayService(mk("payment"));
5230
- this.prices = new PriceService(mk("price"));
5231
- this.media = new MediaService(mk("media"));
5232
- this.segments = new SegmentService(mk("segment"), {
5355
+ const core = createCore(config);
5356
+ this.core = core;
5357
+ this.tenant = core.tenant;
5358
+ this.config = core.config;
5359
+ this.tokenProvider = core.tokenProvider;
5360
+ const mk = core.mk;
5361
+ this.customers = new CustomerService(mk(CustomerService.channel));
5362
+ this.products = new ProductService(mk(ProductService.channel));
5363
+ this.categories = new CategoryService(mk(CategoryService.channel));
5364
+ this.carts = new CartService(mk(CartService.channel));
5365
+ this.checkout = new CheckoutService(mk(CheckoutService.channel));
5366
+ this.payments = new PaymentGatewayService(mk(PaymentGatewayService.channel));
5367
+ this.prices = new PriceService(mk(PriceService.channel));
5368
+ this.media = new MediaService(mk(MediaService.channel));
5369
+ this.segments = new SegmentService(mk(SegmentService.channel), {
5233
5370
  products: this.products,
5234
5371
  categories: this.categories
5235
5372
  });
5236
- this.sites = new SiteService(mk("site"));
5237
- this.sessionContext = new SessionContextService(mk("session-context"));
5238
- this.companies = new CompaniesService(mk("customer-management"));
5239
- this.contacts = new ContactsService(mk("customer-management"));
5240
- this.locations = new LocationsService(mk("customer-management"));
5241
- this.customerGroups = new CustomerGroupsService(mk("iam"));
5242
- this.orders = new OrdersService(mk("orders"));
5243
- this.salesOrders = new SalesOrdersService(mk("sales-orders"));
5244
- this.availability = new AvailabilityService(mk("availability"));
5245
- this.tenantConfig = new TenantConfigService(mk("configuration"));
5246
- this.clientConfig = new ClientConfigService(mk("configuration"));
5247
- this.shoppingLists = new ShoppingListService(mk("shopping-list"));
5248
- this.ragIndexer = new RagIndexerService(mk("ai-rag-indexer"));
5249
- this.sequentialIds = new SequentialIdService(mk("sequential-id"));
5250
- this.fees = new FeeService(mk("fee"));
5251
- this.cloudFunctions = new CloudFunctionsService(mk("cloud-functions"));
5252
- this.webhooks = new WebhookService(mk("webhook"));
5253
- this.schemas = new SchemaService(mk("schema"));
5254
- this.ai = new AiService(mk("ai"));
5255
- this.taxes = new TaxService(mk("tax"));
5256
- this.coupons = new CouponService(mk("coupon"));
5257
- this.rewardPoints = new RewardPointsService(mk("reward-points"));
5258
- this.brands = new BrandService(mk("brand"));
5259
- this.labels = new LabelService(mk("label"));
5260
- this.countries = new CountryService(mk("country"));
5261
- this.currencies = new CurrencyService(mk("currency"));
5262
- this.shipping = new ShippingService(mk("shipping"));
5263
- this.returns = new ReturnsService(mk("returns"));
5264
- this.sepaExport = new SepaExportService(mk("sepa-export"));
5265
- this.indexing = new IndexingService(mk("indexing"));
5266
- this.units = new UnitHandlingService(mk("unit-handling"));
5267
- this.catalogs = new CatalogService(mk("catalog"));
5268
- this.vendors = new VendorService(mk("vendor"));
5269
- this.pickPack = new PickPackService(mk("pick-pack"));
5270
- this.customerAdmin = new CustomerAdminService(mk("customer-admin"));
5271
- this.approvals = new ApprovalService(mk("approval"));
5373
+ this.sites = new SiteService(mk(SiteService.channel));
5374
+ this.sessionContext = new SessionContextService(mk(SessionContextService.channel));
5375
+ this.companies = new CompaniesService(mk(CompaniesService.channel));
5376
+ this.contacts = new ContactsService(mk(ContactsService.channel));
5377
+ this.locations = new LocationsService(mk(LocationsService.channel));
5378
+ this.customerGroups = new CustomerGroupsService(mk(CustomerGroupsService.channel));
5379
+ this.orders = new OrdersService(mk(OrdersService.channel));
5380
+ this.salesOrders = new SalesOrdersService(mk(SalesOrdersService.channel));
5381
+ this.availability = new AvailabilityService(mk(AvailabilityService.channel));
5382
+ this.tenantConfig = new TenantConfigService(mk(TenantConfigService.channel));
5383
+ this.clientConfig = new ClientConfigService(mk(ClientConfigService.channel));
5384
+ this.shoppingLists = new ShoppingListService(mk(ShoppingListService.channel));
5385
+ this.ragIndexer = new RagIndexerService(mk(RagIndexerService.channel));
5386
+ this.sequentialIds = new SequentialIdService(mk(SequentialIdService.channel));
5387
+ this.fees = new FeeService(mk(FeeService.channel));
5388
+ this.cloudFunctions = new CloudFunctionsService(mk(CloudFunctionsService.channel));
5389
+ this.webhooks = new WebhookService(mk(WebhookService.channel));
5390
+ this.schemas = new SchemaService(mk(SchemaService.channel));
5391
+ this.ai = new AiService(mk(AiService.channel));
5392
+ this.taxes = new TaxService(mk(TaxService.channel));
5393
+ this.coupons = new CouponService(mk(CouponService.channel));
5394
+ this.rewardPoints = new RewardPointsService(mk(RewardPointsService.channel));
5395
+ this.brands = new BrandService(mk(BrandService.channel));
5396
+ this.labels = new LabelService(mk(LabelService.channel));
5397
+ this.countries = new CountryService(mk(CountryService.channel));
5398
+ this.currencies = new CurrencyService(mk(CurrencyService.channel));
5399
+ this.shipping = new ShippingService(mk(ShippingService.channel));
5400
+ this.returns = new ReturnsService(mk(ReturnsService.channel));
5401
+ this.sepaExport = new SepaExportService(mk(SepaExportService.channel));
5402
+ this.indexing = new IndexingService(mk(IndexingService.channel));
5403
+ this.units = new UnitHandlingService(mk(UnitHandlingService.channel));
5404
+ this.catalogs = new CatalogService(mk(CatalogService.channel));
5405
+ this.vendors = new VendorService(mk(VendorService.channel));
5406
+ this.pickPack = new PickPackService(mk(PickPackService.channel));
5407
+ this.customerAdmin = new CustomerAdminService(mk(CustomerAdminService.channel));
5408
+ this.approvals = new ApprovalService(mk(ApprovalService.channel));
5272
5409
  }
5273
5410
  /**
5274
5411
  * Re-binds the storefront price context (currency / siteCode / targetLocation)
@@ -5281,21 +5418,15 @@ var EmporixClient = class {
5281
5418
  * read); a language-only change does NOT re-mint the token.
5282
5419
  */
5283
5420
  setStorefrontContext(ctx) {
5284
- if (ctx.language !== void 0) {
5285
- this.requestContext.language = ctx.language || void 0;
5286
- }
5287
- const { language: _language, ...priceContext } = ctx;
5288
- if (Object.keys(priceContext).length > 0) {
5289
- this.tokenProvider.setAnonymousContext?.(priceContext);
5290
- }
5421
+ this.core.setStorefrontContext(ctx);
5291
5422
  }
5292
5423
  /** Sets the runtime log level globally or for one service. */
5293
5424
  setLogLevel(level, opts = {}) {
5294
- this.resolver.set(level, opts.service, opts.force ?? false);
5425
+ this.core.setLogLevel(level, opts);
5295
5426
  }
5296
5427
  /** Returns the effective log level for a service. */
5297
5428
  getLogLevel(service) {
5298
- return this.resolver.get(service);
5429
+ return this.core.getLogLevel(service);
5299
5430
  }
5300
5431
  /**
5301
5432
  * Registers (or clears with `null`) a customer-token refresher. When set, a
@@ -5304,10 +5435,34 @@ var EmporixClient = class {
5304
5435
  * automatically via `autoRefreshCustomerToken`.
5305
5436
  */
5306
5437
  setCustomerTokenRefresher(refresher) {
5307
- this.customerRefresh.set(refresher);
5438
+ this.core.setCustomerTokenRefresher(refresher);
5308
5439
  }
5309
5440
  };
5310
5441
 
5442
+ // src/create-emporix-client.ts
5443
+ function createEmporixClient(config, services) {
5444
+ const { mk, ...core } = createCore(config);
5445
+ const built = {};
5446
+ const entries = Object.entries(services);
5447
+ for (const [key, Svc] of entries) {
5448
+ if (!Svc.deps?.length) built[key] = new Svc(mk(Svc.channel));
5449
+ }
5450
+ for (const [key, Svc] of entries) {
5451
+ if (!Svc.deps?.length) continue;
5452
+ const deps = {};
5453
+ for (const dep of Svc.deps) {
5454
+ if (!(dep in built)) {
5455
+ throw new EmporixError(
5456
+ `createEmporixClient: "${key}" requires "${dep}" in the services map`
5457
+ );
5458
+ }
5459
+ deps[dep] = built[dep];
5460
+ }
5461
+ built[key] = new Svc(mk(Svc.channel), deps);
5462
+ }
5463
+ return { ...core, ...built };
5464
+ }
5465
+
5311
5466
  // src/core/yrn.ts
5312
5467
  function productIdFromYrn(yrn) {
5313
5468
  if (!yrn) return "";
@@ -5341,8 +5496,10 @@ exports.EmporixClient = EmporixClient;
5341
5496
  exports.EmporixError = EmporixError;
5342
5497
  exports.EmporixForbiddenError = EmporixForbiddenError;
5343
5498
  exports.EmporixInsufficientScopeError = EmporixInsufficientScopeError;
5499
+ exports.EmporixNetworkError = EmporixNetworkError;
5344
5500
  exports.EmporixNotFoundError = EmporixNotFoundError;
5345
5501
  exports.EmporixServerError = EmporixServerError;
5502
+ exports.EmporixTimeoutError = EmporixTimeoutError;
5346
5503
  exports.EmporixValidationError = EmporixValidationError;
5347
5504
  exports.FeeService = FeeService;
5348
5505
  exports.HttpClient = HttpClient;
@@ -5376,6 +5533,8 @@ exports.VendorService = VendorService;
5376
5533
  exports.WebhookService = WebhookService;
5377
5534
  exports.auth = auth;
5378
5535
  exports.createConsoleLogger = createConsoleLogger;
5536
+ exports.createCore = createCore;
5537
+ exports.createEmporixClient = createEmporixClient;
5379
5538
  exports.createNoopLogger = createNoopLogger;
5380
5539
  exports.errorFromResponse = errorFromResponse;
5381
5540
  exports.iterateAll = iterateAll;