@wix/himalaya-cli 0.1391.0 → 0.1393.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 (284) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/bookings-v2/src/extensions.d.ts +7 -5
  2. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-bookings.mjs +4 -4
  3. package/dist/cli.mjs +31 -23
  4. package/dist/preview-assets.generated.bin +0 -0
  5. package/guides/sdk-reference.json +4 -4
  6. package/package.json +2 -2
  7. package/templates/beauty-salon/tier5-src/_shared/owner-load-error.ts +115 -12
  8. package/templates/beauty-salon/tier5-src/himi-branded-lite-cart/index.ts +52 -28
  9. package/templates/beauty-salon-owner/dev/index.ts +545 -100
  10. package/templates/beauty-salon-owner/himalaya.content.json +6 -0
  11. package/templates/beauty-salon-owner/tier5-src/_shared/owner-account.ts +6 -2
  12. package/templates/beauty-salon-owner/tier5-src/_shared/owner-booking-respond.ts +82 -0
  13. package/templates/beauty-salon-owner/tier5-src/_shared/owner-load-error.ts +115 -12
  14. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-account/index.ts +7 -4
  15. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-appointments/index.ts +2 -2
  16. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-ask/live.ts +3 -3
  17. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-home/index.ts +2 -2
  18. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-order/index.ts +3 -3
  19. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-orders/index.ts +2 -2
  20. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-overview/index.ts +2 -2
  21. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-post/index.ts +60 -43
  22. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-post-form/index.ts +10 -23
  23. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-posts/index.ts +2 -2
  24. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-product/index.ts +31 -32
  25. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-product-form/index.ts +23 -43
  26. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-products/index.ts +2 -2
  27. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-service/index.ts +18 -20
  28. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-service-form/index.ts +16 -29
  29. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-services/index.ts +2 -2
  30. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-sites/index.ts +2 -2
  31. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-today/index.ts +315 -0
  32. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-wrist/index.ts +42 -15
  33. package/templates/branded-lite/tier5-src/_shared/owner-load-error.ts +115 -12
  34. package/templates/branded-lite/tier5-src/himi-branded-lite-cart/index.ts +52 -28
  35. package/templates/branded-lite/tier5-src/himi-branded-lite-group/index.ts +24 -24
  36. package/templates/community-club/tier5-src/_shared/owner-load-error.ts +115 -12
  37. package/templates/community-club/tier5-src/himi-branded-lite-group/index.ts +24 -24
  38. package/templates/community-club-owner/dev/index.ts +317 -100
  39. package/templates/community-club-owner/himalaya.content.json +6 -0
  40. package/templates/community-club-owner/tier5-src/_shared/owner-account.ts +6 -2
  41. package/templates/community-club-owner/tier5-src/_shared/owner-booking-respond.ts +82 -0
  42. package/templates/community-club-owner/tier5-src/_shared/owner-load-error.ts +115 -12
  43. package/templates/community-club-owner/tier5-src/himi-owner-lite-account/index.ts +7 -4
  44. package/templates/community-club-owner/tier5-src/himi-owner-lite-ask/live.ts +3 -3
  45. package/templates/community-club-owner/tier5-src/himi-owner-lite-event/index.ts +18 -20
  46. package/templates/community-club-owner/tier5-src/himi-owner-lite-event-form/index.ts +20 -28
  47. package/templates/community-club-owner/tier5-src/himi-owner-lite-events/index.ts +2 -2
  48. package/templates/community-club-owner/tier5-src/himi-owner-lite-home/index.ts +2 -2
  49. package/templates/community-club-owner/tier5-src/himi-owner-lite-order/index.ts +3 -3
  50. package/templates/community-club-owner/tier5-src/himi-owner-lite-orders/index.ts +2 -2
  51. package/templates/community-club-owner/tier5-src/himi-owner-lite-overview/index.ts +2 -2
  52. package/templates/community-club-owner/tier5-src/himi-owner-lite-post/index.ts +60 -43
  53. package/templates/community-club-owner/tier5-src/himi-owner-lite-post-form/index.ts +10 -23
  54. package/templates/community-club-owner/tier5-src/himi-owner-lite-posts/index.ts +2 -2
  55. package/templates/community-club-owner/tier5-src/himi-owner-lite-product/index.ts +31 -32
  56. package/templates/community-club-owner/tier5-src/himi-owner-lite-product-form/index.ts +23 -43
  57. package/templates/community-club-owner/tier5-src/himi-owner-lite-products/index.ts +2 -2
  58. package/templates/community-club-owner/tier5-src/himi-owner-lite-sites/index.ts +2 -2
  59. package/templates/community-club-owner/tier5-src/himi-owner-lite-today/index.ts +315 -0
  60. package/templates/community-club-owner/tier5-src/himi-owner-lite-wrist/index.ts +42 -15
  61. package/templates/events-meetups/tier5-src/_shared/owner-load-error.ts +115 -12
  62. package/templates/events-meetups/tier5-src/himi-branded-lite-group/index.ts +24 -24
  63. package/templates/events-meetups-owner/dev/index.ts +275 -100
  64. package/templates/events-meetups-owner/himalaya.content.json +6 -0
  65. package/templates/events-meetups-owner/tier5-src/_shared/owner-account.ts +6 -2
  66. package/templates/events-meetups-owner/tier5-src/_shared/owner-booking-respond.ts +82 -0
  67. package/templates/events-meetups-owner/tier5-src/_shared/owner-load-error.ts +115 -12
  68. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-account/index.ts +7 -4
  69. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-ask/live.ts +3 -3
  70. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-event/index.ts +18 -20
  71. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-event-form/index.ts +20 -28
  72. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-events/index.ts +2 -2
  73. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-home/index.ts +2 -2
  74. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-overview/index.ts +2 -2
  75. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-post/index.ts +60 -43
  76. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-post-form/index.ts +10 -23
  77. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-posts/index.ts +2 -2
  78. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-sites/index.ts +2 -2
  79. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-today/index.ts +315 -0
  80. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-wrist/index.ts +42 -15
  81. package/templates/gym-fitness/tier5-src/_shared/owner-load-error.ts +115 -12
  82. package/templates/gym-fitness/tier5-src/himi-branded-lite-cart/index.ts +52 -28
  83. package/templates/gym-fitness-owner/dev/index.ts +545 -100
  84. package/templates/gym-fitness-owner/himalaya.content.json +6 -0
  85. package/templates/gym-fitness-owner/tier5-src/_shared/owner-account.ts +6 -2
  86. package/templates/gym-fitness-owner/tier5-src/_shared/owner-booking-respond.ts +82 -0
  87. package/templates/gym-fitness-owner/tier5-src/_shared/owner-load-error.ts +115 -12
  88. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-account/index.ts +7 -4
  89. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-appointments/index.ts +2 -2
  90. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-ask/live.ts +3 -3
  91. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-event/index.ts +18 -20
  92. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-event-form/index.ts +20 -28
  93. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-events/index.ts +2 -2
  94. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-home/index.ts +2 -2
  95. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-order/index.ts +3 -3
  96. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-orders/index.ts +2 -2
  97. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-overview/index.ts +2 -2
  98. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-post/index.ts +60 -43
  99. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-post-form/index.ts +10 -23
  100. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-posts/index.ts +2 -2
  101. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-product/index.ts +31 -32
  102. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-product-form/index.ts +23 -43
  103. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-products/index.ts +2 -2
  104. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-service/index.ts +18 -20
  105. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-service-form/index.ts +16 -29
  106. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-services/index.ts +2 -2
  107. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-sites/index.ts +2 -2
  108. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-today/index.ts +315 -0
  109. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-wrist/index.ts +42 -15
  110. package/templates/himi-chat/tier5-src/_shared/owner-load-error.ts +115 -12
  111. package/templates/nonprofit-cause/tier5-src/_shared/owner-load-error.ts +115 -12
  112. package/templates/nonprofit-cause/tier5-src/himi-branded-lite-group/index.ts +24 -24
  113. package/templates/nonprofit-cause-owner/dev/index.ts +503 -100
  114. package/templates/nonprofit-cause-owner/himalaya.content.json +6 -0
  115. package/templates/nonprofit-cause-owner/tier5-src/_shared/owner-account.ts +6 -2
  116. package/templates/nonprofit-cause-owner/tier5-src/_shared/owner-booking-respond.ts +82 -0
  117. package/templates/nonprofit-cause-owner/tier5-src/_shared/owner-load-error.ts +115 -12
  118. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-account/index.ts +7 -4
  119. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-appointments/index.ts +2 -2
  120. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-ask/live.ts +3 -3
  121. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-event/index.ts +18 -20
  122. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-event-form/index.ts +20 -28
  123. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-events/index.ts +2 -2
  124. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-home/index.ts +2 -2
  125. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-overview/index.ts +2 -2
  126. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-post/index.ts +60 -43
  127. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-post-form/index.ts +10 -23
  128. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-posts/index.ts +2 -2
  129. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-service/index.ts +18 -20
  130. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-service-form/index.ts +16 -29
  131. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-services/index.ts +2 -2
  132. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-sites/index.ts +2 -2
  133. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-today/index.ts +315 -0
  134. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-wrist/index.ts +42 -15
  135. package/templates/owner-lite/dev/index.ts +545 -100
  136. package/templates/owner-lite/himalaya.content.json +6 -0
  137. package/templates/owner-lite/tier5-src/_shared/owner-account.ts +6 -2
  138. package/templates/owner-lite/tier5-src/_shared/owner-booking-respond.ts +82 -0
  139. package/templates/owner-lite/tier5-src/_shared/owner-load-error.ts +115 -12
  140. package/templates/owner-lite/tier5-src/himi-owner-lite-account/index.ts +7 -4
  141. package/templates/owner-lite/tier5-src/himi-owner-lite-appointments/index.ts +2 -2
  142. package/templates/owner-lite/tier5-src/himi-owner-lite-ask/live.ts +3 -3
  143. package/templates/owner-lite/tier5-src/himi-owner-lite-event/index.ts +18 -20
  144. package/templates/owner-lite/tier5-src/himi-owner-lite-event-form/index.ts +20 -28
  145. package/templates/owner-lite/tier5-src/himi-owner-lite-events/index.ts +2 -2
  146. package/templates/owner-lite/tier5-src/himi-owner-lite-home/index.ts +2 -2
  147. package/templates/owner-lite/tier5-src/himi-owner-lite-order/index.ts +3 -3
  148. package/templates/owner-lite/tier5-src/himi-owner-lite-orders/index.ts +2 -2
  149. package/templates/owner-lite/tier5-src/himi-owner-lite-overview/index.ts +2 -2
  150. package/templates/owner-lite/tier5-src/himi-owner-lite-post/index.ts +60 -43
  151. package/templates/owner-lite/tier5-src/himi-owner-lite-post-form/index.ts +10 -23
  152. package/templates/owner-lite/tier5-src/himi-owner-lite-posts/index.ts +2 -2
  153. package/templates/owner-lite/tier5-src/himi-owner-lite-product/index.ts +31 -32
  154. package/templates/owner-lite/tier5-src/himi-owner-lite-product-form/index.ts +23 -43
  155. package/templates/owner-lite/tier5-src/himi-owner-lite-products/index.ts +2 -2
  156. package/templates/owner-lite/tier5-src/himi-owner-lite-service/index.ts +18 -20
  157. package/templates/owner-lite/tier5-src/himi-owner-lite-service-form/index.ts +16 -29
  158. package/templates/owner-lite/tier5-src/himi-owner-lite-services/index.ts +2 -2
  159. package/templates/owner-lite/tier5-src/himi-owner-lite-sites/index.ts +2 -2
  160. package/templates/owner-lite/tier5-src/himi-owner-lite-today/index.ts +315 -0
  161. package/templates/owner-lite/tier5-src/himi-owner-lite-wrist/index.ts +42 -15
  162. package/templates/podcast-creator/tier5-src/_shared/owner-load-error.ts +115 -12
  163. package/templates/podcast-creator-owner/dev/index.ts +317 -100
  164. package/templates/podcast-creator-owner/himalaya.content.json +6 -0
  165. package/templates/podcast-creator-owner/tier5-src/_shared/owner-account.ts +6 -2
  166. package/templates/podcast-creator-owner/tier5-src/_shared/owner-booking-respond.ts +82 -0
  167. package/templates/podcast-creator-owner/tier5-src/_shared/owner-load-error.ts +115 -12
  168. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-account/index.ts +7 -4
  169. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-ask/live.ts +3 -3
  170. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-event/index.ts +18 -20
  171. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-event-form/index.ts +20 -28
  172. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-events/index.ts +2 -2
  173. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-home/index.ts +2 -2
  174. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-order/index.ts +3 -3
  175. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-orders/index.ts +2 -2
  176. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-overview/index.ts +2 -2
  177. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-post/index.ts +60 -43
  178. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-post-form/index.ts +10 -23
  179. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-posts/index.ts +2 -2
  180. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-product/index.ts +31 -32
  181. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-product-form/index.ts +23 -43
  182. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-products/index.ts +2 -2
  183. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-sites/index.ts +2 -2
  184. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-today/index.ts +315 -0
  185. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-wrist/index.ts +42 -15
  186. package/templates/portfolio-creative/tier5-src/_shared/owner-load-error.ts +115 -12
  187. package/templates/portfolio-creative/tier5-src/himi-branded-lite-cart/index.ts +52 -28
  188. package/templates/portfolio-creative-owner/dev/index.ts +545 -100
  189. package/templates/portfolio-creative-owner/himalaya.content.json +6 -0
  190. package/templates/portfolio-creative-owner/tier5-src/_shared/owner-account.ts +6 -2
  191. package/templates/portfolio-creative-owner/tier5-src/_shared/owner-booking-respond.ts +82 -0
  192. package/templates/portfolio-creative-owner/tier5-src/_shared/owner-load-error.ts +115 -12
  193. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-account/index.ts +7 -4
  194. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-appointments/index.ts +2 -2
  195. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-ask/live.ts +3 -3
  196. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-home/index.ts +2 -2
  197. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-order/index.ts +3 -3
  198. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-orders/index.ts +2 -2
  199. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-overview/index.ts +2 -2
  200. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-post/index.ts +60 -43
  201. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-post-form/index.ts +10 -23
  202. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-posts/index.ts +2 -2
  203. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-product/index.ts +31 -32
  204. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-product-form/index.ts +23 -43
  205. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-products/index.ts +2 -2
  206. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-service/index.ts +18 -20
  207. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-service-form/index.ts +16 -29
  208. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-services/index.ts +2 -2
  209. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-sites/index.ts +2 -2
  210. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-today/index.ts +315 -0
  211. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-wrist/index.ts +42 -15
  212. package/templates/restaurant/tier5-src/_shared/owner-load-error.ts +115 -12
  213. package/templates/restaurant-owner/dev/index.ts +545 -100
  214. package/templates/restaurant-owner/himalaya.content.json +6 -0
  215. package/templates/restaurant-owner/tier5-src/_shared/owner-account.ts +6 -2
  216. package/templates/restaurant-owner/tier5-src/_shared/owner-booking-respond.ts +82 -0
  217. package/templates/restaurant-owner/tier5-src/_shared/owner-load-error.ts +115 -12
  218. package/templates/restaurant-owner/tier5-src/himi-owner-lite-account/index.ts +7 -4
  219. package/templates/restaurant-owner/tier5-src/himi-owner-lite-appointments/index.ts +2 -2
  220. package/templates/restaurant-owner/tier5-src/himi-owner-lite-ask/live.ts +3 -3
  221. package/templates/restaurant-owner/tier5-src/himi-owner-lite-event/index.ts +18 -20
  222. package/templates/restaurant-owner/tier5-src/himi-owner-lite-event-form/index.ts +20 -28
  223. package/templates/restaurant-owner/tier5-src/himi-owner-lite-events/index.ts +2 -2
  224. package/templates/restaurant-owner/tier5-src/himi-owner-lite-home/index.ts +2 -2
  225. package/templates/restaurant-owner/tier5-src/himi-owner-lite-order/index.ts +3 -3
  226. package/templates/restaurant-owner/tier5-src/himi-owner-lite-orders/index.ts +2 -2
  227. package/templates/restaurant-owner/tier5-src/himi-owner-lite-overview/index.ts +2 -2
  228. package/templates/restaurant-owner/tier5-src/himi-owner-lite-post/index.ts +60 -43
  229. package/templates/restaurant-owner/tier5-src/himi-owner-lite-post-form/index.ts +10 -23
  230. package/templates/restaurant-owner/tier5-src/himi-owner-lite-posts/index.ts +2 -2
  231. package/templates/restaurant-owner/tier5-src/himi-owner-lite-product/index.ts +31 -32
  232. package/templates/restaurant-owner/tier5-src/himi-owner-lite-product-form/index.ts +23 -43
  233. package/templates/restaurant-owner/tier5-src/himi-owner-lite-products/index.ts +2 -2
  234. package/templates/restaurant-owner/tier5-src/himi-owner-lite-service/index.ts +18 -20
  235. package/templates/restaurant-owner/tier5-src/himi-owner-lite-service-form/index.ts +16 -29
  236. package/templates/restaurant-owner/tier5-src/himi-owner-lite-services/index.ts +2 -2
  237. package/templates/restaurant-owner/tier5-src/himi-owner-lite-sites/index.ts +2 -2
  238. package/templates/restaurant-owner/tier5-src/himi-owner-lite-today/index.ts +315 -0
  239. package/templates/restaurant-owner/tier5-src/himi-owner-lite-wrist/index.ts +42 -15
  240. package/templates/retail-store/tier5-src/_shared/owner-load-error.ts +115 -12
  241. package/templates/retail-store/tier5-src/himi-branded-lite-cart/index.ts +52 -28
  242. package/templates/retail-store-owner/dev/index.ts +317 -100
  243. package/templates/retail-store-owner/himalaya.content.json +6 -0
  244. package/templates/retail-store-owner/tier5-src/_shared/owner-account.ts +6 -2
  245. package/templates/retail-store-owner/tier5-src/_shared/owner-booking-respond.ts +82 -0
  246. package/templates/retail-store-owner/tier5-src/_shared/owner-load-error.ts +115 -12
  247. package/templates/retail-store-owner/tier5-src/himi-owner-lite-account/index.ts +7 -4
  248. package/templates/retail-store-owner/tier5-src/himi-owner-lite-ask/live.ts +3 -3
  249. package/templates/retail-store-owner/tier5-src/himi-owner-lite-home/index.ts +2 -2
  250. package/templates/retail-store-owner/tier5-src/himi-owner-lite-order/index.ts +3 -3
  251. package/templates/retail-store-owner/tier5-src/himi-owner-lite-orders/index.ts +2 -2
  252. package/templates/retail-store-owner/tier5-src/himi-owner-lite-overview/index.ts +2 -2
  253. package/templates/retail-store-owner/tier5-src/himi-owner-lite-post/index.ts +60 -43
  254. package/templates/retail-store-owner/tier5-src/himi-owner-lite-post-form/index.ts +10 -23
  255. package/templates/retail-store-owner/tier5-src/himi-owner-lite-posts/index.ts +2 -2
  256. package/templates/retail-store-owner/tier5-src/himi-owner-lite-product/index.ts +31 -32
  257. package/templates/retail-store-owner/tier5-src/himi-owner-lite-product-form/index.ts +23 -43
  258. package/templates/retail-store-owner/tier5-src/himi-owner-lite-products/index.ts +2 -2
  259. package/templates/retail-store-owner/tier5-src/himi-owner-lite-sites/index.ts +2 -2
  260. package/templates/retail-store-owner/tier5-src/himi-owner-lite-today/index.ts +315 -0
  261. package/templates/retail-store-owner/tier5-src/himi-owner-lite-wrist/index.ts +42 -15
  262. package/templates/yoga-studio/tier5-src/_shared/owner-load-error.ts +115 -12
  263. package/templates/yoga-studio-owner/dev/index.ts +503 -100
  264. package/templates/yoga-studio-owner/himalaya.content.json +6 -0
  265. package/templates/yoga-studio-owner/tier5-src/_shared/owner-account.ts +6 -2
  266. package/templates/yoga-studio-owner/tier5-src/_shared/owner-booking-respond.ts +82 -0
  267. package/templates/yoga-studio-owner/tier5-src/_shared/owner-load-error.ts +115 -12
  268. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-account/index.ts +7 -4
  269. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-appointments/index.ts +2 -2
  270. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-ask/live.ts +3 -3
  271. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-event/index.ts +18 -20
  272. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-event-form/index.ts +20 -28
  273. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-events/index.ts +2 -2
  274. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-home/index.ts +2 -2
  275. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-overview/index.ts +2 -2
  276. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-post/index.ts +60 -43
  277. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-post-form/index.ts +10 -23
  278. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-posts/index.ts +2 -2
  279. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-service/index.ts +18 -20
  280. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-service-form/index.ts +16 -29
  281. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-services/index.ts +2 -2
  282. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-sites/index.ts +2 -2
  283. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-today/index.ts +315 -0
  284. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-wrist/index.ts +42 -15
@@ -24,25 +24,33 @@ async function resolveMsid(): Promise<string> {
24
24
  }
25
25
  }
26
26
  import { copyParam, copyTemplate, stashCopy } from "../_shared/himi-copy.js";
27
- import { getAll, upsert, remove as dbRemove, enqueue, type DbEntity } from "@himalaya/local-db";
28
- import { isBridgeUnavailable } from "../_shared/owner-load-error.js";
27
+ import { getAll, upsert, remove as dbRemove, type DbEntity } from "@himalaya/local-db";
28
+ import { isOfflineFailure, writeMayHaveLanded } from "../_shared/owner-load-error.js";
29
29
 
30
30
  // Offline-first (data-offline): the cart is READ-THROUGH — paint the last-synced line
31
31
  // items from the on-device `cart` entity first (instant, works offline), then
32
- // revalidate from Wix and refresh the cache. `remove` is WRITE-BEHIND — the line is
33
- // dropped from the cache OPTIMISTICALLY, then the Wix write is attempted; if it can't
34
- // reach the bridge/network the removal is ENQUEUED for replay on reconnect. The
35
- // checkout redirect path is unchanged. Every local-db call is wrapped so a build
32
+ // revalidate from Wix and refresh the cache.
33
+ // `remove` drops the line from the cache only AFTER Wix confirms it; a failed removal
34
+ // keeps the line on screen and says nothing was removed (no host replays a
35
+ // queued write, so the old "removed offline" promise was a removal that never happened).
36
+ // The checkout redirect path is unchanged. Every local-db call is wrapped so a build
36
37
  // without the `local_database` grant behaves exactly as before (online-only).
37
38
  const ENTITY = "cart";
38
39
  async function readCachedItems(): Promise<Row[]> {
39
40
  try { return (await getAll(ENTITY)) as unknown as Row[]; } catch { return []; }
40
41
  }
42
+ /** Mirror the cart Wix returned: upsert its lines and drop any cached line it no longer has
43
+ * (one removed elsewhere, or a removal whose answer was lost), so the offline paint never
44
+ * shows a line that is gone. */
41
45
  async function writeCachedItems(rows: Row[]): Promise<void> {
42
- try { for (const r of rows) await upsert(ENTITY, r as unknown as DbEntity); } catch { /* capability not granted → online-only */ }
46
+ try {
47
+ const keep = new Set(rows.map((r) => r.id));
48
+ for (const old of (await getAll(ENTITY)) as unknown as Row[]) if (!keep.has(old.id)) await dbRemove(ENTITY, old.id);
49
+ for (const r of rows) await upsert(ENTITY, r as unknown as DbEntity);
50
+ } catch { /* capability not granted → online-only */ }
43
51
  }
52
+
44
53
  async function cacheDrop(id: string): Promise<void> { try { await dbRemove(ENTITY, id); } catch { /* capability not granted */ } }
45
- async function queueWrite(actionId: string, params: Record<string, string>): Promise<void> { try { await enqueue(actionId, params); } catch { /* capability not granted */ } }
46
54
 
47
55
  interface Row {
48
56
  catalogReference?: { appId: string; catalogItemId: string; options?: Record<string, unknown> };
@@ -164,6 +172,39 @@ function derive(state: State): State {
164
172
  };
165
173
  }
166
174
 
175
+ /** Remove one line (the trash button, and "−" at quantity 1). The cache drops it only once
176
+ * Wix confirms; a failure keeps it on screen and says why. */
177
+ /** Remove one line (the trash button, and "−" at quantity 1). The cache drops it only once
178
+ * Wix confirms; a failure keeps it on screen and says why. */
179
+ async function removeLine(state: State, id: string): Promise<State> {
180
+ try {
181
+ await removeLineItemsFromCurrentCart([id]);
182
+ } catch (e) {
183
+ // The line stays visible (and cached) until a read says otherwise.
184
+ if (isOfflineFailure(e)) {
185
+ return derive({ ...state, checkoutHint: copyParam("cart.removeOfflineFailedMessage", "You’re offline — nothing was removed. Try again when you reconnect.") });
186
+ }
187
+ // It may have landed (mid-request drop, after-send envelope, gateway 5xx): say so,
188
+ // rather than "could not remove".
189
+ if (writeMayHaveLanded(e)) {
190
+ return derive({ ...state, checkoutHint: copyParam("cart.removeUnconfirmedMessage", "The connection dropped, so this item may already be removed. Refresh to check.") });
191
+ }
192
+ return derive({ ...state, checkoutHint: copyParam("cart.removeFailedMessage", "Could not remove this item.") });
193
+ }
194
+ // Wix confirmed it: only now does the line leave the cache, and it stays gone even
195
+ // if the re-fetch below fails.
196
+ await cacheDrop(id);
197
+ const removed = copyParam("cart.itemRemovedMessage", "Item removed.");
198
+ try {
199
+ return await refresh(state, removed);
200
+ } catch {
201
+ // The totals Wix last sent still count the removed line, and the new ones did not
202
+ // arrive: show none rather than a wrong one.
203
+ const items = state.items.filter((it) => it.id !== id);
204
+ return derive({ ...state, status: "ready", items, subtotal: "", commerceSubtotal: "", emptyText: items.length ? "" : copyParam("cart.emptyText", "Your cart is empty."), checkoutHint: removed });
205
+ }
206
+ }
207
+
167
208
  async function refresh(state: State, checkoutHint = ""): Promise<State> {
168
209
  const cart = await getCurrentCart();
169
210
  const items = (cart.lineItems ?? []).map(row);
@@ -240,21 +281,7 @@ const svc = defineService<State, {
240
281
  remove: async (state, arg) => {
241
282
  const id = itemId(arg);
242
283
  if (!id) return state;
243
- // Optimistic local delete — the cart drops the row immediately (offline or not).
244
- await cacheDrop(id);
245
- try {
246
- await removeLineItemsFromCurrentCart([id]);
247
- return await refresh(state, copyParam("cart.itemRemovedMessage", "Item removed."));
248
- } catch (e) {
249
- if (isBridgeUnavailable(e)) {
250
- // Offline / no bridge: the optimistic cache drop already shows; queue the
251
- // removal to replay (WriteQueue, idempotent) when connectivity returns.
252
- await queueWrite("tier5.himiStoreCart.remove", { id });
253
- const items = state.items.filter((it) => it.id !== id);
254
- return derive({ ...state, status: "ready", items, emptyText: items.length ? "" : copyParam("cart.emptyText", "Your cart is empty."), checkoutHint: copyParam("cart.removedOfflineMessage", "Removed offline — will sync when you reconnect.") });
255
- }
256
- return derive({ ...state, checkoutHint: copyParam("cart.removeFailedMessage", "Could not remove this item.") });
257
- }
284
+ return removeLine(state, id);
258
285
  },
259
286
  increment: async (state, arg) => {
260
287
  const id = itemId(arg);
@@ -272,12 +299,9 @@ const svc = defineService<State, {
272
299
  const id = itemId(arg);
273
300
  const line = state.items.find((candidate) => candidate.id === id);
274
301
  if (!line) return state;
302
+ // Qty 1 − ⇒ remove the line (the control never dead-ends), with remove's handling.
303
+ if (line.quantity <= 1) return removeLine(state, id);
275
304
  try {
276
- if (line.quantity <= 1) {
277
- // Qty 1 − ⇒ remove the line (the control never dead-ends).
278
- await removeLineItemsFromCurrentCart([id]);
279
- return await refresh(state, copyParam("cart.itemRemovedMessage", "Item removed."));
280
- }
281
305
  const cartId = (await getCurrentCart()).id || "";
282
306
  await updateLineItemQuantity(cartId, id, line.quantity - 1);
283
307
  return await refresh(state);
@@ -4,8 +4,8 @@ import { getMember } from "@himalaya/wix-members";
4
4
  import { signedInEmail } from "../_shared/himi-account";
5
5
  import { initials } from "../_shared/himi-text.js";
6
6
  import { copyParam, stashCopy } from "../_shared/himi-copy.js";
7
- import { get as dbGet, upsert as dbUpsert, enqueue as dbEnqueue, type DbEntity } from "@himalaya/local-db";
8
- import { isBridgeUnavailable } from "../_shared/owner-load-error";
7
+ import { get as dbGet, upsert as dbUpsert, type DbEntity } from "@himalaya/local-db";
8
+ import { isOfflineFailure, writeMayHaveLanded } from "../_shared/owner-load-error";
9
9
 
10
10
  interface MemberAvatar {
11
11
  initials: string;
@@ -13,11 +13,12 @@ interface MemberAvatar {
13
13
  }
14
14
 
15
15
  // Offline-first (data-offline): the group detail READS through the shared `groups`
16
- // cache (get by id) so a previously-synced group still renders offline, and join/leave
17
- // are WRITE-BEHIND — the membership is written OPTIMISTICALLY to the local store, then
18
- // the Wix mutation is attempted; if the bridge/network is unreachable the mutation is
19
- // ENQUEUED for replay on reconnect. Every local-db call is wrapped (try/catch) so a
20
- // build without the `local_database` grant behaves exactly as before (online-only).
16
+ // cache (get by id) so a previously-synced group still renders offline. Join/leave
17
+ // are SERVER-CONFIRMED: the cached membership changes only after Wix accepts it; a
18
+ // failed one leaves it alone and tells the member why. No host replays a queued
19
+ // write, so nothing is queued.
20
+ // Every local-db call is wrapped so a build without the `local_database` grant
21
+ // behaves exactly as before (online-only).
21
22
  const ENTITY = "groups";
22
23
  async function readCachedGroup(id: string): Promise<DbEntity | null> {
23
24
  try { return await dbGet(ENTITY, id); } catch { return null; }
@@ -41,9 +42,6 @@ async function cachePutMembership(state: State, joined: boolean): Promise<void>
41
42
  await dbUpsert(ENTITY, { ...existing, id: state.id, joined: joined ? "true" : "false" });
42
43
  } catch { /* capability not granted */ }
43
44
  }
44
- async function queueWrite(actionId: string, params: Record<string, string>): Promise<void> {
45
- try { await dbEnqueue(actionId, params); } catch { /* capability not granted */ }
46
- }
47
45
 
48
46
  interface State {
49
47
  status: "loading" | "ready" | "error";
@@ -242,17 +240,19 @@ const svc = defineService<State, {
242
240
  if (state.privacy !== "Public" && state.privacy !== "Unknown") {
243
241
  return membershipState({ ...state, message: copyParam("group.privateInviteMessage", "Private groups are available by invitation.") }, false, true);
244
242
  }
245
- // Optimistic local write — persist the joined membership so it survives offline.
246
- await cachePutMembership(state, true);
247
243
  try {
248
244
  await joinGroup(state.id);
245
+ // Wix confirmed it: persist the joined membership so it survives offline.
246
+ await cachePutMembership(state, true);
249
247
  return membershipState({ ...state, message: copyParam("group.joinedMessage", "You joined the group.") }, true, true);
250
248
  } catch (e) {
251
- if (isBridgeUnavailable(e)) {
252
- // Offline / no bridge: the optimistic cache already reflects the join; queue
253
- // the write to replay (WriteQueue, idempotent) when connectivity returns.
254
- await queueWrite("tier5.himiBrandedGroup.join", { id: state.id });
255
- return membershipState({ ...state, message: copyParam("group.joinedOfflineMessage", "You joined the group — it will sync when you reconnect.") }, true, true);
249
+ if (isOfflineFailure(e)) {
250
+ return membershipState({ ...state, message: copyParam("group.offlineFailedMessage", "You’re offline — nothing was saved. Try again when you reconnect.") }, false, true);
251
+ }
252
+ // It may have landed: neither "joined" nor "could not". (No "refresh to check": a load
253
+ // does not read the membership back.)
254
+ if (writeMayHaveLanded(e)) {
255
+ return membershipState({ ...state, message: copyParam("group.joinUnconfirmedMessage", "Wix didn’t confirm this, so you may already have joined the group.") }, false, true);
256
256
  }
257
257
  return membershipState({ ...state, message: copyParam("group.joinFailedMessage", "The group could not be joined. Try again.") }, false, true);
258
258
  }
@@ -260,17 +260,17 @@ const svc = defineService<State, {
260
260
  leave: async (state) => {
261
261
  const signedIn = Boolean(await signedInEmail());
262
262
  if (!signedIn) return membershipState({ ...state, message: copyParam("group.manageSignInMessage", "Sign in from Profile to manage groups.") }, state.isJoined, false);
263
- // Optimistic local write — persist the left membership so it survives offline.
264
- await cachePutMembership(state, false);
265
263
  try {
266
264
  await leaveGroup(state.id);
265
+ // Wix confirmed it: persist the left membership so it survives offline.
266
+ await cachePutMembership(state, false);
267
267
  return membershipState({ ...state, message: copyParam("group.leftMessage", "You left the group.") }, false, true);
268
268
  } catch (e) {
269
- if (isBridgeUnavailable(e)) {
270
- // Offline / no bridge: the optimistic cache already reflects the leave; queue
271
- // the write to replay (WriteQueue, idempotent) when connectivity returns.
272
- await queueWrite("tier5.himiBrandedGroup.leave", { id: state.id });
273
- return membershipState({ ...state, message: copyParam("group.leftOfflineMessage", "You left the group — it will sync when you reconnect.") }, false, true);
269
+ if (isOfflineFailure(e)) {
270
+ return membershipState({ ...state, message: copyParam("group.offlineFailedMessage", "You’re offline — nothing was saved. Try again when you reconnect.") }, true, true);
271
+ }
272
+ if (writeMayHaveLanded(e)) {
273
+ return membershipState({ ...state, message: copyParam("group.leaveUnconfirmedMessage", "Wix didn’t confirm this, so you may already have left the group.") }, true, true);
274
274
  }
275
275
  return membershipState({ ...state, message: copyParam("group.leaveFailedMessage", "The group could not be left. Try again.") }, true, true);
276
276
  }
@@ -20,10 +20,9 @@ export function isOwnerPreviewLive(): boolean {
20
20
  *
21
21
  * `isBridgeUnavailable` cannot answer this: it reads "not live" as "preview",
22
22
  * and on NATIVE there is no input at all, so `undefined` satisfies it. That is
23
- * harmless for the callers that use it to pick a demo fallback or to queue a
24
- * write, and it is deliberately left alone for them — native write-behind
25
- * depends on it. It is NOT harmless for choosing COPY: native workers format
26
- * their failures the same way (`"HTTP \(code): \(body)"`, JSWorker.swift;
23
+ * left alone for the other apps that use it to pick a demo fallback or to queue
24
+ * a write. Owner-lite reads ask `ownerDemoFallback` instead. It is NOT
25
+ * harmless for choosing COPY: native workers format their failures the same way (`"HTTP \(code): \(body)"`, JSWorker.swift;
27
26
  * `"HTTP ${e.code}: ..."`, WebViewJSWorker.kt), so a transient `HTTP 503` on a
28
27
  * phone would otherwise be answered with "open this app on a device" — on the
29
28
  * device. Callers that pick a SENTENCE ask this instead.
@@ -43,11 +42,89 @@ export function isBridgeUnavailable(e: unknown): boolean {
43
42
  return /HTTP (405|501|502|503)\b/.test(String((e as Error)?.message ?? e));
44
43
  }
45
44
 
46
- /** Preserve native write-behind when the bridge is unavailable. This is a
47
- * queue decision, never permission to replace a failed live read with samples. */
48
- export function shouldQueueOwnerWrite(e: unknown): boolean {
49
- if (ownerPreviewMode() === "live" || isOwnerPreviewDemo()) return false;
50
- return /HTTP (405|501|502|503)\b/.test(String((e as Error)?.message ?? e));
45
+ /**
46
+ * Whether a failed owner-lite READ may answer with the built-in demo records.
47
+ *
48
+ * Only where a demo was asked for: a web preview host that is not live. On a phone no
49
+ * mode is injected, so `isBridgeUnavailable` alone is `true` for a transient Wix
50
+ * `HTTP 503` — and the owner was shown sample appointments, orders and sites as if
51
+ * they were their business. Native falls through to the screen's error state.
52
+ * `isBridgeUnavailable` keeps its semantics: other apps' callers depend on it.
53
+ */
54
+ export function ownerDemoFallback(e: unknown): boolean {
55
+ return isOwnerPreviewHost() && !isOwnerPreviewLive() && isBridgeUnavailable(e);
56
+ }
57
+
58
+ /**
59
+ * The sentence for an owner WRITE that failed because the device could not reach Wix at
60
+ * all (a transport failure). Nothing replays a queued write on any platform — every host's
61
+ * `drain` passes an empty closure — so the honest answer is that nothing was saved.
62
+ * Copy-as-configuration under `ownerCommon.`, which every owner screen forwards.
63
+ */
64
+ export function ownerOfflineNotSaved(): string {
65
+ return copyParam(
66
+ "ownerCommon.offlineNotSaved",
67
+ "You’re offline — nothing was saved. Try again when you reconnect.",
68
+ );
69
+ }
70
+
71
+ /** The sentence for an owner WRITE that Wix answered with an unavailable status: the
72
+ * device is online, so it is not "offline" — but nothing was saved all the same. */
73
+ /**
74
+ * Whether a failed WRITE may have landed on Wix anyway, so the user must not be told it
75
+ * was not saved: a transport failure mid-request (timeout, reset, fetch rejection), the web
76
+ * host's after-send envelope (`HTTP 502 {…"sent":true}`), the serve bridge's mid-request
77
+ * `webwix_bridge_upstream_failed`, or a gateway status (502/503/504) that can arrive after
78
+ * the backend already ran. Only connect-time failures (`isOfflineFailure`) and the designed
79
+ * 405/501 bridge refusals prove nothing happened.
80
+ */
81
+ export function writeMayHaveLanded(e: unknown): boolean {
82
+ if (isOfflineFailure(e)) return false;
83
+ if (isTransportFailure(e)) return true;
84
+ const msg = String((e as Error)?.message ?? e ?? "");
85
+ if (/"sent"\s*:\s*true/.test(msg)) return true;
86
+ // The web host's own envelope WITHOUT `sent: true` failed before the request left it, and
87
+ // a disabled owner rung / bridge refuses by design without sending anything.
88
+ if (/\bwebwix_(?:direct_failed|owner_disabled|bridge_disabled)\b/.test(msg)) return false;
89
+ // `webwix_bridge_upstream_failed` stays ambiguous: the same code covers a lookup that failed
90
+ // before sending and a serve-bridge failure mid-request, and nothing in it says which.
91
+ return /\bwebwix_bridge_upstream_failed\b/.test(msg) || /HTTP (502|503|504)\b/.test(msg);
92
+ }
93
+
94
+ /** Wix answered that the record does not exist (`HTTP 404`). A detail must not fall back to
95
+ * its cached row then: that row is what a delete whose reply was lost leaves behind. */
96
+ export function isNotFound(e: unknown): boolean {
97
+ if (/HTTP 404\b/.test(String((e as Error)?.message ?? e ?? ""))) return true;
98
+ // An SDK that answers a 404 with its own "not found" error keeps the HTTP one as `cause`
99
+ // (the blog SDK's getPost, after its query fallback also finds nothing).
100
+ const cause = (e as { cause?: unknown } | null | undefined)?.cause;
101
+ return cause !== undefined && cause !== e && /HTTP 404\b/.test(String((cause as Error)?.message ?? cause));
102
+ }
103
+
104
+ export function ownerUnavailableNotSaved(): string {
105
+ return copyParam(
106
+ "ownerCommon.unavailableNotSaved",
107
+ "Wix isn’t available right now — nothing was saved. Try again in a moment.",
108
+ );
109
+ }
110
+
111
+ /** The sentence for an owner WRITE that may have landed (`writeMayHaveLanded`): it can't
112
+ * be called saved or not saved. */
113
+ export function ownerWriteUnconfirmed(): string {
114
+ return copyParam(
115
+ "ownerCommon.writeUnconfirmed",
116
+ "Wix didn’t confirm this, so it may or may not have been saved. Check before trying again.",
117
+ );
118
+ }
119
+
120
+ /** Display copy for a failed owner write: `ownerOfflineNotSaved` when the request never
121
+ * left the device, `ownerWriteUnconfirmed` when it may have landed, `ownerUnavailableNotSaved`
122
+ * for the designed 405/501 bridge refusals outside a live preview, else `ownerLoadError`. */
123
+ export function ownerWriteError(e: unknown): string {
124
+ if (isOfflineFailure(e)) return ownerOfflineNotSaved();
125
+ if (writeMayHaveLanded(e)) return ownerWriteUnconfirmed();
126
+ if (!isOwnerPreviewLive() && /HTTP (405|501)\b/.test(String((e as Error)?.message ?? e))) return ownerUnavailableNotSaved();
127
+ return ownerLoadError(e);
51
128
  }
52
129
 
53
130
  /** `HTTP 403: …` → "403", when the message carries a status at all. */
@@ -99,6 +176,10 @@ const TRANSPORT = [
99
176
  /^Failed to connect to \S/,
100
177
  /^Unable to resolve host\b/,
101
178
  /\b(?:Connection refused|Network is unreachable|Software caused connection abort)\b/,
179
+ // OkHttp / HttpURLConnection messages a dropped connection produces mid-request, which
180
+ // Android's bridge forwards without the exception class.
181
+ /\b(?:Connection reset|ECONNRESET|ETIMEDOUT|EPIPE|Broken pipe|stream was reset)\b/,
182
+ /^unexpected end of stream\b/i,
102
183
  /^(?:timeout|Read timed out|connect timed out)$/i,
103
184
  /\bFailed to fetch\b/,
104
185
  /\bNetworkError when attempting to fetch\b/,
@@ -113,6 +194,27 @@ export function isTransportFailure(e: unknown): boolean {
113
194
  return TRANSPORT.some((re) => re.test(msg));
114
195
  }
115
196
 
197
+ /** Transport failures that happen while CONNECTING — no connection, no route, no such host,
198
+ * connection refused — so the request provably never left the device. Every other
199
+ * transport failure (a timeout, a reset, a bad or truncated response, a browser's fetch
200
+ * rejection, which says nothing about when it failed) may come after Wix took the write. */
201
+ const NEVER_SENT = [
202
+ /\bNSURLErrorDomain Code=-10(?:09|04|03|06|20|18)\b/, // not connected / cannot connect / no host / DNS / data not allowed / roaming off
203
+ /\b(?:UnknownHost|Connect|NoRouteToHost)Exception\b/,
204
+ /^Failed to connect to \S/,
205
+ /^Unable to resolve host\b/,
206
+ /\b(?:Connection refused|Network is unreachable)\b/,
207
+ /\bnet::ERR_(?:INTERNET_DISCONNECTED|NAME_NOT_RESOLVED|CONNECTION_REFUSED|ADDRESS_UNREACHABLE|NETWORK_ACCESS_DENIED)\b/,
208
+ ];
209
+
210
+ /** No HTTP answer, and the request provably never left the device: the user is offline, and
211
+ * a write certainly did not happen. Anything else may have landed (see `NEVER_SENT`). */
212
+ export function isOfflineFailure(e: unknown): boolean {
213
+ if (!isTransportFailure(e)) return false;
214
+ const msg = String((e as Error)?.message ?? e ?? "");
215
+ return NEVER_SENT.some((re) => re.test(msg));
216
+ }
217
+
116
218
  /** The one sentence for a transport failure. Copy-as-configuration: the key is
117
219
  * under `ownerCommon.`, which every owner screen (Aria included) forwards. */
118
220
  export function ownerTransportFailureText(): string {
@@ -194,8 +296,8 @@ export function ownerPreviewUnavailable(): string {
194
296
  * error says: this names the web preview when there IS one. `isBridgeUnavailable`
195
297
  * reads "not live" as "preview", and native injects no mode at all, so the
196
298
  * default would answer a device-side `HTTP 503` with "open this app on a device"
197
- * — on the device. That predicate is deliberately left alone: native
198
- * write-behind (`shouldQueueOwnerWrite`) depends on exactly it.
299
+ * — on the device. That predicate is deliberately left alone: other apps'
300
+ * demo and write-queue decisions depend on exactly it.
199
301
  *
200
302
  * The reductions this used to add are now in `humanWireError`, so every owner
201
303
  * screen gets them rather than the two that happened to call this.
@@ -232,6 +334,7 @@ export function ownerDisplayError(e: unknown): string {
232
334
  */
233
335
  export function ownerLoadError(e: unknown): string {
234
336
  const msg = String((e as Error)?.message ?? e);
235
- if (isBridgeUnavailable(e)) return ownerPreviewUnavailable();
337
+ // Same host guard as `ownerDisplayError`: on a phone, "open this app on a device" is false.
338
+ if (isOwnerPreviewHost() && isBridgeUnavailable(e)) return ownerPreviewUnavailable();
236
339
  return humanWireError(msg);
237
340
  }
@@ -4,8 +4,8 @@ import { getMember } from "@himalaya/wix-members";
4
4
  import { signedInEmail } from "../_shared/himi-account";
5
5
  import { initials } from "../_shared/himi-text.js";
6
6
  import { copyParam, stashCopy } from "../_shared/himi-copy.js";
7
- import { get as dbGet, upsert as dbUpsert, enqueue as dbEnqueue, type DbEntity } from "@himalaya/local-db";
8
- import { isBridgeUnavailable } from "../_shared/owner-load-error";
7
+ import { get as dbGet, upsert as dbUpsert, type DbEntity } from "@himalaya/local-db";
8
+ import { isOfflineFailure, writeMayHaveLanded } from "../_shared/owner-load-error";
9
9
 
10
10
  interface MemberAvatar {
11
11
  initials: string;
@@ -13,11 +13,12 @@ interface MemberAvatar {
13
13
  }
14
14
 
15
15
  // Offline-first (data-offline): the group detail READS through the shared `groups`
16
- // cache (get by id) so a previously-synced group still renders offline, and join/leave
17
- // are WRITE-BEHIND — the membership is written OPTIMISTICALLY to the local store, then
18
- // the Wix mutation is attempted; if the bridge/network is unreachable the mutation is
19
- // ENQUEUED for replay on reconnect. Every local-db call is wrapped (try/catch) so a
20
- // build without the `local_database` grant behaves exactly as before (online-only).
16
+ // cache (get by id) so a previously-synced group still renders offline. Join/leave
17
+ // are SERVER-CONFIRMED: the cached membership changes only after Wix accepts it; a
18
+ // failed one leaves it alone and tells the member why. No host replays a queued
19
+ // write, so nothing is queued.
20
+ // Every local-db call is wrapped so a build without the `local_database` grant
21
+ // behaves exactly as before (online-only).
21
22
  const ENTITY = "groups";
22
23
  async function readCachedGroup(id: string): Promise<DbEntity | null> {
23
24
  try { return await dbGet(ENTITY, id); } catch { return null; }
@@ -41,9 +42,6 @@ async function cachePutMembership(state: State, joined: boolean): Promise<void>
41
42
  await dbUpsert(ENTITY, { ...existing, id: state.id, joined: joined ? "true" : "false" });
42
43
  } catch { /* capability not granted */ }
43
44
  }
44
- async function queueWrite(actionId: string, params: Record<string, string>): Promise<void> {
45
- try { await dbEnqueue(actionId, params); } catch { /* capability not granted */ }
46
- }
47
45
 
48
46
  interface State {
49
47
  status: "loading" | "ready" | "error";
@@ -242,17 +240,19 @@ const svc = defineService<State, {
242
240
  if (state.privacy !== "Public" && state.privacy !== "Unknown") {
243
241
  return membershipState({ ...state, message: copyParam("group.privateInviteMessage", "Private groups are available by invitation.") }, false, true);
244
242
  }
245
- // Optimistic local write — persist the joined membership so it survives offline.
246
- await cachePutMembership(state, true);
247
243
  try {
248
244
  await joinGroup(state.id);
245
+ // Wix confirmed it: persist the joined membership so it survives offline.
246
+ await cachePutMembership(state, true);
249
247
  return membershipState({ ...state, message: copyParam("group.joinedMessage", "You joined the group.") }, true, true);
250
248
  } catch (e) {
251
- if (isBridgeUnavailable(e)) {
252
- // Offline / no bridge: the optimistic cache already reflects the join; queue
253
- // the write to replay (WriteQueue, idempotent) when connectivity returns.
254
- await queueWrite("tier5.himiBrandedGroup.join", { id: state.id });
255
- return membershipState({ ...state, message: copyParam("group.joinedOfflineMessage", "You joined the group — it will sync when you reconnect.") }, true, true);
249
+ if (isOfflineFailure(e)) {
250
+ return membershipState({ ...state, message: copyParam("group.offlineFailedMessage", "You’re offline — nothing was saved. Try again when you reconnect.") }, false, true);
251
+ }
252
+ // It may have landed: neither "joined" nor "could not". (No "refresh to check": a load
253
+ // does not read the membership back.)
254
+ if (writeMayHaveLanded(e)) {
255
+ return membershipState({ ...state, message: copyParam("group.joinUnconfirmedMessage", "Wix didn’t confirm this, so you may already have joined the group.") }, false, true);
256
256
  }
257
257
  return membershipState({ ...state, message: copyParam("group.joinFailedMessage", "The group could not be joined. Try again.") }, false, true);
258
258
  }
@@ -260,17 +260,17 @@ const svc = defineService<State, {
260
260
  leave: async (state) => {
261
261
  const signedIn = Boolean(await signedInEmail());
262
262
  if (!signedIn) return membershipState({ ...state, message: copyParam("group.manageSignInMessage", "Sign in from Profile to manage groups.") }, state.isJoined, false);
263
- // Optimistic local write — persist the left membership so it survives offline.
264
- await cachePutMembership(state, false);
265
263
  try {
266
264
  await leaveGroup(state.id);
265
+ // Wix confirmed it: persist the left membership so it survives offline.
266
+ await cachePutMembership(state, false);
267
267
  return membershipState({ ...state, message: copyParam("group.leftMessage", "You left the group.") }, false, true);
268
268
  } catch (e) {
269
- if (isBridgeUnavailable(e)) {
270
- // Offline / no bridge: the optimistic cache already reflects the leave; queue
271
- // the write to replay (WriteQueue, idempotent) when connectivity returns.
272
- await queueWrite("tier5.himiBrandedGroup.leave", { id: state.id });
273
- return membershipState({ ...state, message: copyParam("group.leftOfflineMessage", "You left the group — it will sync when you reconnect.") }, false, true);
269
+ if (isOfflineFailure(e)) {
270
+ return membershipState({ ...state, message: copyParam("group.offlineFailedMessage", "You’re offline — nothing was saved. Try again when you reconnect.") }, true, true);
271
+ }
272
+ if (writeMayHaveLanded(e)) {
273
+ return membershipState({ ...state, message: copyParam("group.leaveUnconfirmedMessage", "Wix didn’t confirm this, so you may already have left the group.") }, true, true);
274
274
  }
275
275
  return membershipState({ ...state, message: copyParam("group.leaveFailedMessage", "The group could not be left. Try again.") }, true, true);
276
276
  }