@zenky/storefront-vue 0.10.4 → 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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,36 @@ 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
+ ## 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
+
7
37
  ## 0.10.4 - 2026-07-29
8
38
 
9
39
  > **Breaking.** This release changes the runtime port contract and removes public
package/README.md CHANGED
@@ -73,14 +73,71 @@ cart.itemCount.value // reactive
73
73
  cart.totalPrice.value
74
74
  ```
75
75
 
76
+ ### Call composables and stores synchronously in setup
77
+
78
+ Composables read the runtime through `inject()`, which works while a component
79
+ instance is active or while the owning Vue app is executing `app.runWithContext()`.
80
+ The important cases behave differently:
81
+
82
+ - **Top-level `await` in `<script setup>` is safe.** The SFC compiler wraps it in
83
+ `withAsyncContext()`, which restores the instance afterwards — so composables called
84
+ after `await bootstrap()` at the top level still resolve correctly.
85
+ - **A lifecycle hook has context only in its synchronous prefix.** After its first
86
+ `await`, the component instance is no longer active.
87
+ - **Event handlers, `watch` callbacks, timers, and `.then()` callbacks do not inherit
88
+ component injection context.** Resolve dependencies before registering the callback,
89
+ or deliberately re-enter the owning app with `app.runWithContext()`.
90
+ - **A hand-written `async setup()` is not compiler-wrapped.** Resolve dependencies
91
+ before its first `await`.
92
+
93
+ Resolve the composable up front and call the returned functions later.
94
+
95
+ ```ts
96
+ // ✅ resolve in setup, call after the await
97
+ const { dispatchCheck } = usePromotionsChecker()
98
+
99
+ onMounted(async () => {
100
+ await initializeOrder()
101
+ dispatchCheck()
102
+ })
103
+
104
+ // ❌ resolving after an await — inject() has no instance to read from
105
+ onMounted(async () => {
106
+ await initializeOrder()
107
+ const { dispatchCheck } = usePromotionsChecker()
108
+ })
109
+ ```
110
+
111
+ The same applies inside event handlers, `watch` callbacks, timers, and `.then()` blocks:
112
+ resolve in `setup()`, keep the reference, call it from the callback. Watch for this
113
+ inside `try` blocks in particular — the `catch` swallows the failure and reports it as
114
+ whatever the surrounding operation was supposed to do, so the real cause never surfaces.
115
+
116
+ **Stores fail differently, and worse.** The Pinia stores exported from
117
+ `@zenky/storefront-vue/stores` read the runtime too, but a missed context does not throw:
118
+ Pinia falls back to its module-level active instance. Under concurrent SSR that instance
119
+ belongs to whichever request touched it last, so the lookup succeeds with another user's
120
+ state instead of failing.
121
+
122
+ Two cases behave differently, and the distinction is verified rather than assumed:
123
+
124
+ - **Inside a store action — safe.** Pinia activates the action's own instance for the
125
+ duration of the call, so resolving another store there returns the right one.
126
+ - **In a plain function after an `await`, outside any action and outside
127
+ `runWithContext()` — leaks.** This is the shape to watch for: it is silent, and it
128
+ crosses requests.
129
+
130
+ Resolve core stores in `setup()` for the same reason you resolve composables there. A
131
+ silent leak is far harder to notice than an exception.
132
+
76
133
  ## Runtime Ports
77
134
 
78
- `createStorefront(runtime)` takes one object. Six ports are required; the rest are optional — omit an optional port and the feature that needs it is simply skipped.
135
+ `createStorefront(runtime)` takes one object. Five ports are required; the rest are optional — omit an optional port and the feature that needs it is simply skipped.
79
136
 
80
137
  | Port | Required | What the consumer provides |
81
138
  | --- | --- | --- |
82
139
  | `sdk` | yes | A `ZenkyStorefront` instance (`@zenky/storefront-api`). |
83
- | `config` | yes | `{ baseUrl, baseAuthUrl, salesChannelId? }`. |
140
+ | `config` | no | Reserved consumer configuration; the current core does not read it. |
84
141
  | `storage` | yes | Key/value persistence — cookies, `localStorage`, memory. |
85
142
  | `notifier` | yes | Toasts: `error` / `success` / `warning` / `message`. |
86
143
  | `messages` | yes | Maps stable domain message keys to localized consumer copy. |
@@ -186,13 +243,15 @@ npm run test:coverage # vitest + V8 coverage report
186
243
  npm run check # format + lint + types + tests + build + exports
187
244
  npm run check:exports # publint + are-the-types-wrong (esm-only profile)
188
245
  npm run check:boundaries # reject Nuxt/Unhead and consumer policy in src/
246
+ npm run check:context # reject ambient composables/stores in deferred helpers
189
247
  npm run check:runtime # import all entries in SSR + reject Node-only output
190
248
  npm run check:size # enforce gzip bundle budgets
191
249
  ```
192
250
 
193
251
  ### Local linking with yalc
194
252
 
195
- Until the package is published, link it into a consumer app with [yalc](https://github.com/wclr/yalc):
253
+ To iterate on an unreleased change without cutting a version, link the package into a
254
+ consumer app with [yalc](https://github.com/wclr/yalc):
196
255
 
197
256
  ```bash
198
257
  # in this package, after a build:
@@ -213,6 +272,7 @@ npm run build && npx yalc push
213
272
  - `typecheck` — type-only compile.
214
273
  - `check:exports` — validate the exports map and published types.
215
274
  - `check:boundaries` — reject Nuxt/Unhead APIs, routes, and tenant presets in core source.
275
+ - `check:context` — reject deferred composable/store resolution outside composition setup.
216
276
  - `check:runtime` — verify Node SSR imports and browser/edge-safe ESM output.
217
277
  - `check:size` — enforce root/domain/all-output gzip budgets.
218
278
  - `check:ci` — quality gate with the V8 coverage ratchet.
@@ -1,10 +1,10 @@
1
- export { CASH_DENOMINATIONS_MAJOR, DEFAULT_ROUND_STEPS_MAJOR, ORDER_EVENTS, ORDER_WITH, buildCartLineKey, buildCashChangePresets, buildMainPaymentRequest, getCartErrorCode, getCartErrorHttpCode, getCartErrorMessage, getCashDenominationsMinor, getDefaultRoundStepsMinor, getValidationErrors, logCartError, normalizeAddress, useBonusesReconciliation, useCartAddressSync, useCartCustomerAttachment, useCartDeliveryAttachment, useCartInitialization, useCartMutation, useCartOperations, useCartQuantities, useCartRecalculation, useCartStockWatcher, useCheckoutFlow, useCheckoutSubmit, useCustomerAttach, useOnlinePaymentRetry, useOrderBonuses, useOrderChannel, useOrderDelivery, useOrderPromocode, useOrderSettings, useOrderTotal, usePaymentSelection, useRestrictedAddToCart, useRestrictionGate, useStorefrontCart, useVisibleCartVariants, variantLineKey } from '../chunk-YS5DXYYV.js';
2
- export { useCartCredentials } from '../chunk-YREGCQSB.js';
1
+ export { CASH_DENOMINATIONS_MAJOR, DEFAULT_ROUND_STEPS_MAJOR, ORDER_EVENTS, ORDER_WITH, buildCartLineKey, buildCashChangePresets, buildMainPaymentRequest, getCartErrorCode, getCartErrorHttpCode, getCartErrorMessage, getCashDenominationsMinor, getDefaultRoundStepsMinor, getValidationErrors, logCartError, normalizeAddress, useBonusesReconciliation, useCartAddressSync, useCartCustomerAttachment, useCartDeliveryAttachment, useCartInitialization, useCartMutation, useCartOperations, useCartQuantities, useCartRecalculation, useCartStockWatcher, useCheckoutFlow, useCheckoutSubmit, useCustomerAttach, useOnlinePaymentRetry, useOrderBonuses, useOrderChannel, useOrderDelivery, useOrderPromocode, useOrderSettings, useOrderTotal, usePaymentSelection, useRestrictedAddToCart, useRestrictionGate, useStorefrontCart, useVisibleCartVariants, variantLineKey } from '../chunk-SPMUTUNX.js';
2
+ export { useCartCredentials } from '../chunk-4YAEIKLA.js';
3
3
  import '../chunk-Z3IW4ODZ.js';
4
- import '../chunk-NIQFYJRP.js';
4
+ import '../chunk-SHASMBMV.js';
5
5
  import '../chunk-E3G7NGCH.js';
6
6
  import '../chunk-RO25KNM5.js';
7
7
  import '../chunk-5QCUH3FF.js';
8
- import '../chunk-TB5TBJ4U.js';
8
+ import '../chunk-CUSQYIEU.js';
9
9
  //# sourceMappingURL=index.js.map
10
10
  //# sourceMappingURL=index.js.map
@@ -1,5 +1,5 @@
1
- import { useCartStore, usePromotionsStore } from './chunk-NIQFYJRP.js';
2
- import { useRuntime, useAuthStore, useStoreProfileStore } from './chunk-TB5TBJ4U.js';
1
+ import { useCartStore, usePromotionsStore } from './chunk-SHASMBMV.js';
2
+ import { useRuntime, useAuthStore, useStoreProfileStore } from './chunk-CUSQYIEU.js';
3
3
  import { ref } from 'vue';
4
4
 
5
5
  var KEY_ORDER_ID = "zenky_order_id";
@@ -105,5 +105,5 @@ function usePromotionsChecker() {
105
105
  }
106
106
 
107
107
  export { useCartCredentials, usePromotionsChecker };
108
- //# sourceMappingURL=chunk-YREGCQSB.js.map
109
- //# sourceMappingURL=chunk-YREGCQSB.js.map
108
+ //# sourceMappingURL=chunk-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"]}
@@ -5,7 +5,6 @@ import { defineStore } from 'pinia';
5
5
  var RUNTIME_KEY = /* @__PURE__ */ Symbol.for("zenky.storefront.runtime");
6
6
  var REQUIRED_PORTS = [
7
7
  "sdk",
8
- "config",
9
8
  "storage",
10
9
  "notifier",
11
10
  "activity",
@@ -88,7 +87,7 @@ var AUTH_TOKEN_KEY = "zenky_auth_token";
88
87
  var AUTH_PHONE_KEY = "zenky_auth_phone";
89
88
  var YEAR_SECONDS = 60 * 60 * 24 * 365;
90
89
  var useAuthStore = defineStore("zenky-auth", () => {
91
- const { storage, sdk } = useRuntime();
90
+ const { storage } = useRuntime();
92
91
  const token = ref(null);
93
92
  const phone = ref(null);
94
93
  const countryCode = ref("RU");
@@ -100,7 +99,6 @@ var useAuthStore = defineStore("zenky-auth", () => {
100
99
  function setToken(nextToken, nextPhone, nextCountryCode) {
101
100
  token.value = nextToken;
102
101
  storage.set(AUTH_TOKEN_KEY, nextToken, { maxAge: YEAR_SECONDS });
103
- sdk.setApiToken(nextToken);
104
102
  if (nextPhone) {
105
103
  phone.value = nextPhone;
106
104
  storage.set(AUTH_PHONE_KEY, nextPhone, { maxAge: YEAR_SECONDS });
@@ -114,18 +112,11 @@ var useAuthStore = defineStore("zenky-auth", () => {
114
112
  phone.value = null;
115
113
  storage.remove(AUTH_TOKEN_KEY);
116
114
  storage.remove(AUTH_PHONE_KEY);
117
- sdk.setApiToken(null);
118
115
  }
119
116
  function initFromCookie() {
120
- const savedToken = storage.get(AUTH_TOKEN_KEY);
121
- if (savedToken) {
122
- token.value = savedToken;
123
- sdk.setApiToken(savedToken);
124
- }
125
- const savedPhone = storage.get(AUTH_PHONE_KEY);
126
- if (savedPhone) {
127
- phone.value = savedPhone;
128
- }
117
+ const savedToken = storage.get(AUTH_TOKEN_KEY) || null;
118
+ token.value = savedToken;
119
+ phone.value = storage.get(AUTH_PHONE_KEY) || null;
129
120
  }
130
121
  return {
131
122
  token,
@@ -140,5 +131,5 @@ var useAuthStore = defineStore("zenky-auth", () => {
140
131
  });
141
132
 
142
133
  export { createStorefront, provideStorefront, useAuthStore, useRuntime, useStoreProfileStore };
143
- //# sourceMappingURL=chunk-TB5TBJ4U.js.map
144
- //# sourceMappingURL=chunk-TB5TBJ4U.js.map
134
+ //# sourceMappingURL=chunk-CUSQYIEU.js.map
135
+ //# sourceMappingURL=chunk-CUSQYIEU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ports/runtime.ts","../src/stores/store-profile.ts","../src/stores/auth.ts"],"names":["defineStore","ref","computed"],"mappings":"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","file":"chunk-CUSQYIEU.js","sourcesContent":["import { inject, provide, type App, type InjectionKey, type Plugin } from 'vue'\n\nimport type { StorefrontRuntime } from './index'\n\n// Composition root. Потребитель собирает рантайм (адаптеры) один раз и ставит плагин,\n// доменные composables берут его через useRuntime() вместо прямых Nuxt-вызовов.\n\nconst RUNTIME_KEY = Symbol.for('zenky.storefront.runtime') as InjectionKey<StorefrontRuntime>\n\ntype RequiredPort = {\n [K in keyof StorefrontRuntime]-?: undefined extends StorefrontRuntime[K] ? never : K\n}[keyof StorefrontRuntime]\n\nconst REQUIRED_PORTS = [\n 'sdk',\n 'storage',\n 'notifier',\n 'activity',\n 'messages',\n] as const satisfies readonly RequiredPort[]\n\ntype ListedPort = (typeof REQUIRED_PORTS)[number]\ntype UnlistedRequiredPort = Exclude<RequiredPort, ListedPort>\n\nconst _allRequiredPortsListed: UnlistedRequiredPort extends never ? true : never = true\nvoid _allRequiredPortsListed\n\nfunction assertRequiredPorts(runtime: StorefrontRuntime): void {\n const missing = REQUIRED_PORTS.filter((port) => runtime[port] == null)\n if (missing.length > 0) {\n throw new Error(\n `[@zenky/storefront-vue] Runtime is missing required ports: ${missing.join(', ')}. ` +\n 'See the Runtime Ports table in the README.'\n )\n }\n}\n\n/** Vue-плагин: app.use(createStorefront(runtime)). */\nexport function createStorefront(runtime: StorefrontRuntime): Plugin {\n assertRequiredPorts(runtime)\n\n return {\n install(app: App) {\n app.provide(RUNTIME_KEY, runtime)\n },\n }\n}\n\n/** Альтернатива плагину — provide внутри setup (напр. в изолированном виджете). */\nexport function provideStorefront(runtime: StorefrontRuntime): void {\n assertRequiredPorts(runtime)\n provide(RUNTIME_KEY, runtime)\n}\n\n/** Доступ к рантайму из любого composable/стора ядра. */\nexport function useRuntime(): StorefrontRuntime {\n const runtime = inject(RUNTIME_KEY)\n if (!runtime) {\n throw new Error(\n '[@zenky/storefront-vue] Runtime was not provided. ' +\n 'Install the plugin with app.use(createStorefront(runtime)).'\n )\n }\n return runtime\n}\n","import { defineStore } from 'pinia'\nimport { computed, ref, type ComputedRef, type Ref } from 'vue'\n\nimport type { City, NestedCategory, Stock, Store } from '@zenky/storefront-api'\n\nimport type { Website } from '../website-settings'\n\n// Именованный return-тип (правило dts) — иначе Pinia-инференс развернёт SDK-типы в .d.ts.\nexport interface StoreProfileStore {\n store: Ref<Store | null>\n city: Ref<City | null>\n stock: Ref<Stock | null>\n categories: Ref<NestedCategory[]>\n website: Ref<Website | null>\n initStore: (store: Store, city: City, stock: Stock | null) => void\n setStock: (stock: Stock | null) => void\n setCategories: (categories: NestedCategory[]) => void\n initWebsite: (website: Website | null) => void\n isReady: ComputedRef<boolean>\n hasStock: ComputedRef<boolean>\n currency: ComputedRef<string>\n squareLogoUrl: ComputedRef<string | null>\n}\n\nexport const useStoreProfileStore = defineStore('zenky-store-profile', (): StoreProfileStore => {\n const store = ref<Store | null>(null)\n const city = ref<City | null>(null)\n const stock = ref<Stock | null>(null)\n const categories = ref<NestedCategory[]>([])\n const website = ref<Website | null>(null)\n\n function initStore(newStore: Store, newCity: City, newStock: Stock | null): void {\n store.value = newStore\n city.value = newCity\n stock.value = newStock\n }\n\n function setStock(newStock: Stock | null): void {\n stock.value = newStock\n }\n\n function setCategories(newCategories: NestedCategory[]): void {\n categories.value = newCategories\n }\n\n function initWebsite(newWebsite: Website | null): void {\n website.value = newWebsite\n }\n\n const isReady = computed(() => store.value !== null && city.value !== null)\n const hasStock = computed(() => stock.value !== null)\n const currency = computed<string>(() => store.value?.settings?.currency ?? 'RUB')\n\n const squareLogoUrl = computed<string | null>(() => {\n const logo = store.value?.square_logo ?? store.value?.logo\n if (!logo) return null\n\n return (\n logo.hd?.url ??\n logo.xlarge?.url ??\n logo.large?.url ??\n logo.medium?.url ??\n logo.placeholder?.url ??\n null\n )\n })\n\n return {\n store,\n city,\n stock,\n categories,\n website,\n initStore,\n setStock,\n setCategories,\n initWebsite,\n isReady,\n hasStock,\n currency,\n squareLogoUrl,\n }\n})\n","import { defineStore } from 'pinia'\nimport { computed, ref, type ComputedRef, type Ref } from 'vue'\n\nimport { useRuntime } from '../ports/runtime'\n\n// Ключи совпадают с прежними CookieKey.AuthToken/AuthPhone — чтобы не разлогинить юзеров.\nconst AUTH_TOKEN_KEY = 'zenky_auth_token'\nconst AUTH_PHONE_KEY = 'zenky_auth_phone'\nconst YEAR_SECONDS = 60 * 60 * 24 * 365\n\n// Именованный return-тип (правило dts).\nexport interface AuthStore {\n token: Ref<string | null>\n phone: Ref<string | null>\n countryCode: Ref<string>\n isAuthenticated: ComputedRef<boolean>\n initials: ComputedRef<string>\n setToken: (token: string, phone?: string, countryCode?: string) => void\n clearToken: () => void\n initFromCookie: () => void\n}\n\nexport const useAuthStore = defineStore('zenky-auth', (): AuthStore => {\n // Токен здесь только хранится и отдаётся наружу — в SDK он не пишется. Потребитель\n // передаёт его параметром в каждый вызов: мутация разделяемого клиента на SSR\n // означала бы Bearer одного пользователя в запросах других.\n const { storage } = useRuntime()\n\n const token = ref<string | null>(null)\n const phone = ref<string | null>(null)\n const countryCode = ref('RU')\n\n const isAuthenticated = computed(() => token.value !== null && token.value !== '')\n\n const initials = computed(() => {\n if (!phone.value) return '?'\n return phone.value.replace(/\\D/g, '').slice(-4)\n })\n\n function setToken(nextToken: string, nextPhone?: string, nextCountryCode?: string): void {\n token.value = nextToken\n storage.set(AUTH_TOKEN_KEY, nextToken, { maxAge: YEAR_SECONDS })\n\n if (nextPhone) {\n phone.value = nextPhone\n storage.set(AUTH_PHONE_KEY, nextPhone, { maxAge: YEAR_SECONDS })\n }\n\n if (nextCountryCode) {\n countryCode.value = nextCountryCode\n }\n }\n\n function clearToken(): void {\n token.value = null\n phone.value = null\n storage.remove(AUTH_TOKEN_KEY)\n storage.remove(AUTH_PHONE_KEY)\n }\n\n function initFromCookie(): void {\n const savedToken = storage.get(AUTH_TOKEN_KEY) || null\n token.value = savedToken\n\n phone.value = storage.get(AUTH_PHONE_KEY) || null\n }\n\n return {\n token,\n phone,\n countryCode,\n isAuthenticated,\n initials,\n setToken,\n clearToken,\n initFromCookie,\n }\n})\n"]}
@@ -1,4 +1,4 @@
1
- import { useStoreProfileStore } from './chunk-TB5TBJ4U.js';
1
+ import { useStoreProfileStore } from './chunk-CUSQYIEU.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-SS7B2NLF.js.map
38
- //# sourceMappingURL=chunk-SS7B2NLF.js.map
37
+ //# sourceMappingURL=chunk-CY6LA6C7.js.map
38
+ //# sourceMappingURL=chunk-CY6LA6C7.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-SS7B2NLF.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"]}
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-CY6LA6C7.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"]}
@@ -40,5 +40,5 @@ function createMemoryStorage() {
40
40
  }
41
41
 
42
42
  export { KEY_MESSAGE_FORMATTER, NOOP_ACTIVITY_REPORTER, NOOP_NOTIFIER, NOOP_RUM, createMemoryStorage, err, ok };
43
- //# sourceMappingURL=chunk-OTSAR32A.js.map
44
- //# sourceMappingURL=chunk-OTSAR32A.js.map
43
+ //# sourceMappingURL=chunk-MOG6UMFM.js.map
44
+ //# sourceMappingURL=chunk-MOG6UMFM.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ports/index.ts"],"names":[],"mappings":";AAwIO,IAAM,KAAK,CAAI,KAAA,MAAgC,EAAE,EAAA,EAAI,MAAM,KAAA,EAAM;AACjE,IAAM,MAAM,CAAI,KAAA,MAAgC,EAAE,EAAA,EAAI,OAAO,KAAA,EAAM;AA0BnE,IAAM,aAAA,GAA0B;AAAA,EACnC,OAAO,MAAM;AAAA,EAAC,CAAA;AAAA,EACd,SAAS,MAAM;AAAA,EAAC,CAAA;AAAA,EAChB,SAAS,MAAM;AAAA,EAAC,CAAA;AAAA,EAChB,SAAS,MAAM;AAAA,EAAC;AACpB;AAGO,IAAM,qBAAA,GAA0C;AAAA,EACnD,MAAA,EAAQ,CAAC,GAAA,KAAQ;AACrB;AAEO,IAAM,sBAAA,GAA2C;AAAA,EACpD,OAAO,MAAM;AAAA,EAAC,CAAA;AAAA,EACd,KAAK,MAAM;AAAA,EAAC;AAChB;AAEO,IAAM,QAAA,GAAwB;AAAA,EACjC,MAAM,MAAM;AAAA,EAAC,CAAA;AAAA,EACb,SAAS,MAAM;AAAA,EAAC;AACpB;AAGO,SAAS,mBAAA,GAAsC;AAClD,EAAA,MAAM,GAAA,uBAAU,GAAA,EAAoB;AACpC,EAAA,OAAO;AAAA,IACH,KAAK,CAAC,GAAA,KAAQ,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA,IAAK,IAAA;AAAA,IAC9B,GAAA,EAAK,CAAC,GAAA,EAAK,KAAA,KAAU;AACjB,MAAA,GAAA,CAAI,GAAA,CAAI,KAAK,KAAK,CAAA;AAAA,IACtB,CAAA;AAAA,IACA,MAAA,EAAQ,CAAC,GAAA,KAAQ;AACb,MAAA,GAAA,CAAI,OAAO,GAAG,CAAA;AAAA,IAClB;AAAA,GACJ;AACJ","file":"chunk-OTSAR32A.js","sourcesContent":["// Ports — интерфейсы того, что ядру нужно от рантайма потребителя.\n// Каждый фронт (Nuxt / QR-меню / шаблон) приносит свои адаптеры.\n// Ядро НЕ знает про useCookie, useRuntimeConfig, vue-router и т.п.\n\nimport type { Ref } from 'vue'\n\nimport type { ZenkyIntegrationsSDK } from '@zenky/integrations-sdk'\nimport type { RemoteCatalog, ZenkyStorefront } from '@zenky/storefront-api'\n\nexport interface StorageOptions {\n /** Время жизни в секундах. */\n maxAge?: number\n sameSite?: 'strict' | 'lax' | 'none'\n secure?: boolean\n path?: string\n}\n\n/** Персистентное key-value хранилище (куки / localStorage / память). */\nexport interface StorageAdapter {\n get(key: string): string | null\n set(key: string, value: string, options?: StorageOptions): void\n remove(key: string, options?: StorageOptions): void\n}\n\n/** Конфиг рантайма, который ядро не должно знать откуда берётся. */\nexport interface StorefrontConfig {\n baseUrl: string\n baseAuthUrl: string\n /** Опциональный sales channel для креативов/каналов. */\n salesChannelId?: string\n}\n\n/** Уведомления пользователю (тосты). Реализация — на стороне потребителя. */\nexport interface Notifier {\n error(message: string): void\n success(message: string): void\n warning(message: string): void\n message(title: string, options?: { description?: string }): void\n}\n\n/** Stable message identifiers emitted by domain logic. Text and locale belong to the consumer. */\nexport type StorefrontMessageKey =\n | 'cart.added.title'\n | 'cart.bonuses.changed.description'\n | 'cart.bonuses.changed.title'\n | 'cart.customer.saveFailed'\n | 'cart.customer.updateAfterLoginFailed'\n | 'cart.customer.updated'\n | 'cart.customer.updatedWithName'\n | 'cart.payment.updateFailed'\n | 'cart.promocode.applyFailed'\n | 'cart.promocode.removeFailed'\n | 'cart.stock.catalogReloadFailed'\n | 'cart.stock.checkFailed'\n | 'cart.stock.itemsRemoved'\n | 'cart.stock.pricesUpdated'\n | 'cart.updateFailed'\n\nexport type StorefrontMessageParams = Readonly<\n Record<string, string | number | boolean | null | undefined>\n>\n\n/** Converts domain message identifiers into consumer-owned, localized UI copy. */\nexport interface MessageFormatter {\n format(key: StorefrontMessageKey, params?: StorefrontMessageParams): string\n}\n\n/** Репортер активности (busy-индикаторы, длительные операции). */\nexport interface ActivityReporter {\n begin(kind: string): void\n end(kind: string): void\n}\n\n/** Realtime-канал: подписка на события (WebSocket). Ядро не знает про pusher/транспорт. */\nexport interface RealtimeChannel {\n bind(event: string, handler: (data?: unknown) => void): void\n}\n\nexport interface RealtimeAdapter {\n subscribe(channelName: string): RealtimeChannel | null\n unsubscribe(channelName: string): void\n isReady: Ref<boolean>\n}\n\nexport interface RealtimePort {\n get(): RealtimeAdapter | null\n}\n\nexport interface EventsPort {\n get(): ZenkyIntegrationsSDK | null\n}\n\n/** Перезагрузка каталога при смене склада. Транспорт (fetch) — на стороне потребителя. */\nexport interface CatalogReloader {\n reload(storeId: string, remoteCatalog: RemoteCatalog): Promise<void>\n}\n\n/** RUM-репортер производительности (performance-marks). Реализация — у потребителя. */\nexport interface RumReporter {\n mark(name: string): void\n measure(metric: string, startMark: string): void\n}\n\n/** Идентификаторы commerce-события (session/anonymous) — попадают в checkout-request. */\nexport interface CommerceEventIdentity {\n session_id?: string\n anonymous_id?: string\n}\n\nexport interface CommerceAddedToCartPayload {\n productId: string\n productVariantId: string\n quantity?: number\n unitPrice?: number\n totalPrice?: number\n}\n\nexport interface CommerceRemovedFromCartPayload {\n productId: string\n productVariantId: string\n quantity?: number\n}\n\n/** Commerce-event трекинг (#29). Реализация/очередь/транспорт — у потребителя. */\nexport interface CommerceEventsPort {\n trackAddedToCart(orderId: string, payload: CommerceAddedToCartPayload): void\n trackRemovedFromCart(orderId: string, payload: CommerceRemovedFromCartPayload): void\n getIdentity(): CommerceEventIdentity\n}\n\n/**\n * Railway-style результат: компилятор не даст прочитать `.value`,\n * пока потребитель не проверил `.ok`. Замена throw на публичной границе.\n */\nexport type Result<T = void, E = unknown> = { ok: true; value: T } | { ok: false; error: E }\n\nexport const ok = <T>(value: T): Result<T, never> => ({ ok: true, value })\nexport const err = <E>(error: E): Result<never, E> => ({ ok: false, error })\n\n/** Полный рантайм, который потребитель собирает и отдаёт в createStorefront(). */\nexport interface StorefrontRuntime {\n /** SDK-клиент Zenky. Потребитель создаёт один инстанс и отдаёт сюда. */\n sdk: ZenkyStorefront\n storage: StorageAdapter\n config: StorefrontConfig\n notifier: Notifier\n /** Localized user-facing copy. The core emits only stable message identifiers. */\n messages: MessageFormatter\n activity: ActivityReporter\n /** Ленивый провайдер analytics-интеграции, которая может появиться после setup. */\n events?: EventsPort | null\n /** Ленивый провайдер realtime-транспорта (WebSocket). */\n realtime?: RealtimePort | null\n /** Перезагрузка каталога при смене склада. Нет — reload пропускается. */\n catalogReloader?: CatalogReloader | null\n /** RUM-метрики. Нет — инструментирование пропускается. */\n rum?: RumReporter | null\n /** Commerce-event трекинг (#29). Нет — трекинг пропускается. */\n commerceEvents?: CommerceEventsPort | null\n}\n\n// --- NOOP / in-memory заглушки (SSR, тесты, дефолты) ---\n\nexport const NOOP_NOTIFIER: Notifier = {\n error: () => {},\n success: () => {},\n warning: () => {},\n message: () => {},\n}\n\n/** Useful in headless tests where displaying a localized message is not required. */\nexport const KEY_MESSAGE_FORMATTER: MessageFormatter = {\n format: (key) => key,\n}\n\nexport const NOOP_ACTIVITY_REPORTER: ActivityReporter = {\n begin: () => {},\n end: () => {},\n}\n\nexport const NOOP_RUM: RumReporter = {\n mark: () => {},\n measure: () => {},\n}\n\n/** In-memory storage — для SSR/тестов, без побочных эффектов на реальные куки. */\nexport function createMemoryStorage(): StorageAdapter {\n const map = new Map<string, string>()\n return {\n get: (key) => map.get(key) ?? null,\n set: (key, value) => {\n map.set(key, value)\n },\n remove: (key) => {\n map.delete(key)\n },\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/ports/index.ts"],"names":[],"mappings":";AAwIO,IAAM,KAAK,CAAI,KAAA,MAAgC,EAAE,EAAA,EAAI,MAAM,KAAA,EAAM;AACjE,IAAM,MAAM,CAAI,KAAA,MAAgC,EAAE,EAAA,EAAI,OAAO,KAAA,EAAM;AA2BnE,IAAM,aAAA,GAA0B;AAAA,EACnC,OAAO,MAAM;AAAA,EAAC,CAAA;AAAA,EACd,SAAS,MAAM;AAAA,EAAC,CAAA;AAAA,EAChB,SAAS,MAAM;AAAA,EAAC,CAAA;AAAA,EAChB,SAAS,MAAM;AAAA,EAAC;AACpB;AAGO,IAAM,qBAAA,GAA0C;AAAA,EACnD,MAAA,EAAQ,CAAC,GAAA,KAAQ;AACrB;AAEO,IAAM,sBAAA,GAA2C;AAAA,EACpD,OAAO,MAAM;AAAA,EAAC,CAAA;AAAA,EACd,KAAK,MAAM;AAAA,EAAC;AAChB;AAEO,IAAM,QAAA,GAAwB;AAAA,EACjC,MAAM,MAAM;AAAA,EAAC,CAAA;AAAA,EACb,SAAS,MAAM;AAAA,EAAC;AACpB;AAGO,SAAS,mBAAA,GAAsC;AAClD,EAAA,MAAM,GAAA,uBAAU,GAAA,EAAoB;AACpC,EAAA,OAAO;AAAA,IACH,KAAK,CAAC,GAAA,KAAQ,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA,IAAK,IAAA;AAAA,IAC9B,GAAA,EAAK,CAAC,GAAA,EAAK,KAAA,KAAU;AACjB,MAAA,GAAA,CAAI,GAAA,CAAI,KAAK,KAAK,CAAA;AAAA,IACtB,CAAA;AAAA,IACA,MAAA,EAAQ,CAAC,GAAA,KAAQ;AACb,MAAA,GAAA,CAAI,OAAO,GAAG,CAAA;AAAA,IAClB;AAAA,GACJ;AACJ","file":"chunk-MOG6UMFM.js","sourcesContent":["// Ports — интерфейсы того, что ядру нужно от рантайма потребителя.\n// Каждый фронт (Nuxt / QR-меню / шаблон) приносит свои адаптеры.\n// Ядро НЕ знает про useCookie, useRuntimeConfig, vue-router и т.п.\n\nimport type { Ref } from 'vue'\n\nimport type { ZenkyIntegrationsSDK } from '@zenky/integrations-sdk'\nimport type { RemoteCatalog, ZenkyStorefront } from '@zenky/storefront-api'\n\nexport interface StorageOptions {\n /** Время жизни в секундах. */\n maxAge?: number\n sameSite?: 'strict' | 'lax' | 'none'\n secure?: boolean\n path?: string\n}\n\n/** Персистентное key-value хранилище (куки / localStorage / память). */\nexport interface StorageAdapter {\n get(key: string): string | null\n set(key: string, value: string, options?: StorageOptions): void\n remove(key: string, options?: StorageOptions): void\n}\n\n/** Конфиг рантайма, который ядро не должно знать откуда берётся. */\nexport interface StorefrontConfig {\n baseUrl: string\n baseAuthUrl: string\n /** Опциональный sales channel для креативов/каналов. */\n salesChannelId?: string\n}\n\n/** Уведомления пользователю (тосты). Реализация — на стороне потребителя. */\nexport interface Notifier {\n error(message: string): void\n success(message: string): void\n warning(message: string): void\n message(title: string, options?: { description?: string }): void\n}\n\n/** Stable message identifiers emitted by domain logic. Text and locale belong to the consumer. */\nexport type StorefrontMessageKey =\n | 'cart.added.title'\n | 'cart.bonuses.changed.description'\n | 'cart.bonuses.changed.title'\n | 'cart.customer.saveFailed'\n | 'cart.customer.updateAfterLoginFailed'\n | 'cart.customer.updated'\n | 'cart.customer.updatedWithName'\n | 'cart.payment.updateFailed'\n | 'cart.promocode.applyFailed'\n | 'cart.promocode.removeFailed'\n | 'cart.stock.catalogReloadFailed'\n | 'cart.stock.checkFailed'\n | 'cart.stock.itemsRemoved'\n | 'cart.stock.pricesUpdated'\n | 'cart.updateFailed'\n\nexport type StorefrontMessageParams = Readonly<\n Record<string, string | number | boolean | null | undefined>\n>\n\n/** Converts domain message identifiers into consumer-owned, localized UI copy. */\nexport interface MessageFormatter {\n format(key: StorefrontMessageKey, params?: StorefrontMessageParams): string\n}\n\n/** Репортер активности (busy-индикаторы, длительные операции). */\nexport interface ActivityReporter {\n begin(kind: string): void\n end(kind: string): void\n}\n\n/** Realtime-канал: подписка на события (WebSocket). Ядро не знает про pusher/транспорт. */\nexport interface RealtimeChannel {\n bind(event: string, handler: (data?: unknown) => void): void\n}\n\nexport interface RealtimeAdapter {\n subscribe(channelName: string): RealtimeChannel | null\n unsubscribe(channelName: string): void\n isReady: Ref<boolean>\n}\n\nexport interface RealtimePort {\n get(): RealtimeAdapter | null\n}\n\nexport interface EventsPort {\n get(): ZenkyIntegrationsSDK | null\n}\n\n/** Перезагрузка каталога при смене склада. Транспорт (fetch) — на стороне потребителя. */\nexport interface CatalogReloader {\n reload(storeId: string, remoteCatalog: RemoteCatalog): Promise<void>\n}\n\n/** RUM-репортер производительности (performance-marks). Реализация — у потребителя. */\nexport interface RumReporter {\n mark(name: string): void\n measure(metric: string, startMark: string): void\n}\n\n/** Идентификаторы commerce-события (session/anonymous) — попадают в checkout-request. */\nexport interface CommerceEventIdentity {\n session_id?: string\n anonymous_id?: string\n}\n\nexport interface CommerceAddedToCartPayload {\n productId: string\n productVariantId: string\n quantity?: number\n unitPrice?: number\n totalPrice?: number\n}\n\nexport interface CommerceRemovedFromCartPayload {\n productId: string\n productVariantId: string\n quantity?: number\n}\n\n/** Commerce-event трекинг (#29). Реализация/очередь/транспорт — у потребителя. */\nexport interface CommerceEventsPort {\n trackAddedToCart(orderId: string, payload: CommerceAddedToCartPayload): void\n trackRemovedFromCart(orderId: string, payload: CommerceRemovedFromCartPayload): void\n getIdentity(): CommerceEventIdentity\n}\n\n/**\n * Railway-style результат: компилятор не даст прочитать `.value`,\n * пока потребитель не проверил `.ok`. Замена throw на публичной границе.\n */\nexport type Result<T = void, E = unknown> = { ok: true; value: T } | { ok: false; error: E }\n\nexport const ok = <T>(value: T): Result<T, never> => ({ ok: true, value })\nexport const err = <E>(error: E): Result<never, E> => ({ ok: false, error })\n\n/** Полный рантайм, который потребитель собирает и отдаёт в createStorefront(). */\nexport interface StorefrontRuntime {\n /** SDK-клиент Zenky. Потребитель создаёт один инстанс и отдаёт сюда. */\n sdk: ZenkyStorefront\n storage: StorageAdapter\n /** Reserved consumer configuration. The current core does not read this port. */\n config?: StorefrontConfig\n notifier: Notifier\n /** Localized user-facing copy. The core emits only stable message identifiers. */\n messages: MessageFormatter\n activity: ActivityReporter\n /** Ленивый провайдер analytics-интеграции, которая может появиться после setup. */\n events?: EventsPort | null\n /** Ленивый провайдер realtime-транспорта (WebSocket). */\n realtime?: RealtimePort | null\n /** Перезагрузка каталога при смене склада. Нет — reload пропускается. */\n catalogReloader?: CatalogReloader | null\n /** RUM-метрики. Нет — инструментирование пропускается. */\n rum?: RumReporter | null\n /** Commerce-event трекинг (#29). Нет — трекинг пропускается. */\n commerceEvents?: CommerceEventsPort | null\n}\n\n// --- NOOP / in-memory заглушки (SSR, тесты, дефолты) ---\n\nexport const NOOP_NOTIFIER: Notifier = {\n error: () => {},\n success: () => {},\n warning: () => {},\n message: () => {},\n}\n\n/** Useful in headless tests where displaying a localized message is not required. */\nexport const KEY_MESSAGE_FORMATTER: MessageFormatter = {\n format: (key) => key,\n}\n\nexport const NOOP_ACTIVITY_REPORTER: ActivityReporter = {\n begin: () => {},\n end: () => {},\n}\n\nexport const NOOP_RUM: RumReporter = {\n mark: () => {},\n measure: () => {},\n}\n\n/** In-memory storage — для SSR/тестов, без побочных эффектов на реальные куки. */\nexport function createMemoryStorage(): StorageAdapter {\n const map = new Map<string, string>()\n return {\n get: (key) => map.get(key) ?? null,\n set: (key, value) => {\n map.set(key, value)\n },\n remove: (key) => {\n map.delete(key)\n },\n }\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { createDebounce } from './chunk-XUGXLJZB.js';
2
2
  import { createRuntimeState } from './chunk-5QCUH3FF.js';
3
- import { useRuntime, useStoreProfileStore, useAuthStore } from './chunk-TB5TBJ4U.js';
3
+ import { useRuntime, useStoreProfileStore, useAuthStore } from './chunk-CUSQYIEU.js';
4
4
  import { UnitType } from '@zenky/storefront-api';
5
5
  import { computed, ref, watch } from 'vue';
6
6
 
@@ -561,5 +561,5 @@ function findProductInCatalog(catalog, shortId) {
561
561
  }
562
562
 
563
563
  export { canAddDirectly, findProductInCatalog, formatWeight, getProductWeight, getVariantWeight, resolveVariantPrice, toGrams, usePriceRecalculation, useProductPricing, useProductVariant, useProductVariantModifiers, useProductVariantSelector, useProductsByCategory, useRelatedProducts };
564
- //# sourceMappingURL=chunk-IVG4FQE5.js.map
565
- //# sourceMappingURL=chunk-IVG4FQE5.js.map
564
+ //# sourceMappingURL=chunk-Q2TVQ3BG.js.map
565
+ //# sourceMappingURL=chunk-Q2TVQ3BG.js.map