@viu/emporix-sdk-react 1.0.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 +519 -0
- package/LICENSE +21 -0
- package/README.md +85 -0
- package/dist/chunk-D43CSHK3.js +410 -0
- package/dist/chunk-D43CSHK3.js.map +1 -0
- package/dist/chunk-FBQY2N7S.js +212 -0
- package/dist/chunk-FBQY2N7S.js.map +1 -0
- package/dist/chunk-N3VDSKCT.js +1128 -0
- package/dist/chunk-N3VDSKCT.js.map +1 -0
- package/dist/chunk-TIS4BKHK.js +25 -0
- package/dist/chunk-TIS4BKHK.js.map +1 -0
- package/dist/hooks.cjs +1212 -0
- package/dist/hooks.cjs.map +1 -0
- package/dist/hooks.d.cts +529 -0
- package/dist/hooks.d.ts +529 -0
- package/dist/hooks.js +5 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.cjs +1849 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +67 -0
- package/dist/index.d.ts +67 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/provider-BhvQWnnh.d.cts +133 -0
- package/dist/provider-fvcYdqqX.d.ts +133 -0
- package/dist/provider.cjs +480 -0
- package/dist/provider.cjs.map +1 -0
- package/dist/provider.d.cts +5 -0
- package/dist/provider.d.ts +5 -0
- package/dist/provider.js +4 -0
- package/dist/provider.js.map +1 -0
- package/dist/ssr.cjs +29 -0
- package/dist/ssr.cjs.map +1 -0
- package/dist/ssr.d.cts +23 -0
- package/dist/ssr.d.ts +23 -0
- package/dist/ssr.js +3 -0
- package/dist/ssr.js.map +1 -0
- package/dist/storage.cjs +218 -0
- package/dist/storage.cjs.map +1 -0
- package/dist/storage.d.cts +65 -0
- package/dist/storage.d.ts +65 -0
- package/dist/storage.js +3 -0
- package/dist/storage.js.map +1 -0
- package/package.json +104 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
# @viu/emporix-sdk-react
|
|
2
|
+
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#15](https://github.com/viuteam/emporix-sdk/pull/15) [`5c51a58`](https://github.com/viuteam/emporix-sdk/commit/5c51a58313c63cb7a9e34a4c5e6dc1da2017a827) Thanks [@amnael1](https://github.com/amnael1)! - `credentials.storefront.context` (`{ currency, siteCode, targetLocation }`)
|
|
8
|
+
is now sent at anonymous-login so `prices.matchByContext` resolves prices
|
|
9
|
+
from the session. Adds the `useMatchPrices` React hook. The next-app-router
|
|
10
|
+
and vite-spa examples now include an anonymous guest-checkout flow.
|
|
11
|
+
|
|
12
|
+
BREAKING: `CartService.create` now returns the generated `CartCreated`
|
|
13
|
+
(`{ cartId, yrn }`) — the actual create-endpoint response — instead of the
|
|
14
|
+
`Cart` GET model. Read `cart.cartId` (not `cart.id`) from the result.
|
|
15
|
+
|
|
16
|
+
- [#41](https://github.com/viuteam/emporix-sdk/pull/41) [`c10fc2d`](https://github.com/viuteam/emporix-sdk/commit/c10fc2d362c12cc881caddd301b7f987ba989d47) Thanks [@amnael1](https://github.com/amnael1)! - API-quota reduction: sane QueryClient defaults + bootstrap deduplication.
|
|
17
|
+
|
|
18
|
+
**QueryClient defaults** (only applied when no `queryClient` prop is passed):
|
|
19
|
+
- `staleTime: 30s` — fresh-within-30s policy reduces refetch-on-mount churn.
|
|
20
|
+
- `refetchOnWindowFocus: false` — tabbing back no longer refetches all queries.
|
|
21
|
+
- `retry: 1` — single retry on failure instead of three (caps failed-request
|
|
22
|
+
cost at 2× per query).
|
|
23
|
+
|
|
24
|
+
**Per-hook staleTime overrides:**
|
|
25
|
+
- `useSites`, `useDefaultSite`, `usePaymentModes` — 10 min.
|
|
26
|
+
- `useCategory(ies)`, `useCategoryTree`, `useProductsInCategory(Infinite)`,
|
|
27
|
+
`useMySegment*` — 5 min.
|
|
28
|
+
- `useProducts(Infinite)`, `useProduct`, `useProductByCode`, `useProductSearch`,
|
|
29
|
+
`useMatchPrices` — 60 s.
|
|
30
|
+
- `useCustomerSession.customer` (meQuery) — 30 s.
|
|
31
|
+
- Cart, Addresses keep the 30s default (or 0 where freshness matters).
|
|
32
|
+
|
|
33
|
+
**Bootstrap dedup:**
|
|
34
|
+
- `useActiveCart({ create: true })` and `useCustomerSession.login` cart
|
|
35
|
+
onboarding share a single `bootstrapCart` cache entry — parallel mounts
|
|
36
|
+
trigger one server call instead of N.
|
|
37
|
+
- `useCustomerSession.login` honours `customer.preferredSite` via the same
|
|
38
|
+
`meQuery` cache key — login fires 1 `GET /customer/me` when the cache hits,
|
|
39
|
+
2 in the worst-case timing race (vs always 2 before).
|
|
40
|
+
|
|
41
|
+
No breaking changes. Consumers passing their own `queryClient` to
|
|
42
|
+
`EmporixProvider` keep their existing defaults.
|
|
43
|
+
|
|
44
|
+
- [#47](https://github.com/viuteam/emporix-sdk/pull/47) [`765c54e`](https://github.com/viuteam/emporix-sdk/commit/765c54e8fd61e33cb0d4cc241415e9c56f45c729) Thanks [@amnael1](https://github.com/amnael1)! - B2B foundation:
|
|
45
|
+
- New `CompanyContextProvider` (auto-mounted inside `EmporixProvider`) and `useActiveCompany()` hook.
|
|
46
|
+
- New B2B read hooks: `useMyCompanies`, `useCompany`, `useCompanyContacts`, `useCompanyLocations`, `useCompanyGroups`.
|
|
47
|
+
- New admin mutation hooks: `useCreateCompany`/`useUpdateCompany`/`useDeleteCompany`, `useAssignContact`/`useUpdateContactAssignment`/`useUnassignContact`, `useCreateLocation`/`useUpdateLocation`/`useDeleteLocation`.
|
|
48
|
+
- Convenience hook `useCompanySwitcher()`.
|
|
49
|
+
- New storage keys `"activeLegalEntityId"` and `"refreshToken"` with `get`/`set` helpers on every backend (`useCustomerSession` writes the refresh token through them on login/refresh, clears on logout).
|
|
50
|
+
- New SSR prop `EmporixProvider.initialActiveLegalEntityId` for hydration.
|
|
51
|
+
- New telemetry event `{ type: "company:switched", from, to, durationMs }`.
|
|
52
|
+
- `useCart`, `useCheckout`, `useCustomerAddresses`, `useActiveCart`, `usePaymentModes` now include the active `legalEntityId` in their query keys (and `useCheckout` merges it into the order payload) so cart/orders are scoped per company.
|
|
53
|
+
|
|
54
|
+
Switching company calls `customer.refresh({ legalEntityId })` (eager token rescope), drops the stored cart id, and invalidates company-scoped queries. Without a persisted refresh token in storage, switch falls back to a local-state-only update.
|
|
55
|
+
|
|
56
|
+
- [#34](https://github.com/viuteam/emporix-sdk/pull/34) [`c77ca8c`](https://github.com/viuteam/emporix-sdk/commit/c77ca8caccf522c7cead8dba84042e92c428d893) Thanks [@amnael1](https://github.com/amnael1)! - Add four catalog-UX hooks to `@viu/emporix-sdk-react`:
|
|
57
|
+
- `useProductByCode(code)` — single-product lookup via the `code` field. For slug-based routes (`/products/[slug]`).
|
|
58
|
+
- `useProductSearch(query, params?)` — full-text product search. Disabled on empty query; pair with consumer-side debouncing.
|
|
59
|
+
- `useProductsInCategory(categoryId, params?)` — paginated products for a category landing page.
|
|
60
|
+
- `useProductsInCategoryInfinite(categoryId, params?)` — infinite-scroll variant of the same.
|
|
61
|
+
|
|
62
|
+
All four follow the established `useReadAuth` + `enabled`-gate patterns. No SDK change.
|
|
63
|
+
|
|
64
|
+
- [#33](https://github.com/viuteam/emporix-sdk/pull/33) [`a61917e`](https://github.com/viuteam/emporix-sdk/commit/a61917ed59dde4a01ca9b09b7dd86adc7538ba40) Thanks [@amnael1](https://github.com/amnael1)! - Add customer-account hooks to `@viu/emporix-sdk-react`:
|
|
65
|
+
- `useUpdateCustomer()` — mutation for profile updates, invalidates `useCustomerSession.customer`.
|
|
66
|
+
- `useChangePassword()` — mutation for password change. Customer-only.
|
|
67
|
+
- `useCustomerAddresses()` — query for the customer's address list.
|
|
68
|
+
- `useAddressMutations()` — `{ add, update, remove }` mutations following the `useCartMutations` shape.
|
|
69
|
+
- `usePasswordReset()` — 2-step anonymous flow: `{ request, confirm }`.
|
|
70
|
+
|
|
71
|
+
Internal: a shared `useCustomerOnlyCtx` helper now lives in `hooks/internal/use-read-auth.ts` for hooks that intentionally throw on missing customer token. The previously-local `customerOnlyCtx` in `useCheckout` stays (with different semantics — gates a query via `enabled`).
|
|
72
|
+
|
|
73
|
+
No SDK change.
|
|
74
|
+
|
|
75
|
+
- [#26](https://github.com/viuteam/emporix-sdk/pull/26) [`18e34a0`](https://github.com/viuteam/emporix-sdk/commit/18e34a03cbf4fbfe15a7e4995228bb5268b0e2ee) Thanks [@amnael1](https://github.com/amnael1)! - Customer-cart onboarding on login. After `useCustomerSession.login()` (or the SSO flows `socialLogin` / `exchangeToken`) succeeds, the SDK now automatically loads (or creates) the customer's open Emporix cart for the configured `siteCode` and merges any guest cart into it. The resulting `cartId` is written into `EmporixStorage`, so the UI sees the cart immediately.
|
|
76
|
+
|
|
77
|
+
**SDK (`@viu/emporix-sdk`)**
|
|
78
|
+
- `EmporixClient.config` is now a public read-only field, so hosts can read static settings such as `storefront.context.siteCode` without re-plumbing.
|
|
79
|
+
- **BREAKING:** `CartService.getCurrent(auth)` is now `getCurrent(auth, { siteCode, type?, legalEntityId?, create? })`. `siteCode` is required per the Emporix spec. Returns `null` on 404; with `create: true`, Emporix creates a new cart if none matches.
|
|
80
|
+
- **BREAKING / fix:** `CartService.merge(anonymousCartId, auth)` is now `merge(customerCartId, anonymousCartIds: string[], auth)`. The old signature put the wrong cart-id in the path and sent an empty body — it never actually worked against Emporix. The new signature matches the documented contract (`POST /cart/{tenant}/carts/{customerCartId}/merge` with body `{ carts: […] }`).
|
|
81
|
+
|
|
82
|
+
**React (`@viu/emporix-sdk-react`)**
|
|
83
|
+
- `useCustomerSession.login()`, `socialLogin()`, and `exchangeToken()` now run a best-effort cart-onboarding step: `client.carts.getCurrent({ siteCode, create: true })` to load (or create) the customer cart, then `client.carts.merge(customerCartId, [anonCartId])` if a guest `cartId` was in storage, and finally `storage.setCartId(customerCartId)`. Failures are swallowed so login never blocks on cart trouble. Skipped silently if no `storefront.context.siteCode` is configured.
|
|
84
|
+
|
|
85
|
+
**Migration**
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
// SDK getCurrent:
|
|
89
|
+
- const cart = await client.carts.getCurrent(auth.customer(token));
|
|
90
|
+
+ const cart = await client.carts.getCurrent(auth.customer(token), { siteCode: "main" });
|
|
91
|
+
|
|
92
|
+
// SDK merge:
|
|
93
|
+
- await client.carts.merge(anonCartId, auth.customer(token));
|
|
94
|
+
+ await client.carts.merge(customerCartId, [anonCartId], auth.customer(token));
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
React consumers do not need to change anything — the new behavior kicks in automatically as long as the client's `storefront.context.siteCode` is set (the vite-spa Example already does).
|
|
98
|
+
|
|
99
|
+
- [#19](https://github.com/viuteam/emporix-sdk/pull/19) [`2f823b8`](https://github.com/viuteam/emporix-sdk/commit/2f823b8eb72eca17863757c3f6ccbf3e76442ee3) Thanks [@amnael1](https://github.com/amnael1)! - Add real customer logout. `customers.logout(auth)` calls
|
|
100
|
+
`GET /customer/{tenant}/logout?accessToken=…` authorized with the customer
|
|
101
|
+
token, invalidating it server-side (204). `useCustomerSession().logout()` is
|
|
102
|
+
now async: it performs the server logout best-effort (ignoring failures, e.g.
|
|
103
|
+
an already-expired token) and then clears the local session. The token is
|
|
104
|
+
sent only as a query param the SDK never logs (the logger uses the path, not
|
|
105
|
+
the full URL).
|
|
106
|
+
|
|
107
|
+
- [#22](https://github.com/viuteam/emporix-sdk/pull/22) [`5770532`](https://github.com/viuteam/emporix-sdk/commit/57705327b4d58b1ac410ee958f85ae858a6c862d) Thanks [@amnael1](https://github.com/amnael1)! - Add `SegmentService` (storefront reads only): `list`, `get`, `listItems`,
|
|
108
|
+
`listSegmentItems`, `getCategoryTree`, plus the hydrate helpers
|
|
109
|
+
`listMyProductIds` / `listMyCategoryIds` / `listMyProducts` /
|
|
110
|
+
`listMyCategories` that map segment-item ids to real `Product` /
|
|
111
|
+
`Category` objects via parallel `products.get` / `categories.get` calls.
|
|
112
|
+
All methods require a customer/raw `AuthContext` and use the shared
|
|
113
|
+
`requireCustomer` guard (also adopted by `customer.ts` and `payment.ts`).
|
|
114
|
+
|
|
115
|
+
React adds three lightweight hooks: `useMySegments`, `useMySegmentItems`,
|
|
116
|
+
`useMySegmentCategoryTree`. Each reads the customer token from the
|
|
117
|
+
storage and is `enabled: false` when there is no token (no network call
|
|
118
|
+
for guests). Exposed on the `@viu/emporix-sdk/segment` subpath.
|
|
119
|
+
|
|
120
|
+
- [#18](https://github.com/viuteam/emporix-sdk/pull/18) [`7da7b21`](https://github.com/viuteam/emporix-sdk/commit/7da7b217912782ba5d9b3f1e959d78d70c32c4ba) Thanks [@amnael1](https://github.com/amnael1)! - Add customer token refresh. `customers.refresh({ refreshToken, saasToken?,
|
|
121
|
+
legalEntityId? }, auth?)` calls `GET /customer/{tenant}/refreshauthtoken`
|
|
122
|
+
(authorized with an anonymous token, default), returning a new
|
|
123
|
+
`CustomerSession` with the **same `sessionId`**. The refresh endpoint does
|
|
124
|
+
not return a `saas_token`, so the original is carried forward via the
|
|
125
|
+
`saasToken` input. `useCustomerSession` now captures the refresh/saas tokens
|
|
126
|
+
at `login`, exposes `refreshToken`, and adds a `refreshSession()` action
|
|
127
|
+
that exchanges the refresh token and updates the stored customer token.
|
|
128
|
+
|
|
129
|
+
- [#14](https://github.com/viuteam/emporix-sdk/pull/14) [`4d87f11`](https://github.com/viuteam/emporix-sdk/commit/4d87f11a022996a49dad04af1404394cdd60804f) Thanks [@amnael1](https://github.com/amnael1)! - BREAKING: every service request body now uses the generated OpenAPI request
|
|
130
|
+
type. `carts.create` takes `CreateCart`, `carts.addItem` takes
|
|
131
|
+
`CartItemRequest` (now requires `product`/`quantity`/`price`),
|
|
132
|
+
`carts.updateItem` takes `UpdateCartItem`, `checkout.placeOrder` takes
|
|
133
|
+
`RequestCheckout`, `checkout.placeOrderFromQuote` takes
|
|
134
|
+
`RequestFromQuoteCheckout`, `payments.authorize` takes
|
|
135
|
+
`AuthorizePaymentRequest` (`{ order: { id }, … }`),
|
|
136
|
+
`customers.changePassword` takes `{ currentPassword, newPassword }`,
|
|
137
|
+
`customers.confirmPasswordReset` takes `{ token, password }`,
|
|
138
|
+
`customers.signup`/`update`/`addresses.*` take the generated DTOs. All
|
|
139
|
+
ergonomic input wrappers and input transformations are removed — callers
|
|
140
|
+
send the exact wire shape. `useCartMutations.addItem`/`updateItem` mutation
|
|
141
|
+
variables change accordingly. `CustomerService.login` keeps its literal
|
|
142
|
+
`{ email, password }` input and snake_case `CustomerSession` response (no
|
|
143
|
+
generated request type exists for it).
|
|
144
|
+
|
|
145
|
+
- [#21](https://github.com/viuteam/emporix-sdk/pull/21) [`877c2ab`](https://github.com/viuteam/emporix-sdk/commit/877c2abf791a6d67d438849cd800d5704ec486cb) Thanks [@amnael1](https://github.com/amnael1)! - Add `MediaService`. `client.media.create({ kind: "blob" | "link", ... })`
|
|
146
|
+
posts to `POST /media/{tenant}/assets` (multipart for BLOB, JSON for LINK);
|
|
147
|
+
convenience helpers `uploadFile`, `link`, `attachToProduct`,
|
|
148
|
+
`detachFromProduct`, `listForProduct` wrap the common product-attachment
|
|
149
|
+
flows. `HttpClient` now passes `FormData` bodies through `fetch` verbatim
|
|
150
|
+
(no Content-Type/JSON-stringify). React adds a thin `useProductMedia(id)`
|
|
151
|
+
hook that reads `productMedia` from the existing product query (no
|
|
152
|
+
service-token call in the browser).
|
|
153
|
+
|
|
154
|
+
BREAKING: `ProductService.media` is removed — it called a path
|
|
155
|
+
(`/product/{tenant}/products/{id}/media`) that does not exist in the
|
|
156
|
+
Emporix Product API. Migrate to `client.media.listForProduct(productId)`
|
|
157
|
+
(admin/server) or read `product.productMedia` from `client.products.get`
|
|
158
|
+
(storefront).
|
|
159
|
+
|
|
160
|
+
- [#37](https://github.com/viuteam/emporix-sdk/pull/37) [`380796a`](https://github.com/viuteam/emporix-sdk/commit/380796a53d9543b379b21eb414e3ebc5586e55f8) Thanks [@amnael1](https://github.com/amnael1)! - Add Site Settings Service binding — first stage of multi-site foundation.
|
|
161
|
+
|
|
162
|
+
**SDK**
|
|
163
|
+
- `client.sites.list()` — list active sites for the tenant.
|
|
164
|
+
- `client.sites.get(code)` — retrieve one site by code.
|
|
165
|
+
- `client.sites.current()` — convenience for the `default: true` site.
|
|
166
|
+
- New `Site` type mirroring the `SiteDto` schema (code, name, active,
|
|
167
|
+
default, currency, languages, homeBase, shipToCountries, …).
|
|
168
|
+
|
|
169
|
+
**React**
|
|
170
|
+
- `useSites()` — list active sites.
|
|
171
|
+
- `useDefaultSite()` — the default site.
|
|
172
|
+
|
|
173
|
+
No breaking changes. The active-site runtime context (provider state,
|
|
174
|
+
`setSite`, cache-key migration) follows in MS-2.
|
|
175
|
+
|
|
176
|
+
- [#38](https://github.com/viuteam/emporix-sdk/pull/38) [`cf2af9d`](https://github.com/viuteam/emporix-sdk/commit/cf2af9dbc3b025d3ef8d6cb2657f0c339cce2b7e) Thanks [@amnael1](https://github.com/amnael1)! - Multi-site MS-2: observable site context + cache-key migration.
|
|
177
|
+
|
|
178
|
+
**Provider**
|
|
179
|
+
- `<EmporixProvider initialSiteCode>` prop — resolution order: prop →
|
|
180
|
+
`storage.getSiteCode()` → static `client.config.…context.siteCode` →
|
|
181
|
+
`null`.
|
|
182
|
+
|
|
183
|
+
**Hooks**
|
|
184
|
+
- `useSiteContext()` — returns `{ siteCode, currency, targetLocation,
|
|
185
|
+
setSite }` for the active site. In MS-2 `currency` and `targetLocation`
|
|
186
|
+
are `null` (populated in MS-4). `setSite(code)` writes storage, clears
|
|
187
|
+
`storage.cartId` (carts are site-aware), and invalidates all
|
|
188
|
+
`["emporix"]` queries.
|
|
189
|
+
|
|
190
|
+
**Storage**
|
|
191
|
+
- `EmporixStorage.{get,set}SiteCode` across all three backends (memory,
|
|
192
|
+
localStorage, cookie). localStorage key: `emporix.siteCode`.
|
|
193
|
+
|
|
194
|
+
**Cache keys**
|
|
195
|
+
- All site-aware query keys (`useProducts`, `useCategories`, `useCart`,
|
|
196
|
+
`useActiveCart`, `useCartMutations`, `useMatchPrices`, `useMySegment*`,
|
|
197
|
+
`usePaymentModes`, etc.) now include `siteCode`. Different sites =
|
|
198
|
+
separate cache entries. Internal change — no consumer subscribed
|
|
199
|
+
directly to query keys.
|
|
200
|
+
|
|
201
|
+
No breaking changes. Existing single-site apps work unchanged — they
|
|
202
|
+
implicitly run with the static config's `siteCode` (or `null`).
|
|
203
|
+
|
|
204
|
+
- [#39](https://github.com/viuteam/emporix-sdk/pull/39) [`141521c`](https://github.com/viuteam/emporix-sdk/commit/141521c91f88171006067255294a45b9fdc01a43) Thanks [@amnael1](https://github.com/amnael1)! - Multi-site MS-3: server-side session-context sync.
|
|
205
|
+
|
|
206
|
+
**SDK**
|
|
207
|
+
- `client.sessionContext.get()` — `GET /session-context/{tenant}/me/context`.
|
|
208
|
+
Returns `null` (not throws) when the server returns 404 — i.e. when the
|
|
209
|
+
user has not created a cart yet and no session-context exists.
|
|
210
|
+
- `client.sessionContext.patch(input)` — `PATCH /session-context/{tenant}/me/context`
|
|
211
|
+
with optimistic-locking. Looks up `metadata.version` via GET first
|
|
212
|
+
unless caller provides one. Returns `true` when applied, `false` when
|
|
213
|
+
there is no session context yet (404 on the GET → patch skipped).
|
|
214
|
+
- New `SessionContext` and `SessionContextPatch` types.
|
|
215
|
+
|
|
216
|
+
**React**
|
|
217
|
+
- `setSite()` is now async. It flips local state + storage + cart-id
|
|
218
|
+
- cache-invalidation synchronously (optimistic UI), then PATCHes the
|
|
219
|
+
server. Skips the PATCH when no session exists yet (404 on GET).
|
|
220
|
+
- `useSiteContext()` gains `isSwitching: boolean` and
|
|
221
|
+
`switchError: Error | null`. The optimistic state is NOT rolled back
|
|
222
|
+
on PATCH failure — surface the error in UI; the next user interaction
|
|
223
|
+
retries.
|
|
224
|
+
|
|
225
|
+
No breaking changes. Existing call sites continue to work — `setSite("X")`
|
|
226
|
+
without `await` still flips the UI; awaiting it blocks until the
|
|
227
|
+
server-side sync completes.
|
|
228
|
+
|
|
229
|
+
- [#40](https://github.com/viuteam/emporix-sdk/pull/40) [`b23d3eb`](https://github.com/viuteam/emporix-sdk/commit/b23d3eb51ebe98a0d1f90499409b1b509810722c) Thanks [@amnael1](https://github.com/amnael1)! - Multi-site MS-4: currency + targetLocation auto-derive, preferredSite honour.
|
|
230
|
+
|
|
231
|
+
**Provider**
|
|
232
|
+
- `useSiteContext().currency` and `useSiteContext().targetLocation` are no
|
|
233
|
+
longer always `null`. They derive from the active site's DTO
|
|
234
|
+
(`site.currency` and `site.homeBase.address.country`), cached for 5
|
|
235
|
+
minutes via React-Query.
|
|
236
|
+
- `setSite(code)` fetches the site DTO, populates `currency` /
|
|
237
|
+
`targetLocation`, and includes all three fields in the
|
|
238
|
+
`sessionContext.patch` body so the server is fully in sync.
|
|
239
|
+
- On provider mount with a pre-resolved `siteCode` (from `initialSiteCode`
|
|
240
|
+
prop, storage, or static config), the site DTO is fetched once so
|
|
241
|
+
`currency` and `targetLocation` populate without a user-driven switch.
|
|
242
|
+
|
|
243
|
+
**Login**
|
|
244
|
+
- `useCustomerSession.login` (and `socialLogin` / `exchangeToken`) now read
|
|
245
|
+
`customer.preferredSite`. If it's set and differs from the active site,
|
|
246
|
+
the SDK calls `setSite(preferredSite)` — same flow as a user-driven
|
|
247
|
+
switch. Best-effort: a failure here never blocks login.
|
|
248
|
+
|
|
249
|
+
No breaking changes. Storefronts without `preferredSite` set on their
|
|
250
|
+
customers see no behavior change.
|
|
251
|
+
|
|
252
|
+
- [#42](https://github.com/viuteam/emporix-sdk/pull/42) [`8d22fb8`](https://github.com/viuteam/emporix-sdk/commit/8d22fb8d4cdf5e2ddeba7273ffe4b41a1630d463) Thanks [@amnael1](https://github.com/amnael1)! - Add opt-in telemetry channel for observability + ops-tuning.
|
|
253
|
+
|
|
254
|
+
**SDK (additive)**
|
|
255
|
+
- `TokenProvider.onRefresh(listener)` — optional subscription to
|
|
256
|
+
token-refresh events. `DefaultTokenProvider` implements it (anonymous
|
|
257
|
+
refresh path).
|
|
258
|
+
|
|
259
|
+
**React (additive)**
|
|
260
|
+
- `<EmporixProvider onTelemetry={fn}>` — receives a typed event stream
|
|
261
|
+
covering cache hit/miss, refetches, errors, mutations, auth refreshes,
|
|
262
|
+
and storage writes.
|
|
263
|
+
- `useEmporixTelemetry()` — returns `{ emit }` for consumer-side custom
|
|
264
|
+
events on the same channel.
|
|
265
|
+
- `EmporixStorage.subscribeAll(listener)` — optional subscription to all
|
|
266
|
+
storage write events. Implemented in all three built-in adapters
|
|
267
|
+
(memory, localStorage, cookie).
|
|
268
|
+
|
|
269
|
+
**Event types:**
|
|
270
|
+
- `cache.hit`, `cache.miss`, `query.refetch`, `query.error`
|
|
271
|
+
- `mutation.success`, `mutation.error`
|
|
272
|
+
- `auth.refresh`
|
|
273
|
+
- `storage.write`
|
|
274
|
+
- `custom`
|
|
275
|
+
|
|
276
|
+
No breaking changes. The entire telemetry layer is no-op when
|
|
277
|
+
`onTelemetry` is not passed. Existing `TokenProvider` / `EmporixStorage`
|
|
278
|
+
implementations continue to work without implementing the new optional
|
|
279
|
+
methods.
|
|
280
|
+
|
|
281
|
+
- [#50](https://github.com/viuteam/emporix-sdk/pull/50) [`4157818`](https://github.com/viuteam/emporix-sdk/commit/4157818c27b32ff32a1a41235bc7920137402f88) Thanks [@amnael1](https://github.com/amnael1)! - Order service hooks:
|
|
282
|
+
- Customer-facing: `useMyOrders`, `useMyOrdersInfinite`, `useOrder`, `useCancelOrder`, `useOrderTransition`, `useReorder`.
|
|
283
|
+
- Service-account (backoffice): `useSalesOrder`, `useUpdateSalesOrder` — inert when `auth` is undefined so storefront apps can import them for types without unexpected backend traffic.
|
|
284
|
+
- New `prefetchOrder` SSR helper alongside `prefetchProduct` / `prefetchCart`.
|
|
285
|
+
- `useMyOrders` / `useMyOrdersInfinite` default `legalEntityId` from `useActiveCompany`; explicit `null` disables. Switching the active company auto-invalidates order queries because `legalEntityId` is part of the cache key.
|
|
286
|
+
- `useReorder` uses a single `cart.addItemsBatch` call instead of N sequential `addItem` requests. Per-entry HTTP status feeds the unchanged `{ added, errors }` mutation result; partial failures still don't throw. Caps at 200 line-items (Emporix server-side limit).
|
|
287
|
+
|
|
288
|
+
- [#24](https://github.com/viuteam/emporix-sdk/pull/24) [`2014f71`](https://github.com/viuteam/emporix-sdk/commit/2014f710ee363f35aea1d8af0e85bce69a5bc40a) Thanks [@amnael1](https://github.com/amnael1)! - Harmonize all paginated SDK surfaces on `PaginatedItems<T>`. Removes the
|
|
289
|
+
legacy `Page<T>` shape (whose `total` was always `NaN`, since the HTTP
|
|
290
|
+
client never exposed `X-Total-Count`) and the `paginate()` async
|
|
291
|
+
iterator.
|
|
292
|
+
|
|
293
|
+
**BREAKING:**
|
|
294
|
+
- `ProductService.list` / `ProductService.search` now return
|
|
295
|
+
`PaginatedItems<Product>` (`{ items, pageNumber, pageSize, hasNextPage }`)
|
|
296
|
+
instead of `Page<Product>` (`{ items, total, offset, limit }`).
|
|
297
|
+
- `CategoryService.list` returns `PaginatedItems<Category>`;
|
|
298
|
+
`CategoryService.productsIn` returns `PaginatedItems<Product>`.
|
|
299
|
+
- `useProducts` / `useCategories` now resolve to `PaginatedItems<T>`.
|
|
300
|
+
- `Page<T>` and `paginate()` are no longer exported from `@viu/emporix-sdk`.
|
|
301
|
+
|
|
302
|
+
**Fixed:**
|
|
303
|
+
- `useProductsInfinite` previously over-fetched a trailing empty page
|
|
304
|
+
before terminating, and its `getNextPageParam` was tied to the
|
|
305
|
+
fetched-page count rather than the cursor. It now derives the next
|
|
306
|
+
page from `last.hasNextPage` / `last.pageNumber + 1` — same pattern as
|
|
307
|
+
the segment-hydrate infinite hooks.
|
|
308
|
+
|
|
309
|
+
**Added:**
|
|
310
|
+
- `useCategoriesInfinite` — mirror of `useProductsInfinite`.
|
|
311
|
+
- `iterateAll<T>(fetchPage, start?)` async iterator over
|
|
312
|
+
`PaginatedItems<T>`. Replaces `paginate()` for "iterate every item
|
|
313
|
+
across pages" use cases.
|
|
314
|
+
|
|
315
|
+
**Migration:**
|
|
316
|
+
|
|
317
|
+
```ts
|
|
318
|
+
// Before
|
|
319
|
+
const { items, total } = await client.products.list({
|
|
320
|
+
pageNumber: 1,
|
|
321
|
+
pageSize: 50,
|
|
322
|
+
});
|
|
323
|
+
// total was always NaN.
|
|
324
|
+
|
|
325
|
+
// After
|
|
326
|
+
const { items, hasNextPage } = await client.products.list({
|
|
327
|
+
pageNumber: 1,
|
|
328
|
+
pageSize: 50,
|
|
329
|
+
});
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
```ts
|
|
333
|
+
// Before
|
|
334
|
+
for await (const p of paginate((offset, limit) => svc.list(...), 50)) { ... }
|
|
335
|
+
|
|
336
|
+
// After
|
|
337
|
+
for await (const p of svc.listAll({ pageSize: 50 })) { ... }
|
|
338
|
+
// or, for custom sources:
|
|
339
|
+
for await (const x of iterateAll<X>((pageNumber) => fetchPage(pageNumber))) { ... }
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
- [#31](https://github.com/viuteam/emporix-sdk/pull/31) [`13f23bd`](https://github.com/viuteam/emporix-sdk/commit/13f23bd9016903c59ca1bfa0b340ff096587131e) Thanks [@amnael1](https://github.com/amnael1)! - Add npm publish readiness metadata: `license` (MIT), `repository`, `bugs`, `homepage`, `author`, `keywords` in `package.json`. Adds the `LICENSE` file at the repo root (npm includes it in each package tarball automatically). No code changes; the next release will be the first one with full npm-side metadata for discoverability + provenance attestation.
|
|
343
|
+
|
|
344
|
+
- [#48](https://github.com/viuteam/emporix-sdk/pull/48) [`5f330d5`](https://github.com/viuteam/emporix-sdk/commit/5f330d521119e36ca95b8cfc3bed049572fd1c03) Thanks [@amnael1](https://github.com/amnael1)! - Raise Node.js engines floor from `>=18` to `>=20.19.0`. Node 18 reached end-of-life on 30 April 2025; Node 20 LTS (≥ 20.19.0, which ships flag-free `require(esm)`) is the new minimum. Development happens on Node 24 LTS (`.nvmrc` updated); CI exercises Node 20, 22, and 24.
|
|
345
|
+
|
|
346
|
+
No code changes — no SDK feature uses a Node API beyond what Node 20 provides. Browser consumers are unaffected.
|
|
347
|
+
|
|
348
|
+
- [#3](https://github.com/viuteam/emporix-sdk/pull/3) [`e2f74db`](https://github.com/viuteam/emporix-sdk/commit/e2f74db04edb1d4250add83a4b8208bc33e326c7) Thanks [@amnael1](https://github.com/amnael1)! - Add @viu/emporix-sdk-react: provider, pluggable token storage, customer
|
|
349
|
+
session, query hooks, cart mutations with optimistic updates, error helpers and
|
|
350
|
+
SSR prefetch helpers. Core: expose EmporixClient.tenant for query-key namespacing.
|
|
351
|
+
|
|
352
|
+
- [#23](https://github.com/viuteam/emporix-sdk/pull/23) [`027b816`](https://github.com/viuteam/emporix-sdk/commit/027b816c171e81263b99b791916e33816f148839) Thanks [@amnael1](https://github.com/amnael1)! - Segment hydrate now uses a single Emporix `POST /search` per page instead
|
|
353
|
+
of N+1 `GET /products/{id}` calls. New
|
|
354
|
+
`ProductService.searchByIds(ids, { chunkSize? }, auth?)` and
|
|
355
|
+
`CategoryService.searchByIds(...)` POST `/search` with
|
|
356
|
+
`q="id:(id1,id2,…)"`, chunking at 100 IDs by default. Adds the generic
|
|
357
|
+
`PaginatedItems<T>` (`{ items, pageNumber, pageSize, hasNextPage }`) in
|
|
358
|
+
`core/context.ts`.
|
|
359
|
+
|
|
360
|
+
**BREAKING:** `SegmentService.listMyProducts` and
|
|
361
|
+
`SegmentService.listMyCategories` now return `PaginatedItems<Product>` /
|
|
362
|
+
`PaginatedItems<Category>` instead of a flat `Product[]` / `Category[]`.
|
|
363
|
+
`SegmentService.listItems` gains optional `pageNumber` / `pageSize`
|
|
364
|
+
params (additive). `listMyProductIds` / `listMyCategoryIds` are
|
|
365
|
+
unchanged.
|
|
366
|
+
|
|
367
|
+
React adds four new hooks: `useMySegmentProducts` /
|
|
368
|
+
`useMySegmentProductsInfinite` and `useMySegmentCategories` /
|
|
369
|
+
`useMySegmentCategoriesInfinite`. The infinite variants use
|
|
370
|
+
`useInfiniteQuery` with a `pageNumber` cursor and `hasNextPage`-driven
|
|
371
|
+
`getNextPageParam`. All four are disabled when no customer token is in
|
|
372
|
+
storage.
|
|
373
|
+
|
|
374
|
+
- [#20](https://github.com/viuteam/emporix-sdk/pull/20) [`4cda829`](https://github.com/viuteam/emporix-sdk/commit/4cda82963d307fa12b1e1e628be31879f464ed9d) Thanks [@amnael1](https://github.com/amnael1)! - Add Emporix customer SSO support. `customers.socialLogin({ code, redirectUri,
|
|
375
|
+
codeVerifier?, sessionId? })` performs the Authorization-Code code exchange
|
|
376
|
+
(`POST /customer/{tenant}/socialLogin`); `customers.exchangeToken({
|
|
377
|
+
subjectToken, config? })` performs the RFC 8693 token exchange
|
|
378
|
+
(`POST /customer/{tenant}/exchangeauthtoken`). Both default to anonymous auth
|
|
379
|
+
and return a `CustomerSession` (now with optional `socialAccessToken` /
|
|
380
|
+
`socialIdToken` from socialLogin); `expires_in` is normalized to a number
|
|
381
|
+
across both flows. `useCustomerSession` gains `socialLogin` and
|
|
382
|
+
`exchangeToken` actions that store the session like `login`.
|
|
383
|
+
|
|
384
|
+
- [#35](https://github.com/viuteam/emporix-sdk/pull/35) [`9a260c8`](https://github.com/viuteam/emporix-sdk/commit/9a260c8963a3c44f489d3433e3db624447a5bd4e) Thanks [@amnael1](https://github.com/amnael1)! - `useCart` and `useCartMutations` now read the active cartId from `storage`
|
|
385
|
+
when their `cartId` argument is omitted. Pair with `useActiveCart` to drop
|
|
386
|
+
the `useCartMutations(cartId ?? "")` boilerplate:
|
|
387
|
+
- `useCart()` — disabled until storage has a cartId, then auto-resolves.
|
|
388
|
+
- `useCartMutations()` — resolves cartId at mutate-time; throws
|
|
389
|
+
`EmporixError("no cartId available…")` if storage is empty when a
|
|
390
|
+
mutation runs.
|
|
391
|
+
|
|
392
|
+
`useActiveCart` is now a thin wrapper around `useCart` and shares the same
|
|
393
|
+
React-Query cache key. Optimistic updates from `useCartMutations` now
|
|
394
|
+
propagate to every cart-aware view in one place.
|
|
395
|
+
|
|
396
|
+
`useCreateCart` additionally invalidates `["emporix","cart"]` on success so
|
|
397
|
+
`useActiveCart` picks up the new storage cartId on the next render.
|
|
398
|
+
|
|
399
|
+
`useActiveCart`'s `data` now correctly returns `null` (not `undefined`)
|
|
400
|
+
when storage has no cartId and `create` was not requested — matches the
|
|
401
|
+
documented empty-state signal.
|
|
402
|
+
|
|
403
|
+
No breaking changes — every old call signature still works.
|
|
404
|
+
|
|
405
|
+
- [#32](https://github.com/viuteam/emporix-sdk/pull/32) [`7c90d08`](https://github.com/viuteam/emporix-sdk/commit/7c90d0835f881b4b9528d30d5cda6e823e742b4e) Thanks [@amnael1](https://github.com/amnael1)! - Add `useActiveCart(opts?)` hook to `@viu/emporix-sdk-react`. Resolves to the cart matching `storage.cartId`; with `opts.create = true`, bootstraps a new cart via `client.carts.getCurrent({siteCode, create: true})` when storage is empty.
|
|
406
|
+
|
|
407
|
+
Returns `UseQueryResult<Cart | null>`. Coexists with `useCart(cartId)` (different query-key); use `useActiveCart` for "the storefront's current cart" and `useCart(cartId)` for known ids.
|
|
408
|
+
|
|
409
|
+
Useful for:
|
|
410
|
+
- Cart-page mounts: `useActiveCart({ create: true })`.
|
|
411
|
+
- Header mini-cart: `useActiveCart()` (read-only, no auto-create).
|
|
412
|
+
- B2B quote carts in parallel to shopping carts: `useActiveCart({ create: true, type: "quote" })`.
|
|
413
|
+
|
|
414
|
+
No SDK change; uses the existing `client.carts.getCurrent` and `client.carts.get` APIs. Auto-detects customer vs anonymous auth like the other read hooks.
|
|
415
|
+
|
|
416
|
+
- [#25](https://github.com/viuteam/emporix-sdk/pull/25) [`277ae71`](https://github.com/viuteam/emporix-sdk/commit/277ae7195ab9eecb87677fff4e8fcd16ea3b920b) Thanks [@amnael1](https://github.com/amnael1)! - Hook-only guest checkout + persistent anonymous cart.
|
|
417
|
+
|
|
418
|
+
**SDK (`@viu/emporix-sdk`)**
|
|
419
|
+
- New `AnonymousSessionStore` interface and optional `TokenProvider.attachAnonymousStore` method. When a host (e.g. `EmporixProvider`) supplies a store, `DefaultTokenProvider` bootstraps `anon` from the store on first use (taking the refresh-token path, so `sessionId` is preserved) and writes the rotated `refreshToken` + `sessionId` back after every login / refresh. With no store attached, behavior is identical to before.
|
|
420
|
+
- `invalidateAnonymous()` now also clears the attached store (`write(null)`).
|
|
421
|
+
- `EmporixClient.tokenProvider` is now a public, read-only field — so hosts can call `attachAnonymousStore` after construction.
|
|
422
|
+
|
|
423
|
+
**React (`@viu/emporix-sdk-react`)**
|
|
424
|
+
- `TokenStorage` renamed to `EmporixStorage` (alias `TokenStorage` is kept). New methods: `getCartId / setCartId`, `getAnonymousSession / setAnonymousSession`. All three storage backends — memory, `localStorage`, cookie — implement them.
|
|
425
|
+
- `EmporixProvider` wires the storage's anonymous-session accessors to the SDK's `attachAnonymousStore` so the anonymous cart can survive a browser reload.
|
|
426
|
+
- New `useCreateCart` mutation hook: auto-detects customer vs anonymous auth and persists `cartId` via `storage.setCartId`.
|
|
427
|
+
- `useCheckout` no longer throws on missing customer token — it auto-detects (customer if a token is stored, else anonymous). `usePaymentModes` keeps its customer-only behavior. Backward-compatible for existing logged-in flows.
|
|
428
|
+
|
|
429
|
+
**Migration**
|
|
430
|
+
|
|
431
|
+
No code change needed for existing consumers — both packages' changes are additive or strict supersets. New persistence kicks in automatically when consumers use one of the persistent storage backends (`createLocalStorageStorage()` or `createCookieStorage()`).
|
|
432
|
+
|
|
433
|
+
### Patch Changes
|
|
434
|
+
|
|
435
|
+
- [#45](https://github.com/viuteam/emporix-sdk/pull/45) [`3f700d8`](https://github.com/viuteam/emporix-sdk/commit/3f700d8fbd4796429f998dd441c64816b3c5bfdb) Thanks [@amnael1](https://github.com/amnael1)! - Internal cleanup: drop the redundant `authKind` field from `useReadAuth`'s
|
|
436
|
+
return type and from `bootstrapCart`'s parameter list. Both duplicated
|
|
437
|
+
`ctx.kind` (the discriminator of `AuthContext`) — callers now compose
|
|
438
|
+
`ctx.kind` directly into query keys.
|
|
439
|
+
|
|
440
|
+
No public API changes. No cache-key shape changes (`authKind` values stay
|
|
441
|
+
identical: `"customer"`, `"anonymous"`, etc.). All 151 React tests stay
|
|
442
|
+
green.
|
|
443
|
+
|
|
444
|
+
- [#28](https://github.com/viuteam/emporix-sdk/pull/28) [`4fc01ef`](https://github.com/viuteam/emporix-sdk/commit/4fc01ef737c9397407937ee9ca8098a781ac075e) Thanks [@amnael1](https://github.com/amnael1)! - Add live end-to-end test suite (`@viu/emporix-e2e`, private) running through the `examples/vite-spa` Example against the `viu` tenant. Six specs cover the four critical user flows:
|
|
445
|
+
- **`catalog.spec.ts`** — anonymous catalog renders 12 products; only `GET /anonymous/login` + `GET /product/viu/products` hit Emporix on `/`.
|
|
446
|
+
- **`customer-session.spec.ts`** — login resolves the customer profile + stores the token; logout clears the token.
|
|
447
|
+
- **`guest-checkout.spec.ts`** — `useCreateCart` → `useCartMutations.addItem` → `useCheckout.placeOrder` (anonymous) → real order `EONxxxx` placed on `viu`.
|
|
448
|
+
- **`customer-cart-onboarding.spec.ts`** — guest cart created → login → `GET /cart/viu/carts?siteCode=main&create=true` + `POST /merge` fire → `storage.cartId` switched to the customer cart.
|
|
449
|
+
|
|
450
|
+
This is the first **live** verification of the PR #26 customer-cart-onboarding flow, previously covered only by MSW mocks. No SDK/React code changes — the suite is purely additive test infrastructure (separate `e2e/` workspace package, `@playwright/test` v1.49, `workflow_dispatch` CI workflow). Credentials are env-driven (`EMPORIX_TEST_CUSTOMER_EMAIL` / `_PASSWORD`); login-bound specs skip cleanly without them. Passwords are filled via a custom `fillSecret` helper that bypasses `page.fill()` so values never appear in the HTML report or action log.
|
|
451
|
+
|
|
452
|
+
Local runs: `pnpm e2e`. CI runs: trigger `e2e.yml` from the Actions tab. See [`docs/e2e.md`](../docs/e2e.md) for authoring workflow + Playwright Agent CLI usage.
|
|
453
|
+
|
|
454
|
+
- [#11](https://github.com/viuteam/emporix-sdk/pull/11) [`40f8e65`](https://github.com/viuteam/emporix-sdk/commit/40f8e65177699685c1114714f5b3f080cfab89f2) Thanks [@amnael1](https://github.com/amnael1)! - Order `exports` conditions so `types` resolves first. Node and the
|
|
455
|
+
TypeScript resolver evaluate `exports` conditions in declaration order;
|
|
456
|
+
with `import`/`require` listed before `types`, the `types` condition was
|
|
457
|
+
never reached, emitting build warnings and preventing consumers from
|
|
458
|
+
picking up the generated `.d.ts` entry points. Every subpath in both
|
|
459
|
+
packages now uses `{ types, import, require }` order.
|
|
460
|
+
|
|
461
|
+
- [#44](https://github.com/viuteam/emporix-sdk/pull/44) [`d0cc756`](https://github.com/viuteam/emporix-sdk/commit/d0cc75603db779447c4ffe84aa349c8e59db13df) Thanks [@amnael1](https://github.com/amnael1)! - Include LICENSE in the published npm tarballs. The `files` array already
|
|
462
|
+
declared `LICENSE` but the file was only present at the repo root; npm
|
|
463
|
+
publishes per-package, so a copy now lives inside each package directory.
|
|
464
|
+
Fixes "License: not specified" on npmjs.com and unblocks corporate
|
|
465
|
+
license-compliance scanners (Snyk, Black Duck).
|
|
466
|
+
|
|
467
|
+
- [#46](https://github.com/viuteam/emporix-sdk/pull/46) [`11ca224`](https://github.com/viuteam/emporix-sdk/commit/11ca22430e376814819faec0f9946a234ef0e9bd) Thanks [@ndyn](https://github.com/ndyn)! - Pre-1.0 publish metadata polish:
|
|
468
|
+
- **`@viu/emporix-sdk-react`**: tighten the `@tanstack/react-query` peer
|
|
469
|
+
range from `^5.0.0` to `^5.51.0`. This matches the version the package
|
|
470
|
+
is developed and tested against. The previous range claimed support
|
|
471
|
+
for v5.0–v5.50 that was never exercised in CI; tightening avoids a
|
|
472
|
+
silent runtime mismatch for consumers who happen to be on those older
|
|
473
|
+
patch versions.
|
|
474
|
+
- **Both packages**: replace the bare-string `author: "viuteam"` with an
|
|
475
|
+
`author` object — `{ "name": "viu", "url": "https://github.com/viuteam" }`
|
|
476
|
+
— so the npm package page shows "viu" (our display name) and links
|
|
477
|
+
back to the GitHub org page (`viuteam`, the actual org slug).
|
|
478
|
+
- **`LICENSE` (root and per-package)**: the MIT copyright holder is now
|
|
479
|
+
`VIU AG` (the legal entity) instead of the GitHub org slug `viuteam`,
|
|
480
|
+
so license-compliance scanners attribute the package correctly.
|
|
481
|
+
|
|
482
|
+
- [#45](https://github.com/viuteam/emporix-sdk/pull/45) [`1bf87ce`](https://github.com/viuteam/emporix-sdk/commit/1bf87cec82a04f816200351881a6c77eabc4ed5f) Thanks [@amnael1](https://github.com/amnael1)! - Internal redundancy cleanup. All changes are non-breaking — public API
|
|
483
|
+
unchanged, all 151 React tests stay green.
|
|
484
|
+
|
|
485
|
+
**Storage**
|
|
486
|
+
- Extract `createListenerSet<T>()` helper used by all three backends'
|
|
487
|
+
`subscribeAll` — single try/catch wrapper instead of three copies.
|
|
488
|
+
- Extract `parseAnonymousSession()` helper for the JSON-parse-with-fallback
|
|
489
|
+
shared by localStorage and cookie backends.
|
|
490
|
+
|
|
491
|
+
**Hooks**
|
|
492
|
+
- `emporixKey(resource, args, ctx)` helper centralizes the
|
|
493
|
+
`["emporix", resource, …args, { tenant, authKind, siteCode? }]` cache
|
|
494
|
+
key shape used by 15+ Read hooks.
|
|
495
|
+
- `useEmporixInfinite()` helper centralizes the `initialPageParam: 1` +
|
|
496
|
+
`getNextPageParam` cursor logic shared by 6 infinite-scroll hooks
|
|
497
|
+
(products, categories, segments).
|
|
498
|
+
|
|
499
|
+
**Auth**
|
|
500
|
+
- `useCheckout` now uses the central `useReadAuth` hook instead of a
|
|
501
|
+
local `checkoutCtx` helper.
|
|
502
|
+
- `usePaymentModes` cache key gains a stable `authKind: "customer"`
|
|
503
|
+
component for consistency with other hooks.
|
|
504
|
+
|
|
505
|
+
**Customer session**
|
|
506
|
+
- `useCustomerSession` bundles the three separate `useState` calls
|
|
507
|
+
(token / refreshToken / saasToken) into a single `SessionState` object.
|
|
508
|
+
Login / logout / refresh / SSO flows now flip the session atomically
|
|
509
|
+
via one `setSession(...)` call instead of three. Same public API,
|
|
510
|
+
same behaviour — only an internal state-shape consolidation.
|
|
511
|
+
|
|
512
|
+
- [#27](https://github.com/viuteam/emporix-sdk/pull/27) [`ffb4b07`](https://github.com/viuteam/emporix-sdk/commit/ffb4b07db5186c70783fc6cbf60c6d586ed36eab) Thanks [@amnael1](https://github.com/amnael1)! - Refactor `hooks/queries.ts` into domain-aligned files (`use-products.ts`, `use-categories.ts`, `use-cart.ts`) matching the rest of the package. The shared `useReadAuth` helper now lives in `hooks/internal/use-read-auth.ts`. `use-cart-mutations.ts` is consolidated into `use-cart.ts`, which now holds every cart hook (read + mutations + create).
|
|
513
|
+
|
|
514
|
+
**Fix:** `useCategoriesInfinite` is now re-exported from the package root. It was defined but not exported in the prior release.
|
|
515
|
+
|
|
516
|
+
No public hook name, behavior, or query-key changed. Consumer imports from `@viu/emporix-sdk-react` continue to work.
|
|
517
|
+
|
|
518
|
+
- Updated dependencies [[`5c51a58`](https://github.com/viuteam/emporix-sdk/commit/5c51a58313c63cb7a9e34a4c5e6dc1da2017a827), [`bda4bd8`](https://github.com/viuteam/emporix-sdk/commit/bda4bd8b5b02e2b397f3a0751a45ac204b8572a0), [`765c54e`](https://github.com/viuteam/emporix-sdk/commit/765c54e8fd61e33cb0d4cc241415e9c56f45c729), [`f18e55c`](https://github.com/viuteam/emporix-sdk/commit/f18e55ceec9784e5aad6e95604e016c5858f9bdc), [`f312f22`](https://github.com/viuteam/emporix-sdk/commit/f312f228f17686476ce3458436758bd05af63fce), [`e10854f`](https://github.com/viuteam/emporix-sdk/commit/e10854fc9ef11fec74f24e65dedbe11c3ca09d22), [`959c6cc`](https://github.com/viuteam/emporix-sdk/commit/959c6cc3d0a4a37870cb72d5573b6fde9b0faa65), [`d52bcdc`](https://github.com/viuteam/emporix-sdk/commit/d52bcdc79433daaf143586264a409cad57e404a1), [`18e34a0`](https://github.com/viuteam/emporix-sdk/commit/18e34a03cbf4fbfe15a7e4995228bb5268b0e2ee), [`2f823b8`](https://github.com/viuteam/emporix-sdk/commit/2f823b8eb72eca17863757c3f6ccbf3e76442ee3), [`5770532`](https://github.com/viuteam/emporix-sdk/commit/57705327b4d58b1ac410ee958f85ae858a6c862d), [`7da7b21`](https://github.com/viuteam/emporix-sdk/commit/7da7b217912782ba5d9b3f1e959d78d70c32c4ba), [`4fc01ef`](https://github.com/viuteam/emporix-sdk/commit/4fc01ef737c9397407937ee9ca8098a781ac075e), [`5f6cb4a`](https://github.com/viuteam/emporix-sdk/commit/5f6cb4ad207f4a1c8562d1da1713255762b9c436), [`40f8e65`](https://github.com/viuteam/emporix-sdk/commit/40f8e65177699685c1114714f5b3f080cfab89f2), [`4cdfa41`](https://github.com/viuteam/emporix-sdk/commit/4cdfa411ffb48b79510b0e98faa9ddf6f8c0600c), [`4d87f11`](https://github.com/viuteam/emporix-sdk/commit/4d87f11a022996a49dad04af1404394cdd60804f), [`693c58c`](https://github.com/viuteam/emporix-sdk/commit/693c58c5d148eeef746aef18a8f5dada766d7041), [`59b78a8`](https://github.com/viuteam/emporix-sdk/commit/59b78a87d1dd56568e068c0a7738223714cb086b), [`877c2ab`](https://github.com/viuteam/emporix-sdk/commit/877c2abf791a6d67d438849cd800d5704ec486cb), [`380796a`](https://github.com/viuteam/emporix-sdk/commit/380796a53d9543b379b21eb414e3ebc5586e55f8), [`141521c`](https://github.com/viuteam/emporix-sdk/commit/141521c91f88171006067255294a45b9fdc01a43), [`8d22fb8`](https://github.com/viuteam/emporix-sdk/commit/8d22fb8d4cdf5e2ddeba7273ffe4b41a1630d463), [`4157818`](https://github.com/viuteam/emporix-sdk/commit/4157818c27b32ff32a1a41235bc7920137402f88), [`2014f71`](https://github.com/viuteam/emporix-sdk/commit/2014f710ee363f35aea1d8af0e85bce69a5bc40a), [`d0cc756`](https://github.com/viuteam/emporix-sdk/commit/d0cc75603db779447c4ffe84aa349c8e59db13df), [`dfabb02`](https://github.com/viuteam/emporix-sdk/commit/dfabb02882ca65e2a32e4a52082c0b14dc71faa8), [`11ca224`](https://github.com/viuteam/emporix-sdk/commit/11ca22430e376814819faec0f9946a234ef0e9bd), [`13f23bd`](https://github.com/viuteam/emporix-sdk/commit/13f23bd9016903c59ca1bfa0b340ff096587131e), [`5f330d5`](https://github.com/viuteam/emporix-sdk/commit/5f330d521119e36ca95b8cfc3bed049572fd1c03), [`e2f74db`](https://github.com/viuteam/emporix-sdk/commit/e2f74db04edb1d4250add83a4b8208bc33e326c7), [`027b816`](https://github.com/viuteam/emporix-sdk/commit/027b816c171e81263b99b791916e33816f148839), [`4cda829`](https://github.com/viuteam/emporix-sdk/commit/4cda82963d307fa12b1e1e628be31879f464ed9d), [`277ae71`](https://github.com/viuteam/emporix-sdk/commit/277ae7195ab9eecb87677fff4e8fcd16ea3b920b)]:
|
|
519
|
+
- @viu/emporix-sdk@1.0.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 VIU AG
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# @viu/emporix-sdk-react
|
|
2
|
+
|
|
3
|
+
React bindings for `@viu/emporix-sdk`, built on
|
|
4
|
+
[`@tanstack/react-query`](https://tanstack.com/query) v5. Supports React 18 & 19.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
pnpm add @viu/emporix-sdk-react @viu/emporix-sdk @tanstack/react-query react
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
`@viu/emporix-sdk`, `@tanstack/react-query` and `react` are peer dependencies.
|
|
13
|
+
|
|
14
|
+
## Provider
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
import { EmporixClient } from "@viu/emporix-sdk";
|
|
18
|
+
import { EmporixProvider, createLocalStorageStorage } from "@viu/emporix-sdk-react";
|
|
19
|
+
|
|
20
|
+
const client = new EmporixClient({
|
|
21
|
+
tenant: "mytenant",
|
|
22
|
+
credentials: { backend: { clientId: "", secret: "" }, storefront: { clientId: "x" } },
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
<EmporixProvider client={client} storage={createLocalStorageStorage()}>
|
|
26
|
+
<App />
|
|
27
|
+
</EmporixProvider>;
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Create `EmporixClient` **once** (per app, or once per server for SSR) — never
|
|
31
|
+
per request/render.
|
|
32
|
+
|
|
33
|
+
## Hooks
|
|
34
|
+
|
|
35
|
+
| Hook | Purpose |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| `useCustomerSession()` | `customerToken`, `customer`, `isAuthenticated`, `login`, `signup`, `logout`, `refresh` |
|
|
38
|
+
| `useProduct` / `useProducts` / `useProductsInfinite` / `useProductByCode` / `useProductSearch` | product reads |
|
|
39
|
+
| `useCategory` / `useCategories` / `useCategoryTree` / `useProductsInCategory(Infinite)` | category reads |
|
|
40
|
+
| `useCart(cartId?)` / `useActiveCart(opts?)` / `useCreateCart()` | cart read + bootstrap |
|
|
41
|
+
| `useCartMutations(cartId?)` | add/update/remove/clear/coupons/addresses — optimistic + rollback |
|
|
42
|
+
| `useCheckout()` / `usePaymentModes()` | checkout flow + payment-mode list |
|
|
43
|
+
| `useMatchPrices()` / `useProductMedia()` | price + media reads |
|
|
44
|
+
| `useMySegments` / `useMySegmentItems` / `useMySegment{Products,Categories}(Infinite)` / `useMySegmentCategoryTree` | customer-segment reads |
|
|
45
|
+
| `useUpdateCustomer` / `useChangePassword` / `usePasswordReset` | account management |
|
|
46
|
+
| `useCustomerAddresses` / `useAddressMutations` | address CRUD |
|
|
47
|
+
| `useSites` / `useDefaultSite` / `useSiteContext` | multi-site context |
|
|
48
|
+
| `useActiveCompany` / `useCompanySwitcher` | active legal entity (B2B) |
|
|
49
|
+
| `useMyCompanies` / `useCompany` / `useCompanyContacts` / `useCompanyLocations` / `useCompanyGroups` | B2B reads |
|
|
50
|
+
| `useCreateCompany` / `useUpdateCompany` / `useDeleteCompany` | B2B admin mutations |
|
|
51
|
+
| `useAssignContact` / `useUpdateContactAssignment` / `useUnassignContact` | B2B contact-assignment mutations |
|
|
52
|
+
| `useCreateLocation` / `useUpdateLocation` / `useDeleteLocation` | B2B location mutations |
|
|
53
|
+
|
|
54
|
+
Query keys are namespaced `["emporix", resource, ...args, meta]` where `meta`
|
|
55
|
+
holds the cache discriminators — at minimum `{ tenant, authKind }`, plus
|
|
56
|
+
`siteCode` for site-aware hooks and `legalEntityId` for B2B-aware hooks (cart,
|
|
57
|
+
checkout, addresses, etc. invalidate automatically on company switch).
|
|
58
|
+
Every query hook accepts `{ auth }` to override the token kind for that
|
|
59
|
+
call (default: `customer` if a token is stored, else `anonymous`).
|
|
60
|
+
|
|
61
|
+
## Storage adapters
|
|
62
|
+
|
|
63
|
+
`createMemoryStorage` (default, SSR-safe), `createLocalStorageStorage`,
|
|
64
|
+
`createCookieStorage`. Trade-offs and CSRF notes in
|
|
65
|
+
[`../../docs/react.md`](../../docs/react.md).
|
|
66
|
+
|
|
67
|
+
## Errors & SSR
|
|
68
|
+
|
|
69
|
+
`<EmporixErrorBoundary>` and `useEmporixErrorHandler` for error coordination;
|
|
70
|
+
`prefetchProduct` / `prefetchCart` for server-side hydration. See
|
|
71
|
+
[`../../docs/react.md`](../../docs/react.md).
|
|
72
|
+
|
|
73
|
+
## Subpath exports
|
|
74
|
+
|
|
75
|
+
`.`, `./provider`, `./hooks`, `./storage`, `./ssr`.
|
|
76
|
+
|
|
77
|
+
## Authors
|
|
78
|
+
|
|
79
|
+
- **Dominic Fritschi** — _Maintainer_ — [VIU](https://www.viu.ch)
|
|
80
|
+
- **Andreas Nebiker** — _Contributor_ — [VIU](https://www.viu.ch)
|
|
81
|
+
- The **Team at VIU** — _Contributors_ — [VIU](https://www.viu.ch)
|
|
82
|
+
|
|
83
|
+
## License
|
|
84
|
+
|
|
85
|
+
This project is licensed under the MIT License — see the [LICENSE](./LICENSE) file for details.
|