@zenky/storefront-vue 0.10.8 → 0.10.10

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 (76) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +4 -18
  3. package/dist/cart/index.d.ts +167 -160
  4. package/dist/cart/index.js +7 -7
  5. package/dist/catalog/index.d.ts +23 -24
  6. package/dist/catalog/index.js +2 -2
  7. package/dist/catalogEntity-DgrPsJpf.d.ts +44 -0
  8. package/dist/{chunk-RO25KNM5.js → chunk-2Y6QTHXI.js} +2 -2
  9. package/dist/chunk-2Y6QTHXI.js.map +1 -0
  10. package/dist/{chunk-3FDM6T7F.js → chunk-32SLDGE5.js} +8 -6
  11. package/dist/chunk-32SLDGE5.js.map +1 -0
  12. package/dist/{chunk-5YD4AIY2.js → chunk-46FNHMWC.js} +4 -4
  13. package/dist/chunk-46FNHMWC.js.map +1 -0
  14. package/dist/{chunk-2SMSLZ6G.js → chunk-4UMDIBW5.js} +15 -11
  15. package/dist/chunk-4UMDIBW5.js.map +1 -0
  16. package/dist/{chunk-4IFPVEO7.js → chunk-BUNI6MGH.js} +3 -3
  17. package/dist/chunk-BUNI6MGH.js.map +1 -0
  18. package/dist/{chunk-E3G7NGCH.js → chunk-FS2UNPTY.js} +2 -2
  19. package/dist/chunk-FS2UNPTY.js.map +1 -0
  20. package/dist/{chunk-PTMSPB34.js → chunk-FXKG5TFQ.js} +3 -3
  21. package/dist/chunk-FXKG5TFQ.js.map +1 -0
  22. package/dist/{chunk-MOG6UMFM.js → chunk-GILJFP55.js} +2 -2
  23. package/dist/chunk-GILJFP55.js.map +1 -0
  24. package/dist/{chunk-2CI4RW7V.js → chunk-GLQXTMVW.js} +2 -2
  25. package/dist/{chunk-2CI4RW7V.js.map → chunk-GLQXTMVW.js.map} +1 -1
  26. package/dist/{chunk-MZ66ARDL.js → chunk-GXDTRTUT.js} +2 -2
  27. package/dist/chunk-GXDTRTUT.js.map +1 -0
  28. package/dist/{chunk-Z3IW4ODZ.js → chunk-NSOIL7PW.js} +2 -2
  29. package/dist/chunk-NSOIL7PW.js.map +1 -0
  30. package/dist/{chunk-NG7RUIWW.js → chunk-OBNMXLJO.js} +19 -3
  31. package/dist/chunk-OBNMXLJO.js.map +1 -0
  32. package/dist/{chunk-VFMVQR6Y.js → chunk-QZ3S3NN3.js} +5 -3
  33. package/dist/chunk-QZ3S3NN3.js.map +1 -0
  34. package/dist/{chunk-Z247QRDJ.js → chunk-XULHV6SS.js} +3 -3
  35. package/dist/chunk-XULHV6SS.js.map +1 -0
  36. package/dist/index.d.ts +4 -3
  37. package/dist/index.js +14 -14
  38. package/dist/money/index.d.ts +8 -8
  39. package/dist/money/index.js +1 -1
  40. package/dist/order/index.d.ts +3 -3
  41. package/dist/order/index.js.map +1 -1
  42. package/dist/pagination/index.d.ts +29 -37
  43. package/dist/pagination/index.js.map +1 -1
  44. package/dist/ports/index.d.ts +23 -22
  45. package/dist/ports/index.js +1 -1
  46. package/dist/products/index.d.ts +10 -10
  47. package/dist/products/index.js +3 -3
  48. package/dist/promotions/index.d.ts +5 -5
  49. package/dist/promotions/index.js +3 -3
  50. package/dist/seo/index.d.ts +17 -17
  51. package/dist/seo/index.js +15 -9
  52. package/dist/seo/index.js.map +1 -1
  53. package/dist/snippets/index.js +1 -1
  54. package/dist/stores/index.d.ts +8 -8
  55. package/dist/stores/index.js +4 -4
  56. package/dist/theme/index.d.ts +3 -3
  57. package/dist/theme/index.js +1 -1
  58. package/dist/utils/index.d.ts +16 -16
  59. package/dist/utils/index.js +1 -1
  60. package/docs/architecture.md +85 -0
  61. package/docs/consumer-setup.md +13 -54
  62. package/docs/ports.md +12 -13
  63. package/package.json +1 -1
  64. package/dist/chunk-2SMSLZ6G.js.map +0 -1
  65. package/dist/chunk-3FDM6T7F.js.map +0 -1
  66. package/dist/chunk-4IFPVEO7.js.map +0 -1
  67. package/dist/chunk-5YD4AIY2.js.map +0 -1
  68. package/dist/chunk-E3G7NGCH.js.map +0 -1
  69. package/dist/chunk-MOG6UMFM.js.map +0 -1
  70. package/dist/chunk-MZ66ARDL.js.map +0 -1
  71. package/dist/chunk-NG7RUIWW.js.map +0 -1
  72. package/dist/chunk-PTMSPB34.js.map +0 -1
  73. package/dist/chunk-RO25KNM5.js.map +0 -1
  74. package/dist/chunk-VFMVQR6Y.js.map +0 -1
  75. package/dist/chunk-Z247QRDJ.js.map +0 -1
  76. package/dist/chunk-Z3IW4ODZ.js.map +0 -1
@@ -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 /** 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"]}
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 * A free-mode slot with its own delivery date. The \"night tail\" (00:00–02:00) is shown\n * in the same tab as the start of the business day, but its `date` is already the next\n * day, so `deliver_at` must be built from `interval.date`, not the tab's 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/** Hour:minute within the day, in the store's timezone (not the browser's). */\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 * Normalizes a working window from a start/end pair into minutes of the day.\n * `endMinutes` can be > 24:00, for windows that run past midnight. Splitting the\n * \"night tail\" into calendar dates is done by {@link generateFreeTimeGroups}.\n * - `00:00–00:00` → open 24 hours (`0 … 24:00`).\n * - A window crossing midnight (`10:00–00:00`, `22:00–02:00`, end < start) → the end\n * belongs to the next day, so add 24 hours to it (`02:00` → `26:00`).\n * - A zero-length window (`start === end`, except the 24-hour case) → no schedule.\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 const earliestTodayMinutes = ceilToStep(nowParts.hour * 60 + nowParts.minute + safeOffset, step)\n\n const groups: DeliveryIntervalsGroup[] = []\n\n // One tab = one business day (open → close). The window can run past midnight —\n // then the \"night tail\" 00:00–02:00 stays in the same tab, but its slots' dates\n // are already the next day (see 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 is unique within a single tab: for a 24-hour window, the 00:00 close\n // would collide with the 00:00 open — we keep the first one (that day's open)\n // and skip emitting the duplicate 00:00 close (it's the same as the next tab's\n // open). Dedup happens BEFORE the today-filter, so the closing 00:00 is dropped\n // even when the opening 00:00 gets filtered out as \"in the past\".\n if (seenTimes.has(time)) continue\n seenTimes.add(time)\n\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"]}
@@ -2,22 +2,22 @@ import { Ref, ComputedRef } from 'vue';
2
2
  import { PaginatedResponse } from '@zenky/storefront-api';
3
3
 
4
4
  /**
5
- * Pure composable пагинации списка (товары, статьи блога и т.д.).
5
+ * Pure composable for paginating a list (products, blog articles, etc.).
6
6
  *
7
- * Универсальный — фетчер и тип элемента передаются снаружи через дженерик `T` и
8
- * замыкание, поэтому можно использовать для категории, коллекции, блога и т.п.
9
- * Не зависит от Nuxt — можно вынести в библиотеку.
7
+ * Generic — the fetcher and item type are supplied by the caller via the `T`
8
+ * generic and a closure, so it works for categories, collections, blogs, etc.
9
+ * Does not depend on Nuxt — safe to extract into a library.
10
10
  *
11
- * Поддерживает два режима навигации:
12
- * - `loadPage(N)` — заменяет всё содержимое элементами N-й страницы (для прямого
13
- * ?page=N и для классической пагинации цифрами)
14
- * - `loadMore()` — добавляет следующую страницу к текущему списку (load-more / infinite)
11
+ * Supports two navigation modes:
12
+ * - `loadPage(N)` replaces all content with page N's items (for direct ?page=N
13
+ * navigation and classic numbered pagination)
14
+ * - `loadMore()` appends the next page to the current list (load-more / infinite scroll)
15
15
  *
16
- * Хранит данные не как плоский массив, а как **чанки по страницам** (`pageChunks`).
17
- * Это позволяет UI рендерить каждую страницу отдельной секцией с `data-page` атрибутом,
18
- * что нужно для `content-visibility: auto` (оптимизация рендера скрытых секций).
16
+ * Stores data not as a flat array but as **chunks per page** (`pageChunks`). This lets
17
+ * the UI render each page as its own section with a `data-page` attribute, which
18
+ * `content-visibility: auto` needs (to skip rendering off-screen sections).
19
19
  *
20
- * Параллельные вызовы игнорируются (одна загрузка за раз).
20
+ * Concurrent calls are ignored — only one load runs at a time.
21
21
  */
22
22
  type PaginatedFetcher<T> = (page: number, count: number) => Promise<PaginatedResponse<T>>;
23
23
  interface PageChunk<T> {
@@ -25,61 +25,53 @@ interface PageChunk<T> {
25
25
  items: T[];
26
26
  }
27
27
  interface UsePaginatedListOptions<T> {
28
- /** Размер страницы. По умолчанию 20 — баланс для 2/4/5-колоночных сеток. */
28
+ /** Page size. Defaults to 20, a balance point for 2/4/5-column grids. */
29
29
  perPage?: number;
30
- /** С какой страницы начинать. Используется для инициализации из ?page=N. */
30
+ /** Which page to start from. Used to initialize from ?page=N. */
31
31
  initialPage?: number;
32
32
  /**
33
- * Готовые данные первой загрузки (для SSR-friendly инициализации без повторного
34
- * запроса на клиенте). Если переданы — composable не делает первичный fetch.
33
+ * Pre-loaded data from the first fetch (for SSR-friendly init without
34
+ * refetching on the client). If provided, the composable skips the initial fetch.
35
35
  */
36
36
  initialData?: PaginatedResponse<T> | null;
37
- /** Функция загрузки страницы. Замыкание родителя — может включать фильтры, категорию и т.д. */
37
+ /** Page-loading function. The caller's closure — can capture filters, category, etc. */
38
38
  fetcher: PaginatedFetcher<T>;
39
39
  }
40
40
  interface UsePaginatedList<T> {
41
41
  /**
42
- * Чанки страниц — основной источник данных. Каждый элемент — это загруженная
43
- * страница со своими элементами. При `loadPage` — массив заменяется одним чанком.
44
- * При `loadMore` — новый чанк добавляется в конец.
42
+ * Page chunks — the main data source. Each entry is one loaded page with its
43
+ * own items. `loadPage` replaces the array with a single chunk.
44
+ * `loadMore` appends a new chunk to the end.
45
45
  */
46
46
  pageChunks: Ref<PageChunk<T>[]>;
47
- /** Плоский массив всех загруженных элементов (computed из pageChunks для удобства). */
47
+ /** Flat array of all loaded items (computed from pageChunks for convenience). */
48
48
  items: ComputedRef<T[]>;
49
- /** Самая последняя загруженная страница (не обязательно «текущая» для пагинации). */
49
+ /** The most recently loaded page (not necessarily the "current" page for pagination UI). */
50
50
  currentPage: Ref<number>;
51
- /** Диапазон страниц, чьи элементы сейчас в `pageChunks`. */
51
+ /** Range of pages whose items are currently in `pageChunks`. */
52
52
  pageWindow: Ref<{
53
53
  from: number;
54
54
  to: number;
55
55
  }>;
56
- /** Всего страниц по данным API. */
57
56
  totalPages: Ref<number>;
58
- /** Всего элементов по данным API. */
59
57
  totalItems: Ref<number>;
60
- /** Есть ли следующая страница для load-more. */
61
58
  hasMore: Ref<boolean>;
62
- /** Идёт ли запрос. */
63
59
  loading: Ref<boolean>;
64
- /** Произошла ли ошибка при последнем запросе. */
65
60
  error: Ref<unknown | null>;
66
- /** Заменить state элементами страницы N. Используется для прямого перехода и кликов на цифру. */
61
+ /** Replaces the state with page N's items. Used for direct navigation and page-number clicks. */
67
62
  loadPage(page: number): Promise<void>;
68
- /** Догрузить следующую страницу (append). */
69
63
  loadMore(): Promise<void>;
70
64
  /**
71
- * Применить готовые данные страницы без запроса (используется когда initialData
72
- * приходит асинхронно через `useAsyncData({ lazy: true })` на клиенте).
65
+ * Applies pre-loaded page data without making a request (used when initialData
66
+ * arrives asynchronously via `useAsyncData({ lazy: true })` on the client).
73
67
  */
74
68
  applyInitialData(response: PaginatedResponse<T>, page: number): void;
75
69
  /**
76
- * Принудительно включить loading-флаг и очистить pageChunks. Используется
77
- * когда SSR вернул пустые initialData и мы ждём клиентскую загрузку.
70
+ * Forces the loading flag on and clears pageChunks. Used when SSR returned
71
+ * empty initialData and we're waiting for the client-side load.
78
72
  */
79
73
  startLoading(): void;
80
- /**
81
- * Выключить loading-флаг без применения данных (при ошибке, чтобы скрыть скелетоны).
82
- */
74
+ /** Turns off the loading flag without applying data (on error, to hide skeletons). */
83
75
  stopLoading(): void;
84
76
  }
85
77
  declare function usePaginatedList<T>(options: UsePaginatedListOptions<T>): UsePaginatedList<T>;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pagination/usePaginatedList.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { computed, ref, type ComputedRef, type Ref } from 'vue'\n\nimport type { PaginatedResponse } from '@zenky/storefront-api'\n\n/**\n * Pure composable пагинации списка (товары, статьи блога и т.д.).\n *\n * Универсальный — фетчер и тип элемента передаются снаружи через дженерик `T` и\n * замыкание, поэтому можно использовать для категории, коллекции, блога и т.п.\n * Не зависит от Nuxt — можно вынести в библиотеку.\n *\n * Поддерживает два режима навигации:\n * - `loadPage(N)` — заменяет всё содержимое элементами N-й страницы (для прямого\n * ?page=N и для классической пагинации цифрами)\n * - `loadMore()` — добавляет следующую страницу к текущему списку (load-more / infinite)\n *\n * Хранит данные не как плоский массив, а как **чанки по страницам** (`pageChunks`).\n * Это позволяет UI рендерить каждую страницу отдельной секцией с `data-page` атрибутом,\n * что нужно для `content-visibility: auto` (оптимизация рендера скрытых секций).\n *\n * Параллельные вызовы игнорируются (одна загрузка за раз).\n */\n\nexport type PaginatedFetcher<T> = (page: number, count: number) => Promise<PaginatedResponse<T>>\n\nexport interface PageChunk<T> {\n page: number\n items: T[]\n}\n\nexport interface UsePaginatedListOptions<T> {\n /** Размер страницы. По умолчанию 20 — баланс для 2/4/5-колоночных сеток. */\n perPage?: number\n /** С какой страницы начинать. Используется для инициализации из ?page=N. */\n initialPage?: number\n /**\n * Готовые данные первой загрузки (для SSR-friendly инициализации без повторного\n * запроса на клиенте). Если переданы — composable не делает первичный fetch.\n */\n initialData?: PaginatedResponse<T> | null\n /** Функция загрузки страницы. Замыкание родителя — может включать фильтры, категорию и т.д. */\n fetcher: PaginatedFetcher<T>\n}\n\nexport interface UsePaginatedList<T> {\n /**\n * Чанки страниц — основной источник данных. Каждый элемент — это загруженная\n * страница со своими элементами. При `loadPage` — массив заменяется одним чанком.\n * При `loadMore` — новый чанк добавляется в конец.\n */\n pageChunks: Ref<PageChunk<T>[]>\n /** Плоский массив всех загруженных элементов (computed из pageChunks для удобства). */\n items: ComputedRef<T[]>\n /** Самая последняя загруженная страница (не обязательно «текущая» для пагинации). */\n currentPage: Ref<number>\n /** Диапазон страниц, чьи элементы сейчас в `pageChunks`. */\n pageWindow: Ref<{ from: number; to: number }>\n /** Всего страниц по данным API. */\n totalPages: Ref<number>\n /** Всего элементов по данным API. */\n totalItems: Ref<number>\n /** Есть ли следующая страница для load-more. */\n hasMore: Ref<boolean>\n /** Идёт ли запрос. */\n loading: Ref<boolean>\n /** Произошла ли ошибка при последнем запросе. */\n error: Ref<unknown | null>\n\n /** Заменить state элементами страницы N. Используется для прямого перехода и кликов на цифру. */\n loadPage(page: number): Promise<void>\n /** Догрузить следующую страницу (append). */\n loadMore(): Promise<void>\n /**\n * Применить готовые данные страницы без запроса (используется когда initialData\n * приходит асинхронно через `useAsyncData({ lazy: true })` на клиенте).\n */\n applyInitialData(response: PaginatedResponse<T>, page: number): void\n /**\n * Принудительно включить loading-флаг и очистить pageChunks. Используется\n * когда SSR вернул пустые initialData и мы ждём клиентскую загрузку.\n */\n startLoading(): void\n /**\n * Выключить loading-флаг без применения данных (при ошибке, чтобы скрыть скелетоны).\n */\n stopLoading(): void\n}\n\nconst DEFAULT_PER_PAGE = 20\n\nexport function usePaginatedList<T>(options: UsePaginatedListOptions<T>): UsePaginatedList<T> {\n const perPage = options.perPage ?? DEFAULT_PER_PAGE\n const fetcher = options.fetcher\n\n const pageChunks = ref<PageChunk<T>[]>([]) as Ref<PageChunk<T>[]>\n const currentPage = ref<number>(options.initialPage ?? 1)\n const pageWindow = ref<{ from: number; to: number }>({\n from: options.initialPage ?? 1,\n to: options.initialPage ?? 1,\n })\n const totalPages = ref<number>(1)\n const totalItems = ref<number>(0)\n const hasMore = ref<boolean>(false)\n const loading = ref<boolean>(false)\n const error = ref<unknown | null>(null)\n\n /** Плоский массив для обратной совместимости — просто flatMap по чанкам. */\n const items = computed<T[]>(() => pageChunks.value.flatMap((chunk) => chunk.items))\n\n /**\n * Применить ответ API в replace-режиме (loadPage) — один чанк заменяет всё.\n */\n function applyReplaceResponse(response: PaginatedResponse<T>, page: number): void {\n pageChunks.value = [{ page, items: response.items }]\n currentPage.value = page\n pageWindow.value = { from: page, to: page }\n totalPages.value = response.pagination.total_pages\n totalItems.value = response.pagination.total\n hasMore.value = response.pagination.has_next_page\n }\n\n // Если переданы готовые данные первой страницы — заиспользуем без запроса\n if (options.initialData) {\n applyReplaceResponse(options.initialData, options.initialPage ?? 1)\n }\n\n async function loadPage(page: number): Promise<void> {\n if (loading.value) return\n\n loading.value = true\n error.value = null\n // Очищаем старые данные, чтобы UI показал skeleton вместо застывшей старой страницы.\n pageChunks.value = []\n\n try {\n const response = await fetcher(page, perPage)\n applyReplaceResponse(response, page)\n } catch (e) {\n error.value = e\n console.error('[paginated-list] loadPage failed', e)\n } finally {\n loading.value = false\n }\n }\n\n async function loadMore(): Promise<void> {\n if (loading.value || !hasMore.value) return\n\n const nextPage = currentPage.value + 1\n loading.value = true\n error.value = null\n\n try {\n const response = await fetcher(nextPage, perPage)\n\n // Append — добавляем новый чанк вместо мержа в плоский массив\n pageChunks.value = [...pageChunks.value, { page: nextPage, items: response.items }]\n currentPage.value = nextPage\n pageWindow.value = { from: pageWindow.value.from, to: nextPage }\n totalPages.value = response.pagination.total_pages\n totalItems.value = response.pagination.total\n hasMore.value = response.pagination.has_next_page\n } catch (e) {\n error.value = e\n console.error('[paginated-list] loadMore failed', e)\n } finally {\n loading.value = false\n }\n }\n\n function applyInitialData(response: PaginatedResponse<T>, page: number): void {\n applyReplaceResponse(response, page)\n loading.value = false\n }\n\n function startLoading(): void {\n loading.value = true\n pageChunks.value = []\n }\n\n function stopLoading(): void {\n loading.value = false\n }\n\n return {\n pageChunks,\n items,\n currentPage,\n pageWindow,\n totalPages,\n totalItems,\n hasMore,\n loading,\n error,\n loadPage,\n loadMore,\n applyInitialData,\n startLoading,\n stopLoading,\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/pagination/usePaginatedList.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { computed, ref, type ComputedRef, type Ref } from 'vue'\n\nimport type { PaginatedResponse } from '@zenky/storefront-api'\n\n/**\n * Pure composable for paginating a list (products, blog articles, etc.).\n *\n * Generic — the fetcher and item type are supplied by the caller via the `T`\n * generic and a closure, so it works for categories, collections, blogs, etc.\n * Does not depend on Nuxt — safe to extract into a library.\n *\n * Supports two navigation modes:\n * - `loadPage(N)` replaces all content with page N's items (for direct ?page=N\n * navigation and classic numbered pagination)\n * - `loadMore()` appends the next page to the current list (load-more / infinite scroll)\n *\n * Stores data not as a flat array but as **chunks per page** (`pageChunks`). This lets\n * the UI render each page as its own section with a `data-page` attribute, which\n * `content-visibility: auto` needs (to skip rendering off-screen sections).\n *\n * Concurrent calls are ignored — only one load runs at a time.\n */\n\nexport type PaginatedFetcher<T> = (page: number, count: number) => Promise<PaginatedResponse<T>>\n\nexport interface PageChunk<T> {\n page: number\n items: T[]\n}\n\nexport interface UsePaginatedListOptions<T> {\n /** Page size. Defaults to 20, a balance point for 2/4/5-column grids. */\n perPage?: number\n /** Which page to start from. Used to initialize from ?page=N. */\n initialPage?: number\n /**\n * Pre-loaded data from the first fetch (for SSR-friendly init without\n * refetching on the client). If provided, the composable skips the initial fetch.\n */\n initialData?: PaginatedResponse<T> | null\n /** Page-loading function. The caller's closure — can capture filters, category, etc. */\n fetcher: PaginatedFetcher<T>\n}\n\nexport interface UsePaginatedList<T> {\n /**\n * Page chunks — the main data source. Each entry is one loaded page with its\n * own items. `loadPage` replaces the array with a single chunk.\n * `loadMore` appends a new chunk to the end.\n */\n pageChunks: Ref<PageChunk<T>[]>\n /** Flat array of all loaded items (computed from pageChunks for convenience). */\n items: ComputedRef<T[]>\n /** The most recently loaded page (not necessarily the \"current\" page for pagination UI). */\n currentPage: Ref<number>\n /** Range of pages whose items are currently in `pageChunks`. */\n pageWindow: Ref<{ from: number; to: number }>\n totalPages: Ref<number>\n totalItems: Ref<number>\n hasMore: Ref<boolean>\n loading: Ref<boolean>\n error: Ref<unknown | null>\n\n /** Replaces the state with page N's items. Used for direct navigation and page-number clicks. */\n loadPage(page: number): Promise<void>\n loadMore(): Promise<void>\n /**\n * Applies pre-loaded page data without making a request (used when initialData\n * arrives asynchronously via `useAsyncData({ lazy: true })` on the client).\n */\n applyInitialData(response: PaginatedResponse<T>, page: number): void\n /**\n * Forces the loading flag on and clears pageChunks. Used when SSR returned\n * empty initialData and we're waiting for the client-side load.\n */\n startLoading(): void\n /** Turns off the loading flag without applying data (on error, to hide skeletons). */\n stopLoading(): void\n}\n\nconst DEFAULT_PER_PAGE = 20\n\nexport function usePaginatedList<T>(options: UsePaginatedListOptions<T>): UsePaginatedList<T> {\n const perPage = options.perPage ?? DEFAULT_PER_PAGE\n const fetcher = options.fetcher\n\n const pageChunks = ref<PageChunk<T>[]>([]) as Ref<PageChunk<T>[]>\n const currentPage = ref<number>(options.initialPage ?? 1)\n const pageWindow = ref<{ from: number; to: number }>({\n from: options.initialPage ?? 1,\n to: options.initialPage ?? 1,\n })\n const totalPages = ref<number>(1)\n const totalItems = ref<number>(0)\n const hasMore = ref<boolean>(false)\n const loading = ref<boolean>(false)\n const error = ref<unknown | null>(null)\n\n /** Flat array for backward compatibility — just a flatMap over the chunks. */\n const items = computed<T[]>(() => pageChunks.value.flatMap((chunk) => chunk.items))\n\n /** Applies an API response in replace mode (used by loadPage) — one chunk replaces everything. */\n function applyReplaceResponse(response: PaginatedResponse<T>, page: number): void {\n pageChunks.value = [{ page, items: response.items }]\n currentPage.value = page\n pageWindow.value = { from: page, to: page }\n totalPages.value = response.pagination.total_pages\n totalItems.value = response.pagination.total\n hasMore.value = response.pagination.has_next_page\n }\n\n if (options.initialData) {\n applyReplaceResponse(options.initialData, options.initialPage ?? 1)\n }\n\n async function loadPage(page: number): Promise<void> {\n if (loading.value) return\n\n loading.value = true\n error.value = null\n // Clear old data so the UI shows a skeleton instead of a stale, frozen page.\n pageChunks.value = []\n\n try {\n const response = await fetcher(page, perPage)\n applyReplaceResponse(response, page)\n } catch (e) {\n error.value = e\n console.error('[paginated-list] loadPage failed', e)\n } finally {\n loading.value = false\n }\n }\n\n async function loadMore(): Promise<void> {\n if (loading.value || !hasMore.value) return\n\n const nextPage = currentPage.value + 1\n loading.value = true\n error.value = null\n\n try {\n const response = await fetcher(nextPage, perPage)\n\n pageChunks.value = [...pageChunks.value, { page: nextPage, items: response.items }]\n currentPage.value = nextPage\n pageWindow.value = { from: pageWindow.value.from, to: nextPage }\n totalPages.value = response.pagination.total_pages\n totalItems.value = response.pagination.total\n hasMore.value = response.pagination.has_next_page\n } catch (e) {\n error.value = e\n console.error('[paginated-list] loadMore failed', e)\n } finally {\n loading.value = false\n }\n }\n\n function applyInitialData(response: PaginatedResponse<T>, page: number): void {\n applyReplaceResponse(response, page)\n loading.value = false\n }\n\n function startLoading(): void {\n loading.value = true\n pageChunks.value = []\n }\n\n function stopLoading(): void {\n loading.value = false\n }\n\n return {\n pageChunks,\n items,\n currentPage,\n pageWindow,\n totalPages,\n totalItems,\n hasMore,\n loading,\n error,\n loadPage,\n loadMore,\n applyInitialData,\n startLoading,\n stopLoading,\n }\n}\n"]}
@@ -1,28 +1,28 @@
1
1
  import { Ref } from 'vue';
2
2
  import { ZenkyIntegrationsSDK } from '@zenky/integrations-sdk';
3
- import { RemoteCatalog, ZenkyStorefront } from '@zenky/storefront-api';
3
+ import { RemoteCatalog, RecommendationsBlock, ZenkyStorefront } from '@zenky/storefront-api';
4
4
 
5
5
  interface StorageOptions {
6
- /** Время жизни в секундах. */
6
+ /** Time-to-live, in seconds. */
7
7
  maxAge?: number;
8
8
  sameSite?: 'strict' | 'lax' | 'none';
9
9
  secure?: boolean;
10
10
  path?: string;
11
11
  }
12
- /** Персистентное key-value хранилище (куки / localStorage / память). */
12
+ /** Persistent key-value storage (cookies / localStorage / memory). */
13
13
  interface StorageAdapter {
14
14
  get(key: string): string | null;
15
15
  set(key: string, value: string, options?: StorageOptions): void;
16
16
  remove(key: string, options?: StorageOptions): void;
17
17
  }
18
- /** Конфиг рантайма, который ядро не должно знать откуда берётся. */
18
+ /** Runtime config. The core doesn't need to know where these values come from. */
19
19
  interface StorefrontConfig {
20
20
  baseUrl: string;
21
21
  baseAuthUrl: string;
22
- /** Опциональный sales channel для креативов/каналов. */
22
+ /** Optional sales channel, used for creatives and channels. */
23
23
  salesChannelId?: string;
24
24
  }
25
- /** Уведомления пользователю (тосты). Реализация — на стороне потребителя. */
25
+ /** User-facing notifications (toasts). Implemented on the consumer's side. */
26
26
  interface Notifier {
27
27
  error(message: string): void;
28
28
  success(message: string): void;
@@ -38,12 +38,12 @@ type StorefrontMessageParams = Readonly<Record<string, string | number | boolean
38
38
  interface MessageFormatter {
39
39
  format(key: StorefrontMessageKey, params?: StorefrontMessageParams): string;
40
40
  }
41
- /** Репортер активности (busy-индикаторы, длительные операции). */
41
+ /** Activity reporter (busy indicators, long-running operations). */
42
42
  interface ActivityReporter {
43
43
  begin(kind: string): void;
44
44
  end(kind: string): void;
45
45
  }
46
- /** Realtime-канал: подписка на события (WebSocket). Ядро не знает про pusher/транспорт. */
46
+ /** Realtime channel: subscribes to events (WebSocket). The core doesn't know about Pusher or any specific transport. */
47
47
  interface RealtimeChannel {
48
48
  bind(event: string, handler: (data?: unknown) => void): void;
49
49
  }
@@ -58,16 +58,16 @@ interface RealtimePort {
58
58
  interface EventsPort {
59
59
  get(): ZenkyIntegrationsSDK | null;
60
60
  }
61
- /** Перезагрузка каталога при смене склада. Транспорт (fetch) — на стороне потребителя. */
61
+ /** Reloads the catalog when the stock changes. The transport (fetch) is implemented on the consumer's side. */
62
62
  interface CatalogReloader {
63
63
  reload(storeId: string, remoteCatalog: RemoteCatalog): Promise<void>;
64
64
  }
65
- /** RUM-репортер производительности (performance-marks). Реализация — у потребителя. */
65
+ /** RUM performance reporter (performance marks). Implemented by the consumer. */
66
66
  interface RumReporter {
67
67
  mark(name: string): void;
68
68
  measure(metric: string, startMark: string): void;
69
69
  }
70
- /** Идентификаторы commerce-события (session/anonymous) — попадают в checkout-request. */
70
+ /** Commerce event identifiers (session/anonymous) — included in the checkout request. */
71
71
  interface CommerceEventIdentity {
72
72
  session_id?: string;
73
73
  anonymous_id?: string;
@@ -78,21 +78,22 @@ interface CommerceAddedToCartPayload {
78
78
  quantity?: number;
79
79
  unitPrice?: number;
80
80
  totalPrice?: number;
81
+ recommendationsBlock?: RecommendationsBlock;
81
82
  }
82
83
  interface CommerceRemovedFromCartPayload {
83
84
  productId: string;
84
85
  productVariantId: string;
85
86
  quantity?: number;
86
87
  }
87
- /** Commerce-event трекинг (#29). Реализация/очередь/транспорт — у потребителя. */
88
+ /** Commerce event tracking. Implementation, queueing, and transport are handled by the consumer. */
88
89
  interface CommerceEventsPort {
89
90
  trackAddedToCart(orderId: string, payload: CommerceAddedToCartPayload): void;
90
91
  trackRemovedFromCart(orderId: string, payload: CommerceRemovedFromCartPayload): void;
91
92
  getIdentity(): CommerceEventIdentity;
92
93
  }
93
94
  /**
94
- * Railway-style результат: компилятор не даст прочитать `.value`,
95
- * пока потребитель не проверил `.ok`. Замена throw на публичной границе.
95
+ * Railway-style result: the compiler won't allow reading `.value` until the
96
+ * consumer has checked `.ok`. Replaces throw at the public boundary.
96
97
  */
97
98
  type Result<T = void, E = unknown> = {
98
99
  ok: true;
@@ -103,9 +104,9 @@ type Result<T = void, E = unknown> = {
103
104
  };
104
105
  declare const ok: <T>(value: T) => Result<T, never>;
105
106
  declare const err: <E>(error: E) => Result<never, E>;
106
- /** Полный рантайм, который потребитель собирает и отдаёт в createStorefront(). */
107
+ /** The full runtime that the consumer assembles and passes to createStorefront(). */
107
108
  interface StorefrontRuntime {
108
- /** SDK-клиент Zenky. Потребитель создаёт один инстанс и отдаёт сюда. */
109
+ /** Zenky SDK client. The consumer creates a single instance and provides it here. */
109
110
  sdk: ZenkyStorefront;
110
111
  storage: StorageAdapter;
111
112
  /** Reserved consumer configuration. The current core does not read this port. */
@@ -114,15 +115,15 @@ interface StorefrontRuntime {
114
115
  /** Localized user-facing copy. The core emits only stable message identifiers. */
115
116
  messages: MessageFormatter;
116
117
  activity: ActivityReporter;
117
- /** Ленивый провайдер analytics-интеграции, которая может появиться после setup. */
118
+ /** Lazy provider for the analytics integration, which may become available after setup. */
118
119
  events?: EventsPort | null;
119
- /** Ленивый провайдер realtime-транспорта (WebSocket). */
120
+ /** Lazy provider for the realtime transport (WebSocket). */
120
121
  realtime?: RealtimePort | null;
121
- /** Перезагрузка каталога при смене склада. Нет — reload пропускается. */
122
+ /** Reloads the catalog when the stock changes. If absent, the reload step is skipped. */
122
123
  catalogReloader?: CatalogReloader | null;
123
- /** RUM-метрики. Нет — инструментирование пропускается. */
124
+ /** RUM metrics. If absent, instrumentation is skipped. */
124
125
  rum?: RumReporter | null;
125
- /** Commerce-event трекинг (#29). Нет — трекинг пропускается. */
126
+ /** Commerce event tracking. If absent, tracking is skipped. */
126
127
  commerceEvents?: CommerceEventsPort | null;
127
128
  }
128
129
  declare const NOOP_NOTIFIER: Notifier;
@@ -130,7 +131,7 @@ declare const NOOP_NOTIFIER: Notifier;
130
131
  declare const KEY_MESSAGE_FORMATTER: MessageFormatter;
131
132
  declare const NOOP_ACTIVITY_REPORTER: ActivityReporter;
132
133
  declare const NOOP_RUM: RumReporter;
133
- /** In-memory storage — для SSR/тестов, без побочных эффектов на реальные куки. */
134
+ /** In-memory storage for SSR/tests, without side effects on real cookies. */
134
135
  declare function createMemoryStorage(): StorageAdapter;
135
136
 
136
137
  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 { KEY_MESSAGE_FORMATTER, NOOP_ACTIVITY_REPORTER, NOOP_NOTIFIER, NOOP_RUM, createMemoryStorage, err, ok } from '../chunk-MOG6UMFM.js';
1
+ export { KEY_MESSAGE_FORMATTER, NOOP_ACTIVITY_REPORTER, NOOP_NOTIFIER, NOOP_RUM, createMemoryStorage, err, ok } from '../chunk-GILJFP55.js';
2
2
  //# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map
@@ -1,5 +1,6 @@
1
- import { UnitType, Product, ProductVariant, NestedCategory, ProductModifiersRequest, Discount, ProductVariantOptionValue, CatalogItem, PaginatedResponse } from '@zenky/storefront-api';
1
+ import { UnitType, Product, ProductVariant, NestedCategory, ProductModifiersRequest, Discount, ProductVariantOptionValue, PaginatedResponse } from '@zenky/storefront-api';
2
2
  import { ComputedRef, Ref } from 'vue';
3
+ import { S as StaticCatalogItem } from '../catalogEntity-DgrPsJpf.js';
3
4
 
4
5
  declare function getVariantWeight(variant: ProductVariant | null | undefined): number | null;
5
6
  declare function getProductWeight(product: Product): number | null;
@@ -29,8 +30,8 @@ interface ResolvedPrice {
29
30
  discount: Discount | null;
30
31
  }
31
32
  /**
32
- * Определяет цену варианта с учётом склада.
33
- * Приоритет: prices[stockId] → prices[null] → top-level price.
33
+ * Resolves a variant's price, accounting for stock.
34
+ * Priority: prices[stockId] → prices[null] → top-level price.
34
35
  */
35
36
  declare function resolveVariantPrice(variant: ProductVariant, stockId?: string | null): ResolvedPrice;
36
37
  declare function useProductPricing(product: ComputedRef<Product>, stockId?: ComputedRef<string | null | undefined>): {
@@ -89,23 +90,22 @@ interface UseRelatedProductsApi {
89
90
  fetchForOrder: (orderId: string, orderToken: string, signal?: AbortSignal) => Promise<Product[]>;
90
91
  }
91
92
  /**
92
- * Один из вариантов товара и ни одного модификатора — такой товар можно класть
93
- * в корзину одним кликом по рекомендации, минуя открытие карточки.
93
+ * A single variant and no modifiers — such a product can be added to the cart
94
+ * directly with one click from a recommendation, without opening the product card.
94
95
  */
95
96
  declare function canAddDirectly(product: Product): boolean;
96
97
  declare function useRelatedProducts(): UseRelatedProductsApi;
97
98
 
98
99
  interface CatalogProductMatch {
99
100
  product: Product;
100
- catalogItem: CatalogItem;
101
+ catalogItem: StaticCatalogItem;
101
102
  }
102
- /** Поиск товара по short_id в статичном каталоге. null — если не найден. */
103
- declare function findProductInCatalog(catalog: CatalogItem[], shortId: string): CatalogProductMatch | null;
103
+ declare function findProductInCatalog(catalog: StaticCatalogItem[], shortId: string): CatalogProductMatch | null;
104
104
 
105
105
  interface UseProductDetailApi {
106
- /** Синхронный поиск по уже загруженному статичному каталогу. */
106
+ /** Synchronous search against the already-loaded static catalog. */
107
107
  findInCatalog: (shortId: string) => CatalogProductMatch | null;
108
- /** API-фолбэк, когда товара нет в каталоге. */
108
+ /** API fallback for when the product isn't in the catalog. */
109
109
  fetchProduct: (shortId: string) => Promise<Product | null>;
110
110
  }
111
111
  declare function useProductDetail(): UseProductDetailApi;
@@ -1,7 +1,7 @@
1
- export { canAddDirectly, findProductInCatalog, formatWeight, getProductWeight, getVariantWeight, resolveVariantPrice, toGrams, usePriceRecalculation, useProductDetail, useProductList, useProductPricing, useProductVariant, useProductVariantModifiers, useProductVariantSelector, useProductsByCategory, useRelatedProducts } from '../chunk-3FDM6T7F.js';
1
+ export { canAddDirectly, findProductInCatalog, formatWeight, getProductWeight, getVariantWeight, resolveVariantPrice, toGrams, usePriceRecalculation, useProductDetail, useProductList, useProductPricing, useProductVariant, useProductVariantModifiers, useProductVariantSelector, useProductsByCategory, useRelatedProducts } from '../chunk-32SLDGE5.js';
2
2
  import '../chunk-XUGXLJZB.js';
3
3
  import '../chunk-5QCUH3FF.js';
4
- import '../chunk-Z3IW4ODZ.js';
5
- import '../chunk-VFMVQR6Y.js';
4
+ import '../chunk-NSOIL7PW.js';
5
+ import '../chunk-QZ3S3NN3.js';
6
6
  //# sourceMappingURL=index.js.map
7
7
  //# sourceMappingURL=index.js.map
@@ -2,12 +2,12 @@ interface PromotionsChecker {
2
2
  dispatchCheck: () => Promise<void>;
3
3
  }
4
4
  /**
5
- * Проверка промо-акций. Вызывает dispatchPromotionsChecker после изменения корзины.
6
- * Результат приходит через WebSocket (обрабатывается в useOrderChannel).
5
+ * Checks promotions. Calls dispatchPromotionsChecker after the cart changes.
6
+ * The result arrives over WebSocket (handled in useOrderChannel).
7
7
  *
8
- * Резолвить синхронно в setup, а после await вызывать только `dispatchCheck` — как и
9
- * любой композабл ядра, см. раздел «Call composables and stores synchronously in setup»
10
- * в README.
8
+ * Resolve this synchronously in setup, and call only `dispatchCheck` after an
9
+ * await — like any core composable, see "Call composables and stores
10
+ * synchronously in setup" in the README.
11
11
  *
12
12
  * ```ts
13
13
  * const { dispatchCheck } = usePromotionsChecker()
@@ -1,5 +1,5 @@
1
- export { usePromotionsChecker } from '../chunk-5YD4AIY2.js';
2
- import '../chunk-Z247QRDJ.js';
3
- import '../chunk-VFMVQR6Y.js';
1
+ export { usePromotionsChecker } from '../chunk-46FNHMWC.js';
2
+ import '../chunk-XULHV6SS.js';
3
+ import '../chunk-QZ3S3NN3.js';
4
4
  //# sourceMappingURL=index.js.map
5
5
  //# sourceMappingURL=index.js.map
@@ -1,4 +1,4 @@
1
- import { Media, Store, Product, NestedCategory, Article, OfferArticle, Seo, SeoMetaTag } from '@zenky/storefront-api';
1
+ import { Media, Store, Product, NestedCategory, ProductsCollection, Article, OfferArticle, Seo, SeoMetaTag } from '@zenky/storefront-api';
2
2
 
3
3
  /**
4
4
  * Shared SEO types used across storefront composables.
@@ -29,44 +29,44 @@ declare function stripHtml(html: string): string;
29
29
  declare function prepareOgDescription(text: string | null | undefined, maxLength?: number): string | null;
30
30
 
31
31
  /**
32
- * Каноничный публичный origin сайта из `store.domain`. Fallback (хост запроса)
33
- * приносит потребитель — ядро не знает про useRequestURL.
32
+ * Canonical public origin of the site, from `store.domain`. The fallback (request host)
33
+ * is supplied by the consumer — the core doesn't know about `useRequestURL`.
34
34
  */
35
35
  declare function resolveSiteOrigin(storeDomain: string | null | undefined, fallbackOrigin: string): string;
36
36
 
37
37
  /**
38
- * JSON-LD schema.org/Product. Google → Rich Results (цена/наличие/рейтинг в выдаче).
39
- * Возвращает массив (0 или 1 объект) — потребитель оборачивает в `<script ld+json>`.
38
+ * JSON-LD schema.org/Product. Google uses it for Rich Results (price, availability,
39
+ * rating in search listings).
40
+ * Returns an array of 0 or 1 objects — the consumer wraps it in a `<script ld+json>` tag.
40
41
  * Spec: https://schema.org/Product
41
42
  */
42
43
  declare function buildProductSchema(product: Product, currency: string): Record<string, unknown>[];
43
44
 
44
- /**
45
- * JSON-LD для страницы категории: BreadcrumbList (хлебные крошки) + ItemList
46
- * (первые 10 товаров). Возвращает массив JSON-LD объектов (0–2).
47
- * Spec: https://schema.org/ItemList · https://schema.org/BreadcrumbList
48
- */
45
+ /** JSON-LD for a category page. */
49
46
  declare function buildCategorySchemas(category: NestedCategory, products: Product[], breadcrumbs: BreadcrumbItem[], origin: string): Record<string, unknown>[];
47
+ /** JSON-LD for a products collection page. */
48
+ declare function buildCollectionSchemas(collection: ProductsCollection, products: Product[], breadcrumbs: BreadcrumbItem[], origin: string): Record<string, unknown>[];
50
49
 
51
50
  /**
52
- * JSON-LD schema.org/Article для страницы акции (редакционный контент).
51
+ * JSON-LD schema.org/Article for the offer page's editorial copy.
53
52
  * Spec: https://schema.org/Article
54
53
  */
55
54
  declare function buildOfferArticleSchema(article: OfferArticle, storeName: string, origin: string): Record<string, unknown>[];
56
55
  /**
57
- * JSON-LD schema.org/BlogPosting для статьи блога (Google Rich Results).
56
+ * JSON-LD schema.org/BlogPosting for a blog article — enables Google Rich Results.
58
57
  * Spec: https://schema.org/BlogPosting
59
58
  */
60
59
  declare function buildBlogPostSchema(article: Article, storeName: string, origin: string): Record<string, unknown>[];
61
60
 
62
61
  /**
63
- * JSON-LD schema.org/Organization (или LocalBusiness при наличии физической точки)
64
- * для главной. Google → Knowledge Panel. Все данные из уже загруженного профиля.
62
+ * JSON-LD schema.org/Organization (or LocalBusiness if there's a physical location)
63
+ * for the homepage. Feeds Google's Knowledge Panel. All data comes from the
64
+ * already-loaded profile.
65
65
  * Spec: https://schema.org/Organization · https://schema.org/LocalBusiness
66
66
  */
67
67
  declare function buildOrganizationSchema(store: Store, origin: string): Record<string, unknown>[];
68
68
 
69
- /** Уже разрешённые (с учётом дефолтов потребителя) значения OG/Twitter-тегов. */
69
+ /** Already-resolved OG/Twitter tag values (with the consumer's defaults applied). */
70
70
  interface OgTagsInput {
71
71
  title: string | null;
72
72
  description?: string | null;
@@ -79,7 +79,7 @@ declare function buildOgTags(input: OgTagsInput): Record<string, string>[];
79
79
 
80
80
  /** SDK `Seo.meta` tags mapped to framework-neutral head meta records. */
81
81
  declare function mapSeoMetaTags(tags: SeoMetaTag[]): Record<string, string>[];
82
- /** meta-теги из `Seo`-сущности (description + маппинг `Seo.meta`). Title резолвит потребитель. */
82
+ /** Meta tags from a `Seo` entity (description + `Seo.meta` mapping). The consumer resolves the title. */
83
83
  declare function buildEntitySeoMeta(seo: Seo | null | undefined): Record<string, string>[];
84
84
 
85
- export { type BreadcrumbItem, type OgTagsInput, buildBlogPostSchema, buildCategorySchemas, buildEntitySeoMeta, buildOfferArticleSchema, buildOgTags, buildOrganizationSchema, buildProductSchema, mapSeoMetaTags, prepareOgDescription, resolveMediaUrl, resolveSiteOrigin, resolveStoreLogoUrl, stripHtml };
85
+ export { type BreadcrumbItem, type OgTagsInput, buildBlogPostSchema, buildCategorySchemas, buildCollectionSchemas, buildEntitySeoMeta, buildOfferArticleSchema, buildOgTags, buildOrganizationSchema, buildProductSchema, mapSeoMetaTags, prepareOgDescription, resolveMediaUrl, resolveSiteOrigin, resolveStoreLogoUrl, stripHtml };