@zenky/storefront-vue 0.10.4 → 0.10.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +63 -3
  3. package/dist/cart/index.js +4 -4
  4. package/dist/{chunk-YREGCQSB.js → chunk-5YD4AIY2.js} +5 -5
  5. package/dist/chunk-5YD4AIY2.js.map +1 -0
  6. package/dist/{chunk-YS5DXYYV.js → chunk-E4DUFN2M.js} +21 -28
  7. package/dist/chunk-E4DUFN2M.js.map +1 -0
  8. package/dist/{chunk-OTSAR32A.js → chunk-MOG6UMFM.js} +2 -2
  9. package/dist/{chunk-OTSAR32A.js.map → chunk-MOG6UMFM.js.map} +1 -1
  10. package/dist/{chunk-SS7B2NLF.js → chunk-PTMSPB34.js} +3 -3
  11. package/dist/{chunk-SS7B2NLF.js.map → chunk-PTMSPB34.js.map} +1 -1
  12. package/dist/{chunk-IVG4FQE5.js → chunk-RAJDWCJU.js} +3 -3
  13. package/dist/{chunk-IVG4FQE5.js.map → chunk-RAJDWCJU.js.map} +1 -1
  14. package/dist/{chunk-TB5TBJ4U.js → chunk-VFMVQR6Y.js} +8 -15
  15. package/dist/chunk-VFMVQR6Y.js.map +1 -0
  16. package/dist/{chunk-NIQFYJRP.js → chunk-Z247QRDJ.js} +4 -4
  17. package/dist/{chunk-NIQFYJRP.js.map → chunk-Z247QRDJ.js.map} +1 -1
  18. package/dist/index.js +7 -7
  19. package/dist/ports/index.d.ts +2 -1
  20. package/dist/ports/index.js +1 -1
  21. package/dist/products/index.js +2 -2
  22. package/dist/promotions/index.d.ts +13 -0
  23. package/dist/promotions/index.js +3 -3
  24. package/dist/seo/index.js +2 -2
  25. package/dist/stores/index.d.ts +2 -1
  26. package/dist/stores/index.js +3 -3
  27. package/docs/consumer-setup.md +10 -3
  28. package/docs/ports.md +1 -1
  29. package/docs/releasing.md +2 -1
  30. package/package.json +5 -4
  31. package/dist/chunk-TB5TBJ4U.js.map +0 -1
  32. package/dist/chunk-YREGCQSB.js.map +0 -1
  33. package/dist/chunk-YS5DXYYV.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,45 @@ All notable changes to this project are documented in this file. The format foll
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and releases follow
5
5
  [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## Unreleased
8
+
9
+ ### Added
10
+
11
+ - `authStore.apiToken` — the single answer to "which token goes into an SDK call". It is
12
+ `undefined` unless the store holds a non-empty token, so an empty string can never reach
13
+ an `Authorization` header. Consumers should read it instead of deriving the rule from
14
+ `token` and `isAuthenticated` at each call site.
15
+
16
+ ## 0.10.5 - 2026-07-31
17
+
18
+ ### Changed
19
+
20
+ - `config` is now an optional runtime port because the current core does not read it.
21
+ - The framework-boundary gate now parses TypeScript syntax, so URLs and comment-like
22
+ text inside strings no longer hide violations or create false positives.
23
+ - A runtime-context gate now rejects composable or Pinia-store resolution from deferred
24
+ helpers and store actions; those functions must use dependencies captured in setup.
25
+ - Product restriction and delivery-time operations use public
26
+ `@zenky/storefront-api` resource methods instead of reaching through `sdk.client`.
27
+
28
+ ### Fixed
29
+
30
+ - `authStore.initFromCookie()` now clears stale in-memory SDK credentials when the
31
+ current request has no auth cookies.
32
+ - Payment selection reuses the setup-captured order total, so checkout with applied
33
+ bonuses no longer resolves a composable from a later event/checkout callback.
34
+ - Cart delivery-method validation resolves the order-settings store once in the store
35
+ setup. Pinia already activates the owning instance for the duration of an action, so
36
+ this is consistency rather than a leak fix.
37
+ - Runtime-context documentation now distinguishes Vue injection context, arbitrary
38
+ callbacks, `app.runWithContext()`, and Pinia's conditional global fallback.
39
+
40
+ ### Security
41
+
42
+ - `logCartError` redaction now covers customer addresses, e-mail and phone numbers, and
43
+ checkout/payment/redirect URLs, in object keys, `key=value` assignments, and query
44
+ parameters alike. Cart and checkout failures previously logged these verbatim.
45
+
7
46
  ## 0.10.4 - 2026-07-29
8
47
 
9
48
  > **Breaking.** This release changes the runtime port contract and removes public
package/README.md CHANGED
@@ -73,14 +73,71 @@ cart.itemCount.value // reactive
73
73
  cart.totalPrice.value
74
74
  ```
75
75
 
76
+ ### Call composables and stores synchronously in setup
77
+
78
+ Composables read the runtime through `inject()`, which works while a component
79
+ instance is active or while the owning Vue app is executing `app.runWithContext()`.
80
+ The important cases behave differently:
81
+
82
+ - **Top-level `await` in `<script setup>` is safe.** The SFC compiler wraps it in
83
+ `withAsyncContext()`, which restores the instance afterwards — so composables called
84
+ after `await bootstrap()` at the top level still resolve correctly.
85
+ - **A lifecycle hook has context only in its synchronous prefix.** After its first
86
+ `await`, the component instance is no longer active.
87
+ - **Event handlers, `watch` callbacks, timers, and `.then()` callbacks do not inherit
88
+ component injection context.** Resolve dependencies before registering the callback,
89
+ or deliberately re-enter the owning app with `app.runWithContext()`.
90
+ - **A hand-written `async setup()` is not compiler-wrapped.** Resolve dependencies
91
+ before its first `await`.
92
+
93
+ Resolve the composable up front and call the returned functions later.
94
+
95
+ ```ts
96
+ // ✅ resolve in setup, call after the await
97
+ const { dispatchCheck } = usePromotionsChecker()
98
+
99
+ onMounted(async () => {
100
+ await initializeOrder()
101
+ dispatchCheck()
102
+ })
103
+
104
+ // ❌ resolving after an await — inject() has no instance to read from
105
+ onMounted(async () => {
106
+ await initializeOrder()
107
+ const { dispatchCheck } = usePromotionsChecker()
108
+ })
109
+ ```
110
+
111
+ The same applies inside event handlers, `watch` callbacks, timers, and `.then()` blocks:
112
+ resolve in `setup()`, keep the reference, call it from the callback. Watch for this
113
+ inside `try` blocks in particular — the `catch` swallows the failure and reports it as
114
+ whatever the surrounding operation was supposed to do, so the real cause never surfaces.
115
+
116
+ **Stores fail differently, and worse.** The Pinia stores exported from
117
+ `@zenky/storefront-vue/stores` read the runtime too, but a missed context does not throw:
118
+ Pinia falls back to its module-level active instance. Under concurrent SSR that instance
119
+ belongs to whichever request touched it last, so the lookup succeeds with another user's
120
+ state instead of failing.
121
+
122
+ Two cases behave differently, and the distinction is verified rather than assumed:
123
+
124
+ - **Inside a store action — safe.** Pinia activates the action's own instance for the
125
+ duration of the call, so resolving another store there returns the right one.
126
+ - **In a plain function after an `await`, outside any action and outside
127
+ `runWithContext()` — leaks.** This is the shape to watch for: it is silent, and it
128
+ crosses requests.
129
+
130
+ Resolve core stores in `setup()` for the same reason you resolve composables there. A
131
+ silent leak is far harder to notice than an exception.
132
+
76
133
  ## Runtime Ports
77
134
 
78
- `createStorefront(runtime)` takes one object. Six ports are required; the rest are optional — omit an optional port and the feature that needs it is simply skipped.
135
+ `createStorefront(runtime)` takes one object. Five ports are required; the rest are optional — omit an optional port and the feature that needs it is simply skipped.
79
136
 
80
137
  | Port | Required | What the consumer provides |
81
138
  | --- | --- | --- |
82
139
  | `sdk` | yes | A `ZenkyStorefront` instance (`@zenky/storefront-api`). |
83
- | `config` | yes | `{ baseUrl, baseAuthUrl, salesChannelId? }`. |
140
+ | `config` | no | Reserved consumer configuration; the current core does not read it. |
84
141
  | `storage` | yes | Key/value persistence — cookies, `localStorage`, memory. |
85
142
  | `notifier` | yes | Toasts: `error` / `success` / `warning` / `message`. |
86
143
  | `messages` | yes | Maps stable domain message keys to localized consumer copy. |
@@ -186,13 +243,15 @@ npm run test:coverage # vitest + V8 coverage report
186
243
  npm run check # format + lint + types + tests + build + exports
187
244
  npm run check:exports # publint + are-the-types-wrong (esm-only profile)
188
245
  npm run check:boundaries # reject Nuxt/Unhead and consumer policy in src/
246
+ npm run check:context # reject ambient composables/stores in deferred helpers
189
247
  npm run check:runtime # import all entries in SSR + reject Node-only output
190
248
  npm run check:size # enforce gzip bundle budgets
191
249
  ```
192
250
 
193
251
  ### Local linking with yalc
194
252
 
195
- Until the package is published, link it into a consumer app with [yalc](https://github.com/wclr/yalc):
253
+ To iterate on an unreleased change without cutting a version, link the package into a
254
+ consumer app with [yalc](https://github.com/wclr/yalc):
196
255
 
197
256
  ```bash
198
257
  # in this package, after a build:
@@ -213,6 +272,7 @@ npm run build && npx yalc push
213
272
  - `typecheck` — type-only compile.
214
273
  - `check:exports` — validate the exports map and published types.
215
274
  - `check:boundaries` — reject Nuxt/Unhead APIs, routes, and tenant presets in core source.
275
+ - `check:context` — reject deferred composable/store resolution outside composition setup.
216
276
  - `check:runtime` — verify Node SSR imports and browser/edge-safe ESM output.
217
277
  - `check:size` — enforce root/domain/all-output gzip budgets.
218
278
  - `check:ci` — quality gate with the V8 coverage ratchet.
@@ -1,10 +1,10 @@
1
- export { CASH_DENOMINATIONS_MAJOR, DEFAULT_ROUND_STEPS_MAJOR, ORDER_EVENTS, ORDER_WITH, buildCartLineKey, buildCashChangePresets, buildMainPaymentRequest, getCartErrorCode, getCartErrorHttpCode, getCartErrorMessage, getCashDenominationsMinor, getDefaultRoundStepsMinor, getValidationErrors, logCartError, normalizeAddress, useBonusesReconciliation, useCartAddressSync, useCartCustomerAttachment, useCartDeliveryAttachment, useCartInitialization, useCartMutation, useCartOperations, useCartQuantities, useCartRecalculation, useCartStockWatcher, useCheckoutFlow, useCheckoutSubmit, useCustomerAttach, useOnlinePaymentRetry, useOrderBonuses, useOrderChannel, useOrderDelivery, useOrderPromocode, useOrderSettings, useOrderTotal, usePaymentSelection, useRestrictedAddToCart, useRestrictionGate, useStorefrontCart, useVisibleCartVariants, variantLineKey } from '../chunk-YS5DXYYV.js';
2
- export { useCartCredentials } from '../chunk-YREGCQSB.js';
1
+ export { CASH_DENOMINATIONS_MAJOR, DEFAULT_ROUND_STEPS_MAJOR, ORDER_EVENTS, ORDER_WITH, buildCartLineKey, buildCashChangePresets, buildMainPaymentRequest, getCartErrorCode, getCartErrorHttpCode, getCartErrorMessage, getCashDenominationsMinor, getDefaultRoundStepsMinor, getValidationErrors, logCartError, normalizeAddress, useBonusesReconciliation, useCartAddressSync, useCartCustomerAttachment, useCartDeliveryAttachment, useCartInitialization, useCartMutation, useCartOperations, useCartQuantities, useCartRecalculation, useCartStockWatcher, useCheckoutFlow, useCheckoutSubmit, useCustomerAttach, useOnlinePaymentRetry, useOrderBonuses, useOrderChannel, useOrderDelivery, useOrderPromocode, useOrderSettings, useOrderTotal, usePaymentSelection, useRestrictedAddToCart, useRestrictionGate, useStorefrontCart, useVisibleCartVariants, variantLineKey } from '../chunk-E4DUFN2M.js';
2
+ export { useCartCredentials } from '../chunk-5YD4AIY2.js';
3
3
  import '../chunk-Z3IW4ODZ.js';
4
- import '../chunk-NIQFYJRP.js';
4
+ import '../chunk-Z247QRDJ.js';
5
5
  import '../chunk-E3G7NGCH.js';
6
6
  import '../chunk-RO25KNM5.js';
7
7
  import '../chunk-5QCUH3FF.js';
8
- import '../chunk-TB5TBJ4U.js';
8
+ import '../chunk-VFMVQR6Y.js';
9
9
  //# sourceMappingURL=index.js.map
10
10
  //# sourceMappingURL=index.js.map
@@ -1,5 +1,5 @@
1
- import { useCartStore, usePromotionsStore } from './chunk-NIQFYJRP.js';
2
- import { useRuntime, useAuthStore, useStoreProfileStore } from './chunk-TB5TBJ4U.js';
1
+ import { useCartStore, usePromotionsStore } from './chunk-Z247QRDJ.js';
2
+ import { useRuntime, useAuthStore, useStoreProfileStore } from './chunk-VFMVQR6Y.js';
3
3
  import { ref } from 'vue';
4
4
 
5
5
  var KEY_ORDER_ID = "zenky_order_id";
@@ -26,7 +26,7 @@ function useCartCredentials() {
26
26
  return profileStore.city.id;
27
27
  }
28
28
  function getApiToken() {
29
- return authStore.isAuthenticated ? authStore.token ?? void 0 : void 0;
29
+ return authStore.apiToken;
30
30
  }
31
31
  function buildCredentials(orderId, orderToken) {
32
32
  const credentials = {
@@ -105,5 +105,5 @@ function usePromotionsChecker() {
105
105
  }
106
106
 
107
107
  export { useCartCredentials, usePromotionsChecker };
108
- //# sourceMappingURL=chunk-YREGCQSB.js.map
109
- //# sourceMappingURL=chunk-YREGCQSB.js.map
108
+ //# sourceMappingURL=chunk-5YD4AIY2.js.map
109
+ //# sourceMappingURL=chunk-5YD4AIY2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cart/useCartCredentials.ts","../src/promotions/usePromotionsChecker.ts"],"names":[],"mappings":"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","file":"chunk-5YD4AIY2.js","sourcesContent":["import { ref, type Ref } from 'vue'\n\nimport type { Order, OrderCredentials } from '@zenky/storefront-api'\n\nimport { useRuntime } from '../ports/runtime'\nimport { useAuthStore } from '../stores/auth'\nimport { useCartStore } from '../stores/cart'\nimport { useStoreProfileStore } from '../stores/store-profile'\n\nconst KEY_ORDER_ID = 'zenky_order_id'\nconst KEY_ORDER_TOKEN = 'zenky_order_token'\nconst WEEK_SECONDS = 60 * 60 * 24 * 7\n\n// app-энум OrderStatusKind.Pending = 'pending'.\nconst ORDER_STATUS_PENDING = 'pending'\n\nexport interface CartCredentials {\n orderIdCookie: Ref<string | null>\n orderTokenCookie: Ref<string | null>\n getStoreId: () => string\n getCityId: () => string\n getApiToken: () => string | undefined\n buildCredentials: (orderId: string, orderToken: string) => OrderCredentials\n getCredentials: () => OrderCredentials\n persistCredentials: (savedOrder: Order) => void\n clearPersistedCredentials: () => void\n isOrderActive: (order: Order) => boolean\n}\n\n/**\n * Управление credentials заказа. Персистенс order-id/token — через порт `storage`\n * (ядро не знает про useCookie). Рефы инициализируются из storage, persist пишет в оба.\n */\nexport function useCartCredentials(): CartCredentials {\n const { storage } = useRuntime()\n const cartStore = useCartStore()\n const authStore = useAuthStore()\n const profileStore = useStoreProfileStore()\n\n const orderIdRef = ref<string | null>(storage.get(KEY_ORDER_ID))\n const orderTokenRef = ref<string | null>(storage.get(KEY_ORDER_TOKEN))\n\n function getStoreId(): string {\n if (!profileStore.store) {\n throw new Error('Store is not initialized.')\n }\n\n return profileStore.store.id\n }\n\n function getCityId(): string {\n if (!profileStore.city) {\n throw new Error('City is not initialized.')\n }\n\n return profileStore.city.id\n }\n\n function getApiToken(): string | undefined {\n return authStore.apiToken\n }\n\n function buildCredentials(orderId: string, orderToken: string): OrderCredentials {\n const credentials: OrderCredentials = {\n id: orderId,\n token: orderToken,\n }\n\n const apiToken = getApiToken()\n\n if (apiToken) {\n credentials.api_token = apiToken\n }\n\n return credentials\n }\n\n function getCredentials(): OrderCredentials {\n if (!cartStore.credentials) {\n throw new Error('Cart has no credentials.')\n }\n\n return buildCredentials(cartStore.credentials.id, cartStore.credentials.token)\n }\n\n function persistCredentials(savedOrder: Order): void {\n orderIdRef.value = savedOrder.id\n orderTokenRef.value = savedOrder.token\n storage.set(KEY_ORDER_ID, savedOrder.id, { maxAge: WEEK_SECONDS })\n storage.set(KEY_ORDER_TOKEN, savedOrder.token, { maxAge: WEEK_SECONDS })\n }\n\n function clearPersistedCredentials(): void {\n orderIdRef.value = null\n orderTokenRef.value = null\n storage.remove(KEY_ORDER_ID)\n storage.remove(KEY_ORDER_TOKEN)\n }\n\n function isOrderActive(existingOrder: Order): boolean {\n if (!existingOrder.status) return true\n\n return String(existingOrder.status.kind) === ORDER_STATUS_PENDING\n }\n\n return {\n orderIdCookie: orderIdRef,\n orderTokenCookie: orderTokenRef,\n getStoreId,\n getCityId,\n getApiToken,\n buildCredentials,\n getCredentials,\n persistCredentials,\n clearPersistedCredentials,\n isOrderActive,\n }\n}\n","import { useRuntime } from '../ports/runtime'\nimport { useCartCredentials } from '../cart/useCartCredentials'\nimport { useCartStore } from '../stores/cart'\nimport { usePromotionsStore } from '../stores/promotions'\nimport { useStoreProfileStore } from '../stores/store-profile'\n\nexport interface PromotionsChecker {\n dispatchCheck: () => Promise<void>\n}\n\n/** Таймаут — если WS не ответил, сбросить флаг checking. */\nconst WS_RESPONSE_TIMEOUT_MS = 5000\n\n/**\n * Проверка промо-акций. Вызывает dispatchPromotionsChecker после изменения корзины.\n * Результат приходит через WebSocket (обрабатывается в useOrderChannel).\n *\n * Резолвить синхронно в setup, а после await вызывать только `dispatchCheck` — как и\n * любой композабл ядра, см. раздел «Call composables and stores synchronously in setup»\n * в README.\n *\n * ```ts\n * const { dispatchCheck } = usePromotionsChecker()\n *\n * async function addGift() {\n * await addVariantToOrder()\n * dispatchCheck()\n * }\n * ```\n */\nexport function usePromotionsChecker(): PromotionsChecker {\n const { sdk, events } = useRuntime()\n const cartStore = useCartStore()\n const profileStore = useStoreProfileStore()\n const promotionsStore = usePromotionsStore()\n const credentials = useCartCredentials()\n\n async function dispatchCheck(): Promise<void> {\n if (!cartStore.hasOrder || promotionsStore.checking) return\n\n const storeId = profileStore.store?.id\n if (!storeId) return\n\n promotionsStore.setChecking(true)\n promotionsStore.clearRewards() // Очистить старые — WS заново наполнит актуальные\n events?.get()?.promotionsCheckerStarted({ order: cartStore.order })\n\n try {\n const creds = credentials.getCredentials()\n await sdk.orders.dispatchPromotionsChecker(storeId, creds)\n\n setTimeout(() => {\n if (promotionsStore.checking) promotionsStore.setChecking(false)\n }, WS_RESPONSE_TIMEOUT_MS)\n } catch (e: unknown) {\n console.error('[promotions] check failed', e)\n promotionsStore.setChecking(false)\n }\n }\n\n return { dispatchCheck }\n}\n"]}
@@ -1,10 +1,10 @@
1
- import { useCartCredentials, usePromotionsChecker } from './chunk-YREGCQSB.js';
1
+ import { useCartCredentials, usePromotionsChecker } from './chunk-5YD4AIY2.js';
2
2
  import { useCatalogStore } from './chunk-Z3IW4ODZ.js';
3
- import { useCartStore, useOrderSettingsStore, usePromotionsStore } from './chunk-NIQFYJRP.js';
3
+ import { useCartStore, useOrderSettingsStore, usePromotionsStore } from './chunk-Z247QRDJ.js';
4
4
  import { getRemoteCatalog } from './chunk-E3G7NGCH.js';
5
5
  import { minorToMajor, majorToMinor } from './chunk-RO25KNM5.js';
6
6
  import { createRuntimeState } from './chunk-5QCUH3FF.js';
7
- import { useRuntime, useStoreProfileStore, useAuthStore } from './chunk-TB5TBJ4U.js';
7
+ import { useRuntime, useStoreProfileStore, useAuthStore } from './chunk-VFMVQR6Y.js';
8
8
  import { PaymentMethod, OrderAuthenticationMethod, DeliveryMethod, OrderCartCheckerResultAction, RecaptchaAction } from '@zenky/storefront-api';
9
9
  import { ref, computed, watch, watchEffect, getCurrentScope, onScopeDispose, toValue } from 'vue';
10
10
  import { storeToRefs } from 'pinia';
@@ -98,17 +98,24 @@ var MAX_LOG_DEPTH = 6;
98
98
  var MAX_ARRAY_ITEMS = 25;
99
99
  var MAX_OBJECT_KEYS = 50;
100
100
  var SENSITIVE_KEY_PARTS = [
101
+ "address",
101
102
  "authorization",
103
+ "checkouturl",
102
104
  "cookie",
103
105
  "credential",
106
+ "email",
104
107
  "password",
108
+ "paymentlink",
109
+ "paymentpageurl",
110
+ "phone",
105
111
  "recaptcha",
112
+ "redirecturl",
106
113
  "secret",
107
114
  "token"
108
115
  ];
109
116
  var SENSITIVE_EXACT_KEYS = /* @__PURE__ */ new Set(["cvc", "cvv", "otp", "pan", "pin"]);
110
- var SENSITIVE_ASSIGNMENT = /((?:authorization|cookie|password|recaptcha|secret|(?:api|access|auth|card|order|refresh)[_-]?token|token)\s*[=:]\s*["']?)([^\s,"';&}\]]+)/gi;
111
- var SENSITIVE_QUERY_PARAM = /([?&#](?:authorization|password|recaptcha|secret|(?:api|access|auth|card|order|refresh)[_-]?token|token)=)([^&#\s]+)/gi;
117
+ var SENSITIVE_ASSIGNMENT = /((?:address|authorization|cookie|email|password|phone|recaptcha|secret|(?:checkout|redirect)[_-]?url|payment(?:[_-]?page)?[_-]?(?:link|url)|(?:api|access|auth|card|order|refresh)[_-]?token|token)\s*[=:]\s*["']?)([^\s,"';&}\]]+)/gi;
118
+ var SENSITIVE_QUERY_PARAM = /([?&#](?:address|authorization|email|password|phone|recaptcha|secret|(?:checkout|redirect)[_-]?url|payment(?:[_-]?page)?[_-]?(?:link|url)|(?:api|access|auth|card|order|refresh)[_-]?token|token)=)([^&#\s]+)/gi;
112
119
  var BEARER_TOKEN = /(bearer\s+)[a-z0-9._~+/=-]+/gi;
113
120
  function isSensitiveKey(key) {
114
121
  const normalized = key.replace(/[^a-z0-9]/gi, "").toLowerCase();
@@ -636,7 +643,7 @@ function usePaymentSelection() {
636
643
  const credentials = useCartCredentials();
637
644
  const cartStore = useCartStore();
638
645
  const profileStore = useStoreProfileStore();
639
- const { fetchTotal } = useOrderTotal();
646
+ const { fetchTotal, total } = useOrderTotal();
640
647
  const { run: runMutation } = useCartMutation();
641
648
  async function sendPayments(payments, debounce = PAYMENT_DEBOUNCE_MS) {
642
649
  const storeId = profileStore.store?.id;
@@ -687,7 +694,6 @@ function usePaymentSelection() {
687
694
  }
688
695
  function getCurrentBonusesPayment() {
689
696
  if (!cartStore.hasBonusesApplied) return null;
690
- const { total } = useOrderTotal();
691
697
  const bonusPayment = total.value?.payments?.find(
692
698
  (p) => p.method === PaymentMethod.Bonuses
693
699
  );
@@ -1154,20 +1160,9 @@ function useOrderDelivery(deps = {}) {
1154
1160
  () => {
1155
1161
  const storeId = credentials.getStoreId();
1156
1162
  const orderCredentials = credentials.getCredentials();
1157
- if (typeof orderCredentials === "string") {
1158
- throw new Error("cart:no_credentials");
1159
- }
1160
- const path = sdk.client.getStoreUrl(
1161
- storeId,
1162
- `/orders/${orderCredentials.id}/checkout/delivery/time`,
1163
- { token: orderCredentials.token }
1164
- );
1165
- return sdk.client.request(
1166
- "POST",
1167
- path,
1168
- { deliver_at: deliverAt },
1169
- orderCredentials.api_token ?? null
1170
- );
1163
+ return sdk.orders.setOrderDeliveryTime(storeId, orderCredentials, {
1164
+ deliver_at: deliverAt
1165
+ });
1171
1166
  },
1172
1167
  { deliverAt },
1173
1168
  options.awaitSettle ?? false
@@ -1979,12 +1974,10 @@ function useRestrictedAddToCart() {
1979
1974
  if (!storeId || !cityId) return true;
1980
1975
  let blocking = [];
1981
1976
  try {
1982
- const url = sdk.client.getStoreUrl(storeId, `/products/${product.id}/restrictions`, {
1983
- city_id: cityId,
1984
- stock_id: profileStore.stock?.id ?? void 0
1977
+ const restrictions = await sdk.products.getProductRestrictions(storeId, product.id, {
1978
+ city_id: cityId
1985
1979
  });
1986
- const response = await sdk.client.request("GET", url);
1987
- blocking = (response?.data ?? []).filter((item) => item.is_blocking);
1980
+ blocking = (restrictions ?? []).filter((item) => item.is_blocking);
1988
1981
  } catch (error) {
1989
1982
  logCartError({ scope: "restrictions-check", context: { productId: product.id } }, error);
1990
1983
  return true;
@@ -2014,5 +2007,5 @@ function useVisibleCartVariants() {
2014
2007
  }
2015
2008
 
2016
2009
  export { CASH_DENOMINATIONS_MAJOR, DEFAULT_ROUND_STEPS_MAJOR, ORDER_EVENTS, ORDER_WITH, buildCartLineKey, buildCashChangePresets, buildMainPaymentRequest, getCartErrorCode, getCartErrorHttpCode, getCartErrorMessage, getCashDenominationsMinor, getDefaultRoundStepsMinor, getValidationErrors, logCartError, normalizeAddress, useBonusesReconciliation, useCartAddressSync, useCartCustomerAttachment, useCartDeliveryAttachment, useCartInitialization, useCartMutation, useCartOperations, useCartQuantities, useCartRecalculation, useCartStockWatcher, useCheckoutFlow, useCheckoutSubmit, useCustomerAttach, useOnlinePaymentRetry, useOrderBonuses, useOrderChannel, useOrderDelivery, useOrderPromocode, useOrderSettings, useOrderTotal, usePaymentSelection, useRestrictedAddToCart, useRestrictionGate, useStorefrontCart, useVisibleCartVariants, variantLineKey };
2017
- //# sourceMappingURL=chunk-YS5DXYYV.js.map
2018
- //# sourceMappingURL=chunk-YS5DXYYV.js.map
2010
+ //# sourceMappingURL=chunk-E4DUFN2M.js.map
2011
+ //# sourceMappingURL=chunk-E4DUFN2M.js.map