@zenky/storefront-vue 0.10.0 → 0.10.3
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 +46 -0
- package/README.md +52 -2
- package/dist/cart/index.d.ts +31 -2
- package/dist/cart/index.js +5 -6
- package/dist/catalog/index.js +2 -2
- package/dist/{chunk-BIGTKVC6.js → chunk-57IOMDAM.js} +3 -3
- package/dist/{chunk-BIGTKVC6.js.map → chunk-57IOMDAM.js.map} +1 -1
- package/dist/{chunk-DKWDKVXQ.js → chunk-7FRMMCR5.js} +12 -10
- package/dist/chunk-7FRMMCR5.js.map +1 -0
- package/dist/{chunk-EYRCAUUP.js → chunk-E3G7NGCH.js} +2 -2
- package/dist/chunk-E3G7NGCH.js.map +1 -0
- package/dist/{chunk-VL3T36VM.js → chunk-FFBZKQRV.js} +14 -7
- package/dist/chunk-FFBZKQRV.js.map +1 -0
- package/dist/{chunk-OQLU7FSR.js → chunk-G2X4SBCO.js} +199 -29
- package/dist/chunk-G2X4SBCO.js.map +1 -0
- package/dist/{chunk-AL5W5JSD.js → chunk-GLTOJTZO.js} +2 -2
- package/dist/{chunk-AL5W5JSD.js.map → chunk-GLTOJTZO.js.map} +1 -1
- package/dist/{chunk-IGDDWGS4.js → chunk-JLFBAAFT.js} +20 -11
- package/dist/chunk-JLFBAAFT.js.map +1 -0
- package/dist/{chunk-PJ2LEKW6.js → chunk-MZ66ARDL.js} +18 -3
- package/dist/chunk-MZ66ARDL.js.map +1 -0
- package/dist/{chunk-4MJKN7PL.js → chunk-N3NOTJUC.js} +4 -4
- package/dist/{chunk-4MJKN7PL.js.map → chunk-N3NOTJUC.js.map} +1 -1
- package/dist/{chunk-2OD7CLKD.js → chunk-RYYY7MVP.js} +2 -2
- package/dist/chunk-RYYY7MVP.js.map +1 -0
- package/dist/{chunk-PWHIDGKW.js → chunk-TEG7EL4N.js} +12 -3
- package/dist/chunk-TEG7EL4N.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +11 -11
- package/dist/layout/index.js +8 -4
- package/dist/layout/index.js.map +1 -1
- package/dist/order/index.js.map +1 -1
- package/dist/pagination/index.js.map +1 -1
- package/dist/ports/index.js +1 -1
- package/dist/products/index.js +2 -2
- package/dist/promotions/index.js +3 -3
- package/dist/seo/index.js +5 -5
- package/dist/seo/index.js.map +1 -1
- package/dist/snippets/index.js +1 -1
- package/dist/stores/index.js +3 -3
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.js +1 -1
- package/docs/consumer-setup.md +275 -0
- package/docs/ports.md +144 -0
- package/docs/releasing.md +46 -0
- package/package.json +26 -4
- package/dist/chunk-2OD7CLKD.js.map +0 -1
- package/dist/chunk-DKWDKVXQ.js.map +0 -1
- package/dist/chunk-EYRCAUUP.js.map +0 -1
- package/dist/chunk-IGDDWGS4.js.map +0 -1
- package/dist/chunk-OQLU7FSR.js.map +0 -1
- package/dist/chunk-PJ2LEKW6.js.map +0 -1
- package/dist/chunk-PWHIDGKW.js.map +0 -1
- package/dist/chunk-VL3T36VM.js.map +0 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and releases follow
|
|
5
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## Unreleased
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Pull-request CI for formatting, linting, types, coverage, tests, package exports,
|
|
12
|
+
Node/runtime compatibility, bundle budgets, and secret scanning.
|
|
13
|
+
- Dependabot updates for npm dependencies and GitHub Actions.
|
|
14
|
+
- Public security, contribution, conduct, runtime-port, and release documentation.
|
|
15
|
+
- Coverage ratchet and regression tests for checkout state and credential-safe logging.
|
|
16
|
+
- Cart composables for evaluating product restrictions, confirming blocking
|
|
17
|
+
restrictions, and reading variants that remain visible after optimistic updates.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- GitHub Actions are pinned to immutable commits with minimum workflow permissions.
|
|
22
|
+
- QR-code encoding now uses Web Platform APIs and works without Node `Buffer` or browser
|
|
23
|
+
globals, improving Node SSR and edge-runtime compatibility.
|
|
24
|
+
- npm package metadata now includes its homepage, issue tracker, and supported engines.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- Empty post-checkout orders no longer trigger a minimum-order-price violation.
|
|
29
|
+
|
|
30
|
+
### Security
|
|
31
|
+
|
|
32
|
+
- Cart and checkout errors now pass through recursive redaction before being logged.
|
|
33
|
+
- Direct cart logging no longer emits complete order, credentials, request, or API error
|
|
34
|
+
objects.
|
|
35
|
+
|
|
36
|
+
## 0.10.0 - 2026-07-21
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
|
|
40
|
+
- GitHub release workflow for npm OIDC trusted publishing.
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
|
|
44
|
+
- Package renamed to `@zenky/storefront-vue`.
|
|
45
|
+
- Storefront runtime state and cart flows were isolated across Vue applications and SSR
|
|
46
|
+
requests.
|
package/README.md
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Headless storefront engine for Zenky — Vue 3 + Pinia, no framework lock-in.
|
|
4
4
|
|
|
5
|
+
[](https://github.com/zenky/storefront-vue/actions/workflows/ci.yml)
|
|
6
|
+
[](https://www.npmjs.com/package/@zenky/storefront-vue)
|
|
7
|
+
|
|
5
8
|
One engine behind many storefronts. The cart, order building, checkout, catalog resolution, delivery slots, SEO/JSON-LD, theme, and store/profile state all live here as framework-agnostic composables and Pinia stores. The consumer — a Nuxt site, a QR-code menu, a new template — brings the framework glue (cookies, config, toasts, HTTP transport, `useHead`) and draws its own UI on top.
|
|
6
9
|
|
|
7
10
|
The design is Ports & Adapters: the core declares small ports for everything it needs from the outside world, the consumer provides adapters once, and every composable reads them through `useRuntime()`. The core never imports `useCookie`, `useRoute`, `useHead`, `$fetch`, or anything Nuxt-specific.
|
|
@@ -18,7 +21,7 @@ Peer dependencies (the consumer already has these):
|
|
|
18
21
|
{
|
|
19
22
|
"vue": "^3.5.0",
|
|
20
23
|
"pinia": "^3.0.0",
|
|
21
|
-
"@zenky/storefront-api": ">=0.0.
|
|
24
|
+
"@zenky/storefront-api": ">=0.0.68",
|
|
22
25
|
"@zenky/integrations-sdk": ">=0.1.3"
|
|
23
26
|
}
|
|
24
27
|
```
|
|
@@ -96,6 +99,10 @@ import {
|
|
|
96
99
|
} from '@zenky/storefront-vue/ports'
|
|
97
100
|
```
|
|
98
101
|
|
|
102
|
+
The full public contract, adapter examples, SSR lifecycle, and security boundary are in
|
|
103
|
+
[Runtime Ports](docs/ports.md). For a step-by-step consumer integration and upgrade
|
|
104
|
+
checklist, see [Consumer Setup](docs/consumer-setup.md).
|
|
105
|
+
|
|
99
106
|
## Subpath Imports
|
|
100
107
|
|
|
101
108
|
Each public domain is its own entry point, so bundlers only pull in what you import.
|
|
@@ -113,6 +120,31 @@ import { usePaginatedList } from '@zenky/storefront-vue/pagination'
|
|
|
113
120
|
|
|
114
121
|
Available subpaths: `ports`, `money`, `utils`, `theme`, `stores`, `products`, `catalog`, `cart`, `order`, `promotions`, `seo`, `layout`, `pagination`, `snippets`, `website-settings`.
|
|
115
122
|
|
|
123
|
+
## Runtime Compatibility
|
|
124
|
+
|
|
125
|
+
- ESM-only, targeting ES2022.
|
|
126
|
+
- Vue 3.5+ and Pinia 3.
|
|
127
|
+
- Node.js 20.19+ for SSR and package tooling; Node.js 22 is recommended for production and development.
|
|
128
|
+
- Modern browsers and edge runtimes with standard Web Platform APIs.
|
|
129
|
+
|
|
130
|
+
CI imports every public entry in Node SSR and scans the emitted ESM for CommonJS, Node
|
|
131
|
+
built-ins, `Buffer`, and `process`. Browser-only behavior is guarded; for example,
|
|
132
|
+
online-payment retry accepts an explicit `currentUrl` when no `window` is available.
|
|
133
|
+
|
|
134
|
+
For SSR, create a new Vue app, Pinia instance, storefront runtime, and storage adapter per
|
|
135
|
+
request. Never share `createMemoryStorage()` between users.
|
|
136
|
+
|
|
137
|
+
## Package Size
|
|
138
|
+
|
|
139
|
+
Every domain has a tree-shakeable subpath. CI measures the transitive gzip graph for the
|
|
140
|
+
root, cart, and utils entries plus all emitted JavaScript. The budgets are regression
|
|
141
|
+
ceilings, not size targets; increasing one requires review and a release-note explanation.
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
npm run build
|
|
145
|
+
npm run check:size
|
|
146
|
+
```
|
|
147
|
+
|
|
116
148
|
## Pinia Stores
|
|
117
149
|
|
|
118
150
|
The `stores` subpath exposes setup-style Pinia stores (ids namespaced `zenky-*`): cart, order settings, store profile, catalog, products, auth, promotions. They are plain state containers — no API calls, no UI logic — and they are the reactive backbone the composables read from. Install Pinia before mounting the storefront plugin.
|
|
@@ -138,9 +170,15 @@ majorToMinor(650, 'RUB') // 65000 — user input back into the store
|
|
|
138
170
|
```bash
|
|
139
171
|
npm run dev # tsup --watch
|
|
140
172
|
npm run build # ESM + .d.ts to dist/
|
|
173
|
+
npm run lint # Biome lint
|
|
174
|
+
npm run format # Biome format --write
|
|
141
175
|
npm run typecheck # tsc --noEmit
|
|
142
176
|
npm test # vitest
|
|
177
|
+
npm run test:coverage # vitest + V8 coverage report
|
|
178
|
+
npm run check # format + lint + types + tests + build + exports
|
|
143
179
|
npm run check:exports # publint + are-the-types-wrong (esm-only profile)
|
|
180
|
+
npm run check:runtime # import all entries in SSR + reject Node-only output
|
|
181
|
+
npm run check:size # enforce gzip bundle budgets
|
|
144
182
|
```
|
|
145
183
|
|
|
146
184
|
### Local linking with yalc
|
|
@@ -165,7 +203,19 @@ npm run build && npx yalc push
|
|
|
165
203
|
- `test` / `test:watch` — run the Vitest suite.
|
|
166
204
|
- `typecheck` — type-only compile.
|
|
167
205
|
- `check:exports` — validate the exports map and published types.
|
|
168
|
-
- `
|
|
206
|
+
- `check:runtime` — verify Node SSR imports and browser/edge-safe ESM output.
|
|
207
|
+
- `check:size` — enforce root/domain/all-output gzip budgets.
|
|
208
|
+
- `check:ci` — quality gate with the V8 coverage ratchet.
|
|
209
|
+
- `prepublishOnly` — run the release quality gate.
|
|
210
|
+
|
|
211
|
+
## Contributing and Releases
|
|
212
|
+
|
|
213
|
+
Read [CONTRIBUTING.md](CONTRIBUTING.md) before opening a pull request. User-visible changes
|
|
214
|
+
belong in [CHANGELOG.md](CHANGELOG.md); maintainer steps are documented in the
|
|
215
|
+
[release process](docs/releasing.md).
|
|
216
|
+
|
|
217
|
+
Security vulnerabilities must be reported privately according to
|
|
218
|
+
[SECURITY.md](SECURITY.md), never through a public issue.
|
|
169
219
|
|
|
170
220
|
## License
|
|
171
221
|
|
package/dist/cart/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ProductModifiersRequest, OrderProductVariant, PaymentMethod, OrderPaymentMethodRequest, OrderAuthenticationMethod, OrderCredentials, Order, OrderCheckoutTotal, OrderSettings, OrderPaymentMethod, OrderDeliveryMethod, InclusionRequest, ZenkyStorefront, SetOrderCustomerRequest, SetOrderDeliveryRequest, OrderPromocode, OrderCheckoutResult, RecaptchaAction } from '@zenky/storefront-api';
|
|
1
|
+
import { ProductModifiersRequest, OrderProductVariant, PaymentMethod, OrderPaymentMethodRequest, OrderAuthenticationMethod, OrderCredentials, Order, OrderCheckoutTotal, OrderSettings, OrderPaymentMethod, OrderDeliveryMethod, InclusionRequest, ZenkyStorefront, SetOrderCustomerRequest, SetOrderDeliveryRequest, OrderPromocode, OrderCheckoutResult, RecaptchaAction, EvaluatedRestriction, Media, Product } from '@zenky/storefront-api';
|
|
2
2
|
import { ComputedRef, MaybeRefOrGetter, Ref } from 'vue';
|
|
3
3
|
import { ActivityReporter, Notifier, Result } from '../ports/index.js';
|
|
4
4
|
import '@zenky/integrations-sdk';
|
|
@@ -556,4 +556,33 @@ interface StorefrontCart {
|
|
|
556
556
|
}
|
|
557
557
|
declare function useStorefrontCart(): StorefrontCart;
|
|
558
558
|
|
|
559
|
-
|
|
559
|
+
/** Данные товара для показа в модалке гейта (как строка корзины). */
|
|
560
|
+
interface RestrictionGateProduct {
|
|
561
|
+
name: string;
|
|
562
|
+
image: Media | null;
|
|
563
|
+
}
|
|
564
|
+
interface RestrictionGate {
|
|
565
|
+
isOpen: Ref<boolean>;
|
|
566
|
+
blocking: Ref<EvaluatedRestriction[]>;
|
|
567
|
+
product: Ref<RestrictionGateProduct | null>;
|
|
568
|
+
confirmBlocking: (items: EvaluatedRestriction[], gateProduct: RestrictionGateProduct) => Promise<boolean>;
|
|
569
|
+
confirm: () => void;
|
|
570
|
+
cancel: () => void;
|
|
571
|
+
}
|
|
572
|
+
declare function useRestrictionGate(): RestrictionGate;
|
|
573
|
+
|
|
574
|
+
type RestrictedProduct = Pick<Product, 'id' | 'restrictions' | 'name' | 'images'>;
|
|
575
|
+
interface RestrictedAddToCart {
|
|
576
|
+
checkRestrictionsAllowed: (product: RestrictedProduct, alreadyInCart: boolean) => Promise<boolean>;
|
|
577
|
+
addWithRestrictionCheck: (product: RestrictedProduct, request: CartItemRequest, alreadyInCart: boolean) => Promise<void>;
|
|
578
|
+
}
|
|
579
|
+
declare function useRestrictedAddToCart(): RestrictedAddToCart;
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Позиции корзины, видимые покупателю: серверное количество с учётом оптимистичной дельты.
|
|
583
|
+
* Единый источник для списка, футера и подсветки — иначе блокировка чекаута, поиск
|
|
584
|
+
* блокирующей позиции и реальный рендер списка могут разъехаться.
|
|
585
|
+
*/
|
|
586
|
+
declare function useVisibleCartVariants(): ComputedRef<OrderProductVariant[]>;
|
|
587
|
+
|
|
588
|
+
export { type AttachedCustomerCache, type BonusesReconciliation, type BonusesReconciliationDeps, CASH_DENOMINATIONS_MAJOR, type CachedCustomerView, type CartCredentials, type CartDependencies, type CartErrorScope, type CartInitialization, type CartItemRequest, type CartLineKeyParams, type CartMutationComposable, type CartOperations, type CartQuantities, type CartRecalculation, type CartRecalculationDeps, type CartStockWatcher, type CashChangePresetsOptions, type CheckoutFlowFlags, type CheckoutSubmitComposable, type CustomerAttachComposable, DEFAULT_ROUND_STEPS_MAJOR, type MainPaymentRequestParams, type MutationKind, type MutationOptions, ORDER_EVENTS, ORDER_WITH, type OrderBonusesComposable, type OrderBonusesDeps, type OrderCredentialsLike, type OrderDelivery, type OrderDeliveryDeps, type OrderPromocodeComposable, type OrderPromocodeDeps, type OrderSettingsComposable, type OrderTotal, type PaymentSelection, type PaymentSelectionComposable, type RecaptchaPayloadProvider, type RestrictedAddToCart, type RestrictionGate, type RestrictionGateProduct, type RetryOptions, type StorefrontCart, buildCartLineKey, buildCashChangePresets, buildMainPaymentRequest, getCartErrorCode, getCartErrorHttpCode, getCartErrorMessage, getCashDenominationsMinor, getDefaultRoundStepsMinor, getValidationErrors, logCartError, normalizeAddress, useBonusesReconciliation, useCartAddressSync, useCartCredentials, useCartCustomerAttachment, useCartDeliveryAttachment, useCartInitialization, useCartMutation, useCartOperations, useCartQuantities, useCartRecalculation, useCartStockWatcher, useCheckoutFlow, useCheckoutSubmit, useCustomerAttach, useOnlinePaymentRetry, useOrderBonuses, useOrderChannel, useOrderDelivery, useOrderPromocode, useOrderSettings, useOrderTotal, usePaymentSelection, useRestrictedAddToCart, useRestrictionGate, useStorefrontCart, useVisibleCartVariants, variantLineKey };
|
package/dist/cart/index.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
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, useStorefrontCart, variantLineKey } from '../chunk-
|
|
2
|
-
export { useCartCredentials } from '../chunk-
|
|
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-G2X4SBCO.js';
|
|
2
|
+
export { useCartCredentials } from '../chunk-N3NOTJUC.js';
|
|
3
3
|
import '../chunk-5QCUH3FF.js';
|
|
4
4
|
import '../chunk-Z3IW4ODZ.js';
|
|
5
5
|
import '../chunk-BWUKMWHL.js';
|
|
6
|
-
import '../chunk-
|
|
7
|
-
import '../chunk-
|
|
8
|
-
import '../chunk-
|
|
6
|
+
import '../chunk-TEG7EL4N.js';
|
|
7
|
+
import '../chunk-E3G7NGCH.js';
|
|
8
|
+
import '../chunk-FFBZKQRV.js';
|
|
9
9
|
import '../chunk-V3VVDQIR.js';
|
|
10
10
|
import '../chunk-RO25KNM5.js';
|
|
11
|
-
import '../chunk-AL5W5JSD.js';
|
|
12
11
|
//# sourceMappingURL=index.js.map
|
|
13
12
|
//# sourceMappingURL=index.js.map
|
package/dist/catalog/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { catalogRoutes, collectDescendantIds, findCategoryById, findCategoryByShortId, findRootAncestor, getCategoryPath, groupProductsBySubcategory, useCollections } from '../chunk-
|
|
2
|
-
export { getCity, getRemoteCatalog, getStock } from '../chunk-
|
|
1
|
+
export { catalogRoutes, collectDescendantIds, findCategoryById, findCategoryByShortId, findRootAncestor, getCategoryPath, groupProductsBySubcategory, useCollections } from '../chunk-RYYY7MVP.js';
|
|
2
|
+
export { getCity, getRemoteCatalog, getStock } from '../chunk-E3G7NGCH.js';
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useStoreProfileStore } from './chunk-
|
|
1
|
+
import { useStoreProfileStore } from './chunk-TEG7EL4N.js';
|
|
2
2
|
import { defineStore, storeToRefs } from 'pinia';
|
|
3
3
|
import { ref, computed } from 'vue';
|
|
4
4
|
|
|
@@ -34,5 +34,5 @@ function useStorefrontProfile() {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
export { useProductsStore, useStore, useStorefrontProfile };
|
|
37
|
-
//# sourceMappingURL=chunk-
|
|
38
|
-
//# sourceMappingURL=chunk-
|
|
37
|
+
//# sourceMappingURL=chunk-57IOMDAM.js.map
|
|
38
|
+
//# sourceMappingURL=chunk-57IOMDAM.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/stores/products.ts","../src/stores/useStore.ts","../src/stores/useStorefrontProfile.ts"],"names":["computed"],"mappings":";;;;AAaO,IAAM,gBAAA,GAAmB,WAAA,CAAY,gBAAA,EAAkB,MAAqB;AAC/E,EAAA,MAAM,QAAA,GAAW,GAAA,CAAe,EAAE,CAAA;AAElC,EAAA,SAAS,YAAY,IAAA,EAAuB;AACxC,IAAA,QAAA,CAAS,KAAA,GAAQ,IAAA;AAAA,EACrB;AAEA,EAAA,MAAM,cAAc,QAAA,CAAS,MAAM,QAAA,CAAS,KAAA,CAAM,SAAS,CAAC,CAAA;AAE5D,EAAA,OAAO,EAAE,QAAA,EAAU,WAAA,EAAa,WAAA,EAAY;AAChD,CAAC;AChBM,SAAS,QAAA,GAId;AACE,EAAA,MAAM,eAAe,oBAAA,EAAqB;AAE1C,EAAA,OAAO;AAAA,IACH,KAAA,EAAOA,QAAAA,CAAS,MAAM,YAAA,CAAa,KAAM,CAAA;AAAA,IACzC,IAAA,EAAMA,QAAAA,CAAS,MAAM,YAAA,CAAa,IAAK,CAAA;AAAA,IACvC,KAAA,EAAOA,QAAAA,CAAS,MAAM,YAAA,CAAa,KAAK;AAAA,GAC5C;AACJ;ACbO,SAAS,oBAAA,GAAuB;AACnC,EAAA,MAAM,eAAe,oBAAA,EAAqB;AAC1C,EAAA,MAAM,EAAE,KAAA,EAAO,IAAA,EAAM,OAAO,UAAA,EAAW,GAAI,YAAY,YAAY,CAAA;AAEnE,EAAA,MAAM,OAAA,GAAUA,QAAAA,CAAS,MAAM,YAAA,CAAa,OAAO,CAAA;AACnD,EAAA,MAAM,QAAA,GAAWA,QAAAA,CAAS,MAAM,YAAA,CAAa,QAAQ,CAAA;AAErD,EAAA,OAAO;AAAA,IACH,KAAA;AAAA,IACA,IAAA;AAAA,IACA,KAAA;AAAA,IACA,UAAA;AAAA,IACA,OAAA;AAAA,IACA;AAAA,GACJ;AACJ","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/stores/products.ts","../src/stores/useStore.ts","../src/stores/useStorefrontProfile.ts"],"names":["computed"],"mappings":";;;;AAaO,IAAM,gBAAA,GAAmB,WAAA,CAAY,gBAAA,EAAkB,MAAqB;AAC/E,EAAA,MAAM,QAAA,GAAW,GAAA,CAAe,EAAE,CAAA;AAElC,EAAA,SAAS,YAAY,IAAA,EAAuB;AACxC,IAAA,QAAA,CAAS,KAAA,GAAQ,IAAA;AAAA,EACrB;AAEA,EAAA,MAAM,cAAc,QAAA,CAAS,MAAM,QAAA,CAAS,KAAA,CAAM,SAAS,CAAC,CAAA;AAE5D,EAAA,OAAO,EAAE,QAAA,EAAU,WAAA,EAAa,WAAA,EAAY;AAChD,CAAC;AChBM,SAAS,QAAA,GAId;AACE,EAAA,MAAM,eAAe,oBAAA,EAAqB;AAE1C,EAAA,OAAO;AAAA,IACH,KAAA,EAAOA,QAAAA,CAAS,MAAM,YAAA,CAAa,KAAM,CAAA;AAAA,IACzC,IAAA,EAAMA,QAAAA,CAAS,MAAM,YAAA,CAAa,IAAK,CAAA;AAAA,IACvC,KAAA,EAAOA,QAAAA,CAAS,MAAM,YAAA,CAAa,KAAK;AAAA,GAC5C;AACJ;ACbO,SAAS,oBAAA,GAAuB;AACnC,EAAA,MAAM,eAAe,oBAAA,EAAqB;AAC1C,EAAA,MAAM,EAAE,KAAA,EAAO,IAAA,EAAM,OAAO,UAAA,EAAW,GAAI,YAAY,YAAY,CAAA;AAEnE,EAAA,MAAM,OAAA,GAAUA,QAAAA,CAAS,MAAM,YAAA,CAAa,OAAO,CAAA;AACnD,EAAA,MAAM,QAAA,GAAWA,QAAAA,CAAS,MAAM,YAAA,CAAa,QAAQ,CAAA;AAErD,EAAA,OAAO;AAAA,IACH,KAAA;AAAA,IACA,IAAA;AAAA,IACA,KAAA;AAAA,IACA,UAAA;AAAA,IACA,OAAA;AAAA,IACA;AAAA,GACJ;AACJ","file":"chunk-57IOMDAM.js","sourcesContent":["import { defineStore } from 'pinia'\nimport { computed, ref, type ComputedRef, type Ref } from 'vue'\n\nimport type { Product } from '@zenky/storefront-api'\n\n// Явный тип возврата — сохраняет `Product` именованной ссылкой в .d.ts вместо разворачивания.\nexport interface ProductsStore {\n products: Ref<Product[]>\n setProducts: (list: Product[]) => void\n hasProducts: ComputedRef<boolean>\n}\n\n// Товары держим в сторе, но наполняем из каталога (не из отдельного API-вызова).\nexport const useProductsStore = defineStore('zenky-products', (): ProductsStore => {\n const products = ref<Product[]>([])\n\n function setProducts(list: Product[]): void {\n products.value = list\n }\n\n const hasProducts = computed(() => products.value.length > 0)\n\n return { products, setProducts, hasProducts }\n})\n","import { computed, type ComputedRef } from 'vue'\n\nimport type { City, Stock, Store } from '@zenky/storefront-api'\n\nimport { useStoreProfileStore } from './store-profile'\n\n/** Аксессор загруженного стора/города/склада (store/city — гарантированно загружены). */\nexport function useStore(): {\n store: ComputedRef<Store>\n city: ComputedRef<City>\n stock: ComputedRef<Stock | null>\n} {\n const profileStore = useStoreProfileStore()\n\n return {\n store: computed(() => profileStore.store!),\n city: computed(() => profileStore.city!),\n stock: computed(() => profileStore.stock),\n }\n}\n","import { storeToRefs } from 'pinia'\nimport { computed } from 'vue'\n\nimport { useStoreProfileStore } from './store-profile'\n\n/** Реактивный доступ к профилю (store/city/stock/categories + флаги готовности). */\nexport function useStorefrontProfile() {\n const profileStore = useStoreProfileStore()\n const { store, city, stock, categories } = storeToRefs(profileStore)\n\n const isReady = computed(() => profileStore.isReady)\n const hasStock = computed(() => profileStore.hasStock)\n\n return {\n store,\n city,\n stock,\n categories,\n isReady,\n hasStock,\n }\n}\n"]}
|
|
@@ -33,8 +33,7 @@ function wrapSnippetJs(snippet) {
|
|
|
33
33
|
function parseTagAttributes(raw) {
|
|
34
34
|
const attrs = {};
|
|
35
35
|
const re = /([a-zA-Z][\w:-]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g;
|
|
36
|
-
|
|
37
|
-
while ((match = re.exec(raw)) !== null) {
|
|
36
|
+
for (const match of raw.matchAll(re)) {
|
|
38
37
|
const name = match[1];
|
|
39
38
|
if (name) attrs[name] = match[2] ?? match[3] ?? match[4] ?? true;
|
|
40
39
|
}
|
|
@@ -42,15 +41,18 @@ function parseTagAttributes(raw) {
|
|
|
42
41
|
}
|
|
43
42
|
function parseHeadHtml(html) {
|
|
44
43
|
const result = { meta: [], link: [], script: [] };
|
|
45
|
-
let m;
|
|
46
44
|
const metaRe = /<meta\b([^>]*)>/gi;
|
|
47
|
-
|
|
45
|
+
for (const match of html.matchAll(metaRe)) {
|
|
46
|
+
result.meta.push(parseTagAttributes(match[1] ?? ""));
|
|
47
|
+
}
|
|
48
48
|
const linkRe = /<link\b([^>]*)>/gi;
|
|
49
|
-
|
|
49
|
+
for (const match of html.matchAll(linkRe)) {
|
|
50
|
+
result.link.push(parseTagAttributes(match[1] ?? ""));
|
|
51
|
+
}
|
|
50
52
|
const scriptRe = /<script\b([^>]*)>([\s\S]*?)<\/script>/gi;
|
|
51
|
-
|
|
52
|
-
const attrs = parseTagAttributes(
|
|
53
|
-
const inner = (
|
|
53
|
+
for (const match of html.matchAll(scriptRe)) {
|
|
54
|
+
const attrs = parseTagAttributes(match[1] ?? "");
|
|
55
|
+
const inner = (match[2] ?? "").trim();
|
|
54
56
|
result.script.push(inner ? { ...attrs, innerHTML: inner } : attrs);
|
|
55
57
|
}
|
|
56
58
|
return result;
|
|
@@ -87,5 +89,5 @@ function buildSnippetHead(snippets) {
|
|
|
87
89
|
}
|
|
88
90
|
|
|
89
91
|
export { buildSnippetHead, normalizeSnippets };
|
|
90
|
-
//# sourceMappingURL=chunk-
|
|
91
|
-
//# sourceMappingURL=chunk-
|
|
92
|
+
//# sourceMappingURL=chunk-7FRMMCR5.js.map
|
|
93
|
+
//# sourceMappingURL=chunk-7FRMMCR5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/snippets/snippets.ts","../src/snippets/buildSnippetHead.ts"],"names":[],"mappings":"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","file":"chunk-7FRMMCR5.js","sourcesContent":["export type SnippetPosition = 'head_start' | 'head_end' | 'body_start' | 'body_end'\nexport type SnippetLanguage = 'html' | 'css' | 'javascript'\n\nexport interface Snippet {\n id: string\n name?: string\n position: SnippetPosition\n language: SnippetLanguage\n code: string\n enabled: boolean\n}\n\nexport interface RawSnippetItem {\n language: SnippetLanguage\n content: string\n enabled?: boolean\n name?: string\n}\n\nexport interface SnippetGroup {\n region: SnippetPosition\n snippets: RawSnippetItem[]\n}\n\nexport function normalizeSnippets(groups: SnippetGroup[] | null | undefined): Snippet[] {\n if (!Array.isArray(groups)) return []\n\n return groups.flatMap((group, groupIndex) =>\n (group.snippets ?? [])\n .filter((item) => !!item.content?.trim())\n .map((item, itemIndex): Snippet => {\n const snippet: Snippet = {\n id: `${group.region}-${groupIndex}-${itemIndex}`,\n position: group.region,\n language: item.language,\n code: item.content,\n enabled: item.enabled ?? true,\n }\n // exactOptionalPropertyTypes: name задаём только если оно есть\n if (item.name !== undefined) snippet.name = item.name\n return snippet\n })\n )\n}\n","import type { Snippet } from './snippets'\n\n/** Head-нагрузка для инъекции сниппетов (потребитель отдаёт её в useHead). */\nexport interface SnippetHead {\n meta: Record<string, string | boolean>[]\n link: Record<string, string | boolean>[]\n script: Record<string, unknown>[]\n style: Record<string, string | boolean>[]\n}\n\n/** JS-сниппет в try/catch с dispatch `zenky:snippet-error` при падении. */\nfunction wrapSnippetJs(snippet: Snippet): string {\n const id = JSON.stringify(snippet.id)\n return `;(() => {\n try {\n ${snippet.code}\n } catch (error) {\n console.error('[snippet:error]', { id: ${id}, error });\n window.dispatchEvent(new CustomEvent('zenky:snippet-error', {\n detail: { id: ${id}, message: error instanceof Error ? error.message : String(error) },\n }));\n }\n})();`\n}\n\ntype HeadAttrs = Record<string, string | boolean>\n\ninterface ParsedHeadHtml {\n meta: HeadAttrs[]\n link: HeadAttrs[]\n script: Array<HeadAttrs & { innerHTML?: string }>\n}\n\nfunction parseTagAttributes(raw: string): HeadAttrs {\n const attrs: HeadAttrs = {}\n const re = /([a-zA-Z][\\w:-]*)(?:\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s\"'=<>`]+)))?/g\n for (const match of raw.matchAll(re)) {\n const name = match[1]\n if (name) attrs[name] = match[2] ?? match[3] ?? match[4] ?? true\n }\n return attrs\n}\n\nfunction parseHeadHtml(html: string): ParsedHeadHtml {\n const result: ParsedHeadHtml = { meta: [], link: [], script: [] }\n\n const metaRe = /<meta\\b([^>]*)>/gi\n for (const match of html.matchAll(metaRe)) {\n result.meta.push(parseTagAttributes(match[1] ?? ''))\n }\n\n const linkRe = /<link\\b([^>]*)>/gi\n for (const match of html.matchAll(linkRe)) {\n result.link.push(parseTagAttributes(match[1] ?? ''))\n }\n\n const scriptRe = /<script\\b([^>]*)>([\\s\\S]*?)<\\/script>/gi\n for (const match of html.matchAll(scriptRe)) {\n const attrs = parseTagAttributes(match[1] ?? '')\n const inner = (match[2] ?? '').trim()\n result.script.push(inner ? { ...attrs, innerHTML: inner } : attrs)\n }\n\n return result\n}\n\n/**\n * Раскладывает сниппеты магазина в head-нагрузку: JS (обёрнут в try/catch),\n * CSS (style), head-HTML (распарсенные meta/link/script). Инъекция — у потребителя.\n */\nexport function buildSnippetHead(snippets: Snippet[]): SnippetHead {\n const enabled = snippets.filter((s) => s.enabled)\n\n const jsSnippets = enabled.filter((s) => s.language === 'javascript')\n const cssSnippets = enabled.filter((s) => s.language === 'css')\n const headHtmlSnippets = enabled.filter(\n (s) => s.language === 'html' && s.position.startsWith('head')\n )\n\n const parsedHead = headHtmlSnippets.map((s) => parseHeadHtml(s.code))\n const headMeta = parsedHead.flatMap((p) => p.meta)\n const headLink = parsedHead.flatMap((p) => p.link)\n const headScripts = parsedHead.flatMap((p) => p.script)\n\n return {\n meta: headMeta,\n link: headLink,\n script: [\n ...jsSnippets.map((snippet) => ({\n key: `snippet-js-${snippet.id}`,\n innerHTML: wrapSnippetJs(snippet),\n body: snippet.position.startsWith('body'),\n 'data-snippet-id': snippet.id,\n })),\n ...headScripts,\n ],\n style: cssSnippets.map((snippet) => ({\n key: `snippet-css-${snippet.id}`,\n innerHTML: snippet.code,\n 'data-snippet-id': snippet.id,\n })),\n }\n}\n"]}
|
|
@@ -41,5 +41,5 @@ function getRemoteCatalog(store, city, stock) {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
export { getCity, getRemoteCatalog, getStock };
|
|
44
|
-
//# sourceMappingURL=chunk-
|
|
45
|
-
//# sourceMappingURL=chunk-
|
|
44
|
+
//# sourceMappingURL=chunk-E3G7NGCH.js.map
|
|
45
|
+
//# sourceMappingURL=chunk-E3G7NGCH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/catalog/catalogResolver.ts"],"names":[],"mappings":";AAEO,SAAS,OAAA,CAAQ,OAAc,MAAA,EAAqC;AACvE,EAAA,IAAI,CAAC,KAAA,CAAM,MAAA,CAAO,MAAA,EAAQ,OAAO,IAAA;AAEjC,EAAA,MAAM,WAAA,GAAc,KAAA,CAAM,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,UAAU,CAAA,IAAK,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,IAAK,IAAA;AAEjF,EAAA,IAAI,CAAC,QAAQ,OAAO,WAAA;AAEpB,EAAA,OAAO,KAAA,CAAM,OAAO,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,EAAA,KAAO,MAAM,CAAA,IAAK,WAAA;AACxD;AAEO,SAAS,QAAA,CAAS,MAAY,OAAA,EAAuC;AACxE,EAAA,IAAI,CAAC,IAAA,CAAK,MAAA,EAAQ,MAAA,EAAQ,OAAO,IAAA;AAEjC,EAAA,MAAM,YAAA,GAAe,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,IAAK,IAAA;AAEvC,EAAA,IAAI,CAAC,SAAS,OAAO,YAAA;AAErB,EAAA,OAAO,IAAA,CAAK,OAAO,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,EAAA,KAAO,OAAO,CAAA,IAAK,YAAA;AACxD;AAEO,SAAS,gBAAA,CACZ,KAAA,EACA,IAAA,EACA,KAAA,EACoB;AACpB,EAAA,IAAI,CAAC,KAAA,CAAM,QAAA,CAAS,MAAA,EAAQ;AACxB,IAAA,OAAA,CAAQ,KAAK,4CAAA,EAA8C;AAAA,MACvD,SAAS,KAAA,CAAM,EAAA;AAAA,MACf,QAAQ,IAAA,CAAK,EAAA;AAAA,MACb,OAAA,EAAS,OAAO,EAAA,IAAM;AAAA,KACzB,CAAA;AACD,IAAA,OAAO,IAAA;AAAA,EACX;AAGA,EAAA,IAAI,KAAA,EAAO;AACP,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAA,KAAY,IAAA,CAAK,EAAA,IAAM,CAAA,CAAE,QAAA,KAAa,MAAM,EAAE,CAAA;AACzF,IAAA,IAAI,OAAO,OAAO,KAAA;AAAA,EACtB;AAEA,EAAA,MAAM,QAAA,GAAW,KAAA,CAAM,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAA,KAAY,IAAA,CAAK,EAAA,IAAM,CAAA,CAAE,QAAA,KAAa,IAAI,CAAA;AACxF,EAAA,IAAI,UAAU,OAAO,QAAA;AAErB,EAAA,MAAM,MAAA,GAAS,KAAA,CAAM,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAA,KAAY,IAAA,IAAQ,CAAA,CAAE,QAAA,KAAa,IAAI,CAAA;AACnF,EAAA,IAAI,QAAQ,OAAO,MAAA;AAEnB,EAAA,OAAA,CAAQ,KAAK,gEAAA,EAAkE;AAAA,IAC3E,SAAS,KAAA,CAAM,EAAA;AAAA,IACf,QAAQ,IAAA,CAAK,EAAA;AAAA,IACb,OAAA,EAAS,OAAO,EAAA,IAAM,IAAA;AAAA,IACtB,iBAAA,EAAmB,KAAA,CAAM,QAAA,CAAS,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,MAC1C,SAAS,CAAA,CAAE,OAAA;AAAA,MACX,UAAU,CAAA,CAAE;AAAA,KAChB,CAAE;AAAA,GACL,CAAA;AAED,EAAA,OAAO,IAAA;AACX","file":"chunk-E3G7NGCH.js","sourcesContent":["import type { City, RemoteCatalog, Stock, Store } from '@zenky/storefront-api'\n\nexport function getCity(store: Store, cityId?: string | null): City | null {\n if (!store.cities.length) return null\n\n const defaultCity = store.cities.find((c) => c.is_default) ?? store.cities[0] ?? null\n\n if (!cityId) return defaultCity\n\n return store.cities.find((c) => c.id === cityId) ?? defaultCity\n}\n\nexport function getStock(city: City, stockId?: string | null): Stock | null {\n if (!city.stocks?.length) return null\n\n const defaultStock = city.stocks[0] ?? null\n\n if (!stockId) return defaultStock\n\n return city.stocks.find((s) => s.id === stockId) ?? defaultStock\n}\n\nexport function getRemoteCatalog(\n store: Store,\n city: City,\n stock: Stock | null\n): RemoteCatalog | null {\n if (!store.catalogs.length) {\n console.warn('[catalog-resolver] store.catalogs is empty', {\n storeId: store.id,\n cityId: city.id,\n stockId: stock?.id ?? null,\n })\n return null\n }\n\n // Приоритет: точное совпадение city+stock → city-only → глобальный.\n if (stock) {\n const exact = store.catalogs.find((c) => c.city_id === city.id && c.stock_id === stock.id)\n if (exact) return exact\n }\n\n const cityOnly = store.catalogs.find((c) => c.city_id === city.id && c.stock_id === null)\n if (cityOnly) return cityOnly\n\n const global = store.catalogs.find((c) => c.city_id === null && c.stock_id === null)\n if (global) return global\n\n console.warn('[catalog-resolver] no catalog matched (exact/city-only/global)', {\n storeId: store.id,\n cityId: city.id,\n stockId: stock?.id ?? null,\n availableCatalogs: store.catalogs.map((c) => ({\n city_id: c.city_id,\n stock_id: c.stock_id,\n })),\n })\n\n return null\n}\n"]}
|
|
@@ -158,8 +158,11 @@ var useCartStore = defineStore("zenky-cart", () => {
|
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
function setOrder(next) {
|
|
161
|
-
if (!next
|
|
162
|
-
console.warn("[cart] setOrder ignored \u2014 missing id/token",
|
|
161
|
+
if (!next?.id || !next.token) {
|
|
162
|
+
console.warn("[cart] setOrder ignored \u2014 missing id/token", {
|
|
163
|
+
hasId: Boolean(next?.id),
|
|
164
|
+
hasToken: Boolean(next?.token)
|
|
165
|
+
});
|
|
163
166
|
return;
|
|
164
167
|
}
|
|
165
168
|
order.value = next;
|
|
@@ -169,8 +172,11 @@ var useCartStore = defineStore("zenky-cart", () => {
|
|
|
169
172
|
}
|
|
170
173
|
}
|
|
171
174
|
function patchOrder(partial) {
|
|
172
|
-
if (!partial
|
|
173
|
-
console.warn("[cart] patchOrder ignored \u2014 missing id/token",
|
|
175
|
+
if (!partial?.id || !partial.token) {
|
|
176
|
+
console.warn("[cart] patchOrder ignored \u2014 missing id/token", {
|
|
177
|
+
hasId: Boolean(partial?.id),
|
|
178
|
+
hasToken: Boolean(partial?.token)
|
|
179
|
+
});
|
|
174
180
|
return;
|
|
175
181
|
}
|
|
176
182
|
if (!order.value) {
|
|
@@ -272,7 +278,8 @@ var useCartStore = defineStore("zenky-cart", () => {
|
|
|
272
278
|
function setCheckoutTotal(value) {
|
|
273
279
|
checkoutTotal.value = value;
|
|
274
280
|
const min = value.min_price;
|
|
275
|
-
|
|
281
|
+
const hasItems = (order.value?.variants?.length ?? 0) > 0;
|
|
282
|
+
minPriceViolation.value = hasItems && min != null && value.total > 0 && value.total < min ? {
|
|
276
283
|
remaining: Math.max(0, min - value.total),
|
|
277
284
|
progress: Math.min(1, value.total / min),
|
|
278
285
|
minPrice: min
|
|
@@ -382,5 +389,5 @@ var useCartStore = defineStore("zenky-cart", () => {
|
|
|
382
389
|
});
|
|
383
390
|
|
|
384
391
|
export { useCartStore, useOrderSettingsStore };
|
|
385
|
-
//# sourceMappingURL=chunk-
|
|
386
|
-
//# sourceMappingURL=chunk-
|
|
392
|
+
//# sourceMappingURL=chunk-FFBZKQRV.js.map
|
|
393
|
+
//# sourceMappingURL=chunk-FFBZKQRV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/stores/order-settings.ts","../src/stores/cart.ts"],"names":["defineStore","ref","raw","computed"],"mappings":"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","file":"chunk-FFBZKQRV.js","sourcesContent":["import { DeliveryMethod } from '@zenky/storefront-api'\nimport { defineStore } from 'pinia'\nimport { computed, ref, type ComputedRef, type Ref } from 'vue'\n\nimport type { City, Stock } from '@zenky/storefront-api'\n\nimport { useRuntime } from '../ports/runtime'\n\n// Ключи совпадают с прежними CookieKey.* — чтобы не потерять сохранённые настройки.\nconst KEY_DELIVERY_METHOD = 'zenky_delivery_method'\nconst KEY_ON_PREMISE_TABLE = 'zenky_on_premise_table'\nconst KEY_SELECTED_STOCK_ID = 'zenky_selected_stock_id'\nconst KEY_SELECTED_ADDRESS = 'zenky_selected_address'\nconst KEY_SELECTED_ADDRESS_ID = 'zenky_selected_address_id'\nconst KEY_SELECTED_ADDRESS_NAME = 'zenky_selected_address_name'\n\nconst VALID_DELIVERY_METHODS = new Set<string>(Object.values(DeliveryMethod))\n\nexport interface OrderSettingsStore {\n deliveryMethod: Ref<DeliveryMethod>\n onPremiseTable: Ref<string | null>\n selectedStock: Ref<Stock | null>\n selectedAddress: Ref<string | null>\n selectedAddressId: Ref<string | null>\n selectedAddressName: Ref<string | null>\n setDeliveryMethod: (method: DeliveryMethod) => void\n setOnPremiseTable: (table: string | null) => void\n setSelectedStock: (stock: Stock | null) => void\n setSelectedAddress: (\n address: string | null,\n addressId?: string | null,\n addressName?: string | null\n ) => void\n validateDeliveryMethod: (availableMethods: DeliveryMethod[]) => void\n restoreFromCookies: (city: City) => void\n isDelivery: ComputedRef<boolean>\n isPickup: ComputedRef<boolean>\n isOnPremise: ComputedRef<boolean>\n needsAddress: ComputedRef<boolean>\n needsStock: ComputedRef<boolean>\n needsTable: ComputedRef<boolean>\n}\n\nexport const useOrderSettingsStore = defineStore('zenky-order-settings', (): OrderSettingsStore => {\n const { storage } = useRuntime()\n\n const deliveryMethod = ref<DeliveryMethod>(DeliveryMethod.Delivery)\n const onPremiseTable = ref<string | null>(null)\n const selectedStock = ref<Stock | null>(null)\n const selectedAddress = ref<string | null>(null)\n const selectedAddressId = ref<string | null>(null)\n const selectedAddressName = ref<string | null>(null)\n\n function setDeliveryMethod(method: DeliveryMethod): void {\n deliveryMethod.value = method\n storage.set(KEY_DELIVERY_METHOD, method)\n }\n\n function setOnPremiseTable(table: string | null): void {\n onPremiseTable.value = table\n if (table) storage.set(KEY_ON_PREMISE_TABLE, table)\n else storage.remove(KEY_ON_PREMISE_TABLE)\n }\n\n function setSelectedStock(stock: Stock | null): void {\n selectedStock.value = stock\n if (stock) storage.set(KEY_SELECTED_STOCK_ID, stock.id)\n else storage.remove(KEY_SELECTED_STOCK_ID)\n }\n\n function setSelectedAddress(\n address: string | null,\n addressId?: string | null,\n addressName?: string | null\n ): void {\n selectedAddress.value = address\n selectedAddressId.value = addressId ?? null\n selectedAddressName.value = addressName ?? null\n writeOrRemove(KEY_SELECTED_ADDRESS, address)\n writeOrRemove(KEY_SELECTED_ADDRESS_ID, addressId ?? null)\n writeOrRemove(KEY_SELECTED_ADDRESS_NAME, addressName ?? null)\n }\n\n function writeOrRemove(key: string, value: string | null): void {\n if (value) storage.set(key, value)\n else storage.remove(key)\n }\n\n /** Если текущий метод не входит в доступные — переключить на первый доступный. */\n function validateDeliveryMethod(availableMethods: DeliveryMethod[]): void {\n const first = availableMethods[0]\n if (!first) return\n\n if (!availableMethods.includes(deliveryMethod.value)) {\n deliveryMethod.value = first\n storage.set(KEY_DELIVERY_METHOD, first)\n }\n }\n\n /** Восстановить настройки из cookies. Вызывать после загрузки города. */\n function restoreFromCookies(city: City): void {\n const savedMethod = storage.get(KEY_DELIVERY_METHOD)\n if (savedMethod && VALID_DELIVERY_METHODS.has(savedMethod)) {\n deliveryMethod.value = savedMethod as DeliveryMethod\n }\n\n const savedStockId = storage.get(KEY_SELECTED_STOCK_ID)\n const stocks = city.stocks ?? []\n if (savedStockId && stocks.length) {\n const stock = stocks.find((s) => s.id === savedStockId) ?? null\n selectedStock.value = stock\n if (!stock) storage.remove(KEY_SELECTED_STOCK_ID)\n }\n\n const savedAddress = storage.get(KEY_SELECTED_ADDRESS)\n if (savedAddress) selectedAddress.value = savedAddress\n\n const savedAddressId = storage.get(KEY_SELECTED_ADDRESS_ID)\n if (savedAddressId) selectedAddressId.value = savedAddressId\n\n const savedAddressName = storage.get(KEY_SELECTED_ADDRESS_NAME)\n if (savedAddressName) selectedAddressName.value = savedAddressName\n\n const savedTable = storage.get(KEY_ON_PREMISE_TABLE)\n if (savedTable) onPremiseTable.value = savedTable\n }\n\n const isDelivery = computed(() => deliveryMethod.value === DeliveryMethod.Delivery)\n const isPickup = computed(() => deliveryMethod.value === DeliveryMethod.Pickup)\n const isOnPremise = computed(() => deliveryMethod.value === DeliveryMethod.OnPremise)\n const needsAddress = computed(() => deliveryMethod.value === DeliveryMethod.Delivery)\n const needsStock = computed(\n () =>\n deliveryMethod.value === DeliveryMethod.Pickup ||\n deliveryMethod.value === DeliveryMethod.OnPremise\n )\n const needsTable = computed(() => deliveryMethod.value === DeliveryMethod.OnPremise)\n\n return {\n deliveryMethod,\n onPremiseTable,\n selectedStock,\n selectedAddress,\n selectedAddressId,\n selectedAddressName,\n setDeliveryMethod,\n setOnPremiseTable,\n setSelectedStock,\n setSelectedAddress,\n validateDeliveryMethod,\n restoreFromCookies,\n isDelivery,\n isPickup,\n isOnPremise,\n needsAddress,\n needsStock,\n needsTable,\n }\n})\n","import { PaymentMethod } from '@zenky/storefront-api'\nimport { defineStore } from 'pinia'\nimport { computed, ref, type ComputedRef, type Ref } from 'vue'\n\nimport type {\n DeliveryMethod,\n Order,\n OrderCheckoutTotal,\n OrderDeliveryMethod,\n OrderPaymentMethod,\n OrderPaymentTransaction,\n OrderProductVariant,\n OrderSettings,\n} from '@zenky/storefront-api'\n\nimport { useRuntime } from '../ports/runtime'\nimport { useOrderSettingsStore } from './order-settings'\n\n// Ключи совпадают с прежними CookieKey.* — чтобы не потерять сохранённое.\nconst KEY_COMMENT = 'zenky_order_comment'\nconst KEY_PERSONS_COUNT = 'zenky_order_persons_count'\n\nexport interface CartCredentials {\n id: string\n token: string\n}\n\n/** Намерение по бонусам (business-state) — для headless-reconciliation. */\nexport interface AppliedBonusesIntent {\n enabled: boolean\n /** null = «списать максимум». */\n desiredAmountMinor: number | null\n /** PIN-flow: бонусы сняты, нужно подтвердить заново. */\n requiresConfirmation: boolean\n}\n\nexport interface MinPriceViolation {\n remaining: number\n progress: number\n minPrice: number\n}\n\nfunction emptyBonusesIntent(): AppliedBonusesIntent {\n return { enabled: false, desiredAmountMinor: null, requiresConfirmation: false }\n}\n\nfunction parsePersonsCount(raw: string | null): number {\n const parsed = raw ? Number.parseInt(raw, 10) : NaN\n return Number.isFinite(parsed) && parsed > 0 ? parsed : 0\n}\n\nexport interface CartStore {\n order: Ref<Order | null>\n credentials: Ref<CartCredentials | null>\n loading: Ref<boolean>\n initializing: Ref<boolean>\n optimisticAdjustments: Ref<Record<string, number>>\n lineOptimistic: Ref<Record<string, number>>\n deliveryMethods: Ref<OrderDeliveryMethod[]>\n orderSettings: Ref<OrderSettings | null>\n comment: Ref<string>\n personsCount: Ref<number>\n checkoutTotal: Ref<OrderCheckoutTotal | null>\n selectedPaymentMethod: Ref<PaymentMethod | null>\n selectedPaymentBill: Ref<number | null>\n selectedCardTokenId: Ref<string | null>\n selectedSaveCard: Ref<boolean>\n bonusesIntent: Ref<AppliedBonusesIntent>\n deliveryTimeIntent: Ref<string | null>\n minPriceViolation: Ref<MinPriceViolation | null>\n setOrder: (order: Order) => void\n patchOrder: (partial: Order) => void\n setCredentials: (credentials: CartCredentials) => void\n setLoading: (value: boolean) => void\n setInitializing: (value: boolean) => void\n adjustOptimistic: (productId: string, delta: number) => void\n clearOptimistic: (productId: string) => void\n adjustLineOptimistic: (lineKey: string, delta: number) => void\n setDeliveryMethods: (methods: OrderDeliveryMethod[]) => void\n setOrderSettings: (settings: OrderSettings) => void\n setComment: (value: string) => void\n setPersonsCount: (value: number) => void\n setSelectedPaymentMethod: (method: PaymentMethod | null) => void\n setSelectedPaymentBill: (bill: number | null) => void\n setSelectedCardTokenId: (id: string | null) => void\n setSelectedSaveCard: (value: boolean) => void\n setBonusesIntentEnabled: (value: boolean) => void\n setDesiredBonusesAmount: (value: number | null) => void\n setBonusesRequiresConfirmation: (value: boolean) => void\n clearBonusesIntent: () => void\n setDeliveryTimeIntent: (value: string | null) => void\n restorePaymentSelection: (payments: OrderPaymentTransaction[]) => void\n validatePaymentSelection: () => void\n setOrderPaymentsState: (payments: OrderPaymentTransaction[]) => void\n setCheckoutTotal: (value: OrderCheckoutTotal) => void\n clearCart: () => void\n hasOrder: ComputedRef<boolean>\n hasCredentials: ComputedRef<boolean>\n variants: ComputedRef<OrderProductVariant[]>\n totalPrice: ComputedRef<number>\n itemCount: ComputedRef<number>\n availableDeliveryMethodIds: ComputedRef<DeliveryMethod[]>\n paymentMethods: ComputedRef<OrderPaymentMethod[]>\n hasBonusesApplied: ComputedRef<boolean>\n productQuantities: ComputedRef<Record<string, number>>\n}\n\nexport const useCartStore = defineStore('zenky-cart', (): CartStore => {\n const { storage } = useRuntime()\n\n const order = ref<Order | null>(null)\n const credentials = ref<CartCredentials | null>(null)\n const loading = ref(false)\n const initializing = ref(false)\n const optimisticAdjustments = ref<Record<string, number>>({})\n const lineOptimistic = ref<Record<string, number>>({})\n const deliveryMethods = ref<OrderDeliveryMethod[]>([])\n const orderSettings = ref<OrderSettings | null>(null)\n const comment = ref(storage.get(KEY_COMMENT) ?? '')\n const personsCount = ref(parsePersonsCount(storage.get(KEY_PERSONS_COUNT)))\n const checkoutTotal = ref<OrderCheckoutTotal | null>(null)\n const selectedPaymentMethod = ref<PaymentMethod | null>(null)\n const selectedPaymentBill = ref<number | null>(null)\n const selectedCardTokenId = ref<string | null>(null)\n const selectedSaveCard = ref(false)\n const bonusesIntent = ref<AppliedBonusesIntent>(emptyBonusesIntent())\n const deliveryTimeIntent = ref<string | null>(null)\n const minPriceViolation = ref<MinPriceViolation | null>(null)\n\n function restorePaymentSelection(payments: OrderPaymentTransaction[]): void {\n const restored = payments.find((p) => {\n const raw = p.method as unknown\n const id = typeof raw === 'string' ? raw : ((raw as { id?: string } | null)?.id ?? null)\n return id !== PaymentMethod.Bonuses\n })\n if (!restored) return\n\n const raw = restored.method as unknown\n const methodId = (\n typeof raw === 'string' ? raw : ((raw as { id?: PaymentMethod } | null)?.id ?? null)\n ) as PaymentMethod | null\n if (!methodId || selectedPaymentMethod.value === methodId) return\n\n selectedPaymentMethod.value = methodId\n\n const meta = restored.transaction_meta as { bill?: number | null } | null | undefined\n const billMinor = meta?.bill ?? null\n const newBill = billMinor != null && billMinor > 0 ? billMinor : null\n if (selectedPaymentBill.value !== newBill) {\n selectedPaymentBill.value = newBill\n }\n }\n\n function validatePaymentSelection(): void {\n if (!selectedPaymentMethod.value) return\n const methods = orderSettings.value?.payment_methods ?? []\n if (!methods.some((m) => m.id === selectedPaymentMethod.value)) {\n selectedPaymentMethod.value = null\n selectedPaymentBill.value = null\n }\n }\n\n function setOrder(next: Order): void {\n if (!next?.id || !next.token) {\n console.warn('[cart] setOrder ignored — missing id/token', {\n hasId: Boolean(next?.id),\n hasToken: Boolean(next?.token),\n })\n return\n }\n\n order.value = next\n credentials.value = { id: next.id, token: next.token }\n\n if (Array.isArray(next.payments) && next.payments.length > 0) {\n restorePaymentSelection(next.payments as unknown as OrderPaymentTransaction[])\n }\n }\n\n function patchOrder(partial: Order): void {\n if (!partial?.id || !partial.token) {\n console.warn('[cart] patchOrder ignored — missing id/token', {\n hasId: Boolean(partial?.id),\n hasToken: Boolean(partial?.token),\n })\n return\n }\n\n if (!order.value) {\n order.value = partial\n } else {\n const merged: Order = { ...order.value }\n for (const key of Object.keys(partial) as (keyof Order)[]) {\n const value = partial[key]\n if (value !== undefined) {\n ;(merged as unknown as Record<string, unknown>)[key as string] = value\n }\n }\n order.value = merged\n }\n\n credentials.value = { id: partial.id, token: partial.token }\n\n if (Array.isArray(partial.payments) && partial.payments.length > 0) {\n restorePaymentSelection(partial.payments as unknown as OrderPaymentTransaction[])\n }\n }\n\n function setCredentials(next: CartCredentials): void {\n credentials.value = next\n }\n\n function setLoading(value: boolean): void {\n loading.value = value\n }\n\n function setInitializing(value: boolean): void {\n initializing.value = value\n }\n\n function adjustOptimistic(productId: string, delta: number): void {\n const next = (optimisticAdjustments.value[productId] ?? 0) + delta\n if (next === 0) delete optimisticAdjustments.value[productId]\n else optimisticAdjustments.value[productId] = next\n }\n\n function clearOptimistic(productId: string): void {\n delete optimisticAdjustments.value[productId]\n }\n\n function adjustLineOptimistic(lineKey: string, delta: number): void {\n const next = (lineOptimistic.value[lineKey] ?? 0) + delta\n if (next === 0) delete lineOptimistic.value[lineKey]\n else lineOptimistic.value[lineKey] = next\n }\n\n function setDeliveryMethods(methods: OrderDeliveryMethod[]): void {\n deliveryMethods.value = methods\n const settingsStore = useOrderSettingsStore()\n settingsStore.validateDeliveryMethod(methods.map((m) => m.id))\n }\n\n function setOrderSettings(settings: OrderSettings): void {\n orderSettings.value = settings\n setDeliveryMethods(settings.delivery_methods)\n validatePaymentSelection()\n }\n\n function setComment(value: string): void {\n comment.value = value\n if (value) storage.set(KEY_COMMENT, value)\n else storage.remove(KEY_COMMENT)\n }\n\n function setPersonsCount(value: number): void {\n personsCount.value = value\n if (value > 0) storage.set(KEY_PERSONS_COUNT, String(value))\n else storage.remove(KEY_PERSONS_COUNT)\n }\n\n function setSelectedPaymentMethod(method: PaymentMethod | null): void {\n selectedPaymentMethod.value = method\n }\n\n function setSelectedPaymentBill(bill: number | null): void {\n selectedPaymentBill.value = bill\n }\n\n function setSelectedCardTokenId(id: string | null): void {\n selectedCardTokenId.value = id\n }\n\n function setSelectedSaveCard(value: boolean): void {\n selectedSaveCard.value = value\n }\n\n function setBonusesIntentEnabled(value: boolean): void {\n bonusesIntent.value.enabled = value\n if (!value) {\n bonusesIntent.value.desiredAmountMinor = null\n bonusesIntent.value.requiresConfirmation = false\n }\n }\n\n function setDesiredBonusesAmount(value: number | null): void {\n bonusesIntent.value.desiredAmountMinor = value\n }\n\n function setBonusesRequiresConfirmation(value: boolean): void {\n bonusesIntent.value.requiresConfirmation = value\n }\n\n function clearBonusesIntent(): void {\n bonusesIntent.value = emptyBonusesIntent()\n }\n\n function setDeliveryTimeIntent(value: string | null): void {\n deliveryTimeIntent.value = value\n }\n\n function setOrderPaymentsState(payments: OrderPaymentTransaction[]): void {\n if (order.value) {\n order.value = { ...order.value, payments } as Order\n }\n restorePaymentSelection(payments)\n }\n\n function setCheckoutTotal(value: OrderCheckoutTotal): void {\n checkoutTotal.value = value\n\n const min = value.min_price\n // Пустой заказ (нет variants) с ненулевой доставкой в total — не нарушение минималки.\n const hasItems = (order.value?.variants?.length ?? 0) > 0\n minPriceViolation.value =\n hasItems && min != null && value.total > 0 && value.total < min\n ? {\n remaining: Math.max(0, min - value.total),\n progress: Math.min(1, value.total / min),\n minPrice: min,\n }\n : null\n }\n\n function clearCart(): void {\n order.value = null\n credentials.value = null\n checkoutTotal.value = null\n optimisticAdjustments.value = {}\n lineOptimistic.value = {}\n orderSettings.value = null\n comment.value = ''\n personsCount.value = 0\n storage.remove(KEY_COMMENT)\n storage.remove(KEY_PERSONS_COUNT)\n selectedPaymentMethod.value = null\n selectedPaymentBill.value = null\n selectedCardTokenId.value = null\n selectedSaveCard.value = false\n bonusesIntent.value = emptyBonusesIntent()\n deliveryTimeIntent.value = null\n minPriceViolation.value = null\n }\n\n const hasOrder = computed(() => order.value !== null)\n const hasCredentials = computed(() => credentials.value !== null)\n const variants = computed<OrderProductVariant[]>(() => order.value?.variants ?? [])\n const totalPrice = computed(() => order.value?.total_price ?? 0)\n const itemCount = computed(() => variants.value.reduce((sum, v) => sum + v.quantity, 0))\n const availableDeliveryMethodIds = computed<DeliveryMethod[]>(() =>\n deliveryMethods.value.map((m) => m.id)\n )\n const paymentMethods = computed<OrderPaymentMethod[]>(\n () => orderSettings.value?.payment_methods ?? []\n )\n const hasBonusesApplied = computed(() => {\n const payments = order.value?.payments ?? []\n return (payments as unknown as Array<{ method: unknown }>).some((p) => {\n const raw = p.method\n const id = typeof raw === 'string' ? raw : ((raw as { id?: string } | null)?.id ?? null)\n return id === PaymentMethod.Bonuses\n })\n })\n const productQuantities = computed<Record<string, number>>(() => {\n const map: Record<string, number> = {}\n for (const variant of variants.value) {\n const pid = variant.product_id\n map[pid] = (map[pid] ?? 0) + variant.quantity\n }\n return map\n })\n\n return {\n order,\n credentials,\n loading,\n initializing,\n optimisticAdjustments,\n lineOptimistic,\n deliveryMethods,\n orderSettings,\n comment,\n personsCount,\n checkoutTotal,\n selectedPaymentMethod,\n selectedPaymentBill,\n selectedCardTokenId,\n selectedSaveCard,\n bonusesIntent,\n deliveryTimeIntent,\n minPriceViolation,\n setOrder,\n patchOrder,\n setCredentials,\n setLoading,\n setInitializing,\n adjustOptimistic,\n clearOptimistic,\n adjustLineOptimistic,\n setDeliveryMethods,\n setOrderSettings,\n setComment,\n setPersonsCount,\n setSelectedPaymentMethod,\n setSelectedPaymentBill,\n setSelectedCardTokenId,\n setSelectedSaveCard,\n setBonusesIntentEnabled,\n setDesiredBonusesAmount,\n setBonusesRequiresConfirmation,\n clearBonusesIntent,\n setDeliveryTimeIntent,\n restorePaymentSelection,\n validatePaymentSelection,\n setOrderPaymentsState,\n setCheckoutTotal,\n clearCart,\n hasOrder,\n hasCredentials,\n variants,\n totalPrice,\n itemCount,\n availableDeliveryMethodIds,\n paymentMethods,\n hasBonusesApplied,\n productQuantities,\n }\n})\n"]}
|