@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
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/order/deliveryTime.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type {\n City,\n DeliveryInterval,\n DeliveryIntervalsGroup,\n Schedule,\n Stock,\n} from '@zenky/storefront-api'\n\nconst WEEKDAY_IDS: DeliveryIntervalsGroup['day_id'][] = [\n 'sunday',\n 'monday',\n 'tuesday',\n 'wednesday',\n 'thursday',\n 'friday',\n 'saturday',\n]\n\ninterface TimeParts {\n year: number\n month: number\n day: number\n hour: number\n minute: number\n}\n\ninterface DeliveryTimeWindow {\n startMinutes: number\n endMinutes: number\n}\n\nexport interface GenerateFreeTimeGroupsOptions {\n offsetMinutes: number\n stepMinutes: number\n schedule: Schedule | null | undefined\n storeTimezone?: string | null\n now?: Date\n}\n\n/**\n * Слот free-режима с собственной датой доставки. «Ночной хвост» (00:00–02:00) показывается\n * в той же вкладке, что и начало бизнес-дня, но его `date` — уже следующие сутки, поэтому\n * `deliver_at` строится по `interval.date`, а не по дате вкладки (`group.date`).\n */\nexport interface FreeDeliveryInterval extends DeliveryInterval {\n date: string\n}\n\nconst DEFAULT_MAX_DAYS = 7\nconst FULL_DAY_MINUTES = 24 * 60\n\nexport interface ResolveDeliveryTimeScheduleOptions {\n orderStock?: Stock | null\n selectedStock?: Stock | null\n orderCity?: City | null\n selectedCity?: City | null\n storeCities?: City[]\n}\n\nexport interface ResolvedDeliveryTimeSchedule {\n schedule: Schedule | null\n source: string | null\n}\n\nfunction pad(value: number): string {\n return String(value).padStart(2, '0')\n}\n\nexport function formatYmd(date: Date): string {\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`\n}\n\nfunction formatUtcYmd(date: Date): string {\n return `${date.getUTCFullYear()}-${pad(date.getUTCMonth() + 1)}-${pad(date.getUTCDate())}`\n}\n\nfunction formatDayName(offset: number, date: Date): string {\n if (offset === 0) return 'Сегодня'\n if (offset === 1) return 'Завтра'\n if (offset === 2) return 'Послезавтра'\n return `${pad(date.getUTCDate())}.${pad(date.getUTCMonth() + 1)}`\n}\n\nfunction ceilToStep(minutes: number, step: number): number {\n return Math.ceil(minutes / step) * step\n}\n\nfunction nowInTimezone(timezone: string | null | undefined, now = new Date()): TimeParts {\n try {\n const parts = new Intl.DateTimeFormat('en-US', {\n timeZone: timezone || undefined,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n hour12: false,\n }).formatToParts(now)\n const get = (type: string): string => parts.find((part) => part.type === type)?.value ?? ''\n\n return {\n year: Number(get('year')),\n month: Number(get('month')),\n day: Number(get('day')),\n hour: Number(get('hour') === '24' ? '0' : get('hour')),\n minute: Number(get('minute')),\n }\n } catch {\n return {\n year: now.getFullYear(),\n month: now.getMonth() + 1,\n day: now.getDate(),\n hour: now.getHours(),\n minute: now.getMinutes(),\n }\n }\n}\n\n/** Часы:минуты внутри суток в TZ магазина (а не в TZ браузера). */\nfunction minutesOfDayInTimezone(date: Date, timezone: string | null | undefined): number {\n try {\n const parts = new Intl.DateTimeFormat('en-US', {\n timeZone: timezone || undefined,\n hour: '2-digit',\n minute: '2-digit',\n hour12: false,\n }).formatToParts(date)\n const get = (type: string): string => parts.find((part) => part.type === type)?.value ?? ''\n const hour = Number(get('hour') === '24' ? '0' : get('hour'))\n const minute = Number(get('minute'))\n\n return hour * 60 + minute\n } catch {\n return date.getHours() * 60 + date.getMinutes()\n }\n}\n\nfunction parseTimeToMinutes(value: string): number | null {\n const match = value.trim().match(/^(\\d{1,2}):(\\d{2})/)\n if (!match) return null\n\n const hours = Number(match[1])\n const minutes = Number(match[2])\n if (!Number.isInteger(hours) || !Number.isInteger(minutes)) return null\n if (hours < 0 || hours > 23 || minutes < 0 || minutes > 59) return null\n\n return hours * 60 + minutes\n}\n\n/**\n * Нормализует окно работы из пары «начало/конец» в минутах суток.\n * `endMinutes` может быть > 24:00 — для окон, уходящих за полночь. Раскладку «ночного\n * хвоста» по календарным датам делает {@link generateFreeTimeGroups}.\n * - `00:00–00:00` → круглосуточно (`0 … 24:00`).\n * - Окно через полночь (`10:00–00:00`, `22:00–02:00`, конец < начала) → конец относится к\n * следующим суткам, поэтому добавляем к нему 24 часа (`02:00` → `26:00`).\n * - Нулевое окно (`start === end`, кроме круглосуточного) → расписания нет.\n */\nfunction buildWindow(startMinutes: number, endMinutes: number): DeliveryTimeWindow | null {\n if (startMinutes === 0 && endMinutes === 0) {\n return { startMinutes: 0, endMinutes: FULL_DAY_MINUTES }\n }\n\n if (endMinutes === startMinutes) return null\n\n if (endMinutes < startMinutes) {\n return { startMinutes, endMinutes: endMinutes + FULL_DAY_MINUTES }\n }\n\n return { startMinutes, endMinutes }\n}\n\nfunction parseHoursWindow(hours: string | null | undefined): DeliveryTimeWindow | null {\n if (!hours) return null\n\n const parts = hours.split(/\\s*[-–—]\\s*/)\n if (parts.length < 2) return null\n\n const startMinutes = parseTimeToMinutes(parts[0] ?? '')\n const endMinutes = parseTimeToMinutes(parts[1] ?? '')\n if (startMinutes === null || endMinutes === null) return null\n\n return buildWindow(startMinutes, endMinutes)\n}\n\nfunction getScheduleWindow(\n schedule: Schedule | null | undefined,\n dayId: DeliveryIntervalsGroup['day_id'],\n timezone?: string | null\n): DeliveryTimeWindow | null {\n const dayHours = schedule?.days?.[dayId]?.hours\n const dayWindow = parseHoursWindow(dayHours)\n if (dayWindow) return dayWindow\n\n if (!schedule?.opening_at || !schedule.closing_at) return null\n\n const opening = new Date(schedule.opening_at)\n const closing = new Date(schedule.closing_at)\n if (Number.isNaN(opening.getTime()) || Number.isNaN(closing.getTime())) return null\n\n return buildWindow(\n minutesOfDayInTimezone(opening, timezone),\n minutesOfDayInTimezone(closing, timezone)\n )\n}\n\nfunction hasAvailableScheduleWindow(schedule: Schedule | null | undefined): boolean {\n if (!schedule) return false\n return WEEKDAY_IDS.some((dayId) => getScheduleWindow(schedule, dayId) !== null)\n}\n\nfunction findStockSchedule(city: City | null | undefined): Schedule | null {\n return (\n city?.stocks?.find((stock) => hasAvailableScheduleWindow(stock.schedule))?.schedule ?? null\n )\n}\n\nexport function resolveDeliveryTimeSchedule(\n options: ResolveDeliveryTimeScheduleOptions\n): Schedule | null {\n return resolveDeliveryTimeScheduleWithSource(options).schedule\n}\n\nexport function resolveDeliveryTimeScheduleWithSource(\n options: ResolveDeliveryTimeScheduleOptions\n): ResolvedDeliveryTimeSchedule {\n const cityId = options.orderCity?.id ?? options.selectedCity?.id ?? null\n const storeCity = cityId ? (options.storeCities ?? []).find((city) => city.id === cityId) : null\n const fallbackStoreCity = options.storeCities?.find((city) =>\n hasAvailableScheduleWindow(city.schedule)\n )\n const fallbackStoreCityWithStock = options.storeCities?.find(\n (city) => findStockSchedule(city) !== null\n )\n\n const candidates: ResolvedDeliveryTimeSchedule[] = [\n { schedule: options.orderStock?.schedule ?? null, source: 'order.stock.schedule' },\n { schedule: options.selectedStock?.schedule ?? null, source: 'profile.stock.schedule' },\n { schedule: options.orderCity?.schedule ?? null, source: 'order.city.schedule' },\n { schedule: options.selectedCity?.schedule ?? null, source: 'profile.city.schedule' },\n { schedule: storeCity?.schedule ?? null, source: 'store.cities[current].schedule' },\n { schedule: findStockSchedule(options.orderCity), source: 'order.city.stocks[].schedule' },\n {\n schedule: findStockSchedule(options.selectedCity),\n source: 'profile.city.stocks[].schedule',\n },\n {\n schedule: findStockSchedule(storeCity),\n source: 'store.cities[current].stocks[].schedule',\n },\n { schedule: fallbackStoreCity?.schedule ?? null, source: 'store.cities[].schedule' },\n {\n schedule: findStockSchedule(fallbackStoreCityWithStock),\n source: 'store.cities[].stocks[].schedule',\n },\n ]\n\n return (\n candidates.find((candidate) => hasAvailableScheduleWindow(candidate.schedule)) ?? {\n schedule: null,\n source: null,\n }\n )\n}\n\nexport function generateFreeTimeGroups(\n options: GenerateFreeTimeGroupsOptions\n): DeliveryIntervalsGroup[] {\n const safeOffset = Math.max(10, options.offsetMinutes)\n const step = options.stepMinutes >= 15 ? options.stepMinutes : 15\n const nowParts = nowInTimezone(options.storeTimezone, options.now)\n\n const baseYear = nowParts.year\n const baseMonth = nowParts.month - 1\n const baseDay = nowParts.day\n\n // Минимально допустимое время для слота «сегодня»: сейчас + offset, округлённое вверх.\n const earliestTodayMinutes = ceilToStep(nowParts.hour * 60 + nowParts.minute + safeOffset, step)\n\n const groups: DeliveryIntervalsGroup[] = []\n\n // Одна вкладка = один бизнес-день (открытие → закрытие). Окно может уходить за полночь —\n // тогда «ночной хвост» 00:00–02:00 остаётся в этой же вкладке, но дата у его слотов уже\n // следующая (см. FreeDeliveryInterval.date).\n for (let dayOffset = 0; dayOffset < DEFAULT_MAX_DAYS; dayOffset++) {\n const stamp = new Date(Date.UTC(baseYear, baseMonth, baseDay + dayOffset))\n const dayId = WEEKDAY_IDS[stamp.getUTCDay()] ?? 'monday'\n const window = getScheduleWindow(options.schedule, dayId, options.storeTimezone)\n\n if (!window) continue\n\n const intervals: FreeDeliveryInterval[] = []\n const seenTimes = new Set<string>()\n\n for (let minutes = window.startMinutes; minutes <= window.endMinutes; minutes += step) {\n const dayShift = Math.floor(minutes / FULL_DAY_MINUTES)\n const minuteOfDay = minutes - dayShift * FULL_DAY_MINUTES\n const time = `${pad(Math.floor(minuteOfDay / 60))}:${pad(minuteOfDay % 60)}`\n\n // Внутри одной вкладки HH:MM уникален: у круглосуточного окна закрытие 00:00\n // совпало бы с открытием — оставляем первое (своего дня), дубль-закрытие 00:00\n // не эмитим (он же — открытие следующей вкладки). Дедуп ДО today-фильтра, чтобы\n // закрывающий 00:00 отсеялся, даже когда открытие 00:00 отброшено как «в прошлом».\n if (seenTimes.has(time)) continue\n seenTimes.add(time)\n\n // Слот «сегодня» не раньше, чем сейчас + offset.\n if (dayOffset === 0 && minutes < earliestTodayMinutes) continue\n\n const slotStamp = new Date(\n Date.UTC(baseYear, baseMonth, baseDay + dayOffset + dayShift)\n )\n intervals.push({\n id: time,\n date: formatUtcYmd(slotStamp),\n price: null,\n name: time,\n description: null,\n })\n }\n\n if (!intervals.length) continue\n\n groups.push({\n day_id: dayId,\n date: formatUtcYmd(stamp),\n name: formatDayName(dayOffset, stamp),\n intervals,\n })\n }\n\n return groups\n}\n"]}
1
+ {"version":3,"sources":["../../src/order/deliveryTime.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type {\n City,\n DeliveryInterval,\n DeliveryIntervalsGroup,\n Schedule,\n Stock,\n} from '@zenky/storefront-api'\n\nconst WEEKDAY_IDS: DeliveryIntervalsGroup['day_id'][] = [\n 'sunday',\n 'monday',\n 'tuesday',\n 'wednesday',\n 'thursday',\n 'friday',\n 'saturday',\n]\n\ninterface TimeParts {\n year: number\n month: number\n day: number\n hour: number\n minute: number\n}\n\ninterface DeliveryTimeWindow {\n startMinutes: number\n endMinutes: number\n}\n\nexport interface GenerateFreeTimeGroupsOptions {\n offsetMinutes: number\n stepMinutes: number\n schedule: Schedule | null | undefined\n storeTimezone?: string | null\n now?: Date\n /** Consumer-owned label for a delivery day tab. Defaults to a locale-neutral date. */\n formatDayLabel?: (offset: number, date: Date) => string\n}\n\n/**\n * Слот free-режима с собственной датой доставки. «Ночной хвост» (00:00–02:00) показывается\n * в той же вкладке, что и начало бизнес-дня, но его `date` — уже следующие сутки, поэтому\n * `deliver_at` строится по `interval.date`, а не по дате вкладки (`group.date`).\n */\nexport interface FreeDeliveryInterval extends DeliveryInterval {\n date: string\n}\n\nconst DEFAULT_MAX_DAYS = 7\nconst FULL_DAY_MINUTES = 24 * 60\n\nexport interface ResolveDeliveryTimeScheduleOptions {\n orderStock?: Stock | null\n selectedStock?: Stock | null\n orderCity?: City | null\n selectedCity?: City | null\n storeCities?: City[]\n}\n\nexport interface ResolvedDeliveryTimeSchedule {\n schedule: Schedule | null\n source: string | null\n}\n\nfunction pad(value: number): string {\n return String(value).padStart(2, '0')\n}\n\nexport function formatYmd(date: Date): string {\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`\n}\n\nfunction formatUtcYmd(date: Date): string {\n return `${date.getUTCFullYear()}-${pad(date.getUTCMonth() + 1)}-${pad(date.getUTCDate())}`\n}\n\nfunction formatDefaultDayLabel(_offset: number, date: Date): string {\n return `${pad(date.getUTCDate())}.${pad(date.getUTCMonth() + 1)}`\n}\n\nfunction ceilToStep(minutes: number, step: number): number {\n return Math.ceil(minutes / step) * step\n}\n\nfunction nowInTimezone(timezone: string | null | undefined, now = new Date()): TimeParts {\n try {\n const parts = new Intl.DateTimeFormat('en-US', {\n timeZone: timezone || undefined,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n hour12: false,\n }).formatToParts(now)\n const get = (type: string): string => parts.find((part) => part.type === type)?.value ?? ''\n\n return {\n year: Number(get('year')),\n month: Number(get('month')),\n day: Number(get('day')),\n hour: Number(get('hour') === '24' ? '0' : get('hour')),\n minute: Number(get('minute')),\n }\n } catch {\n return {\n year: now.getFullYear(),\n month: now.getMonth() + 1,\n day: now.getDate(),\n hour: now.getHours(),\n minute: now.getMinutes(),\n }\n }\n}\n\n/** Часы:минуты внутри суток в TZ магазина (а не в TZ браузера). */\nfunction minutesOfDayInTimezone(date: Date, timezone: string | null | undefined): number {\n try {\n const parts = new Intl.DateTimeFormat('en-US', {\n timeZone: timezone || undefined,\n hour: '2-digit',\n minute: '2-digit',\n hour12: false,\n }).formatToParts(date)\n const get = (type: string): string => parts.find((part) => part.type === type)?.value ?? ''\n const hour = Number(get('hour') === '24' ? '0' : get('hour'))\n const minute = Number(get('minute'))\n\n return hour * 60 + minute\n } catch {\n return date.getHours() * 60 + date.getMinutes()\n }\n}\n\nfunction parseTimeToMinutes(value: string): number | null {\n const match = value.trim().match(/^(\\d{1,2}):(\\d{2})/)\n if (!match) return null\n\n const hours = Number(match[1])\n const minutes = Number(match[2])\n if (!Number.isInteger(hours) || !Number.isInteger(minutes)) return null\n if (hours < 0 || hours > 23 || minutes < 0 || minutes > 59) return null\n\n return hours * 60 + minutes\n}\n\n/**\n * Нормализует окно работы из пары «начало/конец» в минутах суток.\n * `endMinutes` может быть > 24:00 — для окон, уходящих за полночь. Раскладку «ночного\n * хвоста» по календарным датам делает {@link generateFreeTimeGroups}.\n * - `00:00–00:00` → круглосуточно (`0 … 24:00`).\n * - Окно через полночь (`10:00–00:00`, `22:00–02:00`, конец < начала) → конец относится к\n * следующим суткам, поэтому добавляем к нему 24 часа (`02:00` → `26:00`).\n * - Нулевое окно (`start === end`, кроме круглосуточного) → расписания нет.\n */\nfunction buildWindow(startMinutes: number, endMinutes: number): DeliveryTimeWindow | null {\n if (startMinutes === 0 && endMinutes === 0) {\n return { startMinutes: 0, endMinutes: FULL_DAY_MINUTES }\n }\n\n if (endMinutes === startMinutes) return null\n\n if (endMinutes < startMinutes) {\n return { startMinutes, endMinutes: endMinutes + FULL_DAY_MINUTES }\n }\n\n return { startMinutes, endMinutes }\n}\n\nfunction parseHoursWindow(hours: string | null | undefined): DeliveryTimeWindow | null {\n if (!hours) return null\n\n const parts = hours.split(/\\s*[-–—]\\s*/)\n if (parts.length < 2) return null\n\n const startMinutes = parseTimeToMinutes(parts[0] ?? '')\n const endMinutes = parseTimeToMinutes(parts[1] ?? '')\n if (startMinutes === null || endMinutes === null) return null\n\n return buildWindow(startMinutes, endMinutes)\n}\n\nfunction getScheduleWindow(\n schedule: Schedule | null | undefined,\n dayId: DeliveryIntervalsGroup['day_id'],\n timezone?: string | null\n): DeliveryTimeWindow | null {\n const dayHours = schedule?.days?.[dayId]?.hours\n const dayWindow = parseHoursWindow(dayHours)\n if (dayWindow) return dayWindow\n\n if (!schedule?.opening_at || !schedule.closing_at) return null\n\n const opening = new Date(schedule.opening_at)\n const closing = new Date(schedule.closing_at)\n if (Number.isNaN(opening.getTime()) || Number.isNaN(closing.getTime())) return null\n\n return buildWindow(\n minutesOfDayInTimezone(opening, timezone),\n minutesOfDayInTimezone(closing, timezone)\n )\n}\n\nfunction hasAvailableScheduleWindow(schedule: Schedule | null | undefined): boolean {\n if (!schedule) return false\n return WEEKDAY_IDS.some((dayId) => getScheduleWindow(schedule, dayId) !== null)\n}\n\nfunction findStockSchedule(city: City | null | undefined): Schedule | null {\n return (\n city?.stocks?.find((stock) => hasAvailableScheduleWindow(stock.schedule))?.schedule ?? null\n )\n}\n\nexport function resolveDeliveryTimeSchedule(\n options: ResolveDeliveryTimeScheduleOptions\n): Schedule | null {\n return resolveDeliveryTimeScheduleWithSource(options).schedule\n}\n\nexport function resolveDeliveryTimeScheduleWithSource(\n options: ResolveDeliveryTimeScheduleOptions\n): ResolvedDeliveryTimeSchedule {\n const cityId = options.orderCity?.id ?? options.selectedCity?.id ?? null\n const storeCity = cityId ? (options.storeCities ?? []).find((city) => city.id === cityId) : null\n const fallbackStoreCity = options.storeCities?.find((city) =>\n hasAvailableScheduleWindow(city.schedule)\n )\n const fallbackStoreCityWithStock = options.storeCities?.find(\n (city) => findStockSchedule(city) !== null\n )\n\n const candidates: ResolvedDeliveryTimeSchedule[] = [\n { schedule: options.orderStock?.schedule ?? null, source: 'order.stock.schedule' },\n { schedule: options.selectedStock?.schedule ?? null, source: 'profile.stock.schedule' },\n { schedule: options.orderCity?.schedule ?? null, source: 'order.city.schedule' },\n { schedule: options.selectedCity?.schedule ?? null, source: 'profile.city.schedule' },\n { schedule: storeCity?.schedule ?? null, source: 'store.cities[current].schedule' },\n { schedule: findStockSchedule(options.orderCity), source: 'order.city.stocks[].schedule' },\n {\n schedule: findStockSchedule(options.selectedCity),\n source: 'profile.city.stocks[].schedule',\n },\n {\n schedule: findStockSchedule(storeCity),\n source: 'store.cities[current].stocks[].schedule',\n },\n { schedule: fallbackStoreCity?.schedule ?? null, source: 'store.cities[].schedule' },\n {\n schedule: findStockSchedule(fallbackStoreCityWithStock),\n source: 'store.cities[].stocks[].schedule',\n },\n ]\n\n return (\n candidates.find((candidate) => hasAvailableScheduleWindow(candidate.schedule)) ?? {\n schedule: null,\n source: null,\n }\n )\n}\n\nexport function generateFreeTimeGroups(\n options: GenerateFreeTimeGroupsOptions\n): DeliveryIntervalsGroup[] {\n const safeOffset = Math.max(10, options.offsetMinutes)\n const step = options.stepMinutes >= 15 ? options.stepMinutes : 15\n const nowParts = nowInTimezone(options.storeTimezone, options.now)\n\n const baseYear = nowParts.year\n const baseMonth = nowParts.month - 1\n const baseDay = nowParts.day\n\n // Минимально допустимое время для слота «сегодня»: сейчас + offset, округлённое вверх.\n const earliestTodayMinutes = ceilToStep(nowParts.hour * 60 + nowParts.minute + safeOffset, step)\n\n const groups: DeliveryIntervalsGroup[] = []\n\n // Одна вкладка = один бизнес-день (открытие → закрытие). Окно может уходить за полночь —\n // тогда «ночной хвост» 00:00–02:00 остаётся в этой же вкладке, но дата у его слотов уже\n // следующая (см. FreeDeliveryInterval.date).\n for (let dayOffset = 0; dayOffset < DEFAULT_MAX_DAYS; dayOffset++) {\n const stamp = new Date(Date.UTC(baseYear, baseMonth, baseDay + dayOffset))\n const dayId = WEEKDAY_IDS[stamp.getUTCDay()] ?? 'monday'\n const window = getScheduleWindow(options.schedule, dayId, options.storeTimezone)\n\n if (!window) continue\n\n const intervals: FreeDeliveryInterval[] = []\n const seenTimes = new Set<string>()\n\n for (let minutes = window.startMinutes; minutes <= window.endMinutes; minutes += step) {\n const dayShift = Math.floor(minutes / FULL_DAY_MINUTES)\n const minuteOfDay = minutes - dayShift * FULL_DAY_MINUTES\n const time = `${pad(Math.floor(minuteOfDay / 60))}:${pad(minuteOfDay % 60)}`\n\n // Внутри одной вкладки HH:MM уникален: у круглосуточного окна закрытие 00:00\n // совпало бы с открытием — оставляем первое (своего дня), дубль-закрытие 00:00\n // не эмитим (он же — открытие следующей вкладки). Дедуп ДО today-фильтра, чтобы\n // закрывающий 00:00 отсеялся, даже когда открытие 00:00 отброшено как «в прошлом».\n if (seenTimes.has(time)) continue\n seenTimes.add(time)\n\n // Слот «сегодня» не раньше, чем сейчас + offset.\n if (dayOffset === 0 && minutes < earliestTodayMinutes) continue\n\n const slotStamp = new Date(\n Date.UTC(baseYear, baseMonth, baseDay + dayOffset + dayShift)\n )\n intervals.push({\n id: time,\n date: formatUtcYmd(slotStamp),\n price: null,\n name: time,\n description: null,\n })\n }\n\n if (!intervals.length) continue\n\n groups.push({\n day_id: dayId,\n date: formatUtcYmd(stamp),\n name: (options.formatDayLabel ?? formatDefaultDayLabel)(dayOffset, stamp),\n intervals,\n })\n }\n\n return groups\n}\n"]}
@@ -31,6 +31,13 @@ interface Notifier {
31
31
  description?: string;
32
32
  }): void;
33
33
  }
34
+ /** Stable message identifiers emitted by domain logic. Text and locale belong to the consumer. */
35
+ type StorefrontMessageKey = 'cart.added.title' | 'cart.bonuses.changed.description' | 'cart.bonuses.changed.title' | 'cart.customer.saveFailed' | 'cart.customer.updateAfterLoginFailed' | 'cart.customer.updated' | 'cart.customer.updatedWithName' | 'cart.payment.updateFailed' | 'cart.promocode.applyFailed' | 'cart.promocode.removeFailed' | 'cart.stock.catalogReloadFailed' | 'cart.stock.checkFailed' | 'cart.stock.itemsRemoved' | 'cart.stock.pricesUpdated' | 'cart.updateFailed';
36
+ type StorefrontMessageParams = Readonly<Record<string, string | number | boolean | null | undefined>>;
37
+ /** Converts domain message identifiers into consumer-owned, localized UI copy. */
38
+ interface MessageFormatter {
39
+ format(key: StorefrontMessageKey, params?: StorefrontMessageParams): string;
40
+ }
34
41
  /** Репортер активности (busy-индикаторы, длительные операции). */
35
42
  interface ActivityReporter {
36
43
  begin(kind: string): void;
@@ -101,8 +108,11 @@ interface StorefrontRuntime {
101
108
  /** SDK-клиент Zenky. Потребитель создаёт один инстанс и отдаёт сюда. */
102
109
  sdk: ZenkyStorefront;
103
110
  storage: StorageAdapter;
104
- config: StorefrontConfig;
111
+ /** Reserved consumer configuration. The current core does not read this port. */
112
+ config?: StorefrontConfig;
105
113
  notifier: Notifier;
114
+ /** Localized user-facing copy. The core emits only stable message identifiers. */
115
+ messages: MessageFormatter;
106
116
  activity: ActivityReporter;
107
117
  /** Ленивый провайдер analytics-интеграции, которая может появиться после setup. */
108
118
  events?: EventsPort | null;
@@ -116,9 +126,11 @@ interface StorefrontRuntime {
116
126
  commerceEvents?: CommerceEventsPort | null;
117
127
  }
118
128
  declare const NOOP_NOTIFIER: Notifier;
129
+ /** Useful in headless tests where displaying a localized message is not required. */
130
+ declare const KEY_MESSAGE_FORMATTER: MessageFormatter;
119
131
  declare const NOOP_ACTIVITY_REPORTER: ActivityReporter;
120
132
  declare const NOOP_RUM: RumReporter;
121
133
  /** In-memory storage — для SSR/тестов, без побочных эффектов на реальные куки. */
122
134
  declare function createMemoryStorage(): StorageAdapter;
123
135
 
124
- export { type ActivityReporter, type CatalogReloader, type CommerceAddedToCartPayload, type CommerceEventIdentity, type CommerceEventsPort, type CommerceRemovedFromCartPayload, type EventsPort, NOOP_ACTIVITY_REPORTER, NOOP_NOTIFIER, NOOP_RUM, type Notifier, type RealtimeAdapter, type RealtimeChannel, type RealtimePort, type Result, type RumReporter, type StorageAdapter, type StorageOptions, type StorefrontConfig, type StorefrontRuntime, createMemoryStorage, err, ok };
136
+ export { type ActivityReporter, type CatalogReloader, type CommerceAddedToCartPayload, type CommerceEventIdentity, type CommerceEventsPort, type CommerceRemovedFromCartPayload, type EventsPort, KEY_MESSAGE_FORMATTER, type MessageFormatter, NOOP_ACTIVITY_REPORTER, NOOP_NOTIFIER, NOOP_RUM, type Notifier, type RealtimeAdapter, type RealtimeChannel, type RealtimePort, type Result, type RumReporter, type StorageAdapter, type StorageOptions, type StorefrontConfig, type StorefrontMessageKey, type StorefrontMessageParams, type StorefrontRuntime, createMemoryStorage, err, ok };
@@ -1,3 +1,3 @@
1
- export { NOOP_ACTIVITY_REPORTER, NOOP_NOTIFIER, NOOP_RUM, createMemoryStorage, err, ok } from '../chunk-GLTOJTZO.js';
1
+ export { KEY_MESSAGE_FORMATTER, NOOP_ACTIVITY_REPORTER, NOOP_NOTIFIER, NOOP_RUM, createMemoryStorage, err, ok } from '../chunk-MOG6UMFM.js';
2
2
  //# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,6 @@
1
- export { canAddDirectly, findProductInCatalog, formatWeight, getProductWeight, getVariantWeight, resolveVariantPrice, toGrams, usePriceRecalculation, useProductPricing, useProductVariant, useProductVariantModifiers, useProductVariantSelector, useProductsByCategory, useRelatedProducts } from '../chunk-JLFBAAFT.js';
2
- import '../chunk-5QCUH3FF.js';
3
- import '../chunk-TEG7EL4N.js';
1
+ export { canAddDirectly, findProductInCatalog, formatWeight, getProductWeight, getVariantWeight, resolveVariantPrice, toGrams, usePriceRecalculation, useProductPricing, useProductVariant, useProductVariantModifiers, useProductVariantSelector, useProductsByCategory, useRelatedProducts } from '../chunk-Q2TVQ3BG.js';
4
2
  import '../chunk-XUGXLJZB.js';
5
- import '../chunk-V3VVDQIR.js';
3
+ import '../chunk-5QCUH3FF.js';
4
+ import '../chunk-CUSQYIEU.js';
6
5
  //# sourceMappingURL=index.js.map
7
6
  //# sourceMappingURL=index.js.map
@@ -4,6 +4,19 @@ interface PromotionsChecker {
4
4
  /**
5
5
  * Проверка промо-акций. Вызывает dispatchPromotionsChecker после изменения корзины.
6
6
  * Результат приходит через WebSocket (обрабатывается в useOrderChannel).
7
+ *
8
+ * Резолвить синхронно в setup, а после await вызывать только `dispatchCheck` — как и
9
+ * любой композабл ядра, см. раздел «Call composables and stores synchronously in setup»
10
+ * в README.
11
+ *
12
+ * ```ts
13
+ * const { dispatchCheck } = usePromotionsChecker()
14
+ *
15
+ * async function addGift() {
16
+ * await addVariantToOrder()
17
+ * dispatchCheck()
18
+ * }
19
+ * ```
7
20
  */
8
21
  declare function usePromotionsChecker(): PromotionsChecker;
9
22
 
@@ -1,7 +1,5 @@
1
- export { usePromotionsChecker } from '../chunk-N3NOTJUC.js';
2
- import '../chunk-BWUKMWHL.js';
3
- import '../chunk-TEG7EL4N.js';
4
- import '../chunk-FFBZKQRV.js';
5
- import '../chunk-V3VVDQIR.js';
1
+ export { usePromotionsChecker } from '../chunk-4YAEIKLA.js';
2
+ import '../chunk-SHASMBMV.js';
3
+ import '../chunk-CUSQYIEU.js';
6
4
  //# sourceMappingURL=index.js.map
7
5
  //# sourceMappingURL=index.js.map
@@ -1,4 +1,4 @@
1
- import { Media, Store, Product, NestedCategory, Article, OfferArticle, Seo, SeoMetaTag as SeoMetaTag$1 } from '@zenky/storefront-api';
1
+ import { Media, Store, Product, NestedCategory, Article, OfferArticle, Seo, SeoMetaTag } from '@zenky/storefront-api';
2
2
 
3
3
  /**
4
4
  * Shared SEO types used across storefront composables.
@@ -9,12 +9,6 @@ interface BreadcrumbItem {
9
9
  to?: string;
10
10
  }
11
11
 
12
- declare const SEO_META_TAG_PRIORITY = "critical";
13
- type SeoMetaTag = Record<string, string>;
14
- declare function withSeoMetaPriority<T extends SeoMetaTag>(tag: T): T & {
15
- tagPriority: typeof SEO_META_TAG_PRIORITY;
16
- };
17
-
18
12
  /**
19
13
  * Resolves the best available URL from a Media object.
20
14
  */
@@ -80,12 +74,12 @@ interface OgTagsInput {
80
74
  type?: string;
81
75
  url?: string | null;
82
76
  }
83
- /** OG + Twitter meta-теги (critical-приоритет). Telegram читает twitter:image. */
77
+ /** Framework-neutral OG + Twitter meta records. The consumer controls head priority. */
84
78
  declare function buildOgTags(input: OgTagsInput): Record<string, string>[];
85
79
 
86
- /** SDK-теги `Seo.meta` → head-meta records (с critical-приоритетом для og/twitter/description). */
87
- declare function mapSeoMetaTags(tags: SeoMetaTag$1[]): Record<string, string>[];
80
+ /** SDK `Seo.meta` tags mapped to framework-neutral head meta records. */
81
+ declare function mapSeoMetaTags(tags: SeoMetaTag[]): Record<string, string>[];
88
82
  /** meta-теги из `Seo`-сущности (description + маппинг `Seo.meta`). Title резолвит потребитель. */
89
83
  declare function buildEntitySeoMeta(seo: Seo | null | undefined): Record<string, string>[];
90
84
 
91
- export { type BreadcrumbItem, type OgTagsInput, buildBlogPostSchema, buildCategorySchemas, buildEntitySeoMeta, buildOfferArticleSchema, buildOgTags, buildOrganizationSchema, buildProductSchema, mapSeoMetaTags, prepareOgDescription, resolveMediaUrl, resolveSiteOrigin, resolveStoreLogoUrl, stripHtml, withSeoMetaPriority };
85
+ export { type BreadcrumbItem, type OgTagsInput, buildBlogPostSchema, buildCategorySchemas, buildEntitySeoMeta, buildOfferArticleSchema, buildOgTags, buildOrganizationSchema, buildProductSchema, mapSeoMetaTags, prepareOgDescription, resolveMediaUrl, resolveSiteOrigin, resolveStoreLogoUrl, stripHtml };
package/dist/seo/index.js CHANGED
@@ -1,18 +1,11 @@
1
- import { resolveVariantPrice } from '../chunk-JLFBAAFT.js';
2
- import '../chunk-5QCUH3FF.js';
3
- import '../chunk-TEG7EL4N.js';
4
1
  import { getSocialLinks } from '../chunk-MZ66ARDL.js';
5
- import '../chunk-XUGXLJZB.js';
6
- import '../chunk-V3VVDQIR.js';
7
2
  import { minorToMajorString } from '../chunk-RO25KNM5.js';
3
+ import { resolveVariantPrice } from '../chunk-Q2TVQ3BG.js';
4
+ import '../chunk-XUGXLJZB.js';
5
+ import '../chunk-5QCUH3FF.js';
6
+ import '../chunk-CUSQYIEU.js';
8
7
  import { ContactType } from '@zenky/storefront-api';
9
8
 
10
- // src/seo/headPriority.ts
11
- var SEO_META_TAG_PRIORITY = "critical";
12
- function withSeoMetaPriority(tag) {
13
- return { ...tag, tagPriority: SEO_META_TAG_PRIORITY };
14
- }
15
-
16
9
  // src/seo/utils.ts
17
10
  function resolveMediaUrl(media) {
18
11
  return media.hd?.url || media.xlarge?.url || media.large?.url || media.medium?.url || media.placeholder?.url || null;
@@ -239,20 +232,20 @@ function buildOrganizationSchema(store, origin) {
239
232
  function buildOgTags(input) {
240
233
  const tags = [];
241
234
  if (input.title) {
242
- tags.push(withSeoMetaPriority({ property: "og:title", content: input.title }));
243
- tags.push(withSeoMetaPriority({ name: "twitter:title", content: input.title }));
235
+ tags.push({ property: "og:title", content: input.title });
236
+ tags.push({ name: "twitter:title", content: input.title });
244
237
  }
245
238
  if (input.description) {
246
- tags.push(withSeoMetaPriority({ property: "og:description", content: input.description }));
247
- tags.push(withSeoMetaPriority({ name: "twitter:description", content: input.description }));
239
+ tags.push({ property: "og:description", content: input.description });
240
+ tags.push({ name: "twitter:description", content: input.description });
248
241
  }
249
242
  if (input.image) {
250
- tags.push(withSeoMetaPriority({ property: "og:image", content: input.image }));
251
- tags.push(withSeoMetaPriority({ name: "twitter:image", content: input.image }));
243
+ tags.push({ property: "og:image", content: input.image });
244
+ tags.push({ name: "twitter:image", content: input.image });
252
245
  }
253
- tags.push(withSeoMetaPriority({ property: "og:type", content: input.type ?? "website" }));
246
+ tags.push({ property: "og:type", content: input.type ?? "website" });
254
247
  if (input.url) {
255
- tags.push(withSeoMetaPriority({ property: "og:url", content: input.url }));
248
+ tags.push({ property: "og:url", content: input.url });
256
249
  }
257
250
  return tags;
258
251
  }
@@ -267,16 +260,13 @@ function mapSeoMetaTags(tags) {
267
260
  for (const additional of tag.additional) {
268
261
  attrs[additional.attribute] = additional.value;
269
262
  }
270
- if (attrs.name === "description" || attrs.name?.startsWith("twitter:") || attrs.property?.startsWith("og:")) {
271
- return withSeoMetaPriority(attrs);
272
- }
273
263
  return attrs;
274
264
  });
275
265
  }
276
266
  function buildEntitySeoMeta(seo) {
277
267
  const tags = [];
278
268
  if (seo?.description) {
279
- tags.push(withSeoMetaPriority({ name: "description", content: seo.description }));
269
+ tags.push({ name: "description", content: seo.description });
280
270
  }
281
271
  if (seo?.meta?.length) {
282
272
  tags.push(...mapSeoMetaTags(seo.meta));
@@ -284,6 +274,6 @@ function buildEntitySeoMeta(seo) {
284
274
  return tags;
285
275
  }
286
276
 
287
- export { buildBlogPostSchema, buildCategorySchemas, buildEntitySeoMeta, buildOfferArticleSchema, buildOgTags, buildOrganizationSchema, buildProductSchema, mapSeoMetaTags, prepareOgDescription, resolveMediaUrl, resolveSiteOrigin, resolveStoreLogoUrl, stripHtml, withSeoMetaPriority };
277
+ export { buildBlogPostSchema, buildCategorySchemas, buildEntitySeoMeta, buildOfferArticleSchema, buildOgTags, buildOrganizationSchema, buildProductSchema, mapSeoMetaTags, prepareOgDescription, resolveMediaUrl, resolveSiteOrigin, resolveStoreLogoUrl, stripHtml };
288
278
  //# sourceMappingURL=index.js.map
289
279
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/seo/headPriority.ts","../../src/seo/utils.ts","../../src/seo/siteOrigin.ts","../../src/seo/productSchema.ts","../../src/seo/categorySchema.ts","../../src/seo/articleSchema.ts","../../src/seo/organizationSchema.ts","../../src/seo/ogTags.ts","../../src/seo/entitySeo.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["const SEO_META_TAG_PRIORITY = 'critical'\n\ntype SeoMetaTag = Record<string, string>\n\nexport function withSeoMetaPriority<T extends SeoMetaTag>(\n tag: T\n): T & { tagPriority: typeof SEO_META_TAG_PRIORITY } {\n return { ...tag, tagPriority: SEO_META_TAG_PRIORITY }\n}\n","import type { Media, Store } from '@zenky/storefront-api'\n\n/**\n * Resolves the best available URL from a Media object.\n */\nexport function resolveMediaUrl(media: Media): string | null {\n return (\n media.hd?.url ||\n media.xlarge?.url ||\n media.large?.url ||\n media.medium?.url ||\n media.placeholder?.url ||\n null\n )\n}\n\n/**\n * Resolves store logo URL, preferring square logo over rectangular.\n * Tries all available size variants so CDN assets with only hd/xlarge are found too.\n */\nexport function resolveStoreLogoUrl(store: Store | null | undefined): string | null {\n if (!store) return null\n if (store.square_logo) {\n const url = resolveMediaUrl(store.square_logo)\n if (url) return url\n }\n if (store.logo) {\n return resolveMediaUrl(store.logo)\n }\n return null\n}\n\n/**\n * Strips HTML tags from a string.\n */\nexport function stripHtml(html: string): string {\n return html.replace(/<[^>]*>/g, '').trim()\n}\n\n/**\n * Prepares a string for use as og:description or meta description:\n * strips HTML tags and truncates to maxLength (default 160).\n */\nexport function prepareOgDescription(\n text: string | null | undefined,\n maxLength = 160\n): string | null {\n if (!text) return null\n const plain = stripHtml(text)\n if (!plain) return null\n return plain.length > maxLength ? `${plain.slice(0, maxLength - 3)}...` : plain\n}\n","/**\n * Каноничный публичный origin сайта из `store.domain`. Fallback (хост запроса)\n * приносит потребитель — ядро не знает про useRequestURL.\n */\nexport function resolveSiteOrigin(\n storeDomain: string | null | undefined,\n fallbackOrigin: string\n): string {\n const domain = storeDomain?.trim()\n if (domain) {\n const host = domain.replace(/^https?:\\/\\//, '').replace(/\\/+$/, '')\n return `https://${host}`\n }\n return fallbackOrigin\n}\n","import type { Product, ProductVariant } from '@zenky/storefront-api'\n\nimport { minorToMajorString } from '../money'\nimport { resolveVariantPrice } from '../products'\nimport { resolveMediaUrl } from './utils'\n\nfunction isProductInStock(variants: ProductVariant[]): boolean {\n if (!variants.length) return false\n return variants.some((variant) => {\n const remainders = variant.remainders\n if (!remainders?.length) return true\n return remainders.some((remainder) => remainder.quantity > 0)\n })\n}\n\n/**\n * JSON-LD schema.org/Product. Google → Rich Results (цена/наличие/рейтинг в выдаче).\n * Возвращает массив (0 или 1 объект) — потребитель оборачивает в `<script ld+json>`.\n * Spec: https://schema.org/Product\n */\nexport function buildProductSchema(product: Product, currency: string): Record<string, unknown>[] {\n const variants = product.variants ?? []\n\n const firstVariant = variants[0]\n let offerBlock: Record<string, unknown> | undefined\n\n if (firstVariant) {\n const resolved = resolveVariantPrice(firstVariant)\n\n offerBlock = {\n '@type': 'Offer',\n price: minorToMajorString(resolved.price, currency),\n priceCurrency: currency,\n availability: isProductInStock(variants)\n ? 'https://schema.org/InStock'\n : 'https://schema.org/OutOfStock',\n ...(firstVariant.sku ? { sku: firstVariant.sku } : {}),\n }\n }\n\n const images = (product.images ?? []).map(resolveMediaUrl).filter((url): url is string => !!url)\n\n const schema: Record<string, unknown> = {\n '@context': 'https://schema.org',\n '@type': 'Product',\n name: product.name,\n }\n\n if (product.description) schema.description = product.description\n if (images.length) schema.image = images\n if (offerBlock) schema.offers = offerBlock\n\n return [schema]\n}\n","import type { NestedCategory, Product } from '@zenky/storefront-api'\n\nimport { resolveMediaUrl } from './utils'\nimport type { BreadcrumbItem } from './types'\n\n/**\n * JSON-LD для страницы категории: BreadcrumbList (хлебные крошки) + ItemList\n * (первые 10 товаров). Возвращает массив JSON-LD объектов (0–2).\n * Spec: https://schema.org/ItemList · https://schema.org/BreadcrumbList\n */\nexport function buildCategorySchemas(\n category: NestedCategory,\n products: Product[],\n breadcrumbs: BreadcrumbItem[],\n origin: string\n): Record<string, unknown>[] {\n const schemas: Record<string, unknown>[] = []\n\n if (breadcrumbs.length) {\n schemas.push({\n '@context': 'https://schema.org',\n '@type': 'BreadcrumbList',\n itemListElement: breadcrumbs.map((crumb, index) => ({\n '@type': 'ListItem',\n position: index + 1,\n name: crumb.label,\n ...(crumb.to ? { item: `${origin}${crumb.to}` } : {}),\n })),\n })\n }\n\n const items = products.slice(0, 10)\n if (items.length) {\n schemas.push({\n '@context': 'https://schema.org',\n '@type': 'ItemList',\n name: category.name,\n numberOfItems: items.length,\n itemListElement: items.map((product, index) => {\n const url = `${origin}/products/${product.short_id}/${product.slug || product.short_id}`\n const firstImage = product.images?.[0]\n const image = firstImage ? resolveMediaUrl(firstImage) : null\n\n const item: Record<string, unknown> = {\n '@type': 'ListItem',\n position: index + 1,\n url,\n name: product.name,\n }\n\n if (image) item.image = image\n\n return item\n }),\n })\n }\n\n return schemas\n}\n","import type { Article, Media, OfferArticle } from '@zenky/storefront-api'\n\nimport { prepareOgDescription, resolveMediaUrl } from './utils'\n\nfunction articleSchema(\n type: 'Article' | 'BlogPosting',\n opts: {\n title: string | null | undefined\n intro: string | null | undefined\n cover: Media | null | undefined\n storeName: string\n origin: string\n }\n): Record<string, unknown> {\n const schema: Record<string, unknown> = {\n '@context': 'https://schema.org',\n '@type': type,\n headline: opts.title ?? '',\n author: {\n '@type': 'Organization',\n name: opts.storeName,\n url: opts.origin,\n },\n }\n\n const description = prepareOgDescription(opts.intro)\n if (description) schema.description = description\n\n const image = opts.cover ? resolveMediaUrl(opts.cover) : null\n if (image) schema.image = image\n\n return schema\n}\n\n/**\n * JSON-LD schema.org/Article для страницы акции (редакционный контент).\n * Spec: https://schema.org/Article\n */\nexport function buildOfferArticleSchema(\n article: OfferArticle,\n storeName: string,\n origin: string\n): Record<string, unknown>[] {\n if (!article.title) return []\n\n return [\n articleSchema('Article', {\n title: article.title,\n intro: article.intro,\n cover: article.cover,\n storeName,\n origin,\n }),\n ]\n}\n\n/**\n * JSON-LD schema.org/BlogPosting для статьи блога (Google Rich Results).\n * Spec: https://schema.org/BlogPosting\n */\nexport function buildBlogPostSchema(\n article: Article,\n storeName: string,\n origin: string\n): Record<string, unknown>[] {\n const schema = articleSchema('BlogPosting', {\n title: article.title,\n intro: article.intro,\n cover: article.cover,\n storeName,\n origin,\n })\n\n if (article.updated_at) {\n schema.dateModified = article.updated_at\n // Нет отдельного datePublished — используем updated_at.\n schema.datePublished = article.updated_at\n }\n\n return [schema]\n}\n","import { ContactType } from '@zenky/storefront-api'\n\nimport type { Schedule, Store } from '@zenky/storefront-api'\n\nimport { getSocialLinks } from '../utils'\n\n/** Ключ дня в Schedule.days → schema.org DayOfWeek. */\nconst SCHEMA_DAY: Record<string, string> = {\n monday: 'Monday',\n tuesday: 'Tuesday',\n wednesday: 'Wednesday',\n thursday: 'Thursday',\n friday: 'Friday',\n saturday: 'Saturday',\n sunday: 'Sunday',\n}\n\n/**\n * Schedule (по дням `hours` — «10:00–22:00») → массив schema.org/OpeningHoursSpecification.\n * Дни без распознаваемого интервала (выходной / круглосуточно / пусто) пропускаем.\n */\nfunction buildOpeningHours(schedule: Schedule | null | undefined): Record<string, unknown>[] {\n if (!schedule) return []\n\n const result: Record<string, unknown>[] = []\n for (const key of Object.keys(SCHEMA_DAY)) {\n const day = schedule.days[key as keyof typeof schedule.days]\n const match = day?.hours?.match(/(\\d{1,2}:\\d{2}).*?(\\d{1,2}:\\d{2})/)\n if (!match) continue\n\n result.push({\n '@type': 'OpeningHoursSpecification',\n dayOfWeek: SCHEMA_DAY[key],\n opens: match[1],\n closes: match[2],\n })\n }\n\n return result\n}\n\n/**\n * JSON-LD schema.org/Organization (или LocalBusiness при наличии физической точки)\n * для главной. Google → Knowledge Panel. Все данные из уже загруженного профиля.\n * Spec: https://schema.org/Organization · https://schema.org/LocalBusiness\n */\nexport function buildOrganizationSchema(store: Store, origin: string): Record<string, unknown>[] {\n const logoUrl =\n store.square_logo?.medium?.url ||\n store.square_logo?.large?.url ||\n store.logo?.medium?.url ||\n store.logo?.large?.url ||\n null\n\n const phones = (store.phones ?? []).map((p) => p.number).filter((n): n is string => !!n)\n const email = store.links?.find((c) => c.type === ContactType.Email)?.value ?? null\n const socialLinks = getSocialLinks(store.links ?? []).map((l) => l.url)\n\n const city = (store.cities ?? []).find((c) => c.is_default) ?? store.cities?.[0] ?? null\n const stock = city?.stocks?.find((st) => st.address) ?? city?.stocks?.[0] ?? null\n\n const streetAddress = stock?.address ?? null\n const geo = stock?.coordinates ?? city?.coordinates ?? null\n const openingHours = buildOpeningHours(stock?.schedule ?? city?.schedule)\n\n const isLocalBusiness = Boolean(streetAddress || geo || openingHours.length)\n\n const schema: Record<string, unknown> = {\n '@context': 'https://schema.org',\n '@type': isLocalBusiness ? 'LocalBusiness' : 'Organization',\n name: store.name,\n url: origin,\n }\n\n if (logoUrl) {\n schema.logo = logoUrl\n schema.image = logoUrl\n }\n\n if (phones.length) schema.telephone = phones.length === 1 ? phones[0] : phones\n if (email) schema.email = email\n if (socialLinks.length) schema.sameAs = socialLinks\n\n if (streetAddress || city?.name) {\n schema.address = {\n '@type': 'PostalAddress',\n ...(streetAddress ? { streetAddress } : {}),\n ...(city?.name ? { addressLocality: city.name } : {}),\n addressCountry: 'RU',\n }\n }\n\n if (geo) {\n schema.geo = {\n '@type': 'GeoCoordinates',\n latitude: geo.latitude,\n longitude: geo.longitude,\n }\n }\n\n if (openingHours.length) schema.openingHoursSpecification = openingHours\n\n return [schema]\n}\n","import { withSeoMetaPriority } from './headPriority'\n\n/** Уже разрешённые (с учётом дефолтов потребителя) значения OG/Twitter-тегов. */\nexport interface OgTagsInput {\n title: string | null\n description?: string | null\n image?: string | null\n type?: string\n url?: string | null\n}\n\n/** OG + Twitter meta-теги (critical-приоритет). Telegram читает twitter:image. */\nexport function buildOgTags(input: OgTagsInput): Record<string, string>[] {\n const tags: Record<string, string>[] = []\n\n if (input.title) {\n tags.push(withSeoMetaPriority({ property: 'og:title', content: input.title }))\n tags.push(withSeoMetaPriority({ name: 'twitter:title', content: input.title }))\n }\n\n if (input.description) {\n tags.push(withSeoMetaPriority({ property: 'og:description', content: input.description }))\n tags.push(withSeoMetaPriority({ name: 'twitter:description', content: input.description }))\n }\n\n if (input.image) {\n tags.push(withSeoMetaPriority({ property: 'og:image', content: input.image }))\n tags.push(withSeoMetaPriority({ name: 'twitter:image', content: input.image }))\n }\n\n tags.push(withSeoMetaPriority({ property: 'og:type', content: input.type ?? 'website' }))\n\n if (input.url) {\n tags.push(withSeoMetaPriority({ property: 'og:url', content: input.url }))\n }\n\n return tags\n}\n","import type { Seo, SeoMetaTag } from '@zenky/storefront-api'\n\nimport { withSeoMetaPriority } from './headPriority'\n\n/** SDK-теги `Seo.meta` → head-meta records (с critical-приоритетом для og/twitter/description). */\nexport function mapSeoMetaTags(tags: SeoMetaTag[]): Record<string, string>[] {\n return tags.map((tag) => {\n const attrs: Record<string, string> = {\n [tag.name.attribute]: tag.name.value,\n [tag.value.attribute]: tag.value.value,\n }\n\n for (const additional of tag.additional) {\n attrs[additional.attribute] = additional.value\n }\n\n if (\n attrs.name === 'description' ||\n attrs.name?.startsWith('twitter:') ||\n attrs.property?.startsWith('og:')\n ) {\n return withSeoMetaPriority(attrs)\n }\n\n return attrs\n })\n}\n\n/** meta-теги из `Seo`-сущности (description + маппинг `Seo.meta`). Title резолвит потребитель. */\nexport function buildEntitySeoMeta(seo: Seo | null | undefined): Record<string, string>[] {\n const tags: Record<string, string>[] = []\n\n if (seo?.description) {\n tags.push(withSeoMetaPriority({ name: 'description', content: seo.description }))\n }\n\n if (seo?.meta?.length) {\n tags.push(...mapSeoMetaTags(seo.meta))\n }\n\n return tags\n}\n"]}
1
+ {"version":3,"sources":["../../src/seo/utils.ts","../../src/seo/siteOrigin.ts","../../src/seo/productSchema.ts","../../src/seo/categorySchema.ts","../../src/seo/articleSchema.ts","../../src/seo/organizationSchema.ts","../../src/seo/ogTags.ts","../../src/seo/entitySeo.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { Media, Store } from '@zenky/storefront-api'\n\n/**\n * Resolves the best available URL from a Media object.\n */\nexport function resolveMediaUrl(media: Media): string | null {\n return (\n media.hd?.url ||\n media.xlarge?.url ||\n media.large?.url ||\n media.medium?.url ||\n media.placeholder?.url ||\n null\n )\n}\n\n/**\n * Resolves store logo URL, preferring square logo over rectangular.\n * Tries all available size variants so CDN assets with only hd/xlarge are found too.\n */\nexport function resolveStoreLogoUrl(store: Store | null | undefined): string | null {\n if (!store) return null\n if (store.square_logo) {\n const url = resolveMediaUrl(store.square_logo)\n if (url) return url\n }\n if (store.logo) {\n return resolveMediaUrl(store.logo)\n }\n return null\n}\n\n/**\n * Strips HTML tags from a string.\n */\nexport function stripHtml(html: string): string {\n return html.replace(/<[^>]*>/g, '').trim()\n}\n\n/**\n * Prepares a string for use as og:description or meta description:\n * strips HTML tags and truncates to maxLength (default 160).\n */\nexport function prepareOgDescription(\n text: string | null | undefined,\n maxLength = 160\n): string | null {\n if (!text) return null\n const plain = stripHtml(text)\n if (!plain) return null\n return plain.length > maxLength ? `${plain.slice(0, maxLength - 3)}...` : plain\n}\n","/**\n * Каноничный публичный origin сайта из `store.domain`. Fallback (хост запроса)\n * приносит потребитель — ядро не знает про useRequestURL.\n */\nexport function resolveSiteOrigin(\n storeDomain: string | null | undefined,\n fallbackOrigin: string\n): string {\n const domain = storeDomain?.trim()\n if (domain) {\n const host = domain.replace(/^https?:\\/\\//, '').replace(/\\/+$/, '')\n return `https://${host}`\n }\n return fallbackOrigin\n}\n","import type { Product, ProductVariant } from '@zenky/storefront-api'\n\nimport { minorToMajorString } from '../money'\nimport { resolveVariantPrice } from '../products'\nimport { resolveMediaUrl } from './utils'\n\nfunction isProductInStock(variants: ProductVariant[]): boolean {\n if (!variants.length) return false\n return variants.some((variant) => {\n const remainders = variant.remainders\n if (!remainders?.length) return true\n return remainders.some((remainder) => remainder.quantity > 0)\n })\n}\n\n/**\n * JSON-LD schema.org/Product. Google → Rich Results (цена/наличие/рейтинг в выдаче).\n * Возвращает массив (0 или 1 объект) — потребитель оборачивает в `<script ld+json>`.\n * Spec: https://schema.org/Product\n */\nexport function buildProductSchema(product: Product, currency: string): Record<string, unknown>[] {\n const variants = product.variants ?? []\n\n const firstVariant = variants[0]\n let offerBlock: Record<string, unknown> | undefined\n\n if (firstVariant) {\n const resolved = resolveVariantPrice(firstVariant)\n\n offerBlock = {\n '@type': 'Offer',\n price: minorToMajorString(resolved.price, currency),\n priceCurrency: currency,\n availability: isProductInStock(variants)\n ? 'https://schema.org/InStock'\n : 'https://schema.org/OutOfStock',\n ...(firstVariant.sku ? { sku: firstVariant.sku } : {}),\n }\n }\n\n const images = (product.images ?? []).map(resolveMediaUrl).filter((url): url is string => !!url)\n\n const schema: Record<string, unknown> = {\n '@context': 'https://schema.org',\n '@type': 'Product',\n name: product.name,\n }\n\n if (product.description) schema.description = product.description\n if (images.length) schema.image = images\n if (offerBlock) schema.offers = offerBlock\n\n return [schema]\n}\n","import type { NestedCategory, Product } from '@zenky/storefront-api'\n\nimport { resolveMediaUrl } from './utils'\nimport type { BreadcrumbItem } from './types'\n\n/**\n * JSON-LD для страницы категории: BreadcrumbList (хлебные крошки) + ItemList\n * (первые 10 товаров). Возвращает массив JSON-LD объектов (0–2).\n * Spec: https://schema.org/ItemList · https://schema.org/BreadcrumbList\n */\nexport function buildCategorySchemas(\n category: NestedCategory,\n products: Product[],\n breadcrumbs: BreadcrumbItem[],\n origin: string\n): Record<string, unknown>[] {\n const schemas: Record<string, unknown>[] = []\n\n if (breadcrumbs.length) {\n schemas.push({\n '@context': 'https://schema.org',\n '@type': 'BreadcrumbList',\n itemListElement: breadcrumbs.map((crumb, index) => ({\n '@type': 'ListItem',\n position: index + 1,\n name: crumb.label,\n ...(crumb.to ? { item: `${origin}${crumb.to}` } : {}),\n })),\n })\n }\n\n const items = products.slice(0, 10)\n if (items.length) {\n schemas.push({\n '@context': 'https://schema.org',\n '@type': 'ItemList',\n name: category.name,\n numberOfItems: items.length,\n itemListElement: items.map((product, index) => {\n const url = `${origin}/products/${product.short_id}/${product.slug || product.short_id}`\n const firstImage = product.images?.[0]\n const image = firstImage ? resolveMediaUrl(firstImage) : null\n\n const item: Record<string, unknown> = {\n '@type': 'ListItem',\n position: index + 1,\n url,\n name: product.name,\n }\n\n if (image) item.image = image\n\n return item\n }),\n })\n }\n\n return schemas\n}\n","import type { Article, Media, OfferArticle } from '@zenky/storefront-api'\n\nimport { prepareOgDescription, resolveMediaUrl } from './utils'\n\nfunction articleSchema(\n type: 'Article' | 'BlogPosting',\n opts: {\n title: string | null | undefined\n intro: string | null | undefined\n cover: Media | null | undefined\n storeName: string\n origin: string\n }\n): Record<string, unknown> {\n const schema: Record<string, unknown> = {\n '@context': 'https://schema.org',\n '@type': type,\n headline: opts.title ?? '',\n author: {\n '@type': 'Organization',\n name: opts.storeName,\n url: opts.origin,\n },\n }\n\n const description = prepareOgDescription(opts.intro)\n if (description) schema.description = description\n\n const image = opts.cover ? resolveMediaUrl(opts.cover) : null\n if (image) schema.image = image\n\n return schema\n}\n\n/**\n * JSON-LD schema.org/Article для страницы акции (редакционный контент).\n * Spec: https://schema.org/Article\n */\nexport function buildOfferArticleSchema(\n article: OfferArticle,\n storeName: string,\n origin: string\n): Record<string, unknown>[] {\n if (!article.title) return []\n\n return [\n articleSchema('Article', {\n title: article.title,\n intro: article.intro,\n cover: article.cover,\n storeName,\n origin,\n }),\n ]\n}\n\n/**\n * JSON-LD schema.org/BlogPosting для статьи блога (Google Rich Results).\n * Spec: https://schema.org/BlogPosting\n */\nexport function buildBlogPostSchema(\n article: Article,\n storeName: string,\n origin: string\n): Record<string, unknown>[] {\n const schema = articleSchema('BlogPosting', {\n title: article.title,\n intro: article.intro,\n cover: article.cover,\n storeName,\n origin,\n })\n\n if (article.updated_at) {\n schema.dateModified = article.updated_at\n // Нет отдельного datePublished — используем updated_at.\n schema.datePublished = article.updated_at\n }\n\n return [schema]\n}\n","import { ContactType } from '@zenky/storefront-api'\n\nimport type { Schedule, Store } from '@zenky/storefront-api'\n\nimport { getSocialLinks } from '../utils'\n\n/** Ключ дня в Schedule.days → schema.org DayOfWeek. */\nconst SCHEMA_DAY: Record<string, string> = {\n monday: 'Monday',\n tuesday: 'Tuesday',\n wednesday: 'Wednesday',\n thursday: 'Thursday',\n friday: 'Friday',\n saturday: 'Saturday',\n sunday: 'Sunday',\n}\n\n/**\n * Schedule (по дням `hours` — «10:00–22:00») → массив schema.org/OpeningHoursSpecification.\n * Дни без распознаваемого интервала (выходной / круглосуточно / пусто) пропускаем.\n */\nfunction buildOpeningHours(schedule: Schedule | null | undefined): Record<string, unknown>[] {\n if (!schedule) return []\n\n const result: Record<string, unknown>[] = []\n for (const key of Object.keys(SCHEMA_DAY)) {\n const day = schedule.days[key as keyof typeof schedule.days]\n const match = day?.hours?.match(/(\\d{1,2}:\\d{2}).*?(\\d{1,2}:\\d{2})/)\n if (!match) continue\n\n result.push({\n '@type': 'OpeningHoursSpecification',\n dayOfWeek: SCHEMA_DAY[key],\n opens: match[1],\n closes: match[2],\n })\n }\n\n return result\n}\n\n/**\n * JSON-LD schema.org/Organization (или LocalBusiness при наличии физической точки)\n * для главной. Google → Knowledge Panel. Все данные из уже загруженного профиля.\n * Spec: https://schema.org/Organization · https://schema.org/LocalBusiness\n */\nexport function buildOrganizationSchema(store: Store, origin: string): Record<string, unknown>[] {\n const logoUrl =\n store.square_logo?.medium?.url ||\n store.square_logo?.large?.url ||\n store.logo?.medium?.url ||\n store.logo?.large?.url ||\n null\n\n const phones = (store.phones ?? []).map((p) => p.number).filter((n): n is string => !!n)\n const email = store.links?.find((c) => c.type === ContactType.Email)?.value ?? null\n const socialLinks = getSocialLinks(store.links ?? []).map((l) => l.url)\n\n const city = (store.cities ?? []).find((c) => c.is_default) ?? store.cities?.[0] ?? null\n const stock = city?.stocks?.find((st) => st.address) ?? city?.stocks?.[0] ?? null\n\n const streetAddress = stock?.address ?? null\n const geo = stock?.coordinates ?? city?.coordinates ?? null\n const openingHours = buildOpeningHours(stock?.schedule ?? city?.schedule)\n\n const isLocalBusiness = Boolean(streetAddress || geo || openingHours.length)\n\n const schema: Record<string, unknown> = {\n '@context': 'https://schema.org',\n '@type': isLocalBusiness ? 'LocalBusiness' : 'Organization',\n name: store.name,\n url: origin,\n }\n\n if (logoUrl) {\n schema.logo = logoUrl\n schema.image = logoUrl\n }\n\n if (phones.length) schema.telephone = phones.length === 1 ? phones[0] : phones\n if (email) schema.email = email\n if (socialLinks.length) schema.sameAs = socialLinks\n\n if (streetAddress || city?.name) {\n schema.address = {\n '@type': 'PostalAddress',\n ...(streetAddress ? { streetAddress } : {}),\n ...(city?.name ? { addressLocality: city.name } : {}),\n addressCountry: 'RU',\n }\n }\n\n if (geo) {\n schema.geo = {\n '@type': 'GeoCoordinates',\n latitude: geo.latitude,\n longitude: geo.longitude,\n }\n }\n\n if (openingHours.length) schema.openingHoursSpecification = openingHours\n\n return [schema]\n}\n","/** Уже разрешённые (с учётом дефолтов потребителя) значения OG/Twitter-тегов. */\nexport interface OgTagsInput {\n title: string | null\n description?: string | null\n image?: string | null\n type?: string\n url?: string | null\n}\n\n/** Framework-neutral OG + Twitter meta records. The consumer controls head priority. */\nexport function buildOgTags(input: OgTagsInput): Record<string, string>[] {\n const tags: Record<string, string>[] = []\n\n if (input.title) {\n tags.push({ property: 'og:title', content: input.title })\n tags.push({ name: 'twitter:title', content: input.title })\n }\n\n if (input.description) {\n tags.push({ property: 'og:description', content: input.description })\n tags.push({ name: 'twitter:description', content: input.description })\n }\n\n if (input.image) {\n tags.push({ property: 'og:image', content: input.image })\n tags.push({ name: 'twitter:image', content: input.image })\n }\n\n tags.push({ property: 'og:type', content: input.type ?? 'website' })\n\n if (input.url) {\n tags.push({ property: 'og:url', content: input.url })\n }\n\n return tags\n}\n","import type { Seo, SeoMetaTag } from '@zenky/storefront-api'\n\n/** SDK `Seo.meta` tags mapped to framework-neutral head meta records. */\nexport function mapSeoMetaTags(tags: SeoMetaTag[]): Record<string, string>[] {\n return tags.map((tag) => {\n const attrs: Record<string, string> = {\n [tag.name.attribute]: tag.name.value,\n [tag.value.attribute]: tag.value.value,\n }\n\n for (const additional of tag.additional) {\n attrs[additional.attribute] = additional.value\n }\n\n return attrs\n })\n}\n\n/** meta-теги из `Seo`-сущности (description + маппинг `Seo.meta`). Title резолвит потребитель. */\nexport function buildEntitySeoMeta(seo: Seo | null | undefined): Record<string, string>[] {\n const tags: Record<string, string>[] = []\n\n if (seo?.description) {\n tags.push({ name: 'description', content: seo.description })\n }\n\n if (seo?.meta?.length) {\n tags.push(...mapSeoMetaTags(seo.meta))\n }\n\n return tags\n}\n"]}
@@ -1,17 +1,23 @@
1
- import { S as Snippet } from '../snippets-BC5bkSjm.js';
2
- export { R as RawSnippetItem, a as SnippetGroup, b as SnippetLanguage, c as SnippetPosition, n as normalizeSnippets } from '../snippets-BC5bkSjm.js';
3
-
4
- /** Head-нагрузка для инъекции сниппетов (потребитель отдаёт её в useHead). */
5
- interface SnippetHead {
6
- meta: Record<string, string | boolean>[];
7
- link: Record<string, string | boolean>[];
8
- script: Record<string, unknown>[];
9
- style: Record<string, string | boolean>[];
1
+ type SnippetPosition = 'head_start' | 'head_end' | 'body_start' | 'body_end';
2
+ type SnippetLanguage = 'html' | 'css' | 'javascript';
3
+ interface Snippet {
4
+ id: string;
5
+ name?: string;
6
+ position: SnippetPosition;
7
+ language: SnippetLanguage;
8
+ code: string;
9
+ enabled: boolean;
10
+ }
11
+ interface RawSnippetItem {
12
+ language: SnippetLanguage;
13
+ content: string;
14
+ enabled?: boolean;
15
+ name?: string;
16
+ }
17
+ interface SnippetGroup {
18
+ region: SnippetPosition;
19
+ snippets: RawSnippetItem[];
10
20
  }
11
- /**
12
- * Раскладывает сниппеты магазина в head-нагрузку: JS (обёрнут в try/catch),
13
- * CSS (style), head-HTML (распарсенные meta/link/script). Инъекция — у потребителя.
14
- */
15
- declare function buildSnippetHead(snippets: Snippet[]): SnippetHead;
21
+ declare function normalizeSnippets(groups: SnippetGroup[] | null | undefined): Snippet[];
16
22
 
17
- export { Snippet, type SnippetHead, buildSnippetHead };
23
+ export { type RawSnippetItem, type Snippet, type SnippetGroup, type SnippetLanguage, type SnippetPosition, normalizeSnippets };
@@ -1,3 +1,3 @@
1
- export { buildSnippetHead, normalizeSnippets } from '../chunk-7FRMMCR5.js';
1
+ export { normalizeSnippets } from '../chunk-2CI4RW7V.js';
2
2
  //# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map
@@ -5,7 +5,7 @@ import * as _zenky_storefront_api from '@zenky/storefront-api';
5
5
  import { CatalogItem, Product, Store, City, Stock, NestedCategory, DeliveryMethod, Order, OrderDeliveryMethod, OrderSettings, OrderCheckoutTotal, PaymentMethod, OrderPaymentTransaction, OrderProductVariant, OrderPaymentMethod } from '@zenky/storefront-api';
6
6
  import { Website } from '../website-settings/index.js';
7
7
  import '@zenky/integrations-sdk';
8
- import '../snippets-BC5bkSjm.js';
8
+ import '../snippets/index.js';
9
9
 
10
10
  interface CatalogStore {
11
11
  catalog: Ref<CatalogItem[]>;
@@ -1,8 +1,6 @@
1
- export { useProductsStore, useStore, useStorefrontProfile } from '../chunk-57IOMDAM.js';
1
+ export { useProductsStore, useStore, useStorefrontProfile } from '../chunk-CY6LA6C7.js';
2
2
  export { useCatalogStore } from '../chunk-Z3IW4ODZ.js';
3
- export { usePromotionsStore } from '../chunk-BWUKMWHL.js';
4
- export { useAuthStore, useStoreProfileStore } from '../chunk-TEG7EL4N.js';
5
- export { useCartStore, useOrderSettingsStore } from '../chunk-FFBZKQRV.js';
6
- import '../chunk-V3VVDQIR.js';
3
+ export { useCartStore, useOrderSettingsStore, usePromotionsStore } from '../chunk-SHASMBMV.js';
4
+ export { useAuthStore, useStoreProfileStore } from '../chunk-CUSQYIEU.js';
7
5
  //# sourceMappingURL=index.js.map
8
6
  //# sourceMappingURL=index.js.map
@@ -47,14 +47,4 @@ interface ThemeData {
47
47
  /** CSS-переменные темы + шрифт из цвето-/шрифто-конфига (инъекция в head — на стороне app). */
48
48
  declare function useTheme(colorConfig: ThemeColorConfig, fontConfig: FontConfig): ThemeData;
49
49
 
50
- interface ThemePreset {
51
- id: string;
52
- label: string;
53
- description: string;
54
- colors: ThemeColorConfig;
55
- }
56
- declare const THEME_PRESETS: ThemePreset[];
57
- /** Тёмные версии пресетов — инвертированные background/text */
58
- declare const DARK_THEME_PRESETS: ThemePreset[];
59
-
60
- export { DARK_THEME_PRESETS, type FontConfig, type PrimaryShades, THEME_PRESETS, type ThemeColorConfig, type ThemeData, type ThemePreset, buildCssVariableMap, generatePrimaryShades, generateShades, useTheme };
50
+ export { type FontConfig, type PrimaryShades, type ThemeColorConfig, type ThemeData, buildCssVariableMap, generatePrimaryShades, generateShades, useTheme };
@@ -1,3 +1,3 @@
1
- export { DARK_THEME_PRESETS, THEME_PRESETS, buildCssVariableMap, generatePrimaryShades, generateShades, useTheme } from '../chunk-GW2QNTAD.js';
1
+ export { buildCssVariableMap, generatePrimaryShades, generateShades, useTheme } from '../chunk-4IFPVEO7.js';
2
2
  //# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map
@@ -1,5 +1,4 @@
1
- import { Phone } from '@zenky/storefront-api';
2
- export { D as DayScheduleInfo, S as SocialLink, T as TodayScheduleInfo, f as formatScheduleStatus, g as getEmailLink, a as getSocialLinks, b as getTodayInfo, c as getWebsiteLink, d as getWeeklySchedule } from '../schedule-Dd3zwHEb.js';
1
+ import { Phone, ContactType, Contact, Schedule } from '@zenky/storefront-api';
3
2
 
4
3
  declare function createDebounce(fn: () => void, delay: number): () => void;
5
4
 
@@ -17,6 +16,30 @@ declare function getPhoneTelLink(phone: Phone | null | undefined): string | null
17
16
  */
18
17
  declare function formatPhoneSpaced(formatted: string | null | undefined): string;
19
18
 
19
+ interface SocialLink {
20
+ type: ContactType;
21
+ url: string;
22
+ label: string;
23
+ }
24
+ declare function getSocialLinks(contacts: Contact[]): SocialLink[];
25
+ declare function getEmailLink(contacts: Contact[]): string | null;
26
+ declare function getWebsiteLink(contacts: Contact[]): string | null;
27
+
28
+ interface DayScheduleInfo {
29
+ dayKey: string;
30
+ name: string;
31
+ hours: string | null;
32
+ }
33
+ interface TodayScheduleInfo {
34
+ isOpenNow: boolean;
35
+ todayHours: string | null;
36
+ openingAt: string | null;
37
+ closingAt: string | null;
38
+ }
39
+ declare function getTodayInfo(schedule: Schedule | null | undefined): TodayScheduleInfo | null;
40
+ declare function getWeeklySchedule(schedule: Schedule | null | undefined, locale?: string): DayScheduleInfo[];
41
+ declare function formatScheduleStatus(schedule: Schedule | null | undefined, locale?: string): string | null;
42
+
20
43
  /**
21
44
  * Генерирует URL картинки QR-кода через Zenky media API.
22
45
  *
@@ -63,4 +86,4 @@ declare function getApiFieldErrors(e: unknown): Record<string, string[]> | null;
63
86
  */
64
87
  declare function formatAddressCityLast(raw: string): string;
65
88
 
66
- export { type OperationChain, buildQrCodeUrl, createDebounce, createOperationChain, formatAddressCityLast, formatDate, formatDateTime, formatPhoneNational, formatPhoneSpaced, getApiErrorMessage, getApiFieldErrors, getPhoneTelLink, pluralize, toDateInputValue, todayInTimezone };
89
+ export { type DayScheduleInfo, type OperationChain, type SocialLink, type TodayScheduleInfo, buildQrCodeUrl, createDebounce, createOperationChain, formatAddressCityLast, formatDate, formatDateTime, formatPhoneNational, formatPhoneSpaced, formatScheduleStatus, getApiErrorMessage, getApiFieldErrors, getEmailLink, getPhoneTelLink, getSocialLinks, getTodayInfo, getWebsiteLink, getWeeklySchedule, pluralize, toDateInputValue, todayInTimezone };
@@ -1,6 +1,6 @@
1
1
  import { Media } from '@zenky/storefront-api';
2
2
  import { ZenkyIntegration } from '@zenky/integrations-sdk';
3
- import { a as SnippetGroup } from '../snippets-BC5bkSjm.js';
3
+ import { SnippetGroup } from '../snippets/index.js';
4
4
 
5
5
  type SettingValue = string | number | boolean | null;
6
6
  interface WebsiteSettingsValues {