@viu/emporix-sdk-react 2.13.0 → 2.14.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 +22 -0
- package/dist/{chunk-KOVOQJ5F.js → chunk-7F5EB5XY.js} +512 -196
- package/dist/chunk-7F5EB5XY.js.map +1 -0
- package/dist/{chunk-4YDWCA7A.js → chunk-CZDVH3WH.js} +165 -107
- package/dist/chunk-CZDVH3WH.js.map +1 -0
- package/dist/{chunk-VMDBYVWG.js → chunk-ZNLAYNF5.js} +11 -4
- package/dist/chunk-ZNLAYNF5.js.map +1 -0
- package/dist/hooks.cjs +601 -315
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.js +185 -4
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +781 -436
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -4
- package/dist/index.d.ts +38 -4
- package/dist/index.js +240 -8
- package/dist/index.js.map +1 -1
- package/dist/provider.cjs +187 -123
- package/dist/provider.cjs.map +1 -1
- package/dist/provider.js +12 -3
- package/dist/provider.js.map +1 -1
- package/dist/ssr.cjs +36 -5
- package/dist/ssr.cjs.map +1 -1
- package/dist/ssr.d.cts +22 -6
- package/dist/ssr.d.ts +22 -6
- package/dist/ssr.js +54 -1
- package/dist/ssr.js.map +1 -1
- package/dist/storage.cjs +39 -9
- package/dist/storage.cjs.map +1 -1
- package/dist/storage.d.cts +5 -1
- package/dist/storage.d.ts +5 -1
- package/dist/storage.js +15 -2
- package/dist/storage.js.map +1 -1
- package/package.json +5 -4
- package/dist/chunk-4YDWCA7A.js.map +0 -1
- package/dist/chunk-KOVOQJ5F.js.map +0 -1
- package/dist/chunk-TIS4BKHK.js +0 -25
- package/dist/chunk-TIS4BKHK.js.map +0 -1
- package/dist/chunk-VMDBYVWG.js.map +0 -1
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import { jsx } from 'react/jsx-runtime';
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
createMemoryStorage
|
|
4
|
+
} from "./chunk-ZNLAYNF5.js";
|
|
6
5
|
|
|
6
|
+
// src/provider.tsx
|
|
7
|
+
import { createContext as createContext3, useCallback as useCallback2, useContext as useContext3, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
|
|
8
|
+
import { QueryClient, QueryClientProvider, useQueryClient as useQueryClient2 } from "@tanstack/react-query";
|
|
9
|
+
import { auth as auth2 } from "@viu/emporix-sdk";
|
|
10
|
+
|
|
11
|
+
// src/telemetry.ts
|
|
12
|
+
import { createContext, useContext } from "react";
|
|
7
13
|
var EmporixTelemetryContext = createContext(null);
|
|
8
14
|
function useEmporixTelemetry() {
|
|
9
15
|
const ctx = useContext(EmporixTelemetryContext);
|
|
@@ -12,6 +18,20 @@ function useEmporixTelemetry() {
|
|
|
12
18
|
}
|
|
13
19
|
return ctx;
|
|
14
20
|
}
|
|
21
|
+
|
|
22
|
+
// src/company-context.tsx
|
|
23
|
+
import {
|
|
24
|
+
createContext as createContext2,
|
|
25
|
+
useCallback,
|
|
26
|
+
useContext as useContext2,
|
|
27
|
+
useEffect,
|
|
28
|
+
useMemo,
|
|
29
|
+
useRef,
|
|
30
|
+
useState
|
|
31
|
+
} from "react";
|
|
32
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
33
|
+
import { auth } from "@viu/emporix-sdk";
|
|
34
|
+
import { jsx } from "react/jsx-runtime";
|
|
15
35
|
var NULL_CTX = {
|
|
16
36
|
activeCompany: null,
|
|
17
37
|
myCompanies: [],
|
|
@@ -24,9 +44,9 @@ var NULL_CTX = {
|
|
|
24
44
|
refetchMyCompanies: async () => {
|
|
25
45
|
}
|
|
26
46
|
};
|
|
27
|
-
var EmporixCompanyContext =
|
|
47
|
+
var EmporixCompanyContext = createContext2(NULL_CTX);
|
|
28
48
|
function useActiveCompany() {
|
|
29
|
-
return
|
|
49
|
+
return useContext2(EmporixCompanyContext);
|
|
30
50
|
}
|
|
31
51
|
function CompanyContextProvider({
|
|
32
52
|
client,
|
|
@@ -41,74 +61,94 @@ function CompanyContextProvider({
|
|
|
41
61
|
const [status, setStatus] = useState("idle");
|
|
42
62
|
const [error, setError] = useState(null);
|
|
43
63
|
const activeRef = useRef(null);
|
|
44
|
-
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
activeRef.current = activeCompany;
|
|
66
|
+
}, [activeCompany]);
|
|
67
|
+
const switchChain = useRef(Promise.resolve());
|
|
45
68
|
const switchTo = useCallback(
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
(
|
|
67
|
-
|
|
69
|
+
(target) => {
|
|
70
|
+
const run = async () => {
|
|
71
|
+
const start = Date.now();
|
|
72
|
+
const from = activeRef.current?.id ?? null;
|
|
73
|
+
const refreshToken = storage.getRefreshToken();
|
|
74
|
+
const token = storage.getCustomerToken();
|
|
75
|
+
if (!refreshToken || !token) {
|
|
76
|
+
setActive(target);
|
|
77
|
+
storage.setActiveLegalEntityId(target?.id ?? null);
|
|
78
|
+
} else {
|
|
79
|
+
const next = await client.customers.refresh({
|
|
80
|
+
refreshToken,
|
|
81
|
+
...target ? { legalEntityId: target.id } : {}
|
|
82
|
+
});
|
|
83
|
+
storage.setCustomerToken(next.customerToken);
|
|
84
|
+
if (next.refreshToken) storage.setRefreshToken(next.refreshToken);
|
|
85
|
+
storage.setCartId(null);
|
|
86
|
+
storage.setActiveLegalEntityId(target?.id ?? null);
|
|
87
|
+
setActive(target);
|
|
88
|
+
qc.invalidateQueries({
|
|
89
|
+
predicate: (q) => Array.isArray(q.queryKey) && q.queryKey.some(
|
|
90
|
+
(k) => k === "cart" || k === "companies" || k === "customer" || k === from || target !== null && k === target.id
|
|
91
|
+
)
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
emit({
|
|
95
|
+
type: "company:switched",
|
|
96
|
+
from,
|
|
97
|
+
to: target?.id ?? null,
|
|
98
|
+
durationMs: Date.now() - start
|
|
68
99
|
});
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
from,
|
|
73
|
-
to: target?.id ?? null,
|
|
74
|
-
durationMs: Date.now() - start
|
|
100
|
+
};
|
|
101
|
+
const task = switchChain.current.then(run, run);
|
|
102
|
+
switchChain.current = task.catch(() => {
|
|
75
103
|
});
|
|
104
|
+
return task;
|
|
76
105
|
},
|
|
77
106
|
[client, storage, qc, emit]
|
|
78
107
|
);
|
|
79
|
-
const load = useCallback(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
setStatus("loading");
|
|
88
|
-
try {
|
|
89
|
-
const companies = await client.companies.listMine(auth.customer(token));
|
|
90
|
-
setMyCompanies(companies);
|
|
91
|
-
const persisted = initialActiveLegalEntityId ?? storage.getActiveLegalEntityId();
|
|
92
|
-
const matched = persisted ? companies.find((c) => c.id === persisted) ?? null : null;
|
|
93
|
-
if (matched) {
|
|
94
|
-
setActive(matched);
|
|
95
|
-
if (storage.getActiveLegalEntityId() !== matched.id) {
|
|
96
|
-
storage.setActiveLegalEntityId(matched.id ?? null);
|
|
97
|
-
}
|
|
98
|
-
} else if (companies.length === 1) {
|
|
99
|
-
await switchTo(companies[0] ?? null);
|
|
100
|
-
} else {
|
|
108
|
+
const load = useCallback(
|
|
109
|
+
async (signal) => {
|
|
110
|
+
const token = storage.getCustomerToken();
|
|
111
|
+
if (!token) {
|
|
112
|
+
if (signal?.cancelled) return;
|
|
113
|
+
setMyCompanies([]);
|
|
101
114
|
setActive(null);
|
|
102
|
-
|
|
115
|
+
setStatus("idle");
|
|
116
|
+
return;
|
|
103
117
|
}
|
|
104
|
-
setStatus("
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
118
|
+
setStatus("loading");
|
|
119
|
+
try {
|
|
120
|
+
const companies = await client.companies.listMine(auth.customer(token));
|
|
121
|
+
if (signal?.cancelled) return;
|
|
122
|
+
setMyCompanies(companies);
|
|
123
|
+
const persisted = initialActiveLegalEntityId ?? storage.getActiveLegalEntityId();
|
|
124
|
+
const matched = persisted ? companies.find((c) => c.id === persisted) ?? null : null;
|
|
125
|
+
if (matched) {
|
|
126
|
+
setActive(matched);
|
|
127
|
+
if (storage.getActiveLegalEntityId() !== matched.id) {
|
|
128
|
+
storage.setActiveLegalEntityId(matched.id ?? null);
|
|
129
|
+
}
|
|
130
|
+
} else if (companies.length === 1) {
|
|
131
|
+
await switchTo(companies[0] ?? null);
|
|
132
|
+
} else {
|
|
133
|
+
setActive(null);
|
|
134
|
+
if (persisted && !matched) storage.setActiveLegalEntityId(null);
|
|
135
|
+
}
|
|
136
|
+
if (signal?.cancelled) return;
|
|
137
|
+
setStatus("idle");
|
|
138
|
+
} catch (e) {
|
|
139
|
+
if (signal?.cancelled) return;
|
|
140
|
+
setError(e);
|
|
141
|
+
setStatus("error");
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
[client, storage, initialActiveLegalEntityId, switchTo]
|
|
145
|
+
);
|
|
110
146
|
useEffect(() => {
|
|
111
|
-
|
|
147
|
+
const signal = { cancelled: false };
|
|
148
|
+
void load(signal);
|
|
149
|
+
return () => {
|
|
150
|
+
signal.cancelled = true;
|
|
151
|
+
};
|
|
112
152
|
}, [load]);
|
|
113
153
|
useEffect(() => {
|
|
114
154
|
let prev = storage.getCustomerToken();
|
|
@@ -153,8 +193,11 @@ function CompanyContextProvider({
|
|
|
153
193
|
}, [activeCompany, myCompanies, status, error, setActiveCompany, load]);
|
|
154
194
|
return /* @__PURE__ */ jsx(EmporixCompanyContext.Provider, { value, children });
|
|
155
195
|
}
|
|
156
|
-
|
|
157
|
-
|
|
196
|
+
|
|
197
|
+
// src/provider.tsx
|
|
198
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
199
|
+
var EmporixContext = createContext3(null);
|
|
200
|
+
var EmporixSiteContext = createContext3(null);
|
|
158
201
|
var DEFAULT_QUERY_OPTIONS = {
|
|
159
202
|
staleTime: 3e4,
|
|
160
203
|
refetchOnWindowFocus: false,
|
|
@@ -173,27 +216,35 @@ function EmporixProvider({
|
|
|
173
216
|
onCustomerSessionExpired,
|
|
174
217
|
children
|
|
175
218
|
}) {
|
|
176
|
-
const value =
|
|
219
|
+
const value = useMemo2(() => {
|
|
177
220
|
const s = storage ?? createMemoryStorage(
|
|
178
221
|
initialCustomerToken !== void 0 ? { initial: initialCustomerToken } : {}
|
|
179
222
|
);
|
|
180
|
-
if (initialCustomerToken && storage && storage.getCustomerToken() === null) {
|
|
181
|
-
storage.setCustomerToken(initialCustomerToken);
|
|
182
|
-
}
|
|
183
223
|
return { client, storage: s };
|
|
184
224
|
}, [client, storage, initialCustomerToken]);
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
)
|
|
189
|
-
|
|
225
|
+
const [fallbackQc] = useState2(() => new QueryClient());
|
|
226
|
+
const qc = queryClient ?? fallbackQc;
|
|
227
|
+
const defaultsRef = useRef2(null);
|
|
228
|
+
if (defaultsRef.current !== qc) {
|
|
229
|
+
qc.setQueryDefaults(["emporix"], {
|
|
230
|
+
...DEFAULT_QUERY_OPTIONS,
|
|
231
|
+
...qc.getDefaultOptions().queries,
|
|
232
|
+
...qc.getQueryDefaults(["emporix"])
|
|
233
|
+
});
|
|
234
|
+
defaultsRef.current = qc;
|
|
235
|
+
}
|
|
236
|
+
const wiredRef = useRef2(null);
|
|
237
|
+
if (wiredRef.current?.client !== client || wiredRef.current?.storage !== value.storage) {
|
|
190
238
|
client.tokenProvider.attachAnonymousStore?.({
|
|
191
239
|
read: () => value.storage.getAnonymousSession(),
|
|
192
240
|
write: (s) => value.storage.setAnonymousSession(s)
|
|
193
241
|
});
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
242
|
+
if (initialCustomerToken && storage && storage.getCustomerToken() === null) {
|
|
243
|
+
storage.setCustomerToken(initialCustomerToken);
|
|
244
|
+
}
|
|
245
|
+
wiredRef.current = { client, storage: value.storage };
|
|
246
|
+
}
|
|
247
|
+
const safeEmit = useCallback2(
|
|
197
248
|
(event) => {
|
|
198
249
|
if (!onTelemetry) return;
|
|
199
250
|
try {
|
|
@@ -204,8 +255,8 @@ function EmporixProvider({
|
|
|
204
255
|
},
|
|
205
256
|
[onTelemetry]
|
|
206
257
|
);
|
|
207
|
-
const telemetryValue =
|
|
208
|
-
|
|
258
|
+
const telemetryValue = useMemo2(() => ({ emit: safeEmit }), [safeEmit]);
|
|
259
|
+
useEffect2(() => {
|
|
209
260
|
if (!onTelemetry) return;
|
|
210
261
|
const startedAt = /* @__PURE__ */ new Map();
|
|
211
262
|
const unsubQuery = qc.getQueryCache().subscribe((event) => {
|
|
@@ -284,7 +335,7 @@ function EmporixProvider({
|
|
|
284
335
|
unsubStorage?.();
|
|
285
336
|
};
|
|
286
337
|
}, [qc, onTelemetry, client, value.storage, safeEmit]);
|
|
287
|
-
|
|
338
|
+
useEffect2(() => {
|
|
288
339
|
if (!autoRefreshCustomerToken) return;
|
|
289
340
|
const storage2 = value.storage;
|
|
290
341
|
client.setCustomerTokenRefresher({
|
|
@@ -314,14 +365,14 @@ function EmporixProvider({
|
|
|
314
365
|
});
|
|
315
366
|
return () => client.setCustomerTokenRefresher(null);
|
|
316
367
|
}, [autoRefreshCustomerToken, client, value.storage, safeEmit, onCustomerSessionExpired]);
|
|
317
|
-
return /* @__PURE__ */
|
|
368
|
+
return /* @__PURE__ */ jsx2(EmporixContext.Provider, { value, children: /* @__PURE__ */ jsx2(EmporixTelemetryContext.Provider, { value: telemetryValue, children: /* @__PURE__ */ jsx2(QueryClientProvider, { client: qc, children: /* @__PURE__ */ jsx2(
|
|
318
369
|
SiteContextProvider,
|
|
319
370
|
{
|
|
320
371
|
client,
|
|
321
372
|
storage: value.storage,
|
|
322
373
|
...initialSiteCode !== void 0 ? { initialSiteCode } : {},
|
|
323
374
|
...initialLanguage !== void 0 ? { initialLanguage } : {},
|
|
324
|
-
children: /* @__PURE__ */
|
|
375
|
+
children: /* @__PURE__ */ jsx2(
|
|
325
376
|
CompanyContextProvider,
|
|
326
377
|
{
|
|
327
378
|
client,
|
|
@@ -340,30 +391,30 @@ function SiteContextProvider({
|
|
|
340
391
|
initialLanguage,
|
|
341
392
|
children
|
|
342
393
|
}) {
|
|
343
|
-
const qc =
|
|
344
|
-
const [siteCode, setSiteCodeState] =
|
|
394
|
+
const qc = useQueryClient2();
|
|
395
|
+
const [siteCode, setSiteCodeState] = useState2(() => {
|
|
345
396
|
if (initialSiteCode !== void 0) return initialSiteCode;
|
|
346
397
|
const fromStorage = storage.getSiteCode();
|
|
347
398
|
if (fromStorage !== null) return fromStorage;
|
|
348
399
|
return client.config?.credentials?.storefront?.context?.siteCode ?? null;
|
|
349
400
|
});
|
|
350
|
-
const [currency, setCurrencyState] =
|
|
401
|
+
const [currency, setCurrencyState] = useState2(
|
|
351
402
|
() => client.config?.credentials?.storefront?.context?.currency ?? null
|
|
352
403
|
);
|
|
353
|
-
const [language, setLanguageState] =
|
|
404
|
+
const [language, setLanguageState] = useState2(() => {
|
|
354
405
|
if (initialLanguage !== void 0) return initialLanguage;
|
|
355
406
|
const fromStorage = storage.getLanguage();
|
|
356
407
|
if (fromStorage !== null) return fromStorage;
|
|
357
408
|
return client.config?.credentials?.storefront?.context?.language ?? null;
|
|
358
409
|
});
|
|
359
|
-
const [targetLocation, setTargetLocation] =
|
|
360
|
-
const [isSwitching, setIsSwitching] =
|
|
361
|
-
const [switchError, setSwitchError] =
|
|
362
|
-
|
|
410
|
+
const [targetLocation, setTargetLocation] = useState2(null);
|
|
411
|
+
const [isSwitching, setIsSwitching] = useState2(false);
|
|
412
|
+
const [switchError, setSwitchError] = useState2(null);
|
|
413
|
+
useEffect2(() => {
|
|
363
414
|
if (!siteCode || currency !== null && targetLocation !== null && language !== null) return;
|
|
364
415
|
let cancelled = false;
|
|
365
416
|
const token = storage.getCustomerToken();
|
|
366
|
-
const authCtx = token ?
|
|
417
|
+
const authCtx = token ? auth2.customer(token) : auth2.anonymous();
|
|
367
418
|
qc.fetchQuery({
|
|
368
419
|
queryKey: [
|
|
369
420
|
"emporix",
|
|
@@ -387,10 +438,10 @@ function SiteContextProvider({
|
|
|
387
438
|
cancelled = true;
|
|
388
439
|
};
|
|
389
440
|
}, [siteCode]);
|
|
390
|
-
|
|
441
|
+
useEffect2(() => {
|
|
391
442
|
if (language) client.setStorefrontContext({ language });
|
|
392
443
|
}, []);
|
|
393
|
-
const setSite =
|
|
444
|
+
const setSite = useCallback2(
|
|
394
445
|
async (code) => {
|
|
395
446
|
storage.setSiteCode(code);
|
|
396
447
|
storage.setCartId(null);
|
|
@@ -405,7 +456,7 @@ function SiteContextProvider({
|
|
|
405
456
|
setIsSwitching(true);
|
|
406
457
|
try {
|
|
407
458
|
const token = storage.getCustomerToken();
|
|
408
|
-
const authCtx = token ?
|
|
459
|
+
const authCtx = token ? auth2.customer(token) : auth2.anonymous();
|
|
409
460
|
const site = await qc.fetchQuery({
|
|
410
461
|
queryKey: [
|
|
411
462
|
"emporix",
|
|
@@ -440,7 +491,7 @@ function SiteContextProvider({
|
|
|
440
491
|
},
|
|
441
492
|
[client, storage, qc, language]
|
|
442
493
|
);
|
|
443
|
-
const setCurrency =
|
|
494
|
+
const setCurrency = useCallback2(
|
|
444
495
|
async (next) => {
|
|
445
496
|
storage.setCartId(null);
|
|
446
497
|
setCurrencyState(next);
|
|
@@ -450,7 +501,7 @@ function SiteContextProvider({
|
|
|
450
501
|
setIsSwitching(true);
|
|
451
502
|
try {
|
|
452
503
|
const token = storage.getCustomerToken();
|
|
453
|
-
const authCtx = token ?
|
|
504
|
+
const authCtx = token ? auth2.customer(token) : auth2.anonymous();
|
|
454
505
|
await client.sessionContext.patch(
|
|
455
506
|
{ currency: next, ...siteCode ? { siteCode } : {} },
|
|
456
507
|
authCtx
|
|
@@ -463,7 +514,7 @@ function SiteContextProvider({
|
|
|
463
514
|
},
|
|
464
515
|
[client, storage, qc, siteCode]
|
|
465
516
|
);
|
|
466
|
-
const setLanguage =
|
|
517
|
+
const setLanguage = useCallback2(
|
|
467
518
|
async (next) => {
|
|
468
519
|
storage.setLanguage(next);
|
|
469
520
|
setLanguageState(next);
|
|
@@ -473,7 +524,7 @@ function SiteContextProvider({
|
|
|
473
524
|
setIsSwitching(true);
|
|
474
525
|
try {
|
|
475
526
|
const token = storage.getCustomerToken();
|
|
476
|
-
const authCtx = token ?
|
|
527
|
+
const authCtx = token ? auth2.customer(token) : auth2.anonymous();
|
|
477
528
|
await client.sessionContext.patch(
|
|
478
529
|
{ language: next, ...siteCode ? { siteCode } : {} },
|
|
479
530
|
authCtx
|
|
@@ -486,7 +537,7 @@ function SiteContextProvider({
|
|
|
486
537
|
},
|
|
487
538
|
[client, storage, qc, siteCode]
|
|
488
539
|
);
|
|
489
|
-
const value =
|
|
540
|
+
const value = useMemo2(
|
|
490
541
|
() => ({
|
|
491
542
|
siteCode,
|
|
492
543
|
currency,
|
|
@@ -500,14 +551,21 @@ function SiteContextProvider({
|
|
|
500
551
|
}),
|
|
501
552
|
[siteCode, currency, targetLocation, language, setSite, setCurrency, setLanguage, isSwitching, switchError]
|
|
502
553
|
);
|
|
503
|
-
return /* @__PURE__ */
|
|
554
|
+
return /* @__PURE__ */ jsx2(EmporixSiteContext.Provider, { value, children });
|
|
504
555
|
}
|
|
505
556
|
function useEmporix() {
|
|
506
|
-
const ctx =
|
|
557
|
+
const ctx = useContext3(EmporixContext);
|
|
507
558
|
if (!ctx) throw new Error("useEmporix must be used within an EmporixProvider");
|
|
508
559
|
return ctx;
|
|
509
560
|
}
|
|
510
561
|
|
|
511
|
-
export {
|
|
512
|
-
|
|
513
|
-
|
|
562
|
+
export {
|
|
563
|
+
useEmporixTelemetry,
|
|
564
|
+
EmporixCompanyContext,
|
|
565
|
+
useActiveCompany,
|
|
566
|
+
CompanyContextProvider,
|
|
567
|
+
EmporixSiteContext,
|
|
568
|
+
EmporixProvider,
|
|
569
|
+
useEmporix
|
|
570
|
+
};
|
|
571
|
+
//# sourceMappingURL=chunk-CZDVH3WH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/provider.tsx","../src/telemetry.ts","../src/company-context.tsx"],"sourcesContent":["import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport { QueryClient, QueryClientProvider, useQueryClient } from \"@tanstack/react-query\";\nimport { auth, type EmporixClient } from \"@viu/emporix-sdk\";\nimport type { EmporixStorage } from \"./storage/index\";\nimport { createMemoryStorage } from \"./storage/memory\";\nimport { EmporixTelemetryContext, type EmporixTelemetryEvent } from \"./telemetry\";\nimport { CompanyContextProvider } from \"./company-context\";\n\ninterface EmporixContextValue {\n client: EmporixClient;\n storage: EmporixStorage;\n}\n\nexport interface SiteContextValue {\n siteCode: string | null;\n /** MS-4 populates this from the active site's DTO. */\n currency: string | null;\n /** MS-4 populates this from the active site's DTO. */\n targetLocation: string | null;\n /** Active language for localized reads (Accept-Language). `null` = site/tenant default. */\n language: string | null;\n /**\n * Asynchronous site switch. Updates local state + storage immediately\n * (optimistic), then PATCHes `/session-context/{tenant}/me/context` so\n * the server sees the same site on the next request. When no session\n * context exists yet (first visit, before any cart), the PATCH is\n * skipped — local state still flips.\n *\n * `isSwitching` is `true` while the PATCH is in flight. `switchError`\n * surfaces a PATCH failure; the optimistic state is NOT rolled back\n * (the cache was already invalidated, the UI already moved on).\n */\n setSite: (code: string | null) => Promise<void>;\n /**\n * Switch the active currency at runtime. Re-binds the anonymous price context\n * (so guest pricing changes even before a cart exists), clears the\n * currency-bound guest cart, and PATCHes an existing server session context.\n * The chosen currency must be in the active site's `availableCurrencies`.\n */\n setCurrency: (currency: string) => Promise<void>;\n /**\n * Switch the active language at runtime. Sets the `Accept-Language` request\n * header (via `setStorefrontContext`), invalidates the React-Query cache so\n * localized reads refetch, and PATCHes an existing server session context.\n * Does NOT clear the cart (language does not affect pricing).\n */\n setLanguage: (language: string) => Promise<void>;\n isSwitching: boolean;\n switchError: Error | null;\n}\n\nconst EmporixContext = createContext<EmporixContextValue | null>(null);\nexport const EmporixSiteContext = createContext<SiteContextValue | null>(null);\n\n/**\n * Balanced React-Query defaults scoped to the `[\"emporix\"]` key namespace of\n * whatever QueryClient is active (the fallback OR a consumer-supplied one).\n * Keeps the Emporix API-quota in check by suppressing window-focus refetches\n * and capping retries. Consumer-set emporix defaults and per-hook options win.\n */\nconst DEFAULT_QUERY_OPTIONS = {\n staleTime: 30_000,\n refetchOnWindowFocus: false,\n retry: 1,\n} as const;\n\n/** Props for {@link EmporixProvider}. */\nexport interface EmporixProviderProps {\n client: EmporixClient;\n queryClient?: QueryClient;\n storage?: EmporixStorage;\n initialCustomerToken?: string;\n /**\n * Initial site code. Resolution order: this prop → `storage.getSiteCode()` →\n * `client.config.credentials.storefront.context.siteCode` → `null`.\n */\n initialSiteCode?: string;\n /**\n * Initial active language. Resolution order: this prop → `storage.getLanguage()`\n * → `client.config.credentials.storefront.context.language` → `null` (then\n * seeded from the active site's `defaultLanguage` on mount).\n */\n initialLanguage?: string;\n /**\n * Initial active legal-entity id (B2B). When set, the CompanyContext\n * provider tries to match it against `companies.listMine()` once the\n * customer is loaded; mismatches are dropped silently.\n */\n initialActiveLegalEntityId?: string | null;\n /**\n * Opt-in telemetry callback. Receives a typed event stream covering cache\n * hit/miss, refetches, errors, mutations, auth refreshes, storage writes,\n * and consumer-emitted custom events. Wire this to Datadog/Sentry/custom\n * analytics. The handler is wrapped in try/catch — a throwing handler\n * never breaks the provider.\n */\n onTelemetry?: (event: EmporixTelemetryEvent) => void;\n /**\n * Opt in to reactive customer-token auto-refresh: on a `customer`-kind 401,\n * the SDK refreshes once (via the stored refresh token + anonymous auth) and\n * retries. Default: false (the customer token stays caller-owned).\n */\n autoRefreshCustomerToken?: boolean;\n /**\n * Called when a customer-token refresh is needed but fails (refresh token\n * expired/revoked) or no refresh token is stored. Use to drive logout /\n * redirect to login.\n */\n onCustomerSessionExpired?: () => void;\n children: ReactNode;\n}\n\n/** Provides the SDK client, token storage, react-query client, and site context to the tree. */\nexport function EmporixProvider({\n client,\n queryClient,\n storage,\n initialCustomerToken,\n initialSiteCode,\n initialLanguage,\n initialActiveLegalEntityId,\n onTelemetry,\n autoRefreshCustomerToken,\n onCustomerSessionExpired,\n children,\n}: EmporixProviderProps): React.JSX.Element {\n const value = useMemo<EmporixContextValue>(() => {\n const s =\n storage ??\n createMemoryStorage(\n initialCustomerToken !== undefined ? { initial: initialCustomerToken } : {},\n );\n return { client, storage: s };\n }, [client, storage, initialCustomerToken]);\n\n // Fallback QueryClient held in state, not useMemo: React may discard a\n // useMemo cache, which would silently drop the entire query cache mid-session.\n // Defaults are applied below via setQueryDefaults, scoped to [\"emporix\"].\n const [fallbackQc] = useState(() => new QueryClient());\n const qc = queryClient ?? fallbackQc;\n\n // Scope our balanced defaults to the [\"emporix\"] key namespace on WHATEVER\n // QueryClient is in use — a bare consumer client (e.g. the next-app-router\n // example) otherwise runs SDK queries with React-Query factory defaults\n // (staleTime 0, focus refetch, retry 3 → multiplied by the SDK's own HTTP\n // retry). We only FILL GAPS: a consumer's explicit choices win, whether set\n // globally (`defaultOptions.queries`) or emporix-scoped — both are spread\n // after ours. Host-app queries outside the namespace are untouched.\n // Ref-guarded: re-applies only for a new client.\n const defaultsRef = useRef<QueryClient | null>(null);\n if (defaultsRef.current !== qc) {\n qc.setQueryDefaults([\"emporix\"], {\n ...DEFAULT_QUERY_OPTIONS,\n ...qc.getDefaultOptions().queries,\n ...qc.getQueryDefaults([\"emporix\"]),\n });\n defaultsRef.current = qc;\n }\n\n // Idempotent wiring that must precede the children's first fetch effects:\n // (1) attach the storage-backed anonymous-session adapter to the SDK token\n // provider, (2) seed the SSR-provided customer token into external storage.\n // Ref-guarded so it re-runs when (client, storage) identity changes — a\n // useState lazy initializer runs once per component INSTANCE and silently\n // skips re-wiring on prop swaps; a useEffect runs AFTER children fetch.\n const wiredRef = useRef<{ client: EmporixClient; storage: EmporixStorage } | null>(null);\n if (wiredRef.current?.client !== client || wiredRef.current?.storage !== value.storage) {\n client.tokenProvider.attachAnonymousStore?.({\n read: () => value.storage.getAnonymousSession(),\n write: (s) => value.storage.setAnonymousSession(s),\n });\n if (initialCustomerToken && storage && storage.getCustomerToken() === null) {\n storage.setCustomerToken(initialCustomerToken);\n }\n wiredRef.current = { client, storage: value.storage };\n }\n\n // Telemetry: stable safeEmit + context value. emit is no-op when no\n // onTelemetry callback was provided (no overhead).\n const safeEmit = useCallback(\n (event: EmporixTelemetryEvent) => {\n if (!onTelemetry) return;\n try {\n onTelemetry(event);\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error(\"[emporix] telemetry handler threw:\", err);\n }\n },\n [onTelemetry],\n );\n const telemetryValue = useMemo(() => ({ emit: safeEmit }), [safeEmit]);\n\n // Source subscriptions: cache + mutation cache + token-provider + storage.\n // All only active when onTelemetry is provided.\n useEffect(() => {\n if (!onTelemetry) return;\n const startedAt = new Map<string, number>();\n\n const unsubQuery = qc.getQueryCache().subscribe((event) => {\n const key = event.query.queryKey;\n if (!Array.isArray(key) || key[0] !== \"emporix\") return;\n if (event.type === \"updated\") {\n const action = event.action as { type: string };\n if (action.type === \"fetch\") {\n const isRefetch = event.query.state.dataUpdateCount > 0;\n if (isRefetch) {\n safeEmit({\n type: \"query.refetch\",\n queryKey: key,\n tenant: client.tenant,\n reason: \"invalidate\",\n });\n }\n startedAt.set(event.query.queryHash, Date.now());\n } else if (action.type === \"success\") {\n const start = startedAt.get(event.query.queryHash);\n startedAt.delete(event.query.queryHash);\n safeEmit({\n type: \"cache.miss\",\n queryKey: key,\n tenant: client.tenant,\n durationMs: start ? Date.now() - start : 0,\n });\n } else if (action.type === \"error\") {\n startedAt.delete(event.query.queryHash);\n safeEmit({\n type: \"query.error\",\n queryKey: key,\n tenant: client.tenant,\n error: event.query.state.error,\n });\n }\n } else if (event.type === \"observerResultsUpdated\") {\n const s = event.query.state;\n if (s.status === \"success\" && s.fetchStatus === \"idle\" && s.dataUpdateCount > 0) {\n safeEmit({ type: \"cache.hit\", queryKey: key, tenant: client.tenant });\n }\n }\n });\n\n const unsubMut = qc.getMutationCache().subscribe((event) => {\n if (event.type !== \"updated\") return;\n const m = event.mutation;\n const dur = Date.now() - (m.state.submittedAt ?? Date.now());\n const mk = m.options.mutationKey;\n if (m.state.status === \"success\") {\n safeEmit({\n type: \"mutation.success\",\n ...(mk ? { mutationKey: mk as readonly unknown[] } : {}),\n tenant: client.tenant,\n durationMs: dur,\n });\n } else if (m.state.status === \"error\") {\n safeEmit({\n type: \"mutation.error\",\n ...(mk ? { mutationKey: mk as readonly unknown[] } : {}),\n tenant: client.tenant,\n error: m.state.error,\n durationMs: dur,\n });\n }\n });\n\n const unsubAuth = client.tokenProvider.onRefresh?.((evt) =>\n safeEmit({ type: \"auth.refresh\", ...evt, tenant: client.tenant }),\n );\n\n const unsubStorage = value.storage.subscribeAll?.((key) =>\n safeEmit({ type: \"storage.write\", key }),\n );\n\n return () => {\n unsubQuery();\n unsubMut();\n unsubAuth?.();\n unsubStorage?.();\n };\n }, [qc, onTelemetry, client, value.storage, safeEmit]);\n\n // Opt-in reactive customer-token auto-refresh. Registered on the client so\n // the core HttpClient can refresh-and-retry a customer 401. Single-flight is\n // handled in the core registry. Off unless `autoRefreshCustomerToken`.\n useEffect(() => {\n if (!autoRefreshCustomerToken) return;\n const storage = value.storage;\n client.setCustomerTokenRefresher({\n refresh: async () => {\n const refreshToken = storage.getRefreshToken();\n if (!refreshToken) {\n safeEmit({ type: \"auth.refresh\", kind: \"customer\", success: false, tenant: client.tenant });\n onCustomerSessionExpired?.();\n return null;\n }\n try {\n const legalEntityId = storage.getActiveLegalEntityId() ?? undefined;\n const s = await client.customers.refresh({\n refreshToken,\n ...(legalEntityId ? { legalEntityId } : {}),\n });\n storage.setCustomerToken(s.customerToken);\n if (s.refreshToken) storage.setRefreshToken(s.refreshToken);\n safeEmit({ type: \"auth.refresh\", kind: \"customer\", success: true, tenant: client.tenant });\n return s.customerToken;\n } catch {\n safeEmit({ type: \"auth.refresh\", kind: \"customer\", success: false, tenant: client.tenant });\n onCustomerSessionExpired?.();\n return null;\n }\n },\n });\n return () => client.setCustomerTokenRefresher(null);\n }, [autoRefreshCustomerToken, client, value.storage, safeEmit, onCustomerSessionExpired]);\n\n return (\n <EmporixContext.Provider value={value}>\n <EmporixTelemetryContext.Provider value={telemetryValue}>\n <QueryClientProvider client={qc}>\n <SiteContextProvider\n client={client}\n storage={value.storage}\n {...(initialSiteCode !== undefined ? { initialSiteCode } : {})}\n {...(initialLanguage !== undefined ? { initialLanguage } : {})}\n >\n <CompanyContextProvider\n client={client}\n storage={value.storage}\n {...(initialActiveLegalEntityId !== undefined\n ? { initialActiveLegalEntityId }\n : {})}\n >\n {children}\n </CompanyContextProvider>\n </SiteContextProvider>\n </QueryClientProvider>\n </EmporixTelemetryContext.Provider>\n </EmporixContext.Provider>\n );\n}\n\n/**\n * Manages the active-site state. Sits inside `QueryClientProvider` so\n * `setSite` can invalidate the React-Query cache on switch.\n */\nfunction SiteContextProvider({\n client,\n storage,\n initialSiteCode,\n initialLanguage,\n children,\n}: {\n client: EmporixClient;\n storage: EmporixStorage;\n initialSiteCode?: string;\n initialLanguage?: string;\n children: ReactNode;\n}): React.JSX.Element {\n const qc = useQueryClient();\n const [siteCode, setSiteCodeState] = useState<string | null>(() => {\n if (initialSiteCode !== undefined) return initialSiteCode;\n const fromStorage = storage.getSiteCode();\n if (fromStorage !== null) return fromStorage;\n return client.config?.credentials?.storefront?.context?.siteCode ?? null;\n });\n const [currency, setCurrencyState] = useState<string | null>(\n () => client.config?.credentials?.storefront?.context?.currency ?? null,\n );\n const [language, setLanguageState] = useState<string | null>(() => {\n if (initialLanguage !== undefined) return initialLanguage;\n const fromStorage = storage.getLanguage();\n if (fromStorage !== null) return fromStorage;\n return client.config?.credentials?.storefront?.context?.language ?? null;\n });\n const [targetLocation, setTargetLocation] = useState<string | null>(null);\n const [isSwitching, setIsSwitching] = useState(false);\n const [switchError, setSwitchError] = useState<Error | null>(null);\n\n // Mount-time derivation: if a siteCode is already resolved, fetch its DTO\n // once so currency + targetLocation populate without a user-driven switch.\n // A currency seeded from the client config is NOT overridden (the user's /\n // persisted choice wins); only fields still `null` are filled in.\n useEffect(() => {\n if (!siteCode || (currency !== null && targetLocation !== null && language !== null)) return;\n let cancelled = false;\n const token = storage.getCustomerToken();\n const authCtx = token ? auth.customer(token) : auth.anonymous();\n qc.fetchQuery({\n queryKey: [\n \"emporix\",\n \"site-by-code\",\n siteCode,\n { tenant: client.tenant, authKind: authCtx.kind },\n ],\n queryFn: () => client.sites.get(siteCode, authCtx),\n staleTime: 5 * 60_000,\n })\n .then((site) => {\n if (cancelled) return;\n if (currency === null) setCurrencyState(site.currency);\n setTargetLocation(site.homeBase?.address?.country ?? null);\n if (language === null && site.defaultLanguage) {\n setLanguageState(site.defaultLanguage);\n client.setStorefrontContext({ language: site.defaultLanguage });\n }\n })\n .catch(() => {\n // Best-effort — silent. setSite-driven derivation surfaces real errors.\n });\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [siteCode]);\n\n // Push the initially-resolved language (prop / storage / config) to the SDK so\n // the very first reads carry `Accept-Language` — React state alone does not\n // reach the client. Mount-only; later changes go through setLanguage / setSite.\n useEffect(() => {\n if (language) client.setStorefrontContext({ language });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const setSite = useCallback(\n async (code: string | null) => {\n // 1) Optimistic flip — UI moves immediately.\n storage.setSiteCode(code);\n storage.setCartId(null);\n setSiteCodeState(code);\n setSwitchError(null);\n void qc.invalidateQueries({ queryKey: [\"emporix\"] });\n\n if (code === null) {\n setCurrencyState(null);\n setTargetLocation(null);\n return;\n }\n\n setIsSwitching(true);\n try {\n const token = storage.getCustomerToken();\n const authCtx = token ? auth.customer(token) : auth.anonymous();\n // 2) Derive currency + targetLocation from the site DTO (cached 5min).\n const site = await qc.fetchQuery({\n queryKey: [\n \"emporix\",\n \"site-by-code\",\n code,\n { tenant: client.tenant, authKind: authCtx.kind },\n ],\n queryFn: () => client.sites.get(code, authCtx),\n staleTime: 5 * 60_000,\n });\n const nextCurrency = site.currency;\n const nextTarget = site.homeBase?.address?.country ?? null;\n setCurrencyState(nextCurrency);\n setTargetLocation(nextTarget);\n // Reset the language if the new site doesn't support the active one.\n if (site.languages && !site.languages.includes(language ?? \"\") && site.defaultLanguage) {\n setLanguageState(site.defaultLanguage);\n client.setStorefrontContext({ language: site.defaultLanguage });\n }\n // 3) Push everything into the session-context PATCH.\n await client.sessionContext.patch(\n {\n siteCode: code,\n ...(nextCurrency ? { currency: nextCurrency } : {}),\n ...(nextTarget ? { targetLocation: nextTarget } : {}),\n },\n authCtx,\n );\n } catch (e) {\n setSwitchError(e instanceof Error ? e : new Error(String(e)));\n } finally {\n setIsSwitching(false);\n }\n },\n [client, storage, qc, language],\n );\n\n const setCurrency = useCallback(\n async (next: string) => {\n // Carts are currency-bound — drop the guest cart so a fresh one is created.\n storage.setCartId(null);\n setCurrencyState(next);\n setSwitchError(null);\n // Re-bind the anonymous price context so guest pricing uses the new\n // currency even before a session/cart exists (sessionContext.patch can't).\n client.setStorefrontContext({ currency: next });\n void qc.invalidateQueries({ queryKey: [\"emporix\"] });\n setIsSwitching(true);\n try {\n const token = storage.getCustomerToken();\n const authCtx = token ? auth.customer(token) : auth.anonymous();\n // Update an existing server session context (no-op / returns false pre-cart).\n await client.sessionContext.patch(\n { currency: next, ...(siteCode ? { siteCode } : {}) },\n authCtx,\n );\n } catch (e) {\n setSwitchError(e instanceof Error ? e : new Error(String(e)));\n } finally {\n setIsSwitching(false);\n }\n },\n [client, storage, qc, siteCode],\n );\n\n const setLanguage = useCallback(\n async (next: string) => {\n storage.setLanguage(next);\n setLanguageState(next);\n setSwitchError(null);\n // Header source — applies to anonymous + pre-session reads too.\n client.setStorefrontContext({ language: next });\n void qc.invalidateQueries({ queryKey: [\"emporix\"] });\n setIsSwitching(true);\n try {\n const token = storage.getCustomerToken();\n const authCtx = token ? auth.customer(token) : auth.anonymous();\n // Update an existing server session context (no-op / returns false pre-cart).\n await client.sessionContext.patch(\n { language: next, ...(siteCode ? { siteCode } : {}) },\n authCtx,\n );\n } catch (e) {\n setSwitchError(e instanceof Error ? e : new Error(String(e)));\n } finally {\n setIsSwitching(false);\n }\n },\n [client, storage, qc, siteCode],\n );\n\n const value = useMemo<SiteContextValue>(\n () => ({\n siteCode,\n currency,\n targetLocation,\n language,\n setSite,\n setCurrency,\n setLanguage,\n isSwitching,\n switchError,\n }),\n [siteCode, currency, targetLocation, language, setSite, setCurrency, setLanguage, isSwitching, switchError],\n );\n\n return <EmporixSiteContext.Provider value={value}>{children}</EmporixSiteContext.Provider>;\n}\n\n/** Returns the SDK client and token storage. Throws outside an {@link EmporixProvider}. */\nexport function useEmporix(): EmporixContextValue {\n const ctx = useContext(EmporixContext);\n if (!ctx) throw new Error(\"useEmporix must be used within an EmporixProvider\");\n return ctx;\n}\n","import { createContext, useContext } from \"react\";\n\n/**\n * All telemetry events emitted through the EmporixProvider's `onTelemetry`\n * callback. Discriminated by `type` — exhaustive switch is type-safe.\n *\n * Consumers can emit their own `{ type: \"custom\" }` events via\n * {@link useEmporixTelemetry}. Namespace `name` with an app-specific\n * prefix (e.g. `\"app.checkout-cta-click\"`) to avoid collisions with\n * future SDK event types.\n */\nexport type EmporixTelemetryEvent =\n // Cache lifecycle (React-Query QueryCache)\n | { type: \"cache.hit\"; queryKey: readonly unknown[]; tenant: string }\n | {\n type: \"cache.miss\";\n queryKey: readonly unknown[];\n tenant: string;\n durationMs: number;\n }\n | {\n type: \"query.refetch\";\n queryKey: readonly unknown[];\n tenant: string;\n reason: \"invalidate\" | \"focus\" | \"stale\";\n }\n | {\n type: \"query.error\";\n queryKey: readonly unknown[];\n tenant: string;\n error: unknown;\n }\n // Mutation lifecycle\n | {\n type: \"mutation.success\";\n mutationKey?: readonly unknown[];\n tenant: string;\n durationMs: number;\n }\n | {\n type: \"mutation.error\";\n mutationKey?: readonly unknown[];\n tenant: string;\n error: unknown;\n durationMs: number;\n }\n // Auth refresh (SDK-side)\n | {\n type: \"auth.refresh\";\n kind: \"anonymous\" | \"customer\";\n tenant: string;\n success: boolean;\n }\n // Storage writes\n | {\n type: \"storage.write\";\n key: \"customerToken\" | \"cartId\" | \"siteCode\" | \"language\" | \"anonymousSession\" | \"activeLegalEntityId\" | \"refreshToken\";\n }\n // Active-company switch (B2B)\n | {\n type: \"company:switched\";\n from: string | null;\n to: string | null;\n durationMs: number;\n }\n // Consumer-emitted\n | { type: \"custom\"; name: string; props?: Record<string, unknown> };\n\n/** Internal: the React context carrying the emit function down the tree. */\nexport const EmporixTelemetryContext = createContext<{\n emit: (event: EmporixTelemetryEvent) => void;\n} | null>(null);\n\n/**\n * Hook to emit custom telemetry events through the same channel as SDK\n * events. Throws when used outside an {@link EmporixProvider}.\n *\n * When the provider has no `onTelemetry` callback configured, `emit` is a\n * no-op — calling it is safe and incurs no overhead.\n */\nexport function useEmporixTelemetry(): {\n emit: (event: EmporixTelemetryEvent) => void;\n} {\n const ctx = useContext(EmporixTelemetryContext);\n if (!ctx) {\n throw new Error(\"useEmporixTelemetry must be used within an EmporixProvider\");\n }\n return ctx;\n}\n","import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from \"react\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { auth, type EmporixClient, type LegalEntity } from \"@viu/emporix-sdk\";\nimport type { EmporixStorage } from \"./storage\";\nimport { useEmporixTelemetry } from \"./telemetry\";\n\nexport type CompanyMode = \"b2c\" | \"b2b\" | \"unresolved\";\n\nexport interface CompanyContextValue {\n /** Active legal entity. `null` = B2C mode. */\n activeCompany: LegalEntity | null;\n /** All legal entities the customer is assigned to. */\n myCompanies: LegalEntity[];\n /**\n * `b2b` = a company is active; `b2c` = none active (and ≤1 available);\n * `unresolved` = multiple companies available, none picked yet — the\n * storefront must render a picker.\n */\n mode: CompanyMode;\n status: \"idle\" | \"loading\" | \"switching\" | \"error\";\n error: unknown;\n /**\n * Switch the active company. Eagerly calls\n * `client.customers.refresh({ legalEntityId })` so the customer token is\n * rescoped server-side, drops the cart id, then invalidates company-scoped\n * queries. Falls back to a local-state-only update when no refresh token\n * is in storage (e.g. fresh page load with memory storage).\n */\n setActiveCompany: (legalEntityId: string | null) => Promise<void>;\n refetchMyCompanies: () => Promise<void>;\n}\n\nconst NULL_CTX: CompanyContextValue = {\n activeCompany: null,\n myCompanies: [],\n mode: \"b2c\",\n status: \"idle\",\n error: null,\n setActiveCompany: async () => {\n throw new Error(\"CompanyContextProvider not mounted\");\n },\n refetchMyCompanies: async () => {},\n};\n\nexport const EmporixCompanyContext = createContext<CompanyContextValue>(NULL_CTX);\n\n/** Returns the active-company context. Safe outside the provider — returns idle B2C defaults. */\nexport function useActiveCompany(): CompanyContextValue {\n return useContext(EmporixCompanyContext);\n}\n\nexport interface CompanyContextProviderProps {\n client: EmporixClient;\n storage: EmporixStorage;\n initialActiveLegalEntityId?: string | null;\n children: ReactNode;\n}\n\nexport function CompanyContextProvider({\n client,\n storage,\n initialActiveLegalEntityId,\n children,\n}: CompanyContextProviderProps): React.JSX.Element {\n const qc = useQueryClient();\n const { emit } = useEmporixTelemetry();\n const [myCompanies, setMyCompanies] = useState<LegalEntity[]>([]);\n const [activeCompany, setActive] = useState<LegalEntity | null>(null);\n const [status, setStatus] = useState<CompanyContextValue[\"status\"]>(\"idle\");\n const [error, setError] = useState<unknown>(null);\n // Ref so switchTo can capture the latest `activeCompany` for telemetry `from`.\n // Written in an effect: render-phase ref writes are illegal under concurrent\n // rendering (an abandoned render's value could leak into a committed pass).\n const activeRef = useRef<LegalEntity | null>(null);\n useEffect(() => {\n activeRef.current = activeCompany;\n }, [activeCompany]);\n\n // Serializes token-rotating switches: two concurrent switchTo calls would\n // both read the same refresh token; with server-side rotation the second\n // consumes a stale token (401, worst case session revocation).\n const switchChain = useRef<Promise<void>>(Promise.resolve());\n\n /** Internal: eager refresh + storage write + state update. */\n const switchTo = useCallback(\n (target: LegalEntity | null): Promise<void> => {\n const run = async (): Promise<void> => {\n const start = Date.now();\n const from = activeRef.current?.id ?? null;\n const refreshToken = storage.getRefreshToken();\n const token = storage.getCustomerToken();\n if (!refreshToken || !token) {\n // Local-state-only fallback — no rescope possible.\n setActive(target);\n storage.setActiveLegalEntityId(target?.id ?? null);\n } else {\n const next = await client.customers.refresh({\n refreshToken,\n ...(target ? { legalEntityId: target.id } : {}),\n });\n storage.setCustomerToken(next.customerToken);\n if (next.refreshToken) storage.setRefreshToken(next.refreshToken);\n storage.setCartId(null);\n storage.setActiveLegalEntityId(target?.id ?? null);\n setActive(target);\n qc.invalidateQueries({\n predicate: (q) =>\n Array.isArray(q.queryKey) &&\n q.queryKey.some(\n (k) =>\n k === \"cart\" ||\n k === \"companies\" ||\n k === \"customer\" ||\n k === from ||\n (target !== null && k === target.id),\n ),\n });\n }\n emit({\n type: \"company:switched\",\n from,\n to: target?.id ?? null,\n durationMs: Date.now() - start,\n });\n };\n // Chain on the previous switch so concurrent calls run in order and each\n // reads the refresh token the prior switch rotated to.\n const task = switchChain.current.then(run, run);\n switchChain.current = task.catch(() => {\n /* keep the chain alive after a failed switch */\n });\n return task;\n },\n [client, storage, qc, emit],\n );\n\n const load = useCallback(\n async (signal?: { cancelled: boolean }) => {\n const token = storage.getCustomerToken();\n if (!token) {\n if (signal?.cancelled) return;\n setMyCompanies([]);\n setActive(null);\n setStatus(\"idle\");\n return;\n }\n setStatus(\"loading\");\n try {\n const companies = await client.companies.listMine(auth.customer(token));\n if (signal?.cancelled) return; // unmounted (StrictMode probe) — no state, no auto-switch\n setMyCompanies(companies);\n const persisted = initialActiveLegalEntityId ?? storage.getActiveLegalEntityId();\n const matched = persisted ? companies.find((c) => c.id === persisted) ?? null : null;\n if (matched) {\n setActive(matched);\n if (storage.getActiveLegalEntityId() !== matched.id) {\n storage.setActiveLegalEntityId(matched.id ?? null);\n }\n } else if (companies.length === 1) {\n await switchTo(companies[0] ?? null);\n } else {\n setActive(null);\n if (persisted && !matched) storage.setActiveLegalEntityId(null);\n }\n if (signal?.cancelled) return;\n setStatus(\"idle\");\n } catch (e) {\n if (signal?.cancelled) return;\n setError(e);\n setStatus(\"error\");\n }\n },\n [client, storage, initialActiveLegalEntityId, switchTo],\n );\n\n useEffect(() => {\n const signal = { cancelled: false };\n void load(signal);\n return () => {\n signal.cancelled = true;\n };\n }, [load]);\n\n // Re-run bootstrap only on token-presence transitions (login/logout). A\n // mid-session token swap (e.g. switch-driven refresh) keeps prev/next both\n // truthy and is ignored — otherwise the auto-pick branch would clobber an\n // explicit B2C choice as soon as the new token is written.\n useEffect(() => {\n let prev = storage.getCustomerToken();\n return storage.subscribe?.((next) => {\n const becameAuth = !prev && next;\n const becameUnauth = prev && !next;\n prev = next;\n if (becameAuth || becameUnauth) void load();\n });\n }, [storage, load]);\n\n const setActiveCompany = useCallback(\n async (legalEntityId: string | null) => {\n setStatus(\"switching\");\n try {\n if (legalEntityId === null) {\n await switchTo(null);\n } else {\n const target = myCompanies.find((c) => c.id === legalEntityId) ?? null;\n if (!target) throw new Error(`setActiveCompany: unknown legalEntityId ${legalEntityId}`);\n await switchTo(target);\n }\n setStatus(\"idle\");\n } catch (e) {\n setError(e);\n setStatus(\"error\");\n throw e;\n }\n },\n [myCompanies, switchTo],\n );\n\n const value = useMemo<CompanyContextValue>(() => {\n const mode: CompanyMode = activeCompany\n ? \"b2b\"\n : myCompanies.length > 1\n ? \"unresolved\"\n : \"b2c\";\n return {\n activeCompany,\n myCompanies,\n mode,\n status,\n error,\n setActiveCompany,\n refetchMyCompanies: load,\n };\n }, [activeCompany, myCompanies, status, error, setActiveCompany, load]);\n\n return (\n <EmporixCompanyContext.Provider value={value}>{children}</EmporixCompanyContext.Provider>\n );\n}\n"],"mappings":"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","names":["createContext","useCallback","useContext","useEffect","useMemo","useRef","useState","useQueryClient","auth","createContext","useContext","createContext","useContext","jsx","createContext","useMemo","useState","useRef","useCallback","useEffect","storage","useQueryClient","auth","useContext"]}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
// src/storage/memory.ts
|
|
2
4
|
function createMemoryStorage(opts = {}) {
|
|
3
5
|
let token = opts.initial ?? null;
|
|
@@ -135,7 +137,7 @@ var REFRESH_NAME = "emporix.refreshToken";
|
|
|
135
137
|
function createCookieStorage(opts = {}) {
|
|
136
138
|
const tokenName = opts.name ?? DEFAULT_TOKEN_NAME;
|
|
137
139
|
const sameSite = opts.sameSite ?? "lax";
|
|
138
|
-
const secure = opts.secure ??
|
|
140
|
+
const secure = opts.secure ?? (typeof location !== "undefined" && location.protocol === "https:");
|
|
139
141
|
if (typeof document === "undefined") {
|
|
140
142
|
console.warn("[emporix] document unavailable; cookie storage falling back to in-memory");
|
|
141
143
|
return createMemoryStorage();
|
|
@@ -226,6 +228,11 @@ function parseAnonymousSession(raw) {
|
|
|
226
228
|
}
|
|
227
229
|
}
|
|
228
230
|
|
|
229
|
-
export {
|
|
230
|
-
|
|
231
|
-
|
|
231
|
+
export {
|
|
232
|
+
createLocalStorageStorage,
|
|
233
|
+
createCookieStorage,
|
|
234
|
+
createListenerSet,
|
|
235
|
+
parseAnonymousSession,
|
|
236
|
+
createMemoryStorage
|
|
237
|
+
};
|
|
238
|
+
//# sourceMappingURL=chunk-ZNLAYNF5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/storage/memory.ts","../src/storage/local-storage.ts","../src/storage/cookie.ts","../src/storage/index.ts"],"sourcesContent":["import {\n createListenerSet,\n type EmporixStorage,\n type EmporixStorageKey,\n type PersistedAnonymousSession,\n} from \"./index\";\n\n/** In-memory token store. Default, SSR-safe, no persistence. */\nexport function createMemoryStorage(opts: { initial?: string } = {}): EmporixStorage {\n let token: string | null = opts.initial ?? null;\n let cartId: string | null = null;\n let anon: PersistedAnonymousSession | null = null;\n let siteCode: string | null = null;\n let language: string | null = null;\n let activeLegalEntityId: string | null = null;\n let refreshToken: string | null = null;\n const tokenListeners = new Set<(t: string | null) => void>();\n const all = createListenerSet<EmporixStorageKey>();\n return {\n getCustomerToken: () => token,\n setCustomerToken: (t) => {\n token = t;\n for (const l of tokenListeners) l(token);\n all.notify(\"customerToken\");\n },\n subscribe: (l) => {\n tokenListeners.add(l);\n return () => tokenListeners.delete(l);\n },\n getCartId: () => cartId,\n setCartId: (id) => {\n cartId = id;\n all.notify(\"cartId\");\n },\n getAnonymousSession: () => anon,\n setAnonymousSession: (s) => {\n anon = s;\n all.notify(\"anonymousSession\");\n },\n getSiteCode: () => siteCode,\n setSiteCode: (code) => {\n siteCode = code;\n all.notify(\"siteCode\");\n },\n getLanguage: () => language,\n setLanguage: (l) => {\n language = l;\n all.notify(\"language\");\n },\n getActiveLegalEntityId: () => activeLegalEntityId,\n setActiveLegalEntityId: (id) => {\n activeLegalEntityId = id;\n all.notify(\"activeLegalEntityId\");\n },\n getRefreshToken: () => refreshToken,\n setRefreshToken: (t) => {\n refreshToken = t;\n all.notify(\"refreshToken\");\n },\n subscribeAll: (l) => all.add(l),\n };\n}\n","import {\n createListenerSet,\n parseAnonymousSession,\n type EmporixStorage,\n type EmporixStorageKey,\n} from \"./index\";\nimport { createMemoryStorage } from \"./memory\";\n\nconst DEFAULT_TOKEN_KEY = \"emporix.customerToken\";\nconst CART_KEY = \"emporix.cartId\";\nconst ANON_KEY = \"emporix.anonymousSession\";\nconst SITE_KEY = \"emporix.siteCode\";\nconst LANGUAGE_KEY = \"emporix.language\";\nconst ACTIVE_LE_KEY = \"emporix.activeLegalEntityId\";\nconst REFRESH_KEY = \"emporix.refreshToken\";\n\n/** Browser `localStorage`-backed store. Falls back to memory on the server. */\nexport function createLocalStorageStorage(opts: { key?: string } = {}): EmporixStorage {\n const tokenKey = opts.key ?? DEFAULT_TOKEN_KEY;\n const available =\n typeof globalThis !== \"undefined\" &&\n typeof (globalThis as { localStorage?: Storage }).localStorage !== \"undefined\";\n if (!available) {\n // eslint-disable-next-line no-console\n console.warn(\"[emporix] localStorage unavailable; falling back to in-memory storage\");\n return createMemoryStorage();\n }\n const ls = (globalThis as unknown as { localStorage: Storage }).localStorage;\n const tokenListeners = new Set<(t: string | null) => void>();\n const all = createListenerSet<EmporixStorageKey>();\n return {\n getCustomerToken: () => ls.getItem(tokenKey),\n setCustomerToken: (t) => {\n if (t === null) ls.removeItem(tokenKey);\n else ls.setItem(tokenKey, t);\n for (const l of tokenListeners) l(t);\n all.notify(\"customerToken\");\n },\n subscribe: (l) => {\n tokenListeners.add(l);\n return () => tokenListeners.delete(l);\n },\n getCartId: () => ls.getItem(CART_KEY),\n setCartId: (id) => {\n if (id === null) ls.removeItem(CART_KEY);\n else ls.setItem(CART_KEY, id);\n all.notify(\"cartId\");\n },\n getAnonymousSession: () => parseAnonymousSession(ls.getItem(ANON_KEY)),\n setAnonymousSession: (s) => {\n if (s === null) ls.removeItem(ANON_KEY);\n else ls.setItem(ANON_KEY, JSON.stringify({ refreshToken: s.refreshToken, sessionId: s.sessionId }));\n all.notify(\"anonymousSession\");\n },\n getSiteCode: () => ls.getItem(SITE_KEY),\n setSiteCode: (code) => {\n if (code === null) ls.removeItem(SITE_KEY);\n else ls.setItem(SITE_KEY, code);\n all.notify(\"siteCode\");\n },\n getLanguage: () => ls.getItem(LANGUAGE_KEY),\n setLanguage: (l) => {\n if (l === null) ls.removeItem(LANGUAGE_KEY);\n else ls.setItem(LANGUAGE_KEY, l);\n all.notify(\"language\");\n },\n getActiveLegalEntityId: () => ls.getItem(ACTIVE_LE_KEY),\n setActiveLegalEntityId: (id) => {\n if (id === null) ls.removeItem(ACTIVE_LE_KEY);\n else ls.setItem(ACTIVE_LE_KEY, id);\n all.notify(\"activeLegalEntityId\");\n },\n getRefreshToken: () => ls.getItem(REFRESH_KEY),\n setRefreshToken: (t) => {\n if (t === null) ls.removeItem(REFRESH_KEY);\n else ls.setItem(REFRESH_KEY, t);\n all.notify(\"refreshToken\");\n },\n subscribeAll: (l) => all.add(l),\n };\n}\n","import {\n createListenerSet,\n parseAnonymousSession,\n type EmporixStorage,\n type EmporixStorageKey,\n} from \"./index\";\nimport { createMemoryStorage } from \"./memory\";\n\nconst DEFAULT_TOKEN_NAME = \"emporix.customerToken\";\nconst CART_NAME = \"emporix.cartId\";\nconst ANON_NAME = \"emporix.anonymousSession\";\nconst SITE_NAME = \"emporix.siteCode\";\nconst LANGUAGE_NAME = \"emporix.language\";\nconst ACTIVE_LE_NAME = \"emporix.activeLegalEntityId\";\nconst REFRESH_NAME = \"emporix.refreshToken\";\n\n/**\n * Cookie-backed store. `Secure` defaults to on for https origins; override\n * with `secure: false` only for non-https dev setups. Consumer must still pick\n * an appropriate `sameSite` for CSRF safety.\n */\nexport function createCookieStorage(\n opts: { name?: string; secure?: boolean; sameSite?: \"lax\" | \"strict\" | \"none\" } = {},\n): EmporixStorage {\n const tokenName = opts.name ?? DEFAULT_TOKEN_NAME;\n const sameSite = opts.sameSite ?? \"lax\";\n // Default: Secure on https origins. Tokens must not ride plain-http\n // cookies in production; localhost/http dev keeps working without opts.\n const secure =\n opts.secure ?? (typeof location !== \"undefined\" && location.protocol === \"https:\");\n if (typeof document === \"undefined\") {\n // eslint-disable-next-line no-console\n console.warn(\"[emporix] document unavailable; cookie storage falling back to in-memory\");\n return createMemoryStorage();\n }\n const attrs = `path=/; SameSite=${sameSite}${secure ? \"; Secure\" : \"\"}`;\n const readCookie = (name: string): string | null => {\n for (const part of document.cookie.split(\"; \")) {\n const [k, ...v] = part.split(\"=\");\n if (k === name) return decodeURIComponent(v.join(\"=\")) || null;\n }\n return null;\n };\n const writeCookie = (name: string, value: string | null): void => {\n document.cookie =\n value === null\n ? `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; ${attrs}`\n : `${name}=${encodeURIComponent(value)}; ${attrs}`;\n };\n const all = createListenerSet<EmporixStorageKey>();\n return {\n getCustomerToken: () => readCookie(tokenName),\n setCustomerToken: (t) => {\n writeCookie(tokenName, t);\n all.notify(\"customerToken\");\n },\n getCartId: () => readCookie(CART_NAME),\n setCartId: (id) => {\n writeCookie(CART_NAME, id);\n all.notify(\"cartId\");\n },\n getAnonymousSession: () => parseAnonymousSession(readCookie(ANON_NAME)),\n setAnonymousSession: (s) => {\n writeCookie(\n ANON_NAME,\n s === null\n ? null\n : JSON.stringify({ refreshToken: s.refreshToken, sessionId: s.sessionId }),\n );\n all.notify(\"anonymousSession\");\n },\n getSiteCode: () => readCookie(SITE_NAME),\n setSiteCode: (code) => {\n writeCookie(SITE_NAME, code);\n all.notify(\"siteCode\");\n },\n getLanguage: () => readCookie(LANGUAGE_NAME),\n setLanguage: (l) => {\n writeCookie(LANGUAGE_NAME, l);\n all.notify(\"language\");\n },\n getActiveLegalEntityId: () => readCookie(ACTIVE_LE_NAME),\n setActiveLegalEntityId: (id) => {\n writeCookie(ACTIVE_LE_NAME, id);\n all.notify(\"activeLegalEntityId\");\n },\n getRefreshToken: () => readCookie(REFRESH_NAME),\n setRefreshToken: (t) => {\n writeCookie(REFRESH_NAME, t);\n all.notify(\"refreshToken\");\n },\n subscribeAll: (l) => all.add(l),\n };\n}\n","/** Pluggable persistence for SDK session state. SSR-safe by default (memory). */\nexport interface EmporixStorage {\n // Customer token (unchanged).\n getCustomerToken(): string | null;\n setCustomerToken(token: string | null): void;\n subscribe?(listener: (token: string | null) => void): () => void;\n\n // Active guest / customer cart id.\n getCartId(): string | null;\n setCartId(id: string | null): void;\n\n // Anonymous session — used by DefaultTokenProvider (via EmporixProvider\n // wiring) to preserve sessionId across page reloads.\n getAnonymousSession(): PersistedAnonymousSession | null;\n setAnonymousSession(session: PersistedAnonymousSession | null): void;\n\n // Active site code (MS-2). `null` = no site bound yet.\n getSiteCode(): string | null;\n setSiteCode(code: string | null): void;\n\n // Active language (Accept-Language). `null` = use the site/tenant default.\n getLanguage(): string | null;\n setLanguage(language: string | null): void;\n\n // Active legal entity id (B2B). `null` = B2C mode.\n getActiveLegalEntityId(): string | null;\n setActiveLegalEntityId(id: string | null): void;\n\n // Refresh token — optional persistence. When absent, B2B company-switch\n // falls back to a local-state-only update (no server-side token rescope).\n getRefreshToken(): string | null;\n setRefreshToken(token: string | null): void;\n\n /**\n * Subscribe to any storage write. The listener receives the key that\n * changed. Returns an unsubscribe function. Optional — backends may no-op.\n * Used by the telemetry layer to emit `storage.write` events.\n */\n subscribeAll?(\n listener: (key: EmporixStorageKey) => void,\n ): () => void;\n}\n\n/** Minimal subset of `AnonymousSession` that needs to outlive a page load. */\nexport interface PersistedAnonymousSession {\n refreshToken: string;\n sessionId: string;\n}\n\n/** Backward-compat alias. New code should prefer `EmporixStorage`. */\nexport type TokenStorage = EmporixStorage;\n\n/** Keys that participate in {@link EmporixStorage.subscribeAll}. */\nexport type EmporixStorageKey =\n | \"customerToken\"\n | \"cartId\"\n | \"siteCode\"\n | \"language\"\n | \"anonymousSession\"\n | \"activeLegalEntityId\"\n | \"refreshToken\";\n\n/**\n * Internal: create a swallow-on-throw listener set used by all three storage\n * backends for `subscribeAll`. Centralizes the try/catch wrapper so a buggy\n * telemetry handler never breaks a storage write.\n */\nexport function createListenerSet<T>(): {\n add(l: (value: T) => void): () => void;\n notify(value: T): void;\n} {\n const listeners = new Set<(v: T) => void>();\n return {\n add(l) {\n listeners.add(l);\n return () => listeners.delete(l);\n },\n notify(value) {\n for (const l of listeners) {\n try {\n l(value);\n } catch {\n // Swallow handler errors; telemetry must never break writes.\n }\n }\n },\n };\n}\n\n/**\n * Internal: parses a raw `anonymousSession` JSON payload (from localStorage\n * or a cookie) into a {@link PersistedAnonymousSession}. Returns `null` for\n * any malformed or missing input.\n */\nexport function parseAnonymousSession(raw: string | null): PersistedAnonymousSession | null {\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as Partial<PersistedAnonymousSession>;\n if (typeof parsed.refreshToken === \"string\" && typeof parsed.sessionId === \"string\") {\n return { refreshToken: parsed.refreshToken, sessionId: parsed.sessionId };\n }\n return null;\n } catch {\n return null;\n }\n}\n\nexport { createMemoryStorage } from \"./memory\";\nexport { createLocalStorageStorage } from \"./local-storage\";\nexport { createCookieStorage } from \"./cookie\";\n"],"mappings":"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","names":[]}
|