@zenky/storefront-vue 0.10.3 → 0.10.5

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 (69) hide show
  1. package/CHANGELOG.md +90 -1
  2. package/README.md +76 -6
  3. package/dist/cart/index.js +5 -7
  4. package/dist/catalog/index.d.ts +1 -11
  5. package/dist/catalog/index.js +1 -1
  6. package/dist/chunk-2CI4RW7V.js +21 -0
  7. package/dist/chunk-2CI4RW7V.js.map +1 -0
  8. package/dist/{chunk-GW2QNTAD.js → chunk-4IFPVEO7.js} +3 -113
  9. package/dist/chunk-4IFPVEO7.js.map +1 -0
  10. package/dist/{chunk-N3NOTJUC.js → chunk-4YAEIKLA.js} +4 -6
  11. package/dist/chunk-4YAEIKLA.js.map +1 -0
  12. package/dist/{chunk-TEG7EL4N.js → chunk-CUSQYIEU.js} +46 -17
  13. package/dist/chunk-CUSQYIEU.js.map +1 -0
  14. package/dist/{chunk-57IOMDAM.js → chunk-CY6LA6C7.js} +3 -3
  15. package/dist/{chunk-57IOMDAM.js.map → chunk-CY6LA6C7.js.map} +1 -1
  16. package/dist/{chunk-GLTOJTZO.js → chunk-MOG6UMFM.js} +6 -3
  17. package/dist/chunk-MOG6UMFM.js.map +1 -0
  18. package/dist/{chunk-RYYY7MVP.js → chunk-NG7RUIWW.js} +3 -13
  19. package/dist/chunk-NG7RUIWW.js.map +1 -0
  20. package/dist/{chunk-JLFBAAFT.js → chunk-Q2TVQ3BG.js} +4 -5
  21. package/dist/chunk-Q2TVQ3BG.js.map +1 -0
  22. package/dist/{chunk-FFBZKQRV.js → chunk-SHASMBMV.js} +42 -5
  23. package/dist/chunk-SHASMBMV.js.map +1 -0
  24. package/dist/{chunk-G2X4SBCO.js → chunk-SPMUTUNX.js} +50 -50
  25. package/dist/chunk-SPMUTUNX.js.map +1 -0
  26. package/dist/index.d.ts +5 -7
  27. package/dist/index.js +13 -15
  28. package/dist/order/index.d.ts +2 -0
  29. package/dist/order/index.js +2 -5
  30. package/dist/order/index.js.map +1 -1
  31. package/dist/ports/index.d.ts +14 -2
  32. package/dist/ports/index.js +1 -1
  33. package/dist/products/index.js +3 -4
  34. package/dist/promotions/index.d.ts +13 -0
  35. package/dist/promotions/index.js +3 -5
  36. package/dist/seo/index.d.ts +5 -11
  37. package/dist/seo/index.js +14 -24
  38. package/dist/seo/index.js.map +1 -1
  39. package/dist/snippets/index.d.ts +21 -15
  40. package/dist/snippets/index.js +1 -1
  41. package/dist/stores/index.d.ts +1 -1
  42. package/dist/stores/index.js +3 -5
  43. package/dist/theme/index.d.ts +1 -11
  44. package/dist/theme/index.js +1 -1
  45. package/dist/utils/index.d.ts +26 -3
  46. package/dist/website-settings/index.d.ts +1 -1
  47. package/docs/consumer-setup.md +15 -4
  48. package/docs/ports.md +5 -1
  49. package/docs/releasing.md +10 -2
  50. package/package.json +8 -10
  51. package/dist/chunk-7FRMMCR5.js +0 -93
  52. package/dist/chunk-7FRMMCR5.js.map +0 -1
  53. package/dist/chunk-BWUKMWHL.js +0 -45
  54. package/dist/chunk-BWUKMWHL.js.map +0 -1
  55. package/dist/chunk-FFBZKQRV.js.map +0 -1
  56. package/dist/chunk-G2X4SBCO.js.map +0 -1
  57. package/dist/chunk-GLTOJTZO.js.map +0 -1
  58. package/dist/chunk-GW2QNTAD.js.map +0 -1
  59. package/dist/chunk-JLFBAAFT.js.map +0 -1
  60. package/dist/chunk-N3NOTJUC.js.map +0 -1
  61. package/dist/chunk-RYYY7MVP.js.map +0 -1
  62. package/dist/chunk-TEG7EL4N.js.map +0 -1
  63. package/dist/chunk-V3VVDQIR.js +0 -27
  64. package/dist/chunk-V3VVDQIR.js.map +0 -1
  65. package/dist/layout/index.d.ts +0 -54
  66. package/dist/layout/index.js +0 -106
  67. package/dist/layout/index.js.map +0 -1
  68. package/dist/schedule-Dd3zwHEb.d.ts +0 -27
  69. package/dist/snippets-BC5bkSjm.d.ts +0 -23
package/CHANGELOG.md CHANGED
@@ -4,7 +4,96 @@ 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
7
+ ## 0.10.5 - 2026-07-31
8
+
9
+ ### Changed
10
+
11
+ - `config` is now an optional runtime port because the current core does not read it.
12
+ - The framework-boundary gate now parses TypeScript syntax, so URLs and comment-like
13
+ text inside strings no longer hide violations or create false positives.
14
+ - A runtime-context gate now rejects composable or Pinia-store resolution from deferred
15
+ helpers and store actions; those functions must use dependencies captured in setup.
16
+ - Product restriction and delivery-time operations use public
17
+ `@zenky/storefront-api` resource methods instead of reaching through `sdk.client`.
18
+
19
+ ### Fixed
20
+
21
+ - `authStore.initFromCookie()` now clears stale in-memory SDK credentials when the
22
+ current request has no auth cookies.
23
+ - Payment selection reuses the setup-captured order total, so checkout with applied
24
+ bonuses no longer resolves a composable from a later event/checkout callback.
25
+ - Cart delivery-method validation resolves the order-settings store once in the store
26
+ setup. Pinia already activates the owning instance for the duration of an action, so
27
+ this is consistency rather than a leak fix.
28
+ - Runtime-context documentation now distinguishes Vue injection context, arbitrary
29
+ callbacks, `app.runWithContext()`, and Pinia's conditional global fallback.
30
+
31
+ ### Security
32
+
33
+ - `logCartError` redaction now covers customer addresses, e-mail and phone numbers, and
34
+ checkout/payment/redirect URLs, in object keys, `key=value` assignments, and query
35
+ parameters alike. Cart and checkout failures previously logged these verbatim.
36
+
37
+ ## 0.10.4 - 2026-07-29
38
+
39
+ > **Breaking.** This release changes the runtime port contract and removes public
40
+ > exports. The version stays in the `0.10.x` range because the package has no stable
41
+ > release yet and has a single, already-migrated consumer. Read the migration notes
42
+ > below before upgrading.
43
+
44
+ ### Migration
45
+
46
+ 1. **Provide the `messages` port.** `StorefrontRuntime` now requires a
47
+ `MessageFormatter`. `createStorefront()` and `provideStorefront()` throw on start
48
+ when any required port is missing, instead of failing later inside a `catch` block.
49
+ Tests and headless consumers can pass `KEY_MESSAGE_FORMATTER`, which returns the key
50
+ itself.
51
+
52
+ ```ts
53
+ import { KEY_MESSAGE_FORMATTER } from '@zenky/storefront-vue/ports'
54
+
55
+ app.use(createStorefront({ ...runtime, messages: KEY_MESSAGE_FORMATTER }))
56
+ ```
57
+
58
+ 2. **Move removed symbols into your app.** Gone from their subpath *and* from the root
59
+ entry: `catalogRoutes` (`./catalog`), `THEME_PRESETS` / `DARK_THEME_PRESETS` /
60
+ `ThemePreset` (`./theme`), `buildSnippetHead` / `SnippetHead` (`./snippets`). Gone
61
+ from their subpath only: `withSeoMetaPriority` (`./seo`) and the entire `./layout`
62
+ subpath (`useHeaderData`, `useFooterData`) — neither was re-exported from the root.
63
+
64
+ 3. **Pass `formatDayLabel` if you rely on localized day tabs.** Without it,
65
+ `generateFreeTimeGroups` labels days as `DD.MM`. This affects only free-slot mode —
66
+ in interval mode the day names come from the API.
67
+
68
+ ### Added
69
+
70
+ - `check:boundaries` gate that fails the build when Nuxt, Unhead, route policy, or
71
+ tenant presets reappear in `src/`.
72
+ - Pull-request quality checks restored in CI.
73
+
74
+ ### Removed
75
+
76
+ - The `./layout` subpath (`useHeaderData`, `useFooterData`, and the `HeaderData`,
77
+ `HeaderDataOptions`, `FooterData`, `FooterDataOptions`, `FormattedPhone`, `LegalLink`
78
+ types) — header and footer composition reads consumer config and belongs to the
79
+ consumer.
80
+ - `catalogRoutes` — catalog route policy is owned by the consumer.
81
+ - `withSeoMetaPriority` — `tagPriority` is Unhead-specific.
82
+ - `THEME_PRESETS`, `DARK_THEME_PRESETS`, `ThemePreset` — tenant branding.
83
+ - `buildSnippetHead`, `SnippetHead` — the head payload shape is framework-specific.
84
+
85
+ ### Changed
86
+
87
+ - Storefront runtime now requires a consumer-owned message formatter. Cart notification
88
+ copy is emitted as stable message keys instead of Russian literals. Error text
89
+ forwarded from the API is passed through untouched and stays in the language the
90
+ backend sent. Formatting helpers — weight units, schedule status, contact labels,
91
+ address parsing, pluralization — remain Russian-only and are tracked as known debt.
92
+ - Delivery slot labels are consumer-configurable and default to locale-neutral dates.
93
+ - SEO builders now return framework-neutral meta records without Unhead-specific fields.
94
+ - `@zenky/storefront-api` peer range moved to `^1.0.1`.
95
+
96
+ ## 0.10.3 - 2026-07-24
8
97
 
9
98
  ### Added
10
99
 
package/README.md CHANGED
@@ -21,7 +21,7 @@ Peer dependencies (the consumer already has these):
21
21
  {
22
22
  "vue": "^3.5.0",
23
23
  "pinia": "^3.0.0",
24
- "@zenky/storefront-api": ">=0.0.68",
24
+ "@zenky/storefront-api": "^1.0.1",
25
25
  "@zenky/integrations-sdk": ">=0.1.3"
26
26
  }
27
27
  ```
@@ -48,6 +48,9 @@ app.use(
48
48
  warning: (m) => toast.warning(m),
49
49
  message: (title, opts) => toast(title, opts),
50
50
  },
51
+ messages: { // consumer-owned localization
52
+ format: (key, params) => i18n.t(key, params),
53
+ },
51
54
  activity: { // busy indicators for long operations
52
55
  begin: (kind) => busy.begin(kind),
53
56
  end: (kind) => busy.end(kind),
@@ -70,6 +73,63 @@ cart.itemCount.value // reactive
70
73
  cart.totalPrice.value
71
74
  ```
72
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
+
73
133
  ## Runtime Ports
74
134
 
75
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.
@@ -77,9 +137,10 @@ cart.totalPrice.value
77
137
  | Port | Required | What the consumer provides |
78
138
  | --- | --- | --- |
79
139
  | `sdk` | yes | A `ZenkyStorefront` instance (`@zenky/storefront-api`). |
80
- | `config` | yes | `{ baseUrl, baseAuthUrl, salesChannelId? }`. |
140
+ | `config` | no | Reserved consumer configuration; the current core does not read it. |
81
141
  | `storage` | yes | Key/value persistence — cookies, `localStorage`, memory. |
82
142
  | `notifier` | yes | Toasts: `error` / `success` / `warning` / `message`. |
143
+ | `messages` | yes | Maps stable domain message keys to localized consumer copy. |
83
144
  | `activity` | yes | `begin(kind)` / `end(kind)` for busy state. |
84
145
  | `events` | no | Lazy `{ get() }` provider for `ZenkyIntegrationsSDK`; resolve on every event. |
85
146
  | `realtime` | no | Lazy `{ get() }` provider for the WebSocket adapter (`subscribe` / `unsubscribe` / `isReady`). |
@@ -93,6 +154,7 @@ Types for every port live in the `ports` subpath, alongside no-op defaults and a
93
154
  import {
94
155
  type StorefrontRuntime,
95
156
  type StorageAdapter,
157
+ KEY_MESSAGE_FORMATTER,
96
158
  NOOP_NOTIFIER,
97
159
  NOOP_ACTIVITY_REPORTER,
98
160
  createMemoryStorage,
@@ -109,16 +171,19 @@ Each public domain is its own entry point, so bundlers only pull in what you imp
109
171
 
110
172
  ```ts
111
173
  import { minorToMajor } from '@zenky/storefront-vue/money'
112
- import { buildCssVariableMap, THEME_PRESETS } from '@zenky/storefront-vue/theme'
174
+ import { buildCssVariableMap } from '@zenky/storefront-vue/theme'
113
175
  import { getRemoteCatalog, findCategoryByShortId } from '@zenky/storefront-vue/catalog'
114
176
  import { useStorefrontCart, useCheckoutSubmit } from '@zenky/storefront-vue/cart'
115
177
  import { generateFreeTimeGroups } from '@zenky/storefront-vue/order'
116
178
  import { buildProductSchema, buildOgTags } from '@zenky/storefront-vue/seo'
117
- import { useHeaderData, useFooterData } from '@zenky/storefront-vue/layout'
118
179
  import { usePaginatedList } from '@zenky/storefront-vue/pagination'
119
180
  ```
120
181
 
121
- Available subpaths: `ports`, `money`, `utils`, `theme`, `stores`, `products`, `catalog`, `cart`, `order`, `promotions`, `seo`, `layout`, `pagination`, `snippets`, `website-settings`.
182
+ Available subpaths: `ports`, `money`, `utils`, `theme`, `stores`, `products`, `catalog`, `cart`, `order`, `promotions`, `seo`, `pagination`, `snippets`, `website-settings`.
183
+
184
+ Routing, tenant theme presets, localized copy, header/footer composition, and conversion to
185
+ framework-specific head records belong to the consumer. Core SEO builders return plain
186
+ records; a Nuxt adapter may add Unhead-specific fields such as `tagPriority`.
122
187
 
123
188
  ## Runtime Compatibility
124
189
 
@@ -177,13 +242,16 @@ npm test # vitest
177
242
  npm run test:coverage # vitest + V8 coverage report
178
243
  npm run check # format + lint + types + tests + build + exports
179
244
  npm run check:exports # publint + are-the-types-wrong (esm-only profile)
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
180
247
  npm run check:runtime # import all entries in SSR + reject Node-only output
181
248
  npm run check:size # enforce gzip bundle budgets
182
249
  ```
183
250
 
184
251
  ### Local linking with yalc
185
252
 
186
- 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):
187
255
 
188
256
  ```bash
189
257
  # in this package, after a build:
@@ -203,6 +271,8 @@ npm run build && npx yalc push
203
271
  - `test` / `test:watch` — run the Vitest suite.
204
272
  - `typecheck` — type-only compile.
205
273
  - `check:exports` — validate the exports map and published types.
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.
206
276
  - `check:runtime` — verify Node SSR imports and browser/edge-safe ESM output.
207
277
  - `check:size` — enforce root/domain/all-output gzip budgets.
208
278
  - `check:ci` — quality gate with the V8 coverage ratchet.
@@ -1,12 +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-G2X4SBCO.js';
2
- export { useCartCredentials } from '../chunk-N3NOTJUC.js';
3
- import '../chunk-5QCUH3FF.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-SPMUTUNX.js';
2
+ export { useCartCredentials } from '../chunk-4YAEIKLA.js';
4
3
  import '../chunk-Z3IW4ODZ.js';
5
- import '../chunk-BWUKMWHL.js';
6
- import '../chunk-TEG7EL4N.js';
4
+ import '../chunk-SHASMBMV.js';
7
5
  import '../chunk-E3G7NGCH.js';
8
- import '../chunk-FFBZKQRV.js';
9
- import '../chunk-V3VVDQIR.js';
10
6
  import '../chunk-RO25KNM5.js';
7
+ import '../chunk-5QCUH3FF.js';
8
+ import '../chunk-CUSQYIEU.js';
11
9
  //# sourceMappingURL=index.js.map
12
10
  //# sourceMappingURL=index.js.map
@@ -60,14 +60,4 @@ declare function useCollections(sdk: ZenkyStorefront): {
60
60
  loadCollections: (storeId: string, request?: CollectionsListRequest) => Promise<ProductsCollection[]>;
61
61
  };
62
62
 
63
- /** URL-хелперы каталога — единая точка правды для путей категорий/коллекций. */
64
- declare const catalogRoutes: {
65
- /** Корневая страница каталога: список категорий + коллекций */
66
- readonly index: () => string;
67
- /** Страница конкретной категории */
68
- readonly category: (shortId: string, slug: string | null) => string;
69
- /** Страница конкретной коллекции */
70
- readonly collection: (id: string) => string;
71
- };
72
-
73
- export { type GroupedProducts, type SubcategoryGroup, catalogRoutes, collectDescendantIds, findCategoryById, findCategoryByShortId, findRootAncestor, getCategoryPath, getCity, getRemoteCatalog, getStock, groupProductsBySubcategory, useCollections };
63
+ export { type GroupedProducts, type SubcategoryGroup, collectDescendantIds, findCategoryById, findCategoryByShortId, findRootAncestor, getCategoryPath, getCity, getRemoteCatalog, getStock, groupProductsBySubcategory, useCollections };
@@ -1,4 +1,4 @@
1
- export { catalogRoutes, collectDescendantIds, findCategoryById, findCategoryByShortId, findRootAncestor, getCategoryPath, groupProductsBySubcategory, useCollections } from '../chunk-RYYY7MVP.js';
1
+ export { collectDescendantIds, findCategoryById, findCategoryByShortId, findRootAncestor, getCategoryPath, groupProductsBySubcategory, useCollections } from '../chunk-NG7RUIWW.js';
2
2
  export { getCity, getRemoteCatalog, getStock } from '../chunk-E3G7NGCH.js';
3
3
  //# sourceMappingURL=index.js.map
4
4
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,21 @@
1
+ // src/snippets/snippets.ts
2
+ function normalizeSnippets(groups) {
3
+ if (!Array.isArray(groups)) return [];
4
+ return groups.flatMap(
5
+ (group, groupIndex) => (group.snippets ?? []).filter((item) => !!item.content?.trim()).map((item, itemIndex) => {
6
+ const snippet = {
7
+ id: `${group.region}-${groupIndex}-${itemIndex}`,
8
+ position: group.region,
9
+ language: item.language,
10
+ code: item.content,
11
+ enabled: item.enabled ?? true
12
+ };
13
+ if (item.name !== void 0) snippet.name = item.name;
14
+ return snippet;
15
+ })
16
+ );
17
+ }
18
+
19
+ export { normalizeSnippets };
20
+ //# sourceMappingURL=chunk-2CI4RW7V.js.map
21
+ //# sourceMappingURL=chunk-2CI4RW7V.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/snippets/snippets.ts"],"names":[],"mappings":";AAwBO,SAAS,kBAAkB,MAAA,EAAsD;AACpF,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,SAAU,EAAC;AAEpC,EAAA,OAAO,MAAA,CAAO,OAAA;AAAA,IAAQ,CAAC,OAAO,UAAA,KAAA,CACzB,KAAA,CAAM,YAAY,EAAC,EACf,OAAO,CAAC,IAAA,KAAS,CAAC,CAAC,IAAA,CAAK,SAAS,IAAA,EAAM,EACvC,GAAA,CAAI,CAAC,MAAM,SAAA,KAAuB;AAC/B,MAAA,MAAM,OAAA,GAAmB;AAAA,QACrB,IAAI,CAAA,EAAG,KAAA,CAAM,MAAM,CAAA,CAAA,EAAI,UAAU,IAAI,SAAS,CAAA,CAAA;AAAA,QAC9C,UAAU,KAAA,CAAM,MAAA;AAAA,QAChB,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,MAAM,IAAA,CAAK,OAAA;AAAA,QACX,OAAA,EAAS,KAAK,OAAA,IAAW;AAAA,OAC7B;AAEA,MAAA,IAAI,IAAA,CAAK,IAAA,KAAS,MAAA,EAAW,OAAA,CAAQ,OAAO,IAAA,CAAK,IAAA;AACjD,MAAA,OAAO,OAAA;AAAA,IACX,CAAC;AAAA,GACT;AACJ","file":"chunk-2CI4RW7V.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"]}
@@ -212,116 +212,6 @@ function useTheme(colorConfig, fontConfig) {
212
212
  };
213
213
  }
214
214
 
215
- // src/theme/presets.ts
216
- var THEME_PRESETS = [
217
- {
218
- id: "yarollov",
219
- label: "Yarollov",
220
- description: "\u0424\u0438\u0440\u043C\u0435\u043D\u043D\u044B\u0439 \u0431\u0440\u0435\u043D\u0434 \u2014 \u043C\u0430\u043B\u0438\u043D\u043E\u0432\u044B\u0439 primary, \u0442\u0451\u043C\u043D\u043E-\u0441\u0438\u043D\u0438\u0439 accent",
221
- colors: {
222
- primary: "#D81C4B",
223
- secondary: "#8272C1",
224
- accent: "#1E1B4B",
225
- background: "#FFFFFF",
226
- text: "#1A1A1A"
227
- }
228
- },
229
- {
230
- id: "orange",
231
- label: "Orange",
232
- description: "\u0422\u0451\u043F\u043B\u044B\u0439 \u043E\u0440\u0430\u043D\u0436\u0435\u0432\u044B\u0439 \u0441 \u0441\u0438\u043D\u0438\u043C \u0430\u043A\u0446\u0435\u043D\u0442\u043E\u043C",
233
- colors: {
234
- primary: "#FE5000",
235
- secondary: "#64748B",
236
- accent: "#007AFF",
237
- background: "#FFFFFF",
238
- text: "#1A1A1A"
239
- }
240
- },
241
- {
242
- id: "sushi03",
243
- label: "Sushi03",
244
- description: "\u0422\u0451\u043C\u043D\u043E-\u0441\u0438\u043D\u0438\u0439 primary + \u0433\u043E\u0440\u0447\u0438\u0447\u043D\u044B\u0439 accent",
245
- colors: {
246
- primary: "#002F8C",
247
- secondary: "#8B9DC3",
248
- accent: "#FFDE69",
249
- background: "#FFFFFF",
250
- text: "#1A1A1A",
251
- success: "#00A980",
252
- danger: "#E61717"
253
- }
254
- },
255
- {
256
- id: "olive",
257
- label: "Olive Whisper",
258
- description: "\u041A\u0438\u0441\u043B\u043E\u0442\u043D\u043E-\u0437\u0435\u043B\u0451\u043D\u044B\u0439 \u043D\u0430 \u0442\u0451\u043C\u043D\u043E\u043C \u0444\u043E\u043D\u0435",
259
- colors: {
260
- primary: "#C0F53D",
261
- secondary: "#0A0D04",
262
- accent: "#C0F53D",
263
- background: "#1A2209",
264
- text: "#FAFFF3",
265
- headerBg: "#1A2209",
266
- footerBg: "#0A0D04",
267
- footerText: "#FAFFF3",
268
- footerTextMuted: "#6B7A4A"
269
- }
270
- }
271
- ];
272
- var DARK_THEME_PRESETS = [
273
- {
274
- id: "yarollov-dark",
275
- label: "Yarollov Dark",
276
- description: "\u0424\u0438\u0440\u043C\u0435\u043D\u043D\u044B\u0439 \u0431\u0440\u0435\u043D\u0434 (\u0442\u0451\u043C\u043D\u0430\u044F)",
277
- colors: {
278
- primary: "#F472B6",
279
- secondary: "#A78BFA",
280
- accent: "#818CF8",
281
- background: "#121212",
282
- text: "#E5E5E5",
283
- headerBg: "#1A1A1A",
284
- footerBg: "#0F0F0F",
285
- footerText: "#A3A3A3",
286
- footerTextMuted: "#525252"
287
- }
288
- },
289
- {
290
- id: "orange-dark",
291
- label: "Orange Dark",
292
- description: "\u0422\u0451\u043F\u043B\u044B\u0439 \u043E\u0440\u0430\u043D\u0436\u0435\u0432\u044B\u0439 (\u0442\u0451\u043C\u043D\u0430\u044F)",
293
- colors: {
294
- primary: "#FE5000",
295
- secondary: "#64748B",
296
- accent: "#60A5FA",
297
- background: "#121212",
298
- text: "#E5E5E5",
299
- headerBg: "#1A1A1A",
300
- footerBg: "#0F0F0F",
301
- footerText: "#A3A3A3",
302
- footerTextMuted: "#525252"
303
- }
304
- },
305
- {
306
- id: "sushi03-dark",
307
- label: "Sushi03 Dark",
308
- description: "\u0422\u0451\u043C\u043D\u043E-\u0441\u0438\u043D\u0438\u0439 (\u0442\u0451\u043C\u043D\u0430\u044F)",
309
- colors: {
310
- primary: "#4D8DE8",
311
- secondary: "#5A6D8A",
312
- accent: "#FFDE69",
313
- background: "#0F1419",
314
- text: "#E5E5E5",
315
- success: "#34D399",
316
- danger: "#F87171",
317
- headerBg: "#161C24",
318
- footerBg: "#0A0F14",
319
- footerText: "#94A3B8",
320
- footerTextMuted: "#475569"
321
- }
322
- }
323
- ];
324
-
325
- export { DARK_THEME_PRESETS, THEME_PRESETS, buildCssVariableMap, generatePrimaryShades, generateShades, useTheme };
326
- //# sourceMappingURL=chunk-GW2QNTAD.js.map
327
- //# sourceMappingURL=chunk-GW2QNTAD.js.map
215
+ export { buildCssVariableMap, generatePrimaryShades, generateShades, useTheme };
216
+ //# sourceMappingURL=chunk-4IFPVEO7.js.map
217
+ //# sourceMappingURL=chunk-4IFPVEO7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/theme/colors.ts","../src/theme/useTheme.ts"],"names":["p","q"],"mappings":"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","file":"chunk-4IFPVEO7.js","sourcesContent":["// Генерация цветовой шкалы и CSS-переменных из базовых цветов бренда.\n// Чистая математика в HSL/RGB — ноль зависимостей, ноль Nuxt. Портируется как есть.\n\nexport interface ThemeColorConfig {\n primary: string\n secondary: string\n accent: string\n background: string\n text: string\n success?: string\n danger?: string\n warning?: string\n info?: string\n /** Цвет текста поверх primary-фона. Если не задан — рассчитывается автоматически. */\n onPrimary?: string\n headerBg?: string\n footerBg?: string\n footerText?: string\n footerTextMuted?: string\n}\n\ninterface HslColor {\n h: number\n s: number\n l: number\n}\n\nfunction hexToHsl(hex: string): HslColor {\n const clean = hex.replace('#', '')\n const r = parseInt(clean.substring(0, 2), 16) / 255\n const g = parseInt(clean.substring(2, 4), 16) / 255\n const b = parseInt(clean.substring(4, 6), 16) / 255\n\n const max = Math.max(r, g, b)\n const min = Math.min(r, g, b)\n const l = (max + min) / 2\n\n if (max === min) {\n return { h: 0, s: 0, l }\n }\n\n const d = max - min\n const s = l > 0.5 ? d / (2 - max - min) : d / (max + min)\n\n let h = 0\n\n if (max === r) {\n h = ((g - b) / d + (g < b ? 6 : 0)) / 6\n } else if (max === g) {\n h = ((b - r) / d + 2) / 6\n } else {\n h = ((r - g) / d + 4) / 6\n }\n\n return { h, s, l }\n}\n\nfunction hslToHex(hsl: HslColor): string {\n const { h, s, l } = hsl\n\n if (s === 0) {\n const v = Math.round(l * 255)\n return `#${v.toString(16).padStart(2, '0').repeat(3)}`\n }\n\n const hue2rgb = (p: number, q: number, t: number): number => {\n let tt = t\n\n if (tt < 0) tt += 1\n if (tt > 1) tt -= 1\n if (tt < 1 / 6) return p + (q - p) * 6 * tt\n if (tt < 1 / 2) return q\n if (tt < 2 / 3) return p + (q - p) * (2 / 3 - tt) * 6\n\n return p\n }\n\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s\n const p = 2 * l - q\n\n const r = Math.round(hue2rgb(p, q, h + 1 / 3) * 255)\n const g = Math.round(hue2rgb(p, q, h) * 255)\n const b = Math.round(hue2rgb(p, q, h - 1 / 3) * 255)\n\n return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`\n}\n\n// ---------------------------------------------------------------------------\n// Color utilities\n// ---------------------------------------------------------------------------\n\n/**\n * Mix two hex colors in HSL space.\n * amount: 0 = pure hex1, 100 = pure hex2.\n */\nfunction mixColors(hex1: string, hex2: string, amount: number): string {\n const c1 = hexToHsl(hex1)\n const c2 = hexToHsl(hex2)\n const t = amount / 100\n\n // Handle achromatic mixing: if one color has no saturation,\n // inherit hue from the other\n let h: number\n if (c1.s === 0 && c2.s === 0) {\n h = 0\n } else if (c1.s === 0) {\n h = c2.h\n } else if (c2.s === 0) {\n h = c1.h\n } else {\n // Shortest path around the hue circle\n let dh = c2.h - c1.h\n if (dh > 0.5) dh -= 1\n if (dh < -0.5) dh += 1\n h = c1.h + dh * t\n if (h < 0) h += 1\n if (h > 1) h -= 1\n }\n\n return hslToHex({\n h,\n s: c1.s + (c2.s - c1.s) * t,\n l: c1.l + (c2.l - c1.l) * t,\n })\n}\n\n/**\n * Mix two hex colors in linear RGB space — matches CSS `linear-gradient` overlay behavior.\n * amount: 0 = pure hex1, 100 = pure hex2.\n */\nfunction mixColorsRgb(hex1: string, hex2: string, amount: number): string {\n const c1 = hex1.replace('#', '')\n const c2 = hex2.replace('#', '')\n const t = amount / 100\n\n const r1 = parseInt(c1.substring(0, 2), 16)\n const g1 = parseInt(c1.substring(2, 4), 16)\n const b1 = parseInt(c1.substring(4, 6), 16)\n const r2 = parseInt(c2.substring(0, 2), 16)\n const g2 = parseInt(c2.substring(2, 4), 16)\n const b2 = parseInt(c2.substring(4, 6), 16)\n\n const r = Math.round(r1 + (r2 - r1) * t)\n const g = Math.round(g1 + (g2 - g1) * t)\n const b = Math.round(b1 + (b2 - b1) * t)\n\n return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`\n}\n\n/**\n * Adjust lightness of a hex color by a relative percentage.\n * delta: -0.05 = 5% darker, +0.05 = 5% lighter.\n */\nfunction adjustLightness(hex: string, delta: number): string {\n const hsl = hexToHsl(hex)\n return hslToHex({\n h: hsl.h,\n s: hsl.s,\n l: Math.min(1, Math.max(0, hsl.l + delta)),\n })\n}\n\n/**\n * Returns a contrasting text color (white or dark) for a given background hex.\n * Uses relative luminance formula (WCAG).\n */\nfunction getContrastColor(hex: string): string {\n const clean = hex.replace('#', '')\n const r = parseInt(clean.substring(0, 2), 16) / 255\n const g = parseInt(clean.substring(2, 4), 16) / 255\n const b = parseInt(clean.substring(4, 6), 16) / 255\n\n // sRGB to linear\n const toLinear = (c: number): number =>\n c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4\n const luminance = 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b)\n\n return luminance > 0.4 ? '#1a1a1a' : '#ffffff'\n}\n\n// ---------------------------------------------------------------------------\n// Primary shades\n// ---------------------------------------------------------------------------\n\nexport interface PrimaryShades {\n lightest: string\n lighter: string\n light: string\n base: string\n dark: string\n darker: string\n darkest: string\n tint: string\n tintHover: string\n tintPressed: string\n ink: string\n}\n\n/** Универсальный генератор 11-ступенчатой шкалы от одного hex. */\nexport function generateShades(\n hex: string,\n bg: string = '#ffffff',\n text: string = '#000000'\n): PrimaryShades {\n return generatePrimaryShades(hex, bg, text)\n}\n\nexport function generatePrimaryShades(\n hex: string,\n bg: string = '#ffffff',\n text: string = '#000000'\n): PrimaryShades {\n const hsl = hexToHsl(hex)\n\n const clamp = (v: number): number => Math.min(1, Math.max(0, v))\n\n // For very dark colors (l < 0.15), dark shades go UP (lighten)\n // because you can't darken black — multiplying 0 by anything stays 0\n const isVeryDark = hsl.l < 0.15\n const dark = isVeryDark ? clamp(hsl.l + 0.12) : clamp(hsl.l * 0.85)\n const darker = isVeryDark ? clamp(hsl.l + 0.08) : clamp(hsl.l * 0.65)\n const darkest = isVeryDark ? clamp(hsl.l + 0.05) : clamp(hsl.l * 0.45)\n\n return {\n lightest: hslToHex({ h: hsl.h, s: hsl.s * 0.3, l: clamp(0.92) }),\n lighter: hslToHex({ h: hsl.h, s: hsl.s * 0.5, l: clamp(0.8) }),\n light: hslToHex({ h: hsl.h, s: hsl.s * 0.7, l: clamp(hsl.l + (1 - hsl.l) * 0.4) }),\n base: hex,\n dark: hslToHex({ h: hsl.h, s: hsl.s, l: dark }),\n darker: hslToHex({ h: hsl.h, s: hsl.s, l: darker }),\n darkest: hslToHex({ h: hsl.h, s: hsl.s, l: darkest }),\n tint: mixColorsRgb(bg, hex, 14),\n tintHover: mixColorsRgb(mixColorsRgb(bg, hex, 14), bg, 34),\n tintPressed: mixColorsRgb(bg, hex, 5),\n ink: mixColorsRgb(text, hex, 44),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Build complete CSS variable map from core colors\n// ---------------------------------------------------------------------------\n\nexport function buildCssVariableMap(config: ThemeColorConfig): Record<string, string> {\n const bg = config.background\n const text = config.text\n const shades = generatePrimaryShades(config.primary, bg, text)\n const secondaryShades = generateShades(config.secondary, bg, text)\n\n const vars: Record<string, string> = {\n // Primary palette\n '--zenky-primary-lightest': shades.lightest,\n '--zenky-primary-lighter': shades.lighter,\n '--zenky-primary-light': shades.light,\n '--zenky-primary': shades.base,\n '--zenky-primary-dark': shades.dark,\n '--zenky-primary-darker': shades.darker,\n '--zenky-primary-darkest': shades.darkest,\n '--zenky-primary-tint': shades.tint,\n '--zenky-primary-tint-hover': shades.tintHover,\n '--zenky-primary-tint-pressed': shades.tintPressed,\n '--zenky-primary-ink': shades.ink,\n\n // Secondary palette\n '--zenky-secondary-lightest': secondaryShades.lightest,\n '--zenky-secondary-lighter': secondaryShades.lighter,\n '--zenky-secondary-light': secondaryShades.light,\n '--zenky-secondary': secondaryShades.base,\n '--zenky-secondary-dark': secondaryShades.dark,\n '--zenky-secondary-darker': secondaryShades.darker,\n '--zenky-secondary-darkest': secondaryShades.darkest,\n\n // Auto-contrast for secondary\n '--zenky-on-secondary': getContrastColor(config.secondary),\n\n // Accent\n '--zenky-accent': config.accent,\n '--zenky-accent-tint': mixColorsRgb(bg, config.accent, 14),\n '--zenky-accent-tint-hover': mixColorsRgb(mixColorsRgb(bg, config.accent, 14), bg, 34),\n '--zenky-accent-tint-pressed': mixColorsRgb(bg, config.accent, 5),\n '--zenky-accent-ink': mixColorsRgb(text, config.accent, 44),\n '--zenky-bg': bg,\n '--zenky-text': text,\n\n // Цвет текста поверх primary: ручная настройка или авто-контраст\n '--zenky-on-primary': config.onPrimary || getContrastColor(config.primary),\n '--zenky-on-accent': getContrastColor(config.accent),\n\n // Derived text shades\n '--zenky-text-muted': mixColors(bg, text, 50),\n '--zenky-text-light': mixColors(bg, text, 35),\n\n // Derived borders\n '--zenky-border-light': mixColors(bg, text, 6),\n '--zenky-border': mixColors(bg, text, 12),\n '--zenky-border-strong': mixColors(bg, text, 35),\n\n // Derived surfaces\n '--zenky-surface-secondary': mixColors(bg, text, 5),\n '--zenky-surface-secondary-hover': mixColors(bg, text, 10),\n '--zenky-surface-active': mixColors(bg, config.primary, 8),\n '--zenky-surface-dark':\n getContrastColor(bg) === '#ffffff'\n ? adjustLightness(bg, 0.08)\n : adjustLightness(text, -0.1),\n '--zenky-control-active': mixColors(bg, text, 80),\n '--zenky-surface-elevated': adjustLightness(bg, 0.06),\n\n // Status (defaults if not provided)\n '--zenky-success': config.success ?? '#22c55e',\n '--zenky-danger': config.danger ?? '#ef4444',\n '--zenky-warning': config.warning ?? '#f59e0b',\n '--zenky-info': config.info ?? '#3b82f6',\n\n // Component semantic (auto-derived with optional overrides)\n '--zenky-header-bg': config.headerBg ?? adjustLightness(bg, -0.02),\n '--zenky-nav-bg': config.headerBg ?? adjustLightness(bg, -0.02),\n '--zenky-footer-bg': config.footerBg ?? adjustLightness(bg, -0.03),\n '--zenky-footer-text': config.footerText ?? mixColors(bg, text, 70),\n '--zenky-footer-text-muted': config.footerTextMuted ?? mixColors(bg, text, 40),\n }\n\n return vars\n}\n","import { computed, type ComputedRef } from 'vue'\n\nimport { buildCssVariableMap, type ThemeColorConfig } from './colors'\n\nexport interface FontConfig {\n family: string\n url: string\n}\n\nexport interface ThemeData {\n cssVariables: ComputedRef<Record<string, string>>\n fontFamily: ComputedRef<string | null>\n fontUrl: ComputedRef<string | null>\n}\n\n/** CSS-переменные темы + шрифт из цвето-/шрифто-конфига (инъекция в head — на стороне app). */\nexport function useTheme(colorConfig: ThemeColorConfig, fontConfig: FontConfig): ThemeData {\n const cssVariables = computed<Record<string, string>>(() => {\n const vars = buildCssVariableMap(colorConfig)\n\n if (fontConfig.family) {\n const stack = `'${fontConfig.family}', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif`\n vars['--zenky-font-sans'] = stack\n }\n\n return vars\n })\n\n const fontFamily = computed<string | null>(() => fontConfig.family || null)\n const fontUrl = computed<string | null>(() => fontConfig.url || null)\n\n return {\n cssVariables,\n fontFamily,\n fontUrl,\n }\n}\n"]}
@@ -1,7 +1,5 @@
1
- import { usePromotionsStore } from './chunk-BWUKMWHL.js';
2
- import { useAuthStore, useStoreProfileStore } from './chunk-TEG7EL4N.js';
3
- import { useCartStore } from './chunk-FFBZKQRV.js';
4
- import { useRuntime } from './chunk-V3VVDQIR.js';
1
+ import { useCartStore, usePromotionsStore } from './chunk-SHASMBMV.js';
2
+ import { useRuntime, useAuthStore, useStoreProfileStore } from './chunk-CUSQYIEU.js';
5
3
  import { ref } from 'vue';
6
4
 
7
5
  var KEY_ORDER_ID = "zenky_order_id";
@@ -107,5 +105,5 @@ function usePromotionsChecker() {
107
105
  }
108
106
 
109
107
  export { useCartCredentials, usePromotionsChecker };
110
- //# sourceMappingURL=chunk-N3NOTJUC.js.map
111
- //# sourceMappingURL=chunk-N3NOTJUC.js.map
108
+ //# sourceMappingURL=chunk-4YAEIKLA.js.map
109
+ //# sourceMappingURL=chunk-4YAEIKLA.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-4YAEIKLA.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.isAuthenticated ? (authStore.token ?? undefined) : undefined\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,7 +1,44 @@
1
- import { useRuntime } from './chunk-V3VVDQIR.js';
1
+ import { ref, computed, inject, provide } from 'vue';
2
2
  import { defineStore } from 'pinia';
3
- import { ref, computed } from 'vue';
4
3
 
4
+ // src/ports/runtime.ts
5
+ var RUNTIME_KEY = /* @__PURE__ */ Symbol.for("zenky.storefront.runtime");
6
+ var REQUIRED_PORTS = [
7
+ "sdk",
8
+ "storage",
9
+ "notifier",
10
+ "activity",
11
+ "messages"
12
+ ];
13
+ function assertRequiredPorts(runtime) {
14
+ const missing = REQUIRED_PORTS.filter((port) => runtime[port] == null);
15
+ if (missing.length > 0) {
16
+ throw new Error(
17
+ `[@zenky/storefront-vue] Runtime is missing required ports: ${missing.join(", ")}. See the Runtime Ports table in the README.`
18
+ );
19
+ }
20
+ }
21
+ function createStorefront(runtime) {
22
+ assertRequiredPorts(runtime);
23
+ return {
24
+ install(app) {
25
+ app.provide(RUNTIME_KEY, runtime);
26
+ }
27
+ };
28
+ }
29
+ function provideStorefront(runtime) {
30
+ assertRequiredPorts(runtime);
31
+ provide(RUNTIME_KEY, runtime);
32
+ }
33
+ function useRuntime() {
34
+ const runtime = inject(RUNTIME_KEY);
35
+ if (!runtime) {
36
+ throw new Error(
37
+ "[@zenky/storefront-vue] Runtime was not provided. Install the plugin with app.use(createStorefront(runtime))."
38
+ );
39
+ }
40
+ return runtime;
41
+ }
5
42
  var useStoreProfileStore = defineStore("zenky-store-profile", () => {
6
43
  const store = ref(null);
7
44
  const city = ref(null);
@@ -50,7 +87,7 @@ var AUTH_TOKEN_KEY = "zenky_auth_token";
50
87
  var AUTH_PHONE_KEY = "zenky_auth_phone";
51
88
  var YEAR_SECONDS = 60 * 60 * 24 * 365;
52
89
  var useAuthStore = defineStore("zenky-auth", () => {
53
- const { storage, sdk } = useRuntime();
90
+ const { storage } = useRuntime();
54
91
  const token = ref(null);
55
92
  const phone = ref(null);
56
93
  const countryCode = ref("RU");
@@ -62,7 +99,6 @@ var useAuthStore = defineStore("zenky-auth", () => {
62
99
  function setToken(nextToken, nextPhone, nextCountryCode) {
63
100
  token.value = nextToken;
64
101
  storage.set(AUTH_TOKEN_KEY, nextToken, { maxAge: YEAR_SECONDS });
65
- sdk.setApiToken(nextToken);
66
102
  if (nextPhone) {
67
103
  phone.value = nextPhone;
68
104
  storage.set(AUTH_PHONE_KEY, nextPhone, { maxAge: YEAR_SECONDS });
@@ -76,18 +112,11 @@ var useAuthStore = defineStore("zenky-auth", () => {
76
112
  phone.value = null;
77
113
  storage.remove(AUTH_TOKEN_KEY);
78
114
  storage.remove(AUTH_PHONE_KEY);
79
- sdk.setApiToken(null);
80
115
  }
81
116
  function initFromCookie() {
82
- const savedToken = storage.get(AUTH_TOKEN_KEY);
83
- if (savedToken) {
84
- token.value = savedToken;
85
- sdk.setApiToken(savedToken);
86
- }
87
- const savedPhone = storage.get(AUTH_PHONE_KEY);
88
- if (savedPhone) {
89
- phone.value = savedPhone;
90
- }
117
+ const savedToken = storage.get(AUTH_TOKEN_KEY) || null;
118
+ token.value = savedToken;
119
+ phone.value = storage.get(AUTH_PHONE_KEY) || null;
91
120
  }
92
121
  return {
93
122
  token,
@@ -101,6 +130,6 @@ var useAuthStore = defineStore("zenky-auth", () => {
101
130
  };
102
131
  });
103
132
 
104
- export { useAuthStore, useStoreProfileStore };
105
- //# sourceMappingURL=chunk-TEG7EL4N.js.map
106
- //# sourceMappingURL=chunk-TEG7EL4N.js.map
133
+ export { createStorefront, provideStorefront, useAuthStore, useRuntime, useStoreProfileStore };
134
+ //# sourceMappingURL=chunk-CUSQYIEU.js.map
135
+ //# sourceMappingURL=chunk-CUSQYIEU.js.map