@viu/emporix-sdk 2.5.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/availability.d.cts +1 -1
- package/dist/availability.d.ts +1 -1
- package/dist/cart.d.cts +1 -1
- package/dist/cart.d.ts +1 -1
- package/dist/category.d.cts +1 -1
- package/dist/category.d.ts +1 -1
- package/dist/checkout.d.cts +1 -1
- package/dist/checkout.d.ts +1 -1
- package/dist/companies.d.cts +1 -1
- package/dist/companies.d.ts +1 -1
- package/dist/contacts.d.cts +1 -1
- package/dist/contacts.d.ts +1 -1
- package/dist/{context-CgUWXqEt.d.cts → context-DJDTlhLW.d.cts} +30 -1
- package/dist/{context-CgUWXqEt.d.ts → context-DJDTlhLW.d.ts} +30 -1
- package/dist/customer-groups.d.cts +1 -1
- package/dist/customer-groups.d.ts +1 -1
- package/dist/customer.d.cts +1 -1
- package/dist/customer.d.ts +1 -1
- package/dist/index.cjs +48 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -3
- package/dist/index.d.ts +11 -3
- package/dist/index.js +48 -4
- package/dist/index.js.map +1 -1
- package/dist/locations.d.cts +1 -1
- package/dist/locations.d.ts +1 -1
- package/dist/media.d.cts +1 -1
- package/dist/media.d.ts +1 -1
- package/dist/orders.d.cts +1 -1
- package/dist/orders.d.ts +1 -1
- package/dist/payment.d.cts +1 -1
- package/dist/payment.d.ts +1 -1
- package/dist/price.d.cts +1 -1
- package/dist/price.d.ts +1 -1
- package/dist/product.d.cts +1 -1
- package/dist/product.d.ts +1 -1
- package/dist/segment.d.cts +1 -1
- package/dist/segment.d.ts +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @viu/emporix-sdk
|
|
2
2
|
|
|
3
|
+
## 2.6.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#92](https://github.com/viuteam/emporix-sdk/pull/92) [`45a2bd8`](https://github.com/viuteam/emporix-sdk/commit/45a2bd8d83cb46d775301790cb2efc60805efc90) Thanks [@amnael1](https://github.com/amnael1)! - Add opt-in reactive customer-token auto-refresh.
|
|
8
|
+
|
|
9
|
+
Core: `EmporixClient.setCustomerTokenRefresher(refresher)` registers a
|
|
10
|
+
single-flight `CustomerTokenRefresher`; on a `customer`-kind 401 the HTTP layer
|
|
11
|
+
refreshes once and retries. Off by default — the customer token stays
|
|
12
|
+
caller-owned.
|
|
13
|
+
|
|
14
|
+
React: `EmporixProvider` gains `autoRefreshCustomerToken` and
|
|
15
|
+
`onCustomerSessionExpired`. When enabled, a customer 401 is transparently
|
|
16
|
+
refreshed via the stored refresh token (anonymous-authorized
|
|
17
|
+
`GET /refreshauthtoken`) and the request is retried; B2B `legalEntityId` is
|
|
18
|
+
preserved.
|
|
19
|
+
|
|
3
20
|
## 2.5.0
|
|
4
21
|
|
|
5
22
|
### Minor Changes
|
package/dist/availability.d.cts
CHANGED
package/dist/availability.d.ts
CHANGED
package/dist/cart.d.cts
CHANGED
package/dist/cart.d.ts
CHANGED
package/dist/category.d.cts
CHANGED
package/dist/category.d.ts
CHANGED
package/dist/checkout.d.cts
CHANGED
package/dist/checkout.d.ts
CHANGED
package/dist/companies.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as ClientContext, b as AuthContext } from './context-
|
|
1
|
+
import { C as ClientContext, b as AuthContext } from './context-DJDTlhLW.cjs';
|
|
2
2
|
import { L as LegalEntity, f as LegalEntityCreate, h as LegalEntityUpdate } from './types.gen-D1QuqPLs.cjs';
|
|
3
3
|
export { A as AccountLimit, e as CustomerGroupRef, g as LegalEntityType, i as LegalInfo } from './types.gen-D1QuqPLs.cjs';
|
|
4
4
|
|
package/dist/companies.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as ClientContext, b as AuthContext } from './context-
|
|
1
|
+
import { C as ClientContext, b as AuthContext } from './context-DJDTlhLW.js';
|
|
2
2
|
import { L as LegalEntity, f as LegalEntityCreate, h as LegalEntityUpdate } from './types.gen-D1QuqPLs.js';
|
|
3
3
|
export { A as AccountLimit, e as CustomerGroupRef, g as LegalEntityType, i as LegalInfo } from './types.gen-D1QuqPLs.js';
|
|
4
4
|
|
package/dist/contacts.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as ClientContext, b as AuthContext } from './context-
|
|
1
|
+
import { C as ClientContext, b as AuthContext } from './context-DJDTlhLW.cjs';
|
|
2
2
|
import { C as ContactAssignment, a as ContactAssignmentCreate, c as ContactAssignmentUpdate } from './types.gen-D1QuqPLs.cjs';
|
|
3
3
|
export { b as ContactAssignmentType } from './types.gen-D1QuqPLs.cjs';
|
|
4
4
|
|
package/dist/contacts.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as ClientContext, b as AuthContext } from './context-
|
|
1
|
+
import { C as ClientContext, b as AuthContext } from './context-DJDTlhLW.js';
|
|
2
2
|
import { C as ContactAssignment, a as ContactAssignmentCreate, c as ContactAssignmentUpdate } from './types.gen-D1QuqPLs.js';
|
|
3
3
|
export { b as ContactAssignmentType } from './types.gen-D1QuqPLs.js';
|
|
4
4
|
|
|
@@ -161,6 +161,19 @@ type AuthContext = {
|
|
|
161
161
|
kind: "raw";
|
|
162
162
|
token: string;
|
|
163
163
|
};
|
|
164
|
+
/**
|
|
165
|
+
* Supplies a fresh customer token when a `customer`-kind request 401s. The host
|
|
166
|
+
* (e.g. EmporixProvider) implements this; the SDK never refreshes the
|
|
167
|
+
* caller-owned customer token unless a refresher is registered.
|
|
168
|
+
*/
|
|
169
|
+
interface CustomerTokenRefresher {
|
|
170
|
+
/**
|
|
171
|
+
* Called on a `customer`-kind 401. Receives the token that just failed;
|
|
172
|
+
* returns a fresh customer token to retry with, or `null` to give up (the
|
|
173
|
+
* 401 then propagates as EmporixAuthError).
|
|
174
|
+
*/
|
|
175
|
+
refresh(expiredToken: string): Promise<string | null>;
|
|
176
|
+
}
|
|
164
177
|
/** An obtained anonymous storefront session. */
|
|
165
178
|
interface AnonymousSession {
|
|
166
179
|
accessToken: string;
|
|
@@ -232,6 +245,20 @@ declare const auth: {
|
|
|
232
245
|
};
|
|
233
246
|
/** Resolves an {@link AuthContext} to a concrete bearer token. */
|
|
234
247
|
declare function resolveToken(ctx: AuthContext, provider: TokenProvider): Promise<string>;
|
|
248
|
+
/**
|
|
249
|
+
* Late-bindable, single-flight holder for an optional
|
|
250
|
+
* {@link CustomerTokenRefresher}. Single-flight is required because Emporix
|
|
251
|
+
* rotates the refresh token on each refresh — concurrent refreshes would
|
|
252
|
+
* invalidate each other. Off (returns `null`) until a refresher is set.
|
|
253
|
+
*/
|
|
254
|
+
declare class CustomerRefreshRegistry {
|
|
255
|
+
private refresher;
|
|
256
|
+
private inflight;
|
|
257
|
+
set(refresher: CustomerTokenRefresher | null): void;
|
|
258
|
+
get enabled(): boolean;
|
|
259
|
+
/** Concurrent callers share one in-flight refresh. */
|
|
260
|
+
refresh(expiredToken: string): Promise<string | null>;
|
|
261
|
+
}
|
|
235
262
|
/** SDK-owned token provider: client-credentials service tokens + anonymous session. */
|
|
236
263
|
declare class DefaultTokenProvider implements TokenProvider {
|
|
237
264
|
private readonly cfg;
|
|
@@ -290,6 +317,8 @@ interface HttpClientOptions {
|
|
|
290
317
|
};
|
|
291
318
|
/** Override the retry backoff delay (ms → Promise). Defaults to a real timer. */
|
|
292
319
|
sleep?: (ms: number) => Promise<void>;
|
|
320
|
+
/** Opt-in customer-token refresher registry (off unless a refresher is set). */
|
|
321
|
+
customerRefresh?: CustomerRefreshRegistry;
|
|
293
322
|
}
|
|
294
323
|
/** Fetch wrapper: auth resolution, JSON parsing, typed error mapping, logging. */
|
|
295
324
|
declare class HttpClient {
|
|
@@ -341,4 +370,4 @@ interface PaginatedItems<T> {
|
|
|
341
370
|
*/
|
|
342
371
|
declare function iterateAll<T>(fetchPage: (pageNumber: number) => Promise<PaginatedItems<T>>, start?: number): AsyncIterable<T>;
|
|
343
372
|
|
|
344
|
-
export { type AnonymousSession as A, type ClientContext as C, DEFAULT_HOST as D, type EmporixConfig as E, HttpClient as H, LEVEL as L, type PaginatedItems as P, type RequestOptions as R, type ServiceCredentials as S, type TokenProvider as T, type AnonymousSessionStore as a, type AuthContext as b, type AuthKind as c,
|
|
373
|
+
export { type AnonymousSession as A, type ClientContext as C, DEFAULT_HOST as D, type EmporixConfig as E, HttpClient as H, LEVEL as L, type PaginatedItems as P, type RequestOptions as R, type ServiceCredentials as S, type TokenProvider as T, type AnonymousSessionStore as a, type AuthContext as b, type AuthKind as c, CustomerRefreshRegistry as d, type CustomerTokenRefresher as e, DefaultTokenProvider as f, type HttpClientOptions as g, LevelResolver as h, type LogFields as i, type LogLevel as j, type Logger as k, type LoggerConfig as l, type LoggerObjectConfig as m, type ResolvedConfig as n, type ServiceName as o, type StorefrontCredentials as p, auth as q, createConsoleLogger as r, createNoopLogger as s, iterateAll as t, redact as u, resolveToken as v, validateConfig as w };
|
|
@@ -161,6 +161,19 @@ type AuthContext = {
|
|
|
161
161
|
kind: "raw";
|
|
162
162
|
token: string;
|
|
163
163
|
};
|
|
164
|
+
/**
|
|
165
|
+
* Supplies a fresh customer token when a `customer`-kind request 401s. The host
|
|
166
|
+
* (e.g. EmporixProvider) implements this; the SDK never refreshes the
|
|
167
|
+
* caller-owned customer token unless a refresher is registered.
|
|
168
|
+
*/
|
|
169
|
+
interface CustomerTokenRefresher {
|
|
170
|
+
/**
|
|
171
|
+
* Called on a `customer`-kind 401. Receives the token that just failed;
|
|
172
|
+
* returns a fresh customer token to retry with, or `null` to give up (the
|
|
173
|
+
* 401 then propagates as EmporixAuthError).
|
|
174
|
+
*/
|
|
175
|
+
refresh(expiredToken: string): Promise<string | null>;
|
|
176
|
+
}
|
|
164
177
|
/** An obtained anonymous storefront session. */
|
|
165
178
|
interface AnonymousSession {
|
|
166
179
|
accessToken: string;
|
|
@@ -232,6 +245,20 @@ declare const auth: {
|
|
|
232
245
|
};
|
|
233
246
|
/** Resolves an {@link AuthContext} to a concrete bearer token. */
|
|
234
247
|
declare function resolveToken(ctx: AuthContext, provider: TokenProvider): Promise<string>;
|
|
248
|
+
/**
|
|
249
|
+
* Late-bindable, single-flight holder for an optional
|
|
250
|
+
* {@link CustomerTokenRefresher}. Single-flight is required because Emporix
|
|
251
|
+
* rotates the refresh token on each refresh — concurrent refreshes would
|
|
252
|
+
* invalidate each other. Off (returns `null`) until a refresher is set.
|
|
253
|
+
*/
|
|
254
|
+
declare class CustomerRefreshRegistry {
|
|
255
|
+
private refresher;
|
|
256
|
+
private inflight;
|
|
257
|
+
set(refresher: CustomerTokenRefresher | null): void;
|
|
258
|
+
get enabled(): boolean;
|
|
259
|
+
/** Concurrent callers share one in-flight refresh. */
|
|
260
|
+
refresh(expiredToken: string): Promise<string | null>;
|
|
261
|
+
}
|
|
235
262
|
/** SDK-owned token provider: client-credentials service tokens + anonymous session. */
|
|
236
263
|
declare class DefaultTokenProvider implements TokenProvider {
|
|
237
264
|
private readonly cfg;
|
|
@@ -290,6 +317,8 @@ interface HttpClientOptions {
|
|
|
290
317
|
};
|
|
291
318
|
/** Override the retry backoff delay (ms → Promise). Defaults to a real timer. */
|
|
292
319
|
sleep?: (ms: number) => Promise<void>;
|
|
320
|
+
/** Opt-in customer-token refresher registry (off unless a refresher is set). */
|
|
321
|
+
customerRefresh?: CustomerRefreshRegistry;
|
|
293
322
|
}
|
|
294
323
|
/** Fetch wrapper: auth resolution, JSON parsing, typed error mapping, logging. */
|
|
295
324
|
declare class HttpClient {
|
|
@@ -341,4 +370,4 @@ interface PaginatedItems<T> {
|
|
|
341
370
|
*/
|
|
342
371
|
declare function iterateAll<T>(fetchPage: (pageNumber: number) => Promise<PaginatedItems<T>>, start?: number): AsyncIterable<T>;
|
|
343
372
|
|
|
344
|
-
export { type AnonymousSession as A, type ClientContext as C, DEFAULT_HOST as D, type EmporixConfig as E, HttpClient as H, LEVEL as L, type PaginatedItems as P, type RequestOptions as R, type ServiceCredentials as S, type TokenProvider as T, type AnonymousSessionStore as a, type AuthContext as b, type AuthKind as c,
|
|
373
|
+
export { type AnonymousSession as A, type ClientContext as C, DEFAULT_HOST as D, type EmporixConfig as E, HttpClient as H, LEVEL as L, type PaginatedItems as P, type RequestOptions as R, type ServiceCredentials as S, type TokenProvider as T, type AnonymousSessionStore as a, type AuthContext as b, type AuthKind as c, CustomerRefreshRegistry as d, type CustomerTokenRefresher as e, DefaultTokenProvider as f, type HttpClientOptions as g, LevelResolver as h, type LogFields as i, type LogLevel as j, type Logger as k, type LoggerConfig as l, type LoggerObjectConfig as m, type ResolvedConfig as n, type ServiceName as o, type StorefrontCredentials as p, auth as q, createConsoleLogger as r, createNoopLogger as s, iterateAll as t, redact as u, resolveToken as v, validateConfig as w };
|
package/dist/customer.d.cts
CHANGED
package/dist/customer.d.ts
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -366,6 +366,26 @@ async function resolveToken(ctx, provider) {
|
|
|
366
366
|
return ctx.token;
|
|
367
367
|
}
|
|
368
368
|
}
|
|
369
|
+
var CustomerRefreshRegistry = class {
|
|
370
|
+
refresher = null;
|
|
371
|
+
inflight = null;
|
|
372
|
+
set(refresher) {
|
|
373
|
+
this.refresher = refresher;
|
|
374
|
+
}
|
|
375
|
+
get enabled() {
|
|
376
|
+
return this.refresher !== null;
|
|
377
|
+
}
|
|
378
|
+
/** Concurrent callers share one in-flight refresh. */
|
|
379
|
+
refresh(expiredToken) {
|
|
380
|
+
if (!this.refresher) return Promise.resolve(null);
|
|
381
|
+
if (this.inflight) return this.inflight;
|
|
382
|
+
const p = Promise.resolve(this.refresher.refresh(expiredToken)).finally(() => {
|
|
383
|
+
this.inflight = null;
|
|
384
|
+
});
|
|
385
|
+
this.inflight = p;
|
|
386
|
+
return p;
|
|
387
|
+
}
|
|
388
|
+
};
|
|
369
389
|
var DefaultTokenProvider = class {
|
|
370
390
|
constructor(cfg) {
|
|
371
391
|
this.cfg = cfg;
|
|
@@ -567,8 +587,10 @@ var HttpClient = class {
|
|
|
567
587
|
const sdkManaged = o.auth.kind === "service" || o.auth.kind === "anonymous";
|
|
568
588
|
const maxAttempts = this.opts.retry.maxAttempts;
|
|
569
589
|
let reauthed = false;
|
|
590
|
+
let customerToken = o.auth.kind === "customer" ? o.auth.token : void 0;
|
|
591
|
+
let customerReauthed = false;
|
|
570
592
|
for (let attempt = 1; ; attempt++) {
|
|
571
|
-
const token = await resolveToken(o.auth, this.opts.provider);
|
|
593
|
+
const token = customerToken ?? await resolveToken(o.auth, this.opts.provider);
|
|
572
594
|
log.debug("http request", {
|
|
573
595
|
authKind: o.auth.kind,
|
|
574
596
|
method: o.method,
|
|
@@ -620,6 +642,15 @@ var HttpClient = class {
|
|
|
620
642
|
log.warn("sdk-managed 401, re-authing once", { authKind: o.auth.kind });
|
|
621
643
|
continue;
|
|
622
644
|
}
|
|
645
|
+
if (o.auth.kind === "customer" && !customerReauthed && this.opts.customerRefresh?.enabled) {
|
|
646
|
+
customerReauthed = true;
|
|
647
|
+
const fresh = await this.opts.customerRefresh.refresh(customerToken);
|
|
648
|
+
if (fresh) {
|
|
649
|
+
customerToken = fresh;
|
|
650
|
+
log.warn("customer 401, refreshed once", { authKind: o.auth.kind });
|
|
651
|
+
continue;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
623
654
|
throw errorFromResponse(res.status, `${o.method} ${o.path} \u2192 401`, parsed);
|
|
624
655
|
}
|
|
625
656
|
const retryable = res.status >= 500 || res.status === 429;
|
|
@@ -4942,7 +4973,7 @@ var ApprovalService = class {
|
|
|
4942
4973
|
};
|
|
4943
4974
|
|
|
4944
4975
|
// package.json
|
|
4945
|
-
var version = "2.
|
|
4976
|
+
var version = "2.6.0";
|
|
4946
4977
|
|
|
4947
4978
|
// src/version.ts
|
|
4948
4979
|
var SDK_VERSION = version;
|
|
@@ -5009,6 +5040,7 @@ var EmporixClient = class {
|
|
|
5009
5040
|
*/
|
|
5010
5041
|
config;
|
|
5011
5042
|
resolver;
|
|
5043
|
+
customerRefresh;
|
|
5012
5044
|
constructor(config) {
|
|
5013
5045
|
const cfg = validateConfig(config);
|
|
5014
5046
|
this.tenant = cfg.tenant;
|
|
@@ -5030,6 +5062,8 @@ var EmporixClient = class {
|
|
|
5030
5062
|
});
|
|
5031
5063
|
const tokenProvider = cfg.tokenProvider ?? new DefaultTokenProvider(cfg);
|
|
5032
5064
|
this.tokenProvider = tokenProvider;
|
|
5065
|
+
const customerRefresh = new CustomerRefreshRegistry();
|
|
5066
|
+
this.customerRefresh = customerRefresh;
|
|
5033
5067
|
const mk = (service) => ({
|
|
5034
5068
|
tenant: cfg.tenant,
|
|
5035
5069
|
tokenProvider,
|
|
@@ -5039,7 +5073,8 @@ var EmporixClient = class {
|
|
|
5039
5073
|
provider: tokenProvider,
|
|
5040
5074
|
logger: root.child({ service: "http" }),
|
|
5041
5075
|
retry: cfg.retry,
|
|
5042
|
-
timeouts: cfg.timeouts
|
|
5076
|
+
timeouts: cfg.timeouts,
|
|
5077
|
+
customerRefresh
|
|
5043
5078
|
})
|
|
5044
5079
|
});
|
|
5045
5080
|
this.customers = new CustomerService(mk("customer"));
|
|
@@ -5098,6 +5133,15 @@ var EmporixClient = class {
|
|
|
5098
5133
|
getLogLevel(service) {
|
|
5099
5134
|
return this.resolver.get(service);
|
|
5100
5135
|
}
|
|
5136
|
+
/**
|
|
5137
|
+
* Registers (or clears with `null`) a customer-token refresher. When set, a
|
|
5138
|
+
* `customer`-kind 401 triggers one refresh-and-retry. Off by default — the
|
|
5139
|
+
* customer token stays caller-owned. The React `EmporixProvider` wires this
|
|
5140
|
+
* automatically via `autoRefreshCustomerToken`.
|
|
5141
|
+
*/
|
|
5142
|
+
setCustomerTokenRefresher(refresher) {
|
|
5143
|
+
this.customerRefresh.set(refresher);
|
|
5144
|
+
}
|
|
5101
5145
|
};
|
|
5102
5146
|
|
|
5103
5147
|
exports.AiService = AiService;
|
|
@@ -5116,6 +5160,7 @@ exports.CouponService = CouponService;
|
|
|
5116
5160
|
exports.CurrencyService = CurrencyService;
|
|
5117
5161
|
exports.CustomerAdminService = CustomerAdminService;
|
|
5118
5162
|
exports.CustomerGroupsService = CustomerGroupsService;
|
|
5163
|
+
exports.CustomerRefreshRegistry = CustomerRefreshRegistry;
|
|
5119
5164
|
exports.CustomerService = CustomerService;
|
|
5120
5165
|
exports.DEFAULT_HOST = DEFAULT_HOST;
|
|
5121
5166
|
exports.DefaultTokenProvider = DefaultTokenProvider;
|