@wix/himalaya-cli 0.1544.0 → 0.1545.0

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 (225) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/agent/src/index.d.ts +5 -2
  2. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/state/src/index.d.ts +14 -0
  3. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/state/src/read.d.ts +60 -0
  4. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/activity-counters-v1/src/index.d.ts +19 -0
  5. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/ai-site-chat/src/index.d.ts +19 -0
  6. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/analytics/src/index.d.ts +42 -2
  7. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/async-jobs/src/index.d.ts +19 -0
  8. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/automations-v1/src/index.d.ts +19 -0
  9. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/badges-v2/src/index.d.ts +19 -0
  10. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/billing-tax-v1/src/index.d.ts +19 -0
  11. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/blog-v3/src/extensions.d.ts +5 -4
  12. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/blog-v3/src/index.d.ts +19 -0
  13. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/bookings-v2/src/extensions.d.ts +4 -4
  14. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/bookings-v2/src/index.d.ts +19 -0
  15. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/business-feed/src/index.d.ts +11 -0
  16. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/business-tools-v1/src/index.d.ts +19 -0
  17. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/chat-web/src/index.d.ts +22 -1
  18. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/comments-v1/src/index.d.ts +19 -0
  19. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/contacts/src/index.d.ts +19 -0
  20. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/coupons/src/index.d.ts +24 -2
  21. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/crm-tasks/src/index.d.ts +11 -0
  22. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/dashboard-setup/src/index.d.ts +11 -0
  23. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/data-collections-v1/src/index.d.ts +19 -0
  24. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/donations/src/index.d.ts +19 -0
  25. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/ecom/src/extensions.d.ts +6 -5
  26. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/ecom/src/index.d.ts +19 -0
  27. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/email-marketing-v1/src/index.d.ts +19 -0
  28. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/events/src/index.d.ts +24 -2
  29. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/faq-v2/src/index.d.ts +19 -0
  30. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/forms/src/index.d.ts +19 -0
  31. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/forum/src/index.d.ts +19 -0
  32. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/genie-chat/src/index.d.ts +11 -0
  33. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/gift-cards/src/index.d.ts +19 -0
  34. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/groups/src/index.d.ts +19 -0
  35. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/inbox/src/extensions.d.ts +2 -1
  36. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/inbox/src/index.d.ts +19 -0
  37. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/invoices/src/index.d.ts +24 -2
  38. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/loyalty/src/index.d.ts +28 -4
  39. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/marketing-v1/src/index.d.ts +19 -0
  40. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/members-feed-viewer/src/index.d.ts +23 -1
  41. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/members-v1/src/index.d.ts +25 -3
  42. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/new-releases/src/index.d.ts +23 -1
  43. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/notification-preferences/src/index.d.ts +23 -2
  44. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/notifications-v3/src/index.d.ts +19 -0
  45. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/online-programs/src/index.d.ts +25 -3
  46. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/portfolio/src/index.d.ts +25 -3
  47. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/pricing-plans/src/index.d.ts +28 -6
  48. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/redirects-v1/src/index.d.ts +19 -0
  49. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/restaurants/src/extensions.d.ts +2 -2
  50. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/restaurants/src/index.d.ts +19 -0
  51. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/reviews/src/index.d.ts +24 -2
  52. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/seo-v1/src/index.d.ts +19 -0
  53. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/site-list/src/index.d.ts +19 -0
  54. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/site-media/src/index.d.ts +11 -0
  55. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/social-feed/src/index.d.ts +23 -1
  56. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/stores-collections/src/display.d.ts +3 -2
  57. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/stores-collections/src/index.d.ts +27 -3
  58. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/stores-v1/src/catalog.d.ts +7 -7
  59. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/stores-v1/src/display.d.ts +4 -3
  60. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/stores-v1/src/extensions.d.ts +2 -1
  61. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/stores-v1/src/index.d.ts +19 -0
  62. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/table-reservations/src/index.d.ts +25 -3
  63. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/users/src/index.d.ts +23 -1
  64. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/video/src/index.d.ts +19 -0
  65. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/wix-data/src/index.d.ts +27 -3
  66. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/workflows-v1/src/index.d.ts +19 -0
  67. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk-auto/_shared/runtime.generated.d.ts +8 -0
  68. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/checkout.mjs +12 -4
  69. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/screens.mjs +36 -11
  70. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/state.mjs +206 -12
  71. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-activity-counters.mjs +19 -5
  72. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-ai-site-chat.mjs +19 -5
  73. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-analytics.mjs +21 -7
  74. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-async-jobs.mjs +19 -5
  75. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-automations.mjs +19 -5
  76. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-badges.mjs +19 -5
  77. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-billing-tax.mjs +19 -5
  78. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-blog.mjs +31 -14
  79. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-bookings.mjs +26 -12
  80. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-business-tools.mjs +20 -6
  81. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-chat-web.mjs +29 -7
  82. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-comments.mjs +28 -5
  83. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-contacts.mjs +19 -5
  84. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-coupons.mjs +14 -6
  85. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-data-collections.mjs +19 -5
  86. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-data.mjs +15 -5
  87. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-donations.mjs +19 -5
  88. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-ecom.mjs +33 -16
  89. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-email-marketing.mjs +19 -5
  90. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-events.mjs +14 -6
  91. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-faq.mjs +20 -6
  92. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-forms.mjs +19 -5
  93. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-forum.mjs +19 -5
  94. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-gift-cards.mjs +19 -5
  95. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-groups.mjs +19 -5
  96. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-inbox.mjs +21 -7
  97. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-invoices.mjs +14 -6
  98. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-loyalty.mjs +16 -8
  99. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-marketing.mjs +19 -5
  100. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-members-feed-viewer.mjs +21 -10
  101. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-members.mjs +17 -8
  102. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-new-releases.mjs +17 -5
  103. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-notification-preferences.mjs +20 -6
  104. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-notifications.mjs +19 -5
  105. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-online-programs.mjs +16 -8
  106. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-portfolio.mjs +16 -8
  107. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-pricing-plans.mjs +22 -14
  108. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-redirects.mjs +19 -5
  109. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-restaurants.mjs +22 -7
  110. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-reviews.mjs +14 -6
  111. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-rich-content-editor.mjs +3 -0
  112. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-seo.mjs +19 -5
  113. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-site-list.mjs +19 -5
  114. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-social-feed.mjs +15 -5
  115. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-stores-collections.mjs +20 -10
  116. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-stores.mjs +116 -83
  117. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-table-reservations.mjs +16 -8
  118. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-users.mjs +15 -5
  119. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-video.mjs +9 -1
  120. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-workflows.mjs +19 -5
  121. package/dist/cli.mjs +90 -57
  122. package/dist/preview-assets.generated.bin +0 -0
  123. package/fixtures/wix-canned.json +8 -8
  124. package/guides/dynamic-list.service.ts +38 -29
  125. package/guides/form-submit.service.ts +2 -1
  126. package/guides/index.json +6 -0
  127. package/guides/offline-reading.md +63 -0
  128. package/guides/recipe-dynamic-list.md +2 -0
  129. package/guides/recipe-four-state.md +1 -0
  130. package/guides/sdk-reference.json +225 -99
  131. package/guides/testing-himi-apps.md +2 -0
  132. package/guides/tier-5-add-a-screen.md +2 -0
  133. package/package.json +2 -2
  134. package/templates/beauty-salon/dev/index.ts +4 -3
  135. package/templates/beauty-salon/tier5-src/_shared/collection-service.ts +6 -9
  136. package/templates/beauty-salon/tier5-src/_shared/iap-presentation.ts +7 -3
  137. package/templates/beauty-salon/tier5-src/himi-branded-lite-home/index.ts +1 -1
  138. package/templates/beauty-salon/tier5-src/himi-branded-lite-orders/index.ts +3 -0
  139. package/templates/beauty-salon-owner/dev/index.ts +19 -19
  140. package/templates/beauty-salon-owner/tier5-src/_shared/collection-service.ts +6 -9
  141. package/templates/beauty-salon-owner/tier5-src/_shared/owner-module-data.ts +1 -1
  142. package/templates/branded-lite/dev/index.ts +38 -20
  143. package/templates/branded-lite/tier5-src/_shared/collection-query-legacy.ts +194 -0
  144. package/templates/branded-lite/tier5-src/_shared/collection-query.ts +158 -99
  145. package/templates/branded-lite/tier5-src/_shared/collection-service.ts +31 -11
  146. package/templates/branded-lite/tier5-src/_shared/iap-presentation.ts +7 -3
  147. package/templates/branded-lite/tier5-src/_shared/read-service.ts +255 -0
  148. package/templates/branded-lite/tier5-src/himi-branded-lite-home/index.ts +1 -1
  149. package/templates/branded-lite/tier5-src/himi-branded-lite-orders/index.ts +3 -0
  150. package/templates/branded-lite/tier5-src/himi-branded-lite-shop/index.ts +202 -159
  151. package/templates/branded-lite/tier5-src/himi-store-product/index.ts +130 -201
  152. package/templates/community-club/dev/index.ts +4 -4
  153. package/templates/community-club/tier5-src/_shared/collection-service.ts +6 -9
  154. package/templates/community-club/tier5-src/_shared/iap-presentation.ts +7 -3
  155. package/templates/community-club/tier5-src/himi-branded-lite-home/index.ts +1 -1
  156. package/templates/community-club-owner/dev/index.ts +19 -19
  157. package/templates/community-club-owner/tier5-src/_shared/collection-service.ts +6 -9
  158. package/templates/community-club-owner/tier5-src/_shared/owner-module-data.ts +1 -1
  159. package/templates/events-meetups/dev/index.ts +3 -3
  160. package/templates/events-meetups/tier5-src/_shared/collection-service.ts +6 -9
  161. package/templates/events-meetups/tier5-src/_shared/iap-presentation.ts +7 -3
  162. package/templates/events-meetups/tier5-src/himi-branded-lite-home/index.ts +1 -1
  163. package/templates/events-meetups-owner/dev/index.ts +17 -17
  164. package/templates/events-meetups-owner/tier5-src/_shared/collection-service.ts +6 -9
  165. package/templates/events-meetups-owner/tier5-src/_shared/owner-module-data.ts +1 -1
  166. package/templates/gym-fitness/dev/index.ts +5 -4
  167. package/templates/gym-fitness/tier5-src/_shared/collection-service.ts +6 -9
  168. package/templates/gym-fitness/tier5-src/_shared/iap-presentation.ts +7 -3
  169. package/templates/gym-fitness/tier5-src/himi-branded-lite-home/index.ts +1 -1
  170. package/templates/gym-fitness/tier5-src/himi-branded-lite-orders/index.ts +3 -0
  171. package/templates/gym-fitness-owner/dev/index.ts +20 -20
  172. package/templates/gym-fitness-owner/tier5-src/_shared/collection-service.ts +6 -9
  173. package/templates/gym-fitness-owner/tier5-src/_shared/owner-module-data.ts +1 -1
  174. package/templates/nonprofit-cause/dev/index.ts +4 -4
  175. package/templates/nonprofit-cause/tier5-src/_shared/collection-service.ts +6 -9
  176. package/templates/nonprofit-cause/tier5-src/_shared/iap-presentation.ts +7 -3
  177. package/templates/nonprofit-cause/tier5-src/himi-branded-lite-home/index.ts +1 -1
  178. package/templates/nonprofit-cause-owner/dev/index.ts +18 -18
  179. package/templates/nonprofit-cause-owner/tier5-src/_shared/collection-service.ts +6 -9
  180. package/templates/nonprofit-cause-owner/tier5-src/_shared/owner-module-data.ts +1 -1
  181. package/templates/owner-lite/dev/index.ts +20 -20
  182. package/templates/owner-lite/tier5-src/_shared/collection-service.ts +6 -9
  183. package/templates/owner-lite/tier5-src/_shared/owner-module-data.ts +1 -1
  184. package/templates/podcast-creator/dev/index.ts +4 -4
  185. package/templates/podcast-creator/tier5-src/_shared/collection-service.ts +6 -9
  186. package/templates/podcast-creator/tier5-src/_shared/iap-presentation.ts +7 -3
  187. package/templates/podcast-creator/tier5-src/himi-branded-lite-home/index.ts +1 -1
  188. package/templates/podcast-creator-owner/dev/index.ts +19 -19
  189. package/templates/podcast-creator-owner/tier5-src/_shared/collection-service.ts +6 -9
  190. package/templates/podcast-creator-owner/tier5-src/_shared/owner-module-data.ts +1 -1
  191. package/templates/portfolio-creative/dev/index.ts +5 -4
  192. package/templates/portfolio-creative/tier5-src/_shared/collection-service.ts +6 -9
  193. package/templates/portfolio-creative/tier5-src/_shared/iap-presentation.ts +7 -3
  194. package/templates/portfolio-creative/tier5-src/himi-branded-lite-home/index.ts +1 -1
  195. package/templates/portfolio-creative/tier5-src/himi-branded-lite-orders/index.ts +3 -0
  196. package/templates/portfolio-creative-owner/dev/index.ts +19 -19
  197. package/templates/portfolio-creative-owner/tier5-src/_shared/collection-service.ts +6 -9
  198. package/templates/portfolio-creative-owner/tier5-src/_shared/owner-module-data.ts +1 -1
  199. package/templates/restaurant/dev/index.ts +3 -3
  200. package/templates/restaurant/tier5-src/_shared/collection-service.ts +6 -9
  201. package/templates/restaurant/tier5-src/_shared/iap-presentation.ts +7 -3
  202. package/templates/restaurant/tier5-src/himi-branded-lite-home/index.ts +1 -1
  203. package/templates/restaurant-owner/dev/index.ts +20 -20
  204. package/templates/restaurant-owner/tier5-src/_shared/collection-service.ts +6 -9
  205. package/templates/restaurant-owner/tier5-src/_shared/owner-module-data.ts +1 -1
  206. package/templates/retail-store/dev/index.ts +19 -1
  207. package/templates/retail-store/tier5-src/_shared/collection-query-legacy.ts +194 -0
  208. package/templates/retail-store/tier5-src/_shared/collection-query.ts +158 -99
  209. package/templates/retail-store/tier5-src/_shared/collection-service.ts +31 -11
  210. package/templates/retail-store/tier5-src/_shared/iap-presentation.ts +7 -3
  211. package/templates/retail-store/tier5-src/_shared/read-service.ts +255 -0
  212. package/templates/retail-store/tier5-src/himi-branded-lite-home/index.ts +1 -1
  213. package/templates/retail-store/tier5-src/himi-branded-lite-orders/index.ts +3 -0
  214. package/templates/retail-store/tier5-src/himi-branded-lite-shop/index.ts +202 -159
  215. package/templates/retail-store/tier5-src/himi-store-product/index.ts +130 -201
  216. package/templates/retail-store-owner/dev/index.ts +18 -18
  217. package/templates/retail-store-owner/tier5-src/_shared/collection-service.ts +6 -9
  218. package/templates/retail-store-owner/tier5-src/_shared/owner-module-data.ts +1 -1
  219. package/templates/yoga-studio/dev/index.ts +4 -4
  220. package/templates/yoga-studio/tier5-src/_shared/collection-service.ts +6 -9
  221. package/templates/yoga-studio/tier5-src/_shared/iap-presentation.ts +7 -3
  222. package/templates/yoga-studio/tier5-src/himi-branded-lite-home/index.ts +1 -1
  223. package/templates/yoga-studio-owner/dev/index.ts +18 -18
  224. package/templates/yoga-studio-owner/tier5-src/_shared/collection-service.ts +6 -9
  225. package/templates/yoga-studio-owner/tier5-src/_shared/owner-module-data.ts +1 -1
@@ -1,3 +1,4 @@
1
+ import { withReadLifecycle, readOptions } from "../_shared/read-service.js";
1
2
  import { withOnlineWrites, offlineWritesEnabled, offlineWriteMessage } from "../_shared/online-actions.js";
2
3
  import { defineService as registerState } from "@himalaya/state";
3
4
  // Tier-5 bundle: himi-store — product detail.
@@ -6,7 +7,10 @@ import { storesAppleSalesEnabled, storesProductOrders, type IapCommerce, type Ia
6
7
  import { iapPriceCopy, iapPurchaseCopy } from "../_shared/iap-worker.js";
7
8
  import { share as shareSheet } from "@himalaya/share";
8
9
  import { addToCurrentCart, getCurrentCart } from "@himalaya/wix-ecom";
9
- import { get, upsert, enqueue, type DbEntity } from "@himalaya/local-db";
10
+ import { upsert, enqueue, type DbEntity } from "@himalaya/local-db";
11
+
12
+ async function cartPut(row: DbEntity): Promise<void> { try { await upsert("cart", row); } catch { /* capability not granted */ } }
13
+ async function queueWrite(actionId: string, params: Record<string, string>): Promise<void> { try { await enqueue(actionId, params); } catch { /* capability not granted */ } }
10
14
  import { getStoreProduct, plainText, productImage, productPrice, wixMediaUrl, productGallery as sdkProductGallery, WIX_DETAIL_IMAGE, type StoreProduct,
11
15
  productOptions, defaultSelection, isSelectionComplete, selectionSummary, cartOptionsPayload,
12
16
  type StoreOption, type StoreOptionChoice, type StoreOptionSelection } from "../_shared/himi-store.js";
@@ -17,21 +21,6 @@ import { isProductSaved, toggleSavedProduct } from "../_shared/himi-store-saved.
17
21
  import { openRichLink } from "../_shared/rich-content-link.js";
18
22
  import { richBody } from "../_shared/rich-body.js";
19
23
 
20
- // Offline-first (data-offline): the detail is a public READ-THROUGH — when the live
21
- // product fetch fails (offline) fall back to the last-synced row the catalog cached
22
- // under the `products` entity. `addToCart` is WRITE-BEHIND against the `cart` entity —
23
- // the line is cached OPTIMISTICALLY, then the Wix write is attempted; if it can't
24
- // reach the bridge/network the add is ENQUEUED for replay on reconnect. Every local-db
25
- // call is wrapped so a build without the `local_database` grant behaves exactly as
26
- // before (online-only, no cache/queue).
27
- const PRODUCTS_ENTITY = "products";
28
- const CART_ENTITY = "cart";
29
- async function readCachedProduct(id: string): Promise<DbEntity | null> {
30
- try { return await get(PRODUCTS_ENTITY, id); } catch { /* capability not granted → online-only */ return null; }
31
- }
32
- async function cartPut(row: DbEntity): Promise<void> { try { await upsert(CART_ENTITY, row); } catch { /* capability not granted */ } }
33
- async function queueWrite(actionId: string, params: Record<string, string>): Promise<void> { try { await enqueue(actionId, params); } catch { /* capability not granted */ } }
34
-
35
24
  /** Live cart size (sum of line-item quantities) for the top-bar cart badge.
36
25
  * Best-effort: a cart error just yields 0 (badge hidden), never fails the screen. */
37
26
  async function cartItemCount(): Promise<number> {
@@ -95,25 +84,6 @@ function productPolicyBody(product: StoreProduct, kind: "returns" | "shipping"):
95
84
  * DIFFERENT product (drop the picks) from the same product coming back (keep them). */
96
85
  let lastLoadedId: string | undefined;
97
86
  let productLoadSequence = 0;
98
- let booting = true;
99
- let bootLoad: { id: string; state: Promise<S> } | undefined;
100
-
101
- /** The host replays the screen's onAppear load right after the module-scope one: that one replay
102
- * joins the boot load instead of reading the product, cart and App Store prices again. Any later
103
- * entry loads afresh, since the cart, the saved flag or a purchase may have changed meanwhile. */
104
- function joinedLoad(id: string, load: () => Promise<S>): Promise<S> {
105
- if (booting) {
106
- booting = false;
107
- const current = { id, state: load() };
108
- bootLoad = current;
109
- const settle = () => { if (bootLoad === current) bootLoad = undefined; };
110
- current.state.then(settle, settle);
111
- return current.state;
112
- }
113
- const replayed = bootLoad;
114
- bootLoad = undefined;
115
- return replayed?.id === id ? replayed.state : load();
116
- }
117
87
 
118
88
  interface OptionSlots {
119
89
  opt1Label: string; opt1Chips: OptionChip[]; opt1Selected: string[]; opt1SelectedId: string; opt1Placeholder: string; noOpt1: boolean;
@@ -280,6 +250,7 @@ interface S {
280
250
  emptyText: string;
281
251
  isLoading: boolean;
282
252
  notLoading: boolean;
253
+ hideContent: boolean;
283
254
  isErrored: boolean;
284
255
  notErrored: boolean;
285
256
  noEmpty: boolean;
@@ -435,6 +406,7 @@ function derive(s: S): S {
435
406
  notAdded: !s.added,
436
407
  isLoading: s.status === "loading",
437
408
  notLoading: s.status !== "loading",
409
+ hideContent: s.status !== "ready" || !s.name,
438
410
  isErrored: s.status === "error",
439
411
  notErrored: s.status !== "error",
440
412
  noEmpty: s.status === "loading" || s.status === "error" || !empty,
@@ -460,11 +432,11 @@ const NOT_APPLE: IapPurchaseFields = { appleRoute: false, accessReady: false, bu
460
432
 
461
433
  let productPricing: IapCommerce;
462
434
  let checkoutEntered = false;
463
- const defineService = withIapPresentation<S>({
435
+ const registerProduct = withIapPresentation<S>({
464
436
  register: withOnlineWrites(registerState, ["beginAdd", "addToCart", "buy"], { derive, messageFields: action => action === "buy" ? ["buyNote"] : ["cartHint"] }),
465
437
  adapters: SELLS_THROUGH_APPLE ? [storesProductOrders] : [],
466
438
  onCreate: commerce => { productPricing = commerce; }, prefix: "product",
467
- transientKeys: ["price", "optionsIncomplete", "cartHint", "cartHidden", "buyHidden", "buyLabel", "buyDisabled", "buyNote", "purchasedNote", "addedSheetPresented", "shareHint"], contentActions: ["load", "paintCached"], concurrentPublishActions: ["buy"],
439
+ transientKeys: ["price", "optionsIncomplete", "cartHint", "cartHidden", "buyHidden", "buyLabel", "buyDisabled", "buyNote", "purchasedNote", "addedSheetPresented", "shareHint"], contentActions: ["load", "readChanged"], concurrentPublishActions: ["buy"],
468
440
  items: state => inputId() ? [{ reference: { kind: "storesProduct", id: inputId() }, commerceDisplayPrice: state.price }] : [],
469
441
  present: (state, price, allowed) => {
470
442
  const purchase = applePurchase(state);
@@ -475,14 +447,33 @@ const defineService = withIapPresentation<S>({
475
447
  return {
476
448
  ...state, price: price(inputId()), ...(purchase.appleRoute ? { wasPrice: "", wasPriceEmpty: false, notOnSale: true } : {}), optionsIncomplete: derive(state).optionsIncomplete || !allowed(inputId()) || lastProduct?.productType?.toLowerCase() === "digital",
477
449
  cartHint, noCartHint: !cartHint || state.added, addDisabled: state.addDisabled || blocked,
478
- cartHidden: purchase.appleRoute,
479
- buyHidden: !purchase.appleRoute || purchase.accessReady, buyLabel: purchase.buyLabel, buyDisabled: purchase.buyDisabled,
450
+ cartHidden: state.status !== "ready" || !state.name || purchase.appleRoute,
451
+ buyHidden: state.status !== "ready" || !state.name || !purchase.appleRoute || purchase.accessReady, buyLabel: purchase.buyLabel, buyDisabled: purchase.buyDisabled,
480
452
  buyNote: state.buyNote === offlineWriteMessage ? state.buyNote : purchase.buyNote,
481
453
  purchasedNote: purchase.accessReady ? copyParam("product.purchasedText", "Purchased") : "",
482
454
  };
483
455
  },
484
456
  });
485
457
 
458
+ // Read recovery commits content before IAP sidecars project prices. Cache and network
459
+ // reads stay inside one safe read lifecycle; price publications never become read results.
460
+ const defineService = withReadLifecycle(registerProduct, "load", {
461
+ // Missing route input is authored local content, not a server response or cache hit.
462
+ localResult: () => !inputId(),
463
+ onInvalidate: () => {
464
+ productLoadSequence++;
465
+ lastProduct = undefined;
466
+ lastLoadedId = undefined;
467
+ cartBadgeEpoch++;
468
+ },
469
+ unavailable: state => {
470
+ lastProduct = undefined;
471
+ lastLoadedId = undefined;
472
+ return { ...derive(state as unknown as S) };
473
+ },
474
+ authoredFallback: state => !inputId() ? { ...derive({ ...state, status: "ready", emptyText: copyParam("product.notFoundText", "Product not found.") } as unknown as S) } : undefined,
475
+ });
476
+
486
477
  /** The App Store action, only for the one shape it sells: digital, with no options to choose, read
487
478
  * from the product loaded for the id on screen (as Add to cart is). A cached product whose
488
479
  * options were never read is not known to have none. */
@@ -502,7 +493,8 @@ function enterCheckout(): void {
502
493
  checkoutEntered = true;
503
494
  }
504
495
 
505
- const svc = defineService<S, {
496
+ const onlineService = defineService;
497
+ const svc = onlineService<S, {
506
498
  load: (s: S, arg?: unknown) => Promise<S>;
507
499
  setQuantity: (s: S, arg?: unknown) => S;
508
500
  toggleReturnPolicy: (s: S) => S;
@@ -510,7 +502,6 @@ const svc = defineService<S, {
510
502
  selectOption: (s: S, arg?: unknown) => S;
511
503
  addToCart: (s: S) => Promise<S>;
512
504
  beginAdd: (s: S, arg?: unknown) => S;
513
- paintCached: (s: S, arg?: unknown) => S;
514
505
  setCartCount: (s: S, arg?: unknown) => S;
515
506
  share: (s: S) => Promise<S>;
516
507
  toggleSave: (s: S) => S;
@@ -565,7 +556,7 @@ const svc = defineService<S, {
565
556
  notAdded: true,
566
557
  emptyText: "",
567
558
  isLoading: true,
568
- notLoading: false,
559
+ notLoading: false, hideContent: true,
569
560
  isErrored: false,
570
561
  notErrored: true,
571
562
  noEmpty: true,
@@ -600,146 +591,106 @@ const svc = defineService<S, {
600
591
  purchasedNote: "",
601
592
  }),
602
593
  actions: {
603
- load: (s, arg): Promise<S> => {
594
+ load: async (s, arg): Promise<S> => {
604
595
  stashCopy(arg);
605
- return joinedLoad(inputId(), async (): Promise<S> => {
606
- enterCheckout();
607
- const sequence = ++productLoadSequence;
596
+ enterCheckout();
597
+ const sequence = ++productLoadSequence;
598
+ const id = inputId();
599
+ // A managed refresh retains the raw product used by the still-visible snapshot.
600
+ // Navigation and legacy loaders keep their existing reset behavior.
601
+ if (!readOptions(arg) || id !== lastLoadedId) lastProduct = undefined;
602
+ // Storage problems must not prevent browsing or buying a product.
603
+ let saved = false;
604
+ try { saved = isProductSaved(id); } catch { /* save action reports a retryable error */ }
605
+ s = { ...s, saved, saveHint: "",
606
+ ...(id !== lastLoadedId ? { adding: false, added: false, shareHint: "", addedSheetPresented: false, quantity: 1, showOptionErrors: false, returnPolicyExpanded: false, shippingInfoExpanded: false } : {}) };
607
+ // A fresh navigation into the product resets any quantity left over
608
+ // from a previous visit to the same worker instance.
609
+ if (!id) {
608
610
  lastProduct = undefined;
609
- const id = inputId();
610
- // Storage problems must not prevent browsing or buying a product.
611
- let saved = false;
612
- try { saved = isProductSaved(id); } catch { /* save action reports a retryable error */ }
613
- s = { ...s, saved, saveHint: "", shareHint: "", adding: false, added: false, addedSheetPresented: false, quantity: 1, showOptionErrors: false, returnPolicyExpanded: false, shippingInfoExpanded: false };
614
- // A fresh navigation into the product resets any quantity left over
615
- // from a previous visit to the same worker instance.
616
- if (!id) {
617
- lastProduct = undefined;
618
- lastLoadedId = undefined;
619
- return derive({ ...s, status: "ready", quantity: 1, optionGroups: [], selection: {}, optionsUnknown: false, descriptionJson: "", emptyText: copyParam("product.notFoundText", "Product not found.") });
620
- }
621
- // The cart count only feeds the top-bar badge: ask for it NOW, beside the product, instead
622
- // of after it — it used to add a whole cart round trip before the page could paint.
623
- const cartCount = cartItemCount();
624
- // The badge must never hold the page: remember the count if it is already in, and
625
- // publish it separately if it lands after the product (#3468 review).
626
- let cartKnown: number | undefined;
627
- void cartCount.then((n) => { cartKnown = n; }, () => {});
628
- // The live product read goes out FIRST too — the local-db read below must never delay it.
629
- // Settled into a value so a failure is handled where it is awaited, never unhandled.
630
- // DESCRIPTION widens the default fieldset with the V3 Ricos description (a V1 catalog ignores it).
631
- const live = getStoreProduct(id, ["DESCRIPTION"]).then(
632
- (r) => ({ ok: true as const, r }),
633
- () => ({ ok: false as const }),
634
- );
635
- // Paint at once from the row the list already synced (name, price, image) — the page used
636
- // to sit on its skeleton for the product round trip even when the list had just shown it.
637
- // The live read then fills in the description and gallery.
638
- const synced = await readCachedProduct(id);
639
- let painted = false;
640
- if (synced && s.status === "loading") {
641
- await svc.paintCached(synced);
642
- painted = true;
643
- }
644
- const outcome = await live;
645
- if (sequence !== productLoadSequence || id !== inputId()) return svc.getState() as S;
646
- // Once painted the page is INTERACTIVE while the live read is on the wire: the visitor may
647
- // save, change the quantity or add to cart. Build on the state as it is NOW, and keep what
648
- // they did — overwriting it would untick a stored save, reset the quantity, and drop the
649
- // in-flight add's `adding` guard (a second tap would add the line twice).
650
- const base: S = painted ? (svc.getState() as S) : s;
651
- const keep = painted
652
- ? { saved: base.saved, saveHint: base.saveHint, quantity: base.quantity, adding: base.adding, added: base.added, cartHint: base.cartHint }
653
- : { cartHint: "", quantity: 1 };
654
- const badge = (): number => {
655
- if (painted && (base.adding || base.added)) return base.cartCount;
656
- if (cartKnown !== undefined) return cartKnown;
657
- const epoch = cartBadgeEpoch;
658
- void cartCount.then((n) => { void svc.setCartCount({ count: n, epoch }); }, () => {});
659
- return base.cartCount;
660
- };
661
- if (outcome.ok) {
662
- const p = (outcome.r.product ?? (outcome.r as unknown as StoreProduct)) as StoreProduct;
663
- const name = cleanTitle(p.name) || "Product";
664
- const image = productImage(p, WIX_DETAIL_IMAGE);
665
- lastProduct = p;
666
- // A group with exactly one choice is chosen for the shopper; a real choice
667
- // is left blank so the pick is deliberate.
668
- const optionGroups = productOptions(p);
669
- const sale = productSale(p);
670
- // A pooled screen re-appearing re-runs `load`. Wiping `selection` there means a
671
- // trip to the cart and back silently clears the size the shopper picked and
672
- // re-disables the CTA with no explanation. Carry the picks when this is the SAME
673
- // product, and only for a choice the product still offers — a stale id would
674
- // resolve to no variant and block the cart just as silently.
675
- const carried: StoreOptionSelection = {};
676
- if (id === lastLoadedId) {
677
- for (const g of optionGroups) {
678
- const chosen = s.selection[g.id];
679
- if (chosen && g.choices.some((c) => c.id === chosen)) carried[g.id] = chosen;
680
- }
611
+ lastLoadedId = undefined;
612
+ return derive({ ...s, status: "ready", quantity: 1, optionGroups: [], selection: {}, optionsUnknown: false, descriptionJson: "", emptyText: copyParam("product.notFoundText", "Product not found.") });
613
+ }
614
+ // The cart count only feeds the top-bar badge: ask for it NOW, beside the product, instead
615
+ // of after it — it used to add a whole cart round trip before the page could paint.
616
+ const cartCount = readOptions(arg)?.cache === "only-if-cached" ? Promise.resolve(s.cartCount) : cartItemCount();
617
+ // The badge must never hold the page: remember the count if it is already in, and
618
+ // publish it separately if it lands after the product (#3468 review).
619
+ let cartKnown: number | undefined;
620
+ void cartCount.then((n) => { cartKnown = n; }, () => {});
621
+ // The live product read goes out FIRST too — the local-db read below must never delay it.
622
+ // Settled into a value so a failure is handled where it is awaited, never unhandled.
623
+ // DESCRIPTION widens the default fieldset with the V3 Ricos description (a V1 catalog ignores it).
624
+ const live = getStoreProduct(id, ["DESCRIPTION"], readOptions(arg)).then(
625
+ (r) => ({ ok: true as const, r }),
626
+ (error) => ({ ok: false as const, error }),
627
+ );
628
+ const outcome = await live;
629
+ if (sequence !== productLoadSequence || id !== inputId()) return svc.getState() as S;
630
+ // The cache may have painted AFTER this network read started. Check the
631
+ // current state when the response lands, not the captured loading state.
632
+ const current = svc.getState() as S;
633
+ const painted = current.status === "ready" && lastLoadedId === id;
634
+ // Once painted the page is INTERACTIVE while the live read is on the wire: the visitor may
635
+ // save, change the quantity or add to cart. Build on the state as it is NOW, and keep what
636
+ // they did — overwriting it would untick a stored save, reset the quantity, and drop the
637
+ // in-flight add's `adding` guard (a second tap would add the line twice).
638
+ const base: S = painted ? current : s;
639
+ const keep = painted
640
+ ? { saved: base.saved, saveHint: base.saveHint, quantity: base.quantity, adding: base.adding, added: base.added, cartHint: base.cartHint }
641
+ : { cartHint: "", quantity: 1 };
642
+ const badge = (): number => {
643
+ if (painted && (base.adding || base.added)) return base.cartCount;
644
+ if (cartKnown !== undefined) return cartKnown;
645
+ const epoch = cartBadgeEpoch;
646
+ void cartCount.then((n) => { void svc.setCartCount({ count: n, epoch }); }, () => {});
647
+ return base.cartCount;
648
+ };
649
+ if (outcome.ok) {
650
+ const p = (outcome.r.product ?? (outcome.r as unknown as StoreProduct)) as StoreProduct;
651
+ const name = cleanTitle(p.name) || "Product";
652
+ const image = productImage(p, WIX_DETAIL_IMAGE);
653
+ lastProduct = p;
654
+ // A group with exactly one choice is chosen for the shopper; a real choice
655
+ // is left blank so the pick is deliberate.
656
+ const optionGroups = productOptions(p);
657
+ const sale = productSale(p);
658
+ // A pooled screen re-appearing re-runs `load`. Wiping `selection` there means a
659
+ // trip to the cart and back silently clears the size the shopper picked and
660
+ // re-disables the CTA with no explanation. Carry the picks when this is the SAME
661
+ // product, and only for a choice the product still offers — a stale id would
662
+ // resolve to no variant and block the cart just as silently.
663
+ const carried: StoreOptionSelection = {};
664
+ if (id === lastLoadedId) {
665
+ for (const g of optionGroups) {
666
+ const chosen = base.selection[g.id];
667
+ if (chosen && g.choices.some((c) => c.id === chosen)) carried[g.id] = chosen;
681
668
  }
682
- lastLoadedId = id;
683
- return derive({
684
- ...base,
685
- ...keep,
686
- status: "ready",
687
- optionGroups,
688
- selection: { ...defaultSelection(optionGroups), ...carried },
689
- optionsUnknown: false,
690
- name,
691
- ...sale,
692
- commercePrice: sale.price,
693
- skuLabel: skuOf(p) ? `SKU: ${skuOf(p)}` : "",
694
- returnPolicyBody: productPolicyBody(p, "returns") || copyParam("product.returnPolicyBody", "") || copyParam("product.policyUnavailable", "Policy details have not been provided by this store."),
695
- shippingInfoBody: productPolicyBody(p, "shipping") || copyParam("product.shippingInfoBody", "") || copyParam("product.policyUnavailable", "Policy details have not been provided by this store."),
696
- ...productBody(p),
697
- image,
698
- gallery: productGallery(p),
699
- initial: (name[0] || "#").toUpperCase(),
700
- shareUrl: productShareUrl(p),
701
- cartCount: badge(),
702
- emptyText: "",
703
- });
704
- }
705
- // Offline: fall back to the last-synced cached product row before the error state.
706
- if (synced) {
707
- const name = String(synced.name ?? "") || "Product";
708
- const image = String(synced.image ?? "");
709
- // The cached list row carries no options, and guessing "none" would offer
710
- // a one-tap Add to cart for a product that needs a colour and a size. So
711
- // the offline detail shows no picker AND marks the options UNKNOWN, which
712
- // keeps `optionsIncomplete` true: the CTA stays disabled and `addToCart`
713
- // refuses. `cartHint` carries the reason, because the options card is hidden
714
- // on `noOptions` and would otherwise leave a dead button unexplained.
715
- lastProduct = undefined;
716
- lastLoadedId = undefined;
717
- return derive({
718
- ...base,
719
- ...keep,
720
- status: "ready",
721
- optionGroups: [],
722
- selection: {},
723
- optionsUnknown: true,
724
- name,
725
- price: String(synced.subtitle ?? ""),
726
- wasPrice: "",
727
- skuLabel: "",
728
- returnPolicyBody: "",
729
- shippingInfoBody: "",
730
- description: "",
731
- descriptionJson: "",
732
- image,
733
- initial: String(synced.initial ?? "") || (name[0] || "#").toUpperCase(),
734
- cartHint: copyParam("product.cartHintOffline", "Reconnect to choose options and add this to your cart."),
735
- cartCount: badge(),
736
- emptyText: "",
737
- });
738
669
  }
739
- lastProduct = undefined;
740
- lastLoadedId = undefined;
741
- return derive({ ...s, status: "error", optionGroups: [], selection: {}, optionsUnknown: false, descriptionJson: "", emptyText: copyParam("product.errorText", "Product could not load.") });
742
- });
670
+ lastLoadedId = id;
671
+ return derive({
672
+ ...base,
673
+ ...keep,
674
+ status: "ready",
675
+ optionGroups,
676
+ selection: { ...defaultSelection(optionGroups), ...carried },
677
+ optionsUnknown: false,
678
+ name,
679
+ ...sale,
680
+ commercePrice: sale.price,
681
+ skuLabel: skuOf(p) ? `SKU: ${skuOf(p)}` : "",
682
+ returnPolicyBody: productPolicyBody(p, "returns") || copyParam("product.returnPolicyBody", "") || copyParam("product.policyUnavailable", "Policy details have not been provided by this store."),
683
+ shippingInfoBody: productPolicyBody(p, "shipping") || copyParam("product.shippingInfoBody", "") || copyParam("product.policyUnavailable", "Policy details have not been provided by this store."),
684
+ ...productBody(p),
685
+ image,
686
+ gallery: productGallery(p),
687
+ initial: (name[0] || "#").toUpperCase(),
688
+ shareUrl: productShareUrl(p),
689
+ cartCount: badge(),
690
+ emptyText: "",
691
+ });
692
+ }
693
+ throw outcome.error;
743
694
  },
744
695
  // The stepper fires onChange with { value } on every tap; clamp 1–99 and
745
696
  // ignore unparsable/garbage args instead of silently zeroing the quantity.
@@ -788,29 +739,7 @@ const svc = defineService<S, {
788
739
  const n = Math.max(0, Math.floor(Number(count)));
789
740
  return Number.isFinite(n) ? derive({ ...s, cartCount: n }) : s;
790
741
  },
791
- paintCached: (s, arg) => {
792
- const row = (arg ?? {}) as DbEntity;
793
- const name = String(row.name ?? "") || "Product";
794
- return derive({
795
- ...s,
796
- status: "ready",
797
- name,
798
- price: String(row.subtitle ?? ""),
799
- commercePrice: String(row.subtitle ?? ""),
800
- description: "",
801
- descriptionJson: "",
802
- image: String(row.image ?? ""),
803
- gallery: [],
804
- initial: String(row.initial ?? "") || (name[0] || "#").toUpperCase(),
805
- // The synced list row carries no options: until the live read says what they are,
806
- // they are UNKNOWN, which keeps the CTA disabled — never a one-tap Add to cart for a
807
- // product that needs a size. The live read replaces this a moment later.
808
- optionGroups: [],
809
- optionsUnknown: true,
810
- emptyText: "",
811
- quantity: 1,
812
- });
813
- },
742
+
814
743
  addToCart: async (s) => {
815
744
  const id = inputId();
816
745
  if (!productPricing.pricing.checkoutGuard({ kind: "storesProduct", id }).allowed || lastProduct?.productType?.toLowerCase() === "digital") return derive({ ...s, cartHint: iapPriceCopy("product").purchaseUnavailable });
@@ -8270,7 +8270,7 @@ const SCREENS = runtimeSetting({
8270
8270
  "package": "himalaya",
8271
8271
  "type": "Text",
8272
8272
  "props": {
8273
- "text": "Showing saved offline results · may be outdated",
8273
+ "text": "Showing previously loaded content · may be outdated",
8274
8274
  "style": "caption",
8275
8275
  "color": "textSecondary"
8276
8276
  }
@@ -11836,7 +11836,7 @@ const SCREENS = runtimeSetting({
11836
11836
  "package": "himalaya",
11837
11837
  "type": "Text",
11838
11838
  "props": {
11839
- "text": "Showing saved offline results · may be outdated",
11839
+ "text": "Showing previously loaded content · may be outdated",
11840
11840
  "style": "caption",
11841
11841
  "color": "textSecondary"
11842
11842
  }
@@ -14914,7 +14914,7 @@ const SCREENS = runtimeSetting({
14914
14914
  "package": "himalaya",
14915
14915
  "type": "Text",
14916
14916
  "props": {
14917
- "text": "Showing saved offline results · may be outdated",
14917
+ "text": "Showing previously loaded content · may be outdated",
14918
14918
  "style": "caption",
14919
14919
  "color": "textSecondary"
14920
14920
  }
@@ -17340,7 +17340,7 @@ const SCREENS = runtimeSetting({
17340
17340
  "package": "himalaya",
17341
17341
  "type": "Text",
17342
17342
  "props": {
17343
- "text": "Showing saved offline results · may be outdated",
17343
+ "text": "Showing previously loaded content · may be outdated",
17344
17344
  "style": "caption",
17345
17345
  "color": "textSecondary"
17346
17346
  }
@@ -1,4 +1,3 @@
1
- import { withOnlineWrites } from './online-actions.js';
2
1
  import { defineService as register, type ServiceDefinition } from '@himalaya/state';
3
2
  import { COLLECTIONS, COLLECTION_CHROME_MIN_ITEMS, initialCollection, normalizeCollection, projectCollection, collectionId, collectionActionsLabel, type CollectionRow } from './collection-contract.js';
4
3
  import { localPreferences, type PreferenceRuntime } from './local-preferences.js';
@@ -95,10 +94,7 @@ export function decorateCollection(name: string, def: { state: State; actions?:
95
94
  if (sort === 'default' || sort === 'az' || sort === 'za') { prefs.sort = sort; changed = true; }
96
95
  }
97
96
  if (Object.prototype.hasOwnProperty.call(input, 'collectionFilter')) {
98
- const requestedFilter = String(input.collectionFilter ?? '');
99
- // Old links to Saved must migrate with the stored preference when this
100
- // collection no longer exposes that filter.
101
- const filter = config.rowStyle === 'flat' && requestedFilter === 'saved' ? 'all' : requestedFilter;
97
+ const filter = String(input.collectionFilter ?? '');
102
98
  const configured = config.filterValues ?? [];
103
99
  const rows = Array.isArray(state[config.rows]) ? state[config.rows] as CollectionRow[] : [];
104
100
  const derived = config.filter ? rows.map(row => String(row[config.filter!] ?? '')).filter(Boolean) : [];
@@ -142,7 +138,7 @@ export function decorateCollection(name: string, def: { state: State; actions?:
142
138
  copyParam('collection.itemActionsFor', 'Actions for {title}'), copyParam('collection.itemActions', 'Item actions'));
143
139
  });
144
140
  if (previewId && !rows.some(row => collectionId(row) === previewId)) previewId = '';
145
- const filterChoices = [{ id: 'all', label: copyParam('collection.all', 'All') }, ...(config.rowStyle === 'flat' ? [] : [{ id: 'saved', label: copyParam('collection.saved', 'Saved') }]),
141
+ const filterChoices = [{ id: 'all', label: copyParam('collection.all', 'All') }, { id: 'saved', label: copyParam('collection.saved', 'Saved') },
146
142
  ...projected.filters.map(label => ({ id: `value:${label}`, label: copyParam(`collection.filter.${label}`, label) }))];
147
143
  const loading = s.status === 'loading' || s.isLoading === true;
148
144
  // Older domain reducers expose `errored` rather than `isErrored`; backend
@@ -223,7 +219,7 @@ export function decorateCollection(name: string, def: { state: State; actions?:
223
219
  ? [copyParam(`collection.${name}.countOne`, config.countNoun[0]), copyParam(`collection.${name}.countMany`, config.countNoun[1])] : undefined }),
224
220
  selectedSummary: `${prefs.selectedIds.length} ${copyParam('collection.selected', 'selected')}`,
225
221
  filterChoices,
226
- chips: config.filterValues && config.rowStyle !== 'flat' ? filterChoices.filter(choice => ['all', 'saved', prefs.filter].includes(choice.id)) : filterChoices,
222
+ chips: config.filterValues ? filterChoices.filter(choice => ['all', 'saved', prefs.filter].includes(choice.id)) : filterChoices,
227
223
  } };
228
224
  };
229
225
  const actions: Record<string, Reducer> = {};
@@ -374,8 +370,9 @@ export function defineBackendCollection<S extends object, Row extends object>(na
374
370
  controller: controller as unknown as BackendCollection['controller'],
375
371
  apply: (state, page) => options.apply(state as S, page as unknown as CollectionQueryState<Row>) as State,
376
372
  });
377
- const registerService = options.onlineWrites ? withOnlineWrites(options.register ?? register, ['confirmCancel', 'confirmOperation', 'retryOperation', 'commitWrite'], { messageFields: options.onlineWriteMessageFields ?? ['actionMessage'] }) : (options.register ?? register);
378
- const handle = registerService(name, definition);
373
+ // Compatibility starters retain their existing mutation behavior; accept the
374
+ // current authoring contract without enabling the offline-write rollout.
375
+ const handle = (options.register ?? register)(name, definition);
379
376
  // Registration restored the state a cold boot saved: the page it showed is this run's, before the first load. Only
380
377
  // when the service's own rows came back with it: a bundle that keeps them out of the restore (its `notHydrated`)
381
378
  // starts its first load as before, never from rows it chose not to restore. Rows that came back empty are the
@@ -103,6 +103,8 @@ export function withIapPresentation<S extends object>(options: {
103
103
  // scopeLanded is the completion of the active load, not a stale load result. It
104
104
  // must publish even if another overlapping onAppear load advanced contentVersion.
105
105
  if (!next || (content && action !== "scopeLanded" && version !== contentVersion)) return undefined;
106
+ // A committed read projection supersedes older load results still carrying a skeleton.
107
+ if (action === "readChanged" && definition.readLifecycle) contentVersion++;
106
108
  if (content) {
107
109
  options.onContent?.(next);
108
110
  const nextItems = options.items(next);
@@ -130,9 +132,11 @@ export function withIapPresentation<S extends object>(options: {
130
132
  };
131
133
  try {
132
134
  const next = reduce(state, ...args);
133
- // Keep synchronous sidecars synchronous. Adding an await lets their old
134
- // catalog snapshot commit after a newer asynchronous refresh.
135
- if (content || (next && typeof (next as Promise<S | undefined>).then === "function")) {
135
+ // A cached read projection must commit before another onAppear can consume it.
136
+ // Other content actions retain their scheduling: shop filters and panels can
137
+ // change while a load is pending, and their existing completion order matters.
138
+ const synchronousReadProjection = action === "readChanged" && !!definition.readLifecycle;
139
+ if ((content && !synchronousReadProjection) || (next && typeof (next as Promise<S | undefined>).then === "function")) {
136
140
  return (async () => {
137
141
  try { return presentResult(await next); }
138
142
  finally { finished(); }
@@ -250,7 +250,7 @@ interface State {
250
250
  hideFeaturedSkeleton: boolean;
251
251
  welcome: string;
252
252
  refreshedAt: string;
253
- /** The resolved home layout preset (RFC 0045 FragmentSlot discriminator).
253
+ /** The resolved home layout preset (shared slot discriminator).
254
254
  * Plain string, never a proto enum — a `$service:` casePath decodes it as a
255
255
  * JSON string and unknown values fall through to the shipped defaultCase. */
256
256
  effectiveLayout: string;