@viu/emporix-sdk 2.15.0 → 2.18.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 +29 -0
- package/README.md +19 -0
- package/dist/category.cjs +28 -0
- package/dist/category.cjs.map +1 -1
- package/dist/category.d.cts +10 -0
- package/dist/category.d.ts +10 -0
- package/dist/category.js +2 -1
- package/dist/{chunk-62PCCHZ2.js → chunk-36T4YPQJ.js} +7 -2
- package/dist/chunk-36T4YPQJ.js.map +1 -0
- package/dist/{chunk-GIZS4BY3.js → chunk-6XND7SYV.js} +20 -2
- package/dist/chunk-6XND7SYV.js.map +1 -0
- package/dist/{chunk-5VTBLBXJ.js → chunk-FZMP5NQZ.js} +10 -4
- package/dist/chunk-FZMP5NQZ.js.map +1 -0
- package/dist/chunk-PYLWZZC4.js +280 -0
- package/dist/chunk-PYLWZZC4.js.map +1 -0
- package/dist/chunk-S5HEIQDK.js +14 -0
- package/dist/chunk-S5HEIQDK.js.map +1 -0
- package/dist/index.cjs +68 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -7
- package/dist/index.d.ts +13 -7
- package/dist/index.js +19 -258
- package/dist/index.js.map +1 -1
- package/dist/orders.cjs +14 -0
- package/dist/orders.cjs.map +1 -1
- package/dist/orders.d.cts +3 -0
- package/dist/orders.d.ts +3 -0
- package/dist/orders.js +2 -1
- package/dist/payment.cjs +24 -7
- package/dist/payment.cjs.map +1 -1
- package/dist/payment.d.cts +7 -3
- package/dist/payment.d.ts +7 -3
- package/dist/payment.js +1 -1
- package/dist/product.cjs +14 -2
- package/dist/product.cjs.map +1 -1
- package/dist/product.d.cts +7 -2
- package/dist/product.d.ts +7 -2
- package/dist/product.js +2 -1
- package/dist/query-mLQs2WFr.d.cts +28 -0
- package/dist/query-mLQs2WFr.d.ts +28 -0
- package/dist/segment.d.cts +1 -0
- package/dist/segment.d.ts +1 -0
- package/package.json +1 -1
- package/dist/chunk-5VTBLBXJ.js.map +0 -1
- package/dist/chunk-62PCCHZ2.js.map +0 -1
- package/dist/chunk-GIZS4BY3.js.map +0 -1
- package/dist/chunk-XEJPH6UN.js +0 -31
- package/dist/chunk-XEJPH6UN.js.map +0 -1
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { requireCustomer } from './chunk-3BDDYX3V.js';
|
|
2
|
+
import { EmporixAuthError, EmporixTimeoutError, EmporixNetworkError } from './chunk-UWGGF4MC.js';
|
|
3
|
+
|
|
4
|
+
// src/core/auth.ts
|
|
5
|
+
var auth = {
|
|
6
|
+
/** Service/custom credential set (default `backend`). */
|
|
7
|
+
service: (credentials) => credentials === void 0 ? { kind: "service" } : { kind: "service", credentials },
|
|
8
|
+
/** Cached anonymous storefront token. */
|
|
9
|
+
anonymous: () => ({ kind: "anonymous" }),
|
|
10
|
+
/** Caller-owned customer bearer token. */
|
|
11
|
+
customer: (token) => ({ kind: "customer", token }),
|
|
12
|
+
/** Exact token, no transformation (SSO / token-exchange). */
|
|
13
|
+
raw: (token) => ({ kind: "raw", token })
|
|
14
|
+
};
|
|
15
|
+
async function resolveToken(ctx, provider) {
|
|
16
|
+
switch (ctx.kind) {
|
|
17
|
+
case "service":
|
|
18
|
+
return provider.getToken(ctx.credentials ?? "backend");
|
|
19
|
+
case "anonymous":
|
|
20
|
+
return (await provider.getAnonymousToken()).accessToken;
|
|
21
|
+
case "customer":
|
|
22
|
+
case "raw":
|
|
23
|
+
return ctx.token;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
var CustomerRefreshRegistry = class {
|
|
27
|
+
refresher = null;
|
|
28
|
+
inflight = null;
|
|
29
|
+
set(refresher) {
|
|
30
|
+
this.refresher = refresher;
|
|
31
|
+
}
|
|
32
|
+
get enabled() {
|
|
33
|
+
return this.refresher !== null;
|
|
34
|
+
}
|
|
35
|
+
/** Concurrent callers share one in-flight refresh. */
|
|
36
|
+
refresh(expiredToken) {
|
|
37
|
+
if (!this.refresher) return Promise.resolve(null);
|
|
38
|
+
if (this.inflight) return this.inflight;
|
|
39
|
+
const p = Promise.resolve(this.refresher.refresh(expiredToken)).finally(() => {
|
|
40
|
+
this.inflight = null;
|
|
41
|
+
});
|
|
42
|
+
this.inflight = p;
|
|
43
|
+
return p;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
var DefaultTokenProvider = class {
|
|
47
|
+
constructor(cfg) {
|
|
48
|
+
this.cfg = cfg;
|
|
49
|
+
}
|
|
50
|
+
cfg;
|
|
51
|
+
serviceCache = /* @__PURE__ */ new Map();
|
|
52
|
+
serviceLocks = /* @__PURE__ */ new Map();
|
|
53
|
+
anon;
|
|
54
|
+
anonLock;
|
|
55
|
+
anonStore;
|
|
56
|
+
contextOverride;
|
|
57
|
+
refreshListeners = /* @__PURE__ */ new Set();
|
|
58
|
+
onRefresh(listener) {
|
|
59
|
+
this.refreshListeners.add(listener);
|
|
60
|
+
return () => {
|
|
61
|
+
this.refreshListeners.delete(listener);
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
notifyRefresh(kind, success) {
|
|
65
|
+
for (const l of this.refreshListeners) {
|
|
66
|
+
try {
|
|
67
|
+
l({ kind, success });
|
|
68
|
+
} catch {
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
attachAnonymousStore(store) {
|
|
73
|
+
this.anonStore = store;
|
|
74
|
+
if (!this.anon) {
|
|
75
|
+
const persisted = store.read();
|
|
76
|
+
if (persisted) {
|
|
77
|
+
this.anon = {
|
|
78
|
+
accessToken: "",
|
|
79
|
+
refreshToken: persisted.refreshToken,
|
|
80
|
+
sessionId: persisted.sessionId,
|
|
81
|
+
expiresIn: 0,
|
|
82
|
+
expiresAt: 0
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
creds(set) {
|
|
88
|
+
if (set === "backend") {
|
|
89
|
+
const b = this.cfg.credentials.backend;
|
|
90
|
+
if (!b?.clientId || !b.secret) {
|
|
91
|
+
throw new EmporixAuthError(
|
|
92
|
+
"A 'service' AuthContext was used but credentials.backend is not configured"
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
return b;
|
|
96
|
+
}
|
|
97
|
+
const c = this.cfg.credentials.custom?.[set];
|
|
98
|
+
if (!c) throw new Error(`Unknown credential set "${set}"`);
|
|
99
|
+
return c;
|
|
100
|
+
}
|
|
101
|
+
fresh(e) {
|
|
102
|
+
if (!e) return false;
|
|
103
|
+
const now = Date.now();
|
|
104
|
+
if (now - e.obtainedAt >= this.cfg.cache.maxLifetimeSeconds * 1e3) return false;
|
|
105
|
+
return now < e.expiresAt;
|
|
106
|
+
}
|
|
107
|
+
async getToken(set) {
|
|
108
|
+
this.creds(set);
|
|
109
|
+
const cached = this.serviceCache.get(set);
|
|
110
|
+
if (this.fresh(cached)) return cached.token;
|
|
111
|
+
const inflight = this.serviceLocks.get(set);
|
|
112
|
+
if (inflight) return inflight;
|
|
113
|
+
const p = this.requestServiceToken(set).finally(() => this.serviceLocks.delete(set));
|
|
114
|
+
this.serviceLocks.set(set, p);
|
|
115
|
+
return p;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* fetch with the configured read timeout. Token endpoints sit in front of
|
|
119
|
+
* single-flight locks — one hung call would otherwise block every request
|
|
120
|
+
* on this credential set forever.
|
|
121
|
+
*/
|
|
122
|
+
async boundedFetch(url, init = {}) {
|
|
123
|
+
const ms = this.cfg.timeouts?.readMs ?? 6e4;
|
|
124
|
+
const controller = new AbortController();
|
|
125
|
+
const timer = setTimeout(() => controller.abort(), ms);
|
|
126
|
+
try {
|
|
127
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
128
|
+
} catch (err) {
|
|
129
|
+
if (err.name === "AbortError") {
|
|
130
|
+
throw new EmporixTimeoutError(`token request timed out after ${ms}ms`);
|
|
131
|
+
}
|
|
132
|
+
throw new EmporixNetworkError(`token request network failure: ${err.message}`);
|
|
133
|
+
} finally {
|
|
134
|
+
clearTimeout(timer);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
async requestServiceToken(set) {
|
|
138
|
+
const c = this.creds(set);
|
|
139
|
+
const body = new URLSearchParams({
|
|
140
|
+
grant_type: "client_credentials",
|
|
141
|
+
client_id: c.clientId,
|
|
142
|
+
client_secret: c.secret
|
|
143
|
+
});
|
|
144
|
+
if (c.scope) body.set("scope", c.scope);
|
|
145
|
+
const res = await this.boundedFetch(`${this.cfg.host}/oauth/token`, {
|
|
146
|
+
method: "POST",
|
|
147
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
148
|
+
body
|
|
149
|
+
});
|
|
150
|
+
const json = await res.json().catch(() => ({}));
|
|
151
|
+
if (!res.ok) {
|
|
152
|
+
throw new EmporixAuthError(`Token request failed for "${set}"`, res.status, json);
|
|
153
|
+
}
|
|
154
|
+
const obtainedAt = Date.now();
|
|
155
|
+
const ttl = Number(json.expires_in ?? 3600);
|
|
156
|
+
this.serviceCache.set(set, {
|
|
157
|
+
token: json.access_token,
|
|
158
|
+
obtainedAt,
|
|
159
|
+
expiresAt: obtainedAt + (ttl - this.cfg.cache.expirationBufferSeconds) * 1e3
|
|
160
|
+
});
|
|
161
|
+
return this.serviceCache.get(set).token;
|
|
162
|
+
}
|
|
163
|
+
invalidate(set) {
|
|
164
|
+
this.serviceCache.delete(set);
|
|
165
|
+
}
|
|
166
|
+
anonFresh() {
|
|
167
|
+
return !!this.anon && Date.now() < this.anon.expiresAt;
|
|
168
|
+
}
|
|
169
|
+
async getAnonymousToken() {
|
|
170
|
+
if (this.anonFresh()) return this.stripExpiry(this.anon);
|
|
171
|
+
if (this.anonLock) return this.anonLock;
|
|
172
|
+
const canRefresh = !!this.anon?.refreshToken;
|
|
173
|
+
const obtain = canRefresh ? this.fetchAnonymous("refresh").catch(() => this.fetchAnonymous("login")) : this.fetchAnonymous("login");
|
|
174
|
+
const p = obtain.finally(() => {
|
|
175
|
+
this.anonLock = void 0;
|
|
176
|
+
});
|
|
177
|
+
this.anonLock = p;
|
|
178
|
+
return p;
|
|
179
|
+
}
|
|
180
|
+
/** Refreshes the anonymous session, preserving its sessionId. */
|
|
181
|
+
async refreshAnonymous() {
|
|
182
|
+
if (!this.anon) return this.getAnonymousToken();
|
|
183
|
+
return this.fetchAnonymous("refresh");
|
|
184
|
+
}
|
|
185
|
+
invalidateAnonymous() {
|
|
186
|
+
this.anon = void 0;
|
|
187
|
+
this.anonStore?.write(null);
|
|
188
|
+
}
|
|
189
|
+
setAnonymousContext(ctx) {
|
|
190
|
+
const base = this.contextOverride ?? this.cfg.credentials.storefront?.context ?? {};
|
|
191
|
+
this.contextOverride = { ...base, ...ctx };
|
|
192
|
+
this.invalidateAnonymous();
|
|
193
|
+
}
|
|
194
|
+
/** Force a stale access token while keeping the refresh token + sessionId. */
|
|
195
|
+
expireAnonymous() {
|
|
196
|
+
if (this.anon) this.anon = { ...this.anon, expiresAt: 0 };
|
|
197
|
+
}
|
|
198
|
+
stripExpiry(s) {
|
|
199
|
+
const { expiresAt: _expiresAt, ...rest } = s;
|
|
200
|
+
return rest;
|
|
201
|
+
}
|
|
202
|
+
async fetchAnonymous(mode) {
|
|
203
|
+
const sf = this.cfg.credentials.storefront;
|
|
204
|
+
if (!sf?.clientId) {
|
|
205
|
+
throw new Error("credentials.storefront.clientId is required for anonymous tokens");
|
|
206
|
+
}
|
|
207
|
+
const url = new URL(`${this.cfg.host}/customerlogin/auth/anonymous/${mode}`);
|
|
208
|
+
url.searchParams.set("tenant", this.cfg.tenant);
|
|
209
|
+
url.searchParams.set("client_id", sf.clientId);
|
|
210
|
+
const c = this.contextOverride ?? sf.context;
|
|
211
|
+
if (c?.currency) url.searchParams.set("currency", c.currency);
|
|
212
|
+
if (c?.siteCode) url.searchParams.set("siteCode", c.siteCode);
|
|
213
|
+
if (c?.targetLocation) url.searchParams.set("targetLocation", c.targetLocation);
|
|
214
|
+
if (mode === "refresh" && this.anon) {
|
|
215
|
+
url.searchParams.set("refresh_token", this.anon.refreshToken);
|
|
216
|
+
}
|
|
217
|
+
try {
|
|
218
|
+
const res = await this.boundedFetch(url, { method: "GET" });
|
|
219
|
+
const json = await res.json().catch(() => ({}));
|
|
220
|
+
if (!res.ok) {
|
|
221
|
+
this.notifyRefresh("anonymous", false);
|
|
222
|
+
throw new EmporixAuthError(`Anonymous token ${mode} failed`, res.status, json);
|
|
223
|
+
}
|
|
224
|
+
const obtainedAt = Date.now();
|
|
225
|
+
this.anon = {
|
|
226
|
+
accessToken: json.access_token,
|
|
227
|
+
refreshToken: json.refresh_token,
|
|
228
|
+
sessionId: json.sessionId,
|
|
229
|
+
expiresIn: json.expires_in,
|
|
230
|
+
expiresAt: obtainedAt + (json.expires_in - this.cfg.cache.expirationBufferSeconds) * 1e3
|
|
231
|
+
};
|
|
232
|
+
this.anonStore?.write({
|
|
233
|
+
refreshToken: this.anon.refreshToken,
|
|
234
|
+
sessionId: this.anon.sessionId
|
|
235
|
+
});
|
|
236
|
+
this.notifyRefresh("anonymous", true);
|
|
237
|
+
return this.stripExpiry(this.anon);
|
|
238
|
+
} catch (err) {
|
|
239
|
+
if (!(err instanceof EmporixAuthError)) {
|
|
240
|
+
this.notifyRefresh("anonymous", false);
|
|
241
|
+
}
|
|
242
|
+
throw err;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
// src/services/payment.ts
|
|
248
|
+
var ANON = auth.anonymous();
|
|
249
|
+
var PaymentGatewayService = class {
|
|
250
|
+
constructor(ctx) {
|
|
251
|
+
this.ctx = ctx;
|
|
252
|
+
}
|
|
253
|
+
ctx;
|
|
254
|
+
static channel = "payment";
|
|
255
|
+
/**
|
|
256
|
+
* Lists configured frontend payment modes. The endpoint requires a bearer
|
|
257
|
+
* token but no customer scope ("No scope required"), so it defaults to an
|
|
258
|
+
* anonymous context and works for guests and logged-in customers alike.
|
|
259
|
+
*/
|
|
260
|
+
async listPaymentModes(authCtx = ANON) {
|
|
261
|
+
return this.ctx.http.request({
|
|
262
|
+
method: "GET",
|
|
263
|
+
path: `/payment-gateway/${this.ctx.tenant}/paymentmodes/frontend`,
|
|
264
|
+
auth: authCtx
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
/** Authorizes a post-checkout (deferred) payment for an existing order. */
|
|
268
|
+
async authorize(input, authCtx) {
|
|
269
|
+
return this.ctx.http.request({
|
|
270
|
+
method: "POST",
|
|
271
|
+
path: `/payment-gateway/${this.ctx.tenant}/payment/frontend/authorize`,
|
|
272
|
+
auth: requireCustomer(authCtx),
|
|
273
|
+
body: input
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
export { CustomerRefreshRegistry, DefaultTokenProvider, PaymentGatewayService, auth, resolveToken };
|
|
279
|
+
//# sourceMappingURL=chunk-PYLWZZC4.js.map
|
|
280
|
+
//# sourceMappingURL=chunk-PYLWZZC4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/auth.ts","../src/services/payment.ts"],"names":[],"mappings":"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","file":"chunk-PYLWZZC4.js","sourcesContent":["import type { ResolvedConfig, ServiceCredentials } from \"./config\";\nimport { EmporixAuthError, EmporixTimeoutError, EmporixNetworkError } from \"./errors\";\n\n/** Which token a call should use. */\nexport type AuthKind = \"service\" | \"customer\" | \"anonymous\" | \"raw\";\n\n/** Caller-supplied, per-call auth selector. Never stored on the client. */\nexport type AuthContext =\n | { kind: \"service\"; credentials?: string }\n | { kind: \"anonymous\" }\n | { kind: \"customer\"; token: string }\n | { kind: \"raw\"; token: string };\n\n/**\n * Supplies a fresh customer token when a `customer`-kind request 401s. The host\n * (e.g. EmporixProvider) implements this; the SDK never refreshes the\n * caller-owned customer token unless a refresher is registered.\n */\nexport interface CustomerTokenRefresher {\n /**\n * Called on a `customer`-kind 401. Receives the token that just failed;\n * returns a fresh customer token to retry with, or `null` to give up (the\n * 401 then propagates as EmporixAuthError).\n */\n refresh(expiredToken: string): Promise<string | null>;\n}\n\n/** An obtained anonymous storefront session. */\nexport interface AnonymousSession {\n accessToken: string;\n refreshToken: string;\n sessionId: string;\n expiresIn: number;\n}\n\n/**\n * Persistence callback for anonymous sessions. `read` is called once on the\n * first need for an anonymous token to bootstrap a possibly-existing session;\n * `write` is called after every successful login or refresh. `write(null)`\n * means the SDK is invalidating the stored session.\n */\nexport interface AnonymousSessionStore {\n read(): { refreshToken: string; sessionId: string } | null;\n write(session: { refreshToken: string; sessionId: string } | null): void;\n}\n\n/** Supplies SDK-managed tokens (service/custom + anonymous). May be user-injected. */\nexport interface TokenProvider {\n /** Service/custom client-credentials token for the named credential set. */\n getToken(credentialSet: string): Promise<string>;\n /** Cached anonymous storefront session (preserves sessionId across refreshes). */\n getAnonymousToken(): Promise<AnonymousSession>;\n /** Refresh the anonymous session, preserving sessionId. */\n refreshAnonymous?(): Promise<AnonymousSession>;\n /** Invalidate a cached SDK-managed token so the next call re-auths. */\n invalidate?(credentialSet: string): void;\n /** Invalidate the cached anonymous session entirely (next call re-logs in). */\n invalidateAnonymous?(): void;\n /**\n * Mark the anonymous access token stale but keep the refresh token, so the\n * next {@link getAnonymousToken} refreshes (preserving sessionId) rather\n * than starting a brand-new session.\n */\n expireAnonymous?(): void;\n /**\n * Install a persistence adapter for the anonymous session. The host (e.g.\n * `EmporixProvider`) calls this at construction so the SDK can bootstrap\n * an existing session and persist refreshes. Idempotent: a later call\n * replaces the previous adapter.\n */\n attachAnonymousStore?(store: AnonymousSessionStore): void;\n /**\n * Override the storefront context (currency/site/country) used for the next\n * anonymous login, then invalidate the current anonymous session so it\n * re-mints with the new context. No-op for providers without anon support.\n */\n setAnonymousContext?(ctx: {\n currency?: string;\n siteCode?: string;\n targetLocation?: string;\n }): void;\n /**\n * Subscribe to token-refresh events. Optional — implementations may no-op.\n * Returns an unsubscribe function. `DefaultTokenProvider` emits for the\n * anonymous-login / anonymous-refresh paths.\n */\n onRefresh?(\n listener: (event: { kind: \"anonymous\" | \"customer\"; success: boolean }) => void,\n ): () => void;\n}\n\n/** Tiny constructors for {@link AuthContext}. */\nexport const auth = {\n /** Service/custom credential set (default `backend`). */\n service: (credentials?: string): AuthContext =>\n credentials === undefined ? { kind: \"service\" } : { kind: \"service\", credentials },\n /** Cached anonymous storefront token. */\n anonymous: (): AuthContext => ({ kind: \"anonymous\" }),\n /** Caller-owned customer bearer token. */\n customer: (token: string): AuthContext => ({ kind: \"customer\", token }),\n /** Exact token, no transformation (SSO / token-exchange). */\n raw: (token: string): AuthContext => ({ kind: \"raw\", token }),\n};\n\n/** Resolves an {@link AuthContext} to a concrete bearer token. */\nexport async function resolveToken(ctx: AuthContext, provider: TokenProvider): Promise<string> {\n switch (ctx.kind) {\n case \"service\":\n return provider.getToken(ctx.credentials ?? \"backend\");\n case \"anonymous\":\n return (await provider.getAnonymousToken()).accessToken;\n case \"customer\":\n case \"raw\":\n return ctx.token;\n }\n}\n\n/**\n * Late-bindable, single-flight holder for an optional\n * {@link CustomerTokenRefresher}. Single-flight is required because Emporix\n * rotates the refresh token on each refresh — concurrent refreshes would\n * invalidate each other. Off (returns `null`) until a refresher is set.\n */\nexport class CustomerRefreshRegistry {\n private refresher: CustomerTokenRefresher | null = null;\n private inflight: Promise<string | null> | null = null;\n\n set(refresher: CustomerTokenRefresher | null): void {\n this.refresher = refresher;\n }\n\n get enabled(): boolean {\n return this.refresher !== null;\n }\n\n /** Concurrent callers share one in-flight refresh. */\n refresh(expiredToken: string): Promise<string | null> {\n if (!this.refresher) return Promise.resolve(null);\n if (this.inflight) return this.inflight;\n const p = Promise.resolve(this.refresher.refresh(expiredToken)).finally(() => {\n this.inflight = null;\n });\n this.inflight = p;\n return p;\n }\n}\n\ninterface CacheEntry {\n token: string;\n expiresAt: number;\n obtainedAt: number;\n}\n\n/** SDK-owned token provider: client-credentials service tokens + anonymous session. */\nexport class DefaultTokenProvider implements TokenProvider {\n private readonly serviceCache = new Map<string, CacheEntry>();\n private readonly serviceLocks = new Map<string, Promise<string>>();\n private anon: (AnonymousSession & { expiresAt: number }) | undefined;\n private anonLock: Promise<AnonymousSession> | undefined;\n private anonStore?: AnonymousSessionStore;\n private contextOverride:\n | { currency?: string; siteCode?: string; targetLocation?: string }\n | undefined;\n private readonly refreshListeners = new Set<\n (event: { kind: \"anonymous\" | \"customer\"; success: boolean }) => void\n >();\n\n constructor(private readonly cfg: ResolvedConfig) {}\n\n onRefresh(\n listener: (event: { kind: \"anonymous\" | \"customer\"; success: boolean }) => void,\n ): () => void {\n this.refreshListeners.add(listener);\n return () => {\n this.refreshListeners.delete(listener);\n };\n }\n\n private notifyRefresh(kind: \"anonymous\" | \"customer\", success: boolean): void {\n for (const l of this.refreshListeners) {\n try {\n l({ kind, success });\n } catch {\n // Never let a telemetry listener break the auth path.\n }\n }\n }\n\n attachAnonymousStore(store: AnonymousSessionStore): void {\n this.anonStore = store;\n // Bootstrap `this.anon` from the store if we don't have it yet. The seeded\n // session has expiresAt = 0 so the next getAnonymousToken triggers a refresh\n // (which preserves sessionId) instead of a fresh login.\n if (!this.anon) {\n const persisted = store.read();\n if (persisted) {\n this.anon = {\n accessToken: \"\",\n refreshToken: persisted.refreshToken,\n sessionId: persisted.sessionId,\n expiresIn: 0,\n expiresAt: 0,\n };\n }\n }\n }\n\n private creds(set: string): ServiceCredentials {\n if (set === \"backend\") {\n const b = this.cfg.credentials.backend;\n if (!b?.clientId || !b.secret) {\n throw new EmporixAuthError(\n \"A 'service' AuthContext was used but credentials.backend is not configured\",\n );\n }\n return b;\n }\n const c = this.cfg.credentials.custom?.[set];\n if (!c) throw new Error(`Unknown credential set \"${set}\"`);\n return c;\n }\n\n private fresh(e: CacheEntry | undefined): boolean {\n if (!e) return false;\n const now = Date.now();\n if (now - e.obtainedAt >= this.cfg.cache.maxLifetimeSeconds * 1000) return false;\n return now < e.expiresAt;\n }\n\n async getToken(set: string): Promise<string> {\n // Surface an unknown credential set before entering the cache/lock path.\n this.creds(set);\n const cached = this.serviceCache.get(set);\n if (this.fresh(cached)) return cached!.token;\n const inflight = this.serviceLocks.get(set);\n if (inflight) return inflight;\n const p = this.requestServiceToken(set).finally(() => this.serviceLocks.delete(set));\n this.serviceLocks.set(set, p);\n return p;\n }\n\n /**\n * fetch with the configured read timeout. Token endpoints sit in front of\n * single-flight locks — one hung call would otherwise block every request\n * on this credential set forever.\n */\n private async boundedFetch(url: string | URL, init: RequestInit = {}): Promise<Response> {\n const ms = this.cfg.timeouts?.readMs ?? 60_000;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), ms);\n try {\n return await fetch(url, { ...init, signal: controller.signal });\n } catch (err) {\n if ((err as Error).name === \"AbortError\") {\n throw new EmporixTimeoutError(`token request timed out after ${ms}ms`);\n }\n throw new EmporixNetworkError(`token request network failure: ${(err as Error).message}`);\n } finally {\n clearTimeout(timer);\n }\n }\n\n private async requestServiceToken(set: string): Promise<string> {\n const c = this.creds(set);\n const body = new URLSearchParams({\n grant_type: \"client_credentials\",\n client_id: c.clientId,\n client_secret: c.secret,\n });\n if (c.scope) body.set(\"scope\", c.scope);\n const res = await this.boundedFetch(`${this.cfg.host}/oauth/token`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body,\n });\n const json = (await res.json().catch(() => ({}))) as Record<string, unknown>;\n if (!res.ok) {\n throw new EmporixAuthError(`Token request failed for \"${set}\"`, res.status, json);\n }\n const obtainedAt = Date.now();\n const ttl = Number((json.expires_in as number | undefined) ?? 3600);\n this.serviceCache.set(set, {\n token: json.access_token as string,\n obtainedAt,\n expiresAt: obtainedAt + (ttl - this.cfg.cache.expirationBufferSeconds) * 1000,\n });\n return this.serviceCache.get(set)!.token;\n }\n\n invalidate(set: string): void {\n this.serviceCache.delete(set);\n }\n\n private anonFresh(): boolean {\n return !!this.anon && Date.now() < this.anon.expiresAt;\n }\n\n async getAnonymousToken(): Promise<AnonymousSession> {\n if (this.anonFresh()) return this.stripExpiry(this.anon!);\n if (this.anonLock) return this.anonLock;\n // Token expired but a refresh token survives → refresh to keep the same\n // sessionId; only fall back to a brand-new login if the refresh fails.\n const canRefresh = !!this.anon?.refreshToken;\n const obtain = canRefresh\n ? this.fetchAnonymous(\"refresh\").catch(() => this.fetchAnonymous(\"login\"))\n : this.fetchAnonymous(\"login\");\n const p = obtain.finally(() => {\n this.anonLock = undefined;\n });\n this.anonLock = p;\n return p;\n }\n\n /** Refreshes the anonymous session, preserving its sessionId. */\n async refreshAnonymous(): Promise<AnonymousSession> {\n if (!this.anon) return this.getAnonymousToken();\n return this.fetchAnonymous(\"refresh\");\n }\n\n invalidateAnonymous(): void {\n this.anon = undefined;\n this.anonStore?.write(null);\n }\n\n setAnonymousContext(ctx: {\n currency?: string;\n siteCode?: string;\n targetLocation?: string;\n }): void {\n const base = this.contextOverride ?? this.cfg.credentials.storefront?.context ?? {};\n this.contextOverride = { ...base, ...ctx };\n this.invalidateAnonymous();\n }\n\n /** Force a stale access token while keeping the refresh token + sessionId. */\n expireAnonymous(): void {\n if (this.anon) this.anon = { ...this.anon, expiresAt: 0 };\n }\n\n private stripExpiry(s: AnonymousSession & { expiresAt: number }): AnonymousSession {\n const { expiresAt: _expiresAt, ...rest } = s;\n return rest;\n }\n\n private async fetchAnonymous(mode: \"login\" | \"refresh\"): Promise<AnonymousSession> {\n const sf = this.cfg.credentials.storefront;\n if (!sf?.clientId) {\n throw new Error(\"credentials.storefront.clientId is required for anonymous tokens\");\n }\n const url = new URL(`${this.cfg.host}/customerlogin/auth/anonymous/${mode}`);\n url.searchParams.set(\"tenant\", this.cfg.tenant);\n url.searchParams.set(\"client_id\", sf.clientId);\n // Context is the runtime override (set via setAnonymousContext) if present,\n // else the config-fixed context.\n const c = this.contextOverride ?? sf.context;\n if (c?.currency) url.searchParams.set(\"currency\", c.currency);\n if (c?.siteCode) url.searchParams.set(\"siteCode\", c.siteCode);\n if (c?.targetLocation) url.searchParams.set(\"targetLocation\", c.targetLocation);\n if (mode === \"refresh\" && this.anon) {\n url.searchParams.set(\"refresh_token\", this.anon.refreshToken);\n }\n try {\n const res = await this.boundedFetch(url, { method: \"GET\" });\n const json = (await res.json().catch(() => ({}))) as Record<string, unknown>;\n if (!res.ok) {\n this.notifyRefresh(\"anonymous\", false);\n throw new EmporixAuthError(`Anonymous token ${mode} failed`, res.status, json);\n }\n const obtainedAt = Date.now();\n this.anon = {\n accessToken: json.access_token as string,\n refreshToken: json.refresh_token as string,\n sessionId: json.sessionId as string,\n expiresIn: json.expires_in as number,\n expiresAt:\n obtainedAt +\n ((json.expires_in as number) - this.cfg.cache.expirationBufferSeconds) * 1000,\n };\n this.anonStore?.write({\n refreshToken: this.anon.refreshToken,\n sessionId: this.anon.sessionId,\n });\n this.notifyRefresh(\"anonymous\", true);\n return this.stripExpiry(this.anon);\n } catch (err) {\n // Re-throw EmporixAuthError as-is; for non-Emporix errors (network), also notify.\n if (!(err instanceof EmporixAuthError)) {\n this.notifyRefresh(\"anonymous\", false);\n }\n throw err;\n }\n }\n}\n// Customer-token refreshes happen via client.customers.refresh() and don't\n// route through this TokenProvider — only the anonymous flow notifies.\n// React-side useCustomerSession.refresh emits its own telemetry event in a\n// follow-up if needed.\n","import type { ClientContext } from \"../core/context\";\nimport { auth, type AuthContext } from \"../core/auth\";\nimport { requireCustomer } from \"../core/require-customer\";\nimport type {\n PaymentModeFrontendResponse,\n AuthorizePaymentRequest,\n} from \"../generated/payment\";\n\nconst ANON: AuthContext = auth.anonymous();\n\n/** A frontend payment mode (generated). */\nexport type PaymentMode = PaymentModeFrontendResponse;\n\n/** Post-checkout authorize request (generated; caller sends the exact wire shape). */\nexport type AuthorizePaymentInput = AuthorizePaymentRequest;\n\n/** Post-checkout authorize result. */\nexport interface AuthorizePaymentResult {\n successful: boolean;\n paymentTransactionId?: string;\n authorizationToken?: string;\n requiresExternalPayment?: boolean;\n externalPaymentRedirectURL?: string;\n externalPaymentHttpMethod?: string;\n [k: string]: unknown;\n}\n\n/** Payment-Gateway: list frontend payment modes, authorize deferred payments. */\nexport class PaymentGatewayService {\n static readonly channel = \"payment\" as const;\n constructor(private readonly ctx: ClientContext) {}\n\n /**\n * Lists configured frontend payment modes. The endpoint requires a bearer\n * token but no customer scope (\"No scope required\"), so it defaults to an\n * anonymous context and works for guests and logged-in customers alike.\n */\n async listPaymentModes(authCtx: AuthContext = ANON): Promise<PaymentMode[]> {\n return this.ctx.http.request<PaymentMode[]>({\n method: \"GET\",\n path: `/payment-gateway/${this.ctx.tenant}/paymentmodes/frontend`,\n auth: authCtx,\n });\n }\n\n /** Authorizes a post-checkout (deferred) payment for an existing order. */\n async authorize(\n input: AuthorizePaymentInput,\n authCtx?: AuthContext,\n ): Promise<AuthorizePaymentResult> {\n return this.ctx.http.request<AuthorizePaymentResult>({\n method: \"POST\",\n path: `/payment-gateway/${this.ctx.tenant}/payment/frontend/authorize`,\n auth: requireCustomer(authCtx),\n body: input,\n });\n }\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// src/core/query.ts
|
|
2
|
+
function resolveQuery(q, cap) {
|
|
3
|
+
if (typeof q === "string") return q;
|
|
4
|
+
if (q.usesCompound === true && !cap.compoundLogicalQuery) {
|
|
5
|
+
throw new Error(
|
|
6
|
+
"This filter uses or()/compoundLogicalQuery, which the target service does not support. Combine conditions with and() (space-separated AND) instead."
|
|
7
|
+
);
|
|
8
|
+
}
|
|
9
|
+
return q.toString();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export { resolveQuery };
|
|
13
|
+
//# sourceMappingURL=chunk-S5HEIQDK.js.map
|
|
14
|
+
//# sourceMappingURL=chunk-S5HEIQDK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/query.ts"],"names":[],"mappings":";AA4BO,SAAS,YAAA,CAAa,GAAa,GAAA,EAA8B;AACtE,EAAA,IAAI,OAAO,CAAA,KAAM,QAAA,EAAU,OAAO,CAAA;AAClC,EAAA,IAAI,CAAA,CAAE,YAAA,KAAiB,IAAA,IAAQ,CAAC,IAAI,oBAAA,EAAsB;AACxD,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KAEF;AAAA,EACF;AACA,EAAA,OAAO,EAAE,QAAA,EAAS;AACpB","file":"chunk-S5HEIQDK.js","sourcesContent":["/**\n * A built query filter — structurally matched, NOT imported, so the SDK stays\n * decoupled from `@viu/emporix-mixins` (which lists the SDK as an optional\n * peer; a real import would be circular). `@viu/emporix-mixins`' `MixinFilter<E>`\n * satisfies this shape.\n */\nexport interface BuiltQuery<E extends string = string> {\n toString(): string;\n readonly usesCompound?: boolean;\n /** Phantom entity tag — gates which service a filter may be passed to. */\n readonly __entity?: E;\n}\n\n/** A `q` value a service method accepts: a raw DSL string or a built filter for entity `E`. */\nexport type QueryFor<E extends string = string> = string | BuiltQuery<E>;\n\n/** Per-service capability flags consulted by {@link resolveQuery}. */\nexport interface QueryCapability {\n /** Whether the target service supports the `compoundLogicalQuery` (OR) operator. */\n compoundLogicalQuery: boolean;\n}\n\n/**\n * Normalizes a `string | BuiltQuery` into a `q` string and enforces the\n * `compoundLogicalQuery` capability gate: an `or()`-built filter passed to a\n * service that does not support it throws rather than silently producing a\n * query the backend cannot execute.\n */\nexport function resolveQuery(q: QueryFor, cap: QueryCapability): string {\n if (typeof q === \"string\") return q;\n if (q.usesCompound === true && !cap.compoundLogicalQuery) {\n throw new Error(\n \"This filter uses or()/compoundLogicalQuery, which the target service does not support. \" +\n \"Combine conditions with and() (space-separated AND) instead.\",\n );\n }\n return q.toString();\n}\n"]}
|
package/dist/index.cjs
CHANGED
|
@@ -783,7 +783,7 @@ var HttpClient = class {
|
|
|
783
783
|
};
|
|
784
784
|
|
|
785
785
|
// package.json
|
|
786
|
-
var version = "2.
|
|
786
|
+
var version = "2.18.0";
|
|
787
787
|
|
|
788
788
|
// src/version.ts
|
|
789
789
|
var SDK_VERSION = version;
|
|
@@ -1071,6 +1071,17 @@ async function* iterateAll(fetchPage, start = 1) {
|
|
|
1071
1071
|
}
|
|
1072
1072
|
}
|
|
1073
1073
|
|
|
1074
|
+
// src/core/query.ts
|
|
1075
|
+
function resolveQuery(q, cap) {
|
|
1076
|
+
if (typeof q === "string") return q;
|
|
1077
|
+
if (q.usesCompound === true && !cap.compoundLogicalQuery) {
|
|
1078
|
+
throw new Error(
|
|
1079
|
+
"This filter uses or()/compoundLogicalQuery, which the target service does not support. Combine conditions with and() (space-separated AND) instead."
|
|
1080
|
+
);
|
|
1081
|
+
}
|
|
1082
|
+
return q.toString();
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1074
1085
|
// src/services/product.ts
|
|
1075
1086
|
var ANON = { kind: "anonymous" };
|
|
1076
1087
|
var ProductService = class {
|
|
@@ -1116,14 +1127,19 @@ var ProductService = class {
|
|
|
1116
1127
|
const pageSize = params.pageSize ?? 50;
|
|
1117
1128
|
return iterateAll((pageNumber) => this.list({ pageNumber, pageSize }, auth2));
|
|
1118
1129
|
}
|
|
1119
|
-
/**
|
|
1130
|
+
/**
|
|
1131
|
+
* Searches products by a `q` filter — a raw Emporix DSL string or a built
|
|
1132
|
+
* filter (e.g. `@viu/emporix-mixins`' `mixinQuery(...)`). Product supports
|
|
1133
|
+
* `compoundLogicalQuery`, so `or()` filters are allowed.
|
|
1134
|
+
*/
|
|
1120
1135
|
async search(query, params = {}, auth2 = ANON) {
|
|
1136
|
+
const q = resolveQuery(query, { compoundLogicalQuery: true });
|
|
1121
1137
|
const pageNumber = params.pageNumber ?? 1;
|
|
1122
1138
|
const pageSize = params.pageSize ?? 50;
|
|
1123
1139
|
const items = await this.ctx.http.request({
|
|
1124
1140
|
method: "GET",
|
|
1125
1141
|
path: `/product/${this.ctx.tenant}/products`,
|
|
1126
|
-
query: { q
|
|
1142
|
+
query: { q, pageNumber, pageSize },
|
|
1127
1143
|
auth: auth2
|
|
1128
1144
|
});
|
|
1129
1145
|
return { items, pageNumber, pageSize, hasNextPage: items.length === pageSize };
|
|
@@ -1261,6 +1277,23 @@ var CategoryService = class {
|
|
|
1261
1277
|
});
|
|
1262
1278
|
return { items, pageNumber, pageSize, hasNextPage: items.length === pageSize };
|
|
1263
1279
|
}
|
|
1280
|
+
/**
|
|
1281
|
+
* Searches categories by a `q` filter — a raw Emporix DSL string or a built
|
|
1282
|
+
* filter (e.g. `@viu/emporix-mixins`' `mixinQuery(...)`). Category does not
|
|
1283
|
+
* support `compoundLogicalQuery`, so `or()` filters are rejected.
|
|
1284
|
+
*/
|
|
1285
|
+
async search(query, params = {}, auth2 = ANON2) {
|
|
1286
|
+
const q = resolveQuery(query, { compoundLogicalQuery: false });
|
|
1287
|
+
const pageNumber = params.pageNumber ?? 1;
|
|
1288
|
+
const pageSize = params.pageSize ?? 50;
|
|
1289
|
+
const items = await this.ctx.http.request({
|
|
1290
|
+
method: "GET",
|
|
1291
|
+
path: `/category/${this.ctx.tenant}/categories`,
|
|
1292
|
+
query: { q, pageNumber, pageSize },
|
|
1293
|
+
auth: auth2
|
|
1294
|
+
});
|
|
1295
|
+
return { items, pageNumber, pageSize, hasNextPage: items.length === pageSize };
|
|
1296
|
+
}
|
|
1264
1297
|
/** Async-iterates every category across pages. */
|
|
1265
1298
|
listAll(params = {}, auth2 = ANON2) {
|
|
1266
1299
|
const pageSize = params.pageSize ?? 50;
|
|
@@ -1585,26 +1618,31 @@ var CheckoutService = class {
|
|
|
1585
1618
|
};
|
|
1586
1619
|
|
|
1587
1620
|
// src/services/payment.ts
|
|
1621
|
+
var ANON3 = auth.anonymous();
|
|
1588
1622
|
var PaymentGatewayService = class {
|
|
1589
1623
|
constructor(ctx) {
|
|
1590
1624
|
this.ctx = ctx;
|
|
1591
1625
|
}
|
|
1592
1626
|
ctx;
|
|
1593
1627
|
static channel = "payment";
|
|
1594
|
-
/**
|
|
1595
|
-
|
|
1628
|
+
/**
|
|
1629
|
+
* Lists configured frontend payment modes. The endpoint requires a bearer
|
|
1630
|
+
* token but no customer scope ("No scope required"), so it defaults to an
|
|
1631
|
+
* anonymous context and works for guests and logged-in customers alike.
|
|
1632
|
+
*/
|
|
1633
|
+
async listPaymentModes(authCtx = ANON3) {
|
|
1596
1634
|
return this.ctx.http.request({
|
|
1597
1635
|
method: "GET",
|
|
1598
1636
|
path: `/payment-gateway/${this.ctx.tenant}/paymentmodes/frontend`,
|
|
1599
|
-
auth:
|
|
1637
|
+
auth: authCtx
|
|
1600
1638
|
});
|
|
1601
1639
|
}
|
|
1602
1640
|
/** Authorizes a post-checkout (deferred) payment for an existing order. */
|
|
1603
|
-
async authorize(input,
|
|
1641
|
+
async authorize(input, authCtx) {
|
|
1604
1642
|
return this.ctx.http.request({
|
|
1605
1643
|
method: "POST",
|
|
1606
1644
|
path: `/payment-gateway/${this.ctx.tenant}/payment/frontend/authorize`,
|
|
1607
|
-
auth: requireCustomer(
|
|
1645
|
+
auth: requireCustomer(authCtx),
|
|
1608
1646
|
body: input
|
|
1609
1647
|
});
|
|
1610
1648
|
}
|
|
@@ -1621,10 +1659,10 @@ function normalizeMatch(raw) {
|
|
|
1621
1659
|
};
|
|
1622
1660
|
return { ...base, itemId, itemRef };
|
|
1623
1661
|
}
|
|
1624
|
-
var
|
|
1662
|
+
var ANON4 = { kind: "anonymous" };
|
|
1625
1663
|
var SERVICE = { kind: "service" };
|
|
1626
1664
|
function requireContextAuth(auth2) {
|
|
1627
|
-
const a = auth2 ??
|
|
1665
|
+
const a = auth2 ?? ANON4;
|
|
1628
1666
|
if (a.kind === "anonymous" || a.kind === "customer" || a.kind === "raw") return a;
|
|
1629
1667
|
throw new EmporixAuthError(
|
|
1630
1668
|
"match-prices-by-context requires an anonymous, customer, or raw AuthContext"
|
|
@@ -2096,7 +2134,7 @@ var SegmentService = class {
|
|
|
2096
2134
|
};
|
|
2097
2135
|
|
|
2098
2136
|
// src/services/site.ts
|
|
2099
|
-
var
|
|
2137
|
+
var ANON5 = auth.anonymous();
|
|
2100
2138
|
var SiteService = class {
|
|
2101
2139
|
constructor(ctx) {
|
|
2102
2140
|
this.ctx = ctx;
|
|
@@ -2104,7 +2142,7 @@ var SiteService = class {
|
|
|
2104
2142
|
ctx;
|
|
2105
2143
|
static channel = "site";
|
|
2106
2144
|
/** Lists active sites. */
|
|
2107
|
-
async list(authCtx =
|
|
2145
|
+
async list(authCtx = ANON5) {
|
|
2108
2146
|
return this.ctx.http.request({
|
|
2109
2147
|
method: "GET",
|
|
2110
2148
|
path: `/site/${this.ctx.tenant}/sites`,
|
|
@@ -2112,7 +2150,7 @@ var SiteService = class {
|
|
|
2112
2150
|
});
|
|
2113
2151
|
}
|
|
2114
2152
|
/** Retrieves one site by code. */
|
|
2115
|
-
async get(code, authCtx =
|
|
2153
|
+
async get(code, authCtx = ANON5) {
|
|
2116
2154
|
return this.ctx.http.request({
|
|
2117
2155
|
method: "GET",
|
|
2118
2156
|
path: `/site/${this.ctx.tenant}/sites/${code}`,
|
|
@@ -2123,7 +2161,7 @@ var SiteService = class {
|
|
|
2123
2161
|
* Returns the tenant's default site (the one with `default: true`).
|
|
2124
2162
|
* Throws if no default is configured — a tenant should always have one.
|
|
2125
2163
|
*/
|
|
2126
|
-
async current(authCtx =
|
|
2164
|
+
async current(authCtx = ANON5) {
|
|
2127
2165
|
const sites = await this.list(authCtx);
|
|
2128
2166
|
const def = sites.find((s) => s.default);
|
|
2129
2167
|
if (!def) {
|
|
@@ -2136,7 +2174,7 @@ var SiteService = class {
|
|
|
2136
2174
|
};
|
|
2137
2175
|
|
|
2138
2176
|
// src/services/session-context.ts
|
|
2139
|
-
var
|
|
2177
|
+
var ANON6 = auth.anonymous();
|
|
2140
2178
|
var SessionContextService = class {
|
|
2141
2179
|
constructor(ctx) {
|
|
2142
2180
|
this.ctx = ctx;
|
|
@@ -2148,7 +2186,7 @@ var SessionContextService = class {
|
|
|
2148
2186
|
* 404 (no session exists yet — the session-context is created server-side
|
|
2149
2187
|
* only after the user creates a cart).
|
|
2150
2188
|
*/
|
|
2151
|
-
async get(authCtx =
|
|
2189
|
+
async get(authCtx = ANON6) {
|
|
2152
2190
|
try {
|
|
2153
2191
|
return await this.ctx.http.request({
|
|
2154
2192
|
method: "GET",
|
|
@@ -2166,7 +2204,7 @@ var SessionContextService = class {
|
|
|
2166
2204
|
* server returned 404 on the version-lookup GET, so there is nothing to
|
|
2167
2205
|
* update). Non-404 errors propagate.
|
|
2168
2206
|
*/
|
|
2169
|
-
async patch(input, authCtx =
|
|
2207
|
+
async patch(input, authCtx = ANON6) {
|
|
2170
2208
|
let version2 = input.version;
|
|
2171
2209
|
if (version2 === void 0) {
|
|
2172
2210
|
const current = await this.get(authCtx);
|
|
@@ -2431,6 +2469,9 @@ var OrdersService = class {
|
|
|
2431
2469
|
setIfDefined2(query, "status", opts.status);
|
|
2432
2470
|
setIfDefined2(query, "legalEntityId", opts.legalEntityId);
|
|
2433
2471
|
setIfDefined2(query, "siteCode", opts.siteCode);
|
|
2472
|
+
if (opts.q !== void 0) {
|
|
2473
|
+
setIfDefined2(query, "q", resolveQuery(opts.q, { compoundLogicalQuery: false }));
|
|
2474
|
+
}
|
|
2434
2475
|
const headers = this.saasHeader(opts.saasToken);
|
|
2435
2476
|
const items = await this.ctx.http.request({
|
|
2436
2477
|
method: "GET",
|
|
@@ -2501,7 +2542,7 @@ var SalesOrdersService = class {
|
|
|
2501
2542
|
};
|
|
2502
2543
|
|
|
2503
2544
|
// src/services/availability.ts
|
|
2504
|
-
var
|
|
2545
|
+
var ANON7 = { kind: "anonymous" };
|
|
2505
2546
|
var AvailabilityService = class {
|
|
2506
2547
|
constructor(ctx) {
|
|
2507
2548
|
this.ctx = ctx;
|
|
@@ -2512,7 +2553,7 @@ var AvailabilityService = class {
|
|
|
2512
2553
|
* Single product. Resolves the availability record, or — when
|
|
2513
2554
|
* `opts.defaultAvailableOnNotFound` is set — a default available record on 404.
|
|
2514
2555
|
*/
|
|
2515
|
-
async get(productId, siteCode, auth2 =
|
|
2556
|
+
async get(productId, siteCode, auth2 = ANON7, opts = {}) {
|
|
2516
2557
|
try {
|
|
2517
2558
|
return await this.ctx.http.request({
|
|
2518
2559
|
method: "GET",
|
|
@@ -2535,7 +2576,7 @@ var AvailabilityService = class {
|
|
|
2535
2576
|
* `opts.defaultAvailableOnNotFound` is set). The result preserves input order
|
|
2536
2577
|
* and length. An empty `productIds` resolves to `[]` without a request.
|
|
2537
2578
|
*/
|
|
2538
|
-
async getMany(productIds, siteCode, auth2 =
|
|
2579
|
+
async getMany(productIds, siteCode, auth2 = ANON7, opts = {}) {
|
|
2539
2580
|
if (productIds.length === 0) return [];
|
|
2540
2581
|
const found = await this.ctx.http.request({
|
|
2541
2582
|
method: "POST",
|
|
@@ -4946,13 +4987,14 @@ var VendorService = class {
|
|
|
4946
4987
|
auth: auth2
|
|
4947
4988
|
});
|
|
4948
4989
|
}
|
|
4949
|
-
/** Search vendors (`POST /vendors/search`). */
|
|
4990
|
+
/** Search vendors (`POST /vendors/search`). A built filter in `q` is resolved to a string. */
|
|
4950
4991
|
async searchVendors(query, auth2 = SERVICE24) {
|
|
4992
|
+
const body = query.q !== void 0 ? { ...query, q: resolveQuery(query.q, { compoundLogicalQuery: false }) } : query;
|
|
4951
4993
|
return this.ctx.http.request({
|
|
4952
4994
|
method: "POST",
|
|
4953
4995
|
path: `${this.base()}/vendors/search`,
|
|
4954
4996
|
auth: auth2,
|
|
4955
|
-
body
|
|
4997
|
+
body
|
|
4956
4998
|
});
|
|
4957
4999
|
}
|
|
4958
5000
|
/** Create a vendor. */
|
|
@@ -5136,9 +5178,10 @@ var CustomerAdminService = class {
|
|
|
5136
5178
|
...Object.keys(query).length ? { query } : {}
|
|
5137
5179
|
});
|
|
5138
5180
|
}
|
|
5139
|
-
/** Search customers (`POST /customers/search`). */
|
|
5181
|
+
/** Search customers (`POST /customers/search`). A built filter in `q` is resolved to a string. */
|
|
5140
5182
|
async searchCustomers(query, auth2 = SERVICE26) {
|
|
5141
|
-
|
|
5183
|
+
const body = query.q !== void 0 ? { ...query, q: resolveQuery(query.q, { compoundLogicalQuery: false }) } : query;
|
|
5184
|
+
return this.ctx.http.request({ method: "POST", path: `${this.base()}/search`, auth: auth2, body });
|
|
5142
5185
|
}
|
|
5143
5186
|
/** Retrieve a customer profile by number. */
|
|
5144
5187
|
async getCustomer(customerNumber, auth2 = SERVICE26) {
|
|
@@ -5540,6 +5583,7 @@ exports.errorFromResponse = errorFromResponse;
|
|
|
5540
5583
|
exports.iterateAll = iterateAll;
|
|
5541
5584
|
exports.productIdFromYrn = productIdFromYrn;
|
|
5542
5585
|
exports.redact = redact;
|
|
5586
|
+
exports.resolveQuery = resolveQuery;
|
|
5543
5587
|
exports.resolveToken = resolveToken;
|
|
5544
5588
|
exports.validateConfig = validateConfig;
|
|
5545
5589
|
//# sourceMappingURL=index.cjs.map
|