@wix/himalaya-cli 0.1582.0 → 0.1584.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 (336) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/builder.d.ts +8 -0
  2. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/schema.d.ts +26 -2
  3. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/validator.d.ts +18 -0
  4. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/blog-v3/src/extensions.d.ts +2 -0
  5. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/comments-v1/src/extensions.d.ts +2 -0
  6. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/events/src/index.d.ts +3 -0
  7. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/groups/src/extensions.d.ts +15 -0
  8. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/loyalty/src/extensions.d.ts +13 -0
  9. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/members-v1/src/index.d.ts +19 -4
  10. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/core.mjs +5 -1
  11. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/sdui.mjs +5 -1
  12. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-comments.mjs +3 -0
  13. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-events.mjs +4 -2
  14. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-groups.mjs +5 -0
  15. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-loyalty.mjs +4 -0
  16. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-members.mjs +10 -3
  17. package/dist/cli.mjs +1098 -702
  18. package/dist/preview-assets.generated.bin +0 -0
  19. package/fixtures/wix-canned.json +25 -0
  20. package/guides/component-reference.json +4 -3
  21. package/guides/component-reference.md +24 -2
  22. package/guides/one-app-to-himi-app.md +52 -1
  23. package/guides/sdk-reference.json +37 -9
  24. package/guides/wix-api-usage.md +9 -0
  25. package/package.json +2 -2
  26. package/templates/beauty-salon/config.ts +27 -1
  27. package/templates/beauty-salon/dev/index.ts +2285 -757
  28. package/templates/beauty-salon/himalaya.content.json +3 -0
  29. package/templates/beauty-salon/tier5-src/_shared/booking-location.ts +147 -0
  30. package/templates/beauty-salon/tier5-src/_shared/booking-session.ts +222 -0
  31. package/templates/beauty-salon/tier5-src/_shared/branded-lite-hosted.ts +1 -1
  32. package/templates/beauty-salon/tier5-src/_shared/collection-contract.ts +19 -3
  33. package/templates/beauty-salon/tier5-src/_shared/himi-restaurants.ts +2 -1
  34. package/templates/beauty-salon/tier5-src/_shared/owner-editor-value.ts +164 -0
  35. package/templates/beauty-salon/tier5-src/_shared/store-product-info.ts +50 -0
  36. package/templates/beauty-salon/tier5-src/himi-blog-post/index.ts +21 -8
  37. package/templates/beauty-salon/tier5-src/himi-booking-service/index.ts +277 -14
  38. package/templates/beauty-salon/tier5-src/himi-booking-services/index.ts +351 -92
  39. package/templates/beauty-salon/tier5-src/himi-booking-time/index.ts +25 -5
  40. package/templates/beauty-salon/tier5-src/himi-branded-lite-agenda/index.ts +219 -220
  41. package/templates/beauty-salon/tier5-src/himi-branded-lite-category/index.ts +3 -2
  42. package/templates/beauty-salon/tier5-src/himi-branded-lite-notifsettings/index.ts +173 -0
  43. package/templates/beauty-salon/tier5-src/himi-branded-lite-plans/index.ts +2 -1
  44. package/templates/beauty-salon/tier5-src/himi-store-product/index.ts +14 -3
  45. package/templates/beauty-salon/tier5-src/wix-spaces-plan-detail/index.ts +2 -1
  46. package/templates/beauty-salon/tier5-src/wix-spaces-whats-new/index.ts +2 -1
  47. package/templates/beauty-salon-owner/dev/index.ts +129 -66
  48. package/templates/beauty-salon-owner/tier5-src/_shared/collection-contract.ts +19 -3
  49. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-post/index.ts +7 -0
  50. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-product/index.ts +39 -6
  51. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-product-form/index.ts +14 -8
  52. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-products/index.ts +7 -4
  53. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-service/index.ts +38 -7
  54. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-service-form/index.ts +53 -7
  55. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-services/index.ts +4 -2
  56. package/templates/branded-lite/config.ts +29 -1
  57. package/templates/branded-lite/dev/index.ts +8371 -5565
  58. package/templates/branded-lite/himalaya.content.json +3 -0
  59. package/templates/branded-lite/l10n/en.json +2 -2
  60. package/templates/branded-lite/tier5-src/_shared/booking-location.ts +147 -0
  61. package/templates/branded-lite/tier5-src/_shared/booking-session.ts +222 -0
  62. package/templates/branded-lite/tier5-src/_shared/branded-lite-hosted.ts +1 -1
  63. package/templates/branded-lite/tier5-src/_shared/collection-contract.ts +19 -3
  64. package/templates/branded-lite/tier5-src/_shared/event-registration.ts +86 -0
  65. package/templates/branded-lite/tier5-src/_shared/himi-restaurants.ts +2 -1
  66. package/templates/branded-lite/tier5-src/_shared/owner-editor-value.ts +164 -0
  67. package/templates/branded-lite/tier5-src/_shared/store-product-info.ts +50 -0
  68. package/templates/branded-lite/tier5-src/himi-blog-post/index.ts +21 -8
  69. package/templates/branded-lite/tier5-src/himi-booking-service/index.ts +277 -14
  70. package/templates/branded-lite/tier5-src/himi-booking-services/index.ts +351 -92
  71. package/templates/branded-lite/tier5-src/himi-booking-time/index.ts +25 -5
  72. package/templates/branded-lite/tier5-src/himi-branded-lite-agenda/index.ts +219 -220
  73. package/templates/branded-lite/tier5-src/himi-branded-lite-badges/index.ts +2 -1
  74. package/templates/branded-lite/tier5-src/himi-branded-lite-category/index.ts +3 -2
  75. package/templates/branded-lite/tier5-src/himi-branded-lite-feed/index.ts +4 -3
  76. package/templates/branded-lite/tier5-src/himi-branded-lite-group-about/index.ts +243 -0
  77. package/templates/branded-lite/tier5-src/himi-branded-lite-loyalty/index.ts +115 -49
  78. package/templates/branded-lite/tier5-src/himi-branded-lite-plans/index.ts +2 -1
  79. package/templates/branded-lite/tier5-src/himi-branded-lite-podcasts/index.ts +2 -1
  80. package/templates/branded-lite/tier5-src/himi-branded-lite-portfolio/index.ts +2 -1
  81. package/templates/branded-lite/tier5-src/himi-branded-lite-portfolio-project/index.ts +3 -2
  82. package/templates/branded-lite/tier5-src/himi-branded-lite-program/facts.ts +52 -0
  83. package/templates/branded-lite/tier5-src/himi-branded-lite-program/index.ts +21 -11
  84. package/templates/branded-lite/tier5-src/himi-branded-lite-video/index.ts +2 -1
  85. package/templates/branded-lite/tier5-src/himi-events-detail/index.ts +12 -86
  86. package/templates/branded-lite/tier5-src/himi-events-list/index.ts +47 -6
  87. package/templates/branded-lite/tier5-src/himi-store-product/index.ts +13 -3
  88. package/templates/branded-lite/tier5-src/wix-spaces-forum-post/index.ts +3 -2
  89. package/templates/branded-lite/tier5-src/wix-spaces-member-detail/index.ts +53 -37
  90. package/templates/branded-lite/tier5-src/wix-spaces-members/index.ts +100 -34
  91. package/templates/branded-lite/tier5-src/wix-spaces-plan-detail/index.ts +2 -1
  92. package/templates/branded-lite/tier5-src/wix-spaces-whats-new/index.ts +2 -1
  93. package/templates/community-club/config.ts +36 -1
  94. package/templates/community-club/dev/index.ts +1930 -401
  95. package/templates/community-club/himalaya.content.json +6 -0
  96. package/templates/community-club/tier5-src/_shared/branded-lite-hosted.ts +1 -1
  97. package/templates/community-club/tier5-src/_shared/collection-contract.ts +19 -3
  98. package/templates/community-club/tier5-src/_shared/event-registration.ts +86 -0
  99. package/templates/community-club/tier5-src/_shared/himi-restaurants.ts +2 -1
  100. package/templates/community-club/tier5-src/himi-blog-post/index.ts +21 -8
  101. package/templates/community-club/tier5-src/himi-branded-lite-feed/index.ts +4 -3
  102. package/templates/community-club/tier5-src/himi-branded-lite-group-about/index.ts +243 -0
  103. package/templates/community-club/tier5-src/himi-branded-lite-notifsettings/index.ts +173 -0
  104. package/templates/community-club/tier5-src/himi-events-detail/index.ts +12 -86
  105. package/templates/community-club/tier5-src/himi-events-list/index.ts +47 -6
  106. package/templates/community-club/tier5-src/wix-spaces-whats-new/index.ts +2 -1
  107. package/templates/community-club-owner/dev/index.ts +53 -1
  108. package/templates/community-club-owner/tier5-src/_shared/collection-contract.ts +19 -3
  109. package/templates/community-club-owner/tier5-src/himi-owner-lite-event/index.ts +16 -8
  110. package/templates/community-club-owner/tier5-src/himi-owner-lite-event-form/index.ts +16 -7
  111. package/templates/community-club-owner/tier5-src/himi-owner-lite-events/index.ts +4 -2
  112. package/templates/community-club-owner/tier5-src/himi-owner-lite-post/index.ts +7 -0
  113. package/templates/community-club-owner/tier5-src/himi-owner-lite-product/index.ts +39 -6
  114. package/templates/community-club-owner/tier5-src/himi-owner-lite-product-form/index.ts +14 -8
  115. package/templates/community-club-owner/tier5-src/himi-owner-lite-products/index.ts +7 -4
  116. package/templates/events-meetups/config.ts +36 -1
  117. package/templates/events-meetups/dev/index.ts +1930 -401
  118. package/templates/events-meetups/himalaya.content.json +6 -0
  119. package/templates/events-meetups/tier5-src/_shared/branded-lite-hosted.ts +1 -1
  120. package/templates/events-meetups/tier5-src/_shared/collection-contract.ts +19 -3
  121. package/templates/events-meetups/tier5-src/_shared/event-registration.ts +86 -0
  122. package/templates/events-meetups/tier5-src/_shared/himi-restaurants.ts +2 -1
  123. package/templates/events-meetups/tier5-src/himi-blog-post/index.ts +21 -8
  124. package/templates/events-meetups/tier5-src/himi-branded-lite-feed/index.ts +4 -3
  125. package/templates/events-meetups/tier5-src/himi-branded-lite-group-about/index.ts +243 -0
  126. package/templates/events-meetups/tier5-src/himi-branded-lite-notifsettings/index.ts +173 -0
  127. package/templates/events-meetups/tier5-src/himi-events-detail/index.ts +12 -86
  128. package/templates/events-meetups/tier5-src/himi-events-list/index.ts +47 -6
  129. package/templates/events-meetups/tier5-src/wix-spaces-whats-new/index.ts +2 -1
  130. package/templates/events-meetups-owner/dev/index.ts +6 -0
  131. package/templates/events-meetups-owner/tier5-src/_shared/collection-contract.ts +19 -3
  132. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-event/index.ts +16 -8
  133. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-event-form/index.ts +16 -7
  134. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-events/index.ts +4 -2
  135. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-post/index.ts +7 -0
  136. package/templates/gym-fitness/config.ts +27 -1
  137. package/templates/gym-fitness/dev/index.ts +2803 -844
  138. package/templates/gym-fitness/himalaya.content.json +3 -0
  139. package/templates/gym-fitness/tier5-src/_shared/booking-location.ts +147 -0
  140. package/templates/gym-fitness/tier5-src/_shared/booking-session.ts +222 -0
  141. package/templates/gym-fitness/tier5-src/_shared/branded-lite-hosted.ts +1 -1
  142. package/templates/gym-fitness/tier5-src/_shared/collection-contract.ts +19 -3
  143. package/templates/gym-fitness/tier5-src/_shared/event-registration.ts +86 -0
  144. package/templates/gym-fitness/tier5-src/_shared/himi-restaurants.ts +2 -1
  145. package/templates/gym-fitness/tier5-src/_shared/owner-editor-value.ts +164 -0
  146. package/templates/gym-fitness/tier5-src/_shared/store-product-info.ts +50 -0
  147. package/templates/gym-fitness/tier5-src/himi-blog-post/index.ts +21 -8
  148. package/templates/gym-fitness/tier5-src/himi-booking-service/index.ts +277 -14
  149. package/templates/gym-fitness/tier5-src/himi-booking-services/index.ts +351 -92
  150. package/templates/gym-fitness/tier5-src/himi-booking-time/index.ts +25 -5
  151. package/templates/gym-fitness/tier5-src/himi-branded-lite-agenda/index.ts +219 -220
  152. package/templates/gym-fitness/tier5-src/himi-branded-lite-category/index.ts +3 -2
  153. package/templates/gym-fitness/tier5-src/himi-branded-lite-notifsettings/index.ts +173 -0
  154. package/templates/gym-fitness/tier5-src/himi-branded-lite-plans/index.ts +2 -1
  155. package/templates/gym-fitness/tier5-src/himi-events-detail/index.ts +12 -86
  156. package/templates/gym-fitness/tier5-src/himi-events-list/index.ts +47 -6
  157. package/templates/gym-fitness/tier5-src/himi-store-product/index.ts +14 -3
  158. package/templates/gym-fitness/tier5-src/wix-spaces-plan-detail/index.ts +2 -1
  159. package/templates/gym-fitness/tier5-src/wix-spaces-whats-new/index.ts +2 -1
  160. package/templates/gym-fitness-owner/dev/index.ts +132 -66
  161. package/templates/gym-fitness-owner/tier5-src/_shared/collection-contract.ts +19 -3
  162. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-event/index.ts +16 -8
  163. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-event-form/index.ts +16 -7
  164. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-events/index.ts +4 -2
  165. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-post/index.ts +7 -0
  166. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-product/index.ts +39 -6
  167. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-product-form/index.ts +14 -8
  168. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-products/index.ts +7 -4
  169. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-service/index.ts +38 -7
  170. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-service-form/index.ts +53 -7
  171. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-services/index.ts +4 -2
  172. package/templates/nonprofit-cause/config.ts +36 -1
  173. package/templates/nonprofit-cause/dev/index.ts +1925 -396
  174. package/templates/nonprofit-cause/himalaya.content.json +6 -0
  175. package/templates/nonprofit-cause/tier5-src/_shared/branded-lite-hosted.ts +1 -1
  176. package/templates/nonprofit-cause/tier5-src/_shared/collection-contract.ts +19 -3
  177. package/templates/nonprofit-cause/tier5-src/_shared/event-registration.ts +86 -0
  178. package/templates/nonprofit-cause/tier5-src/_shared/himi-restaurants.ts +2 -1
  179. package/templates/nonprofit-cause/tier5-src/himi-blog-post/index.ts +21 -8
  180. package/templates/nonprofit-cause/tier5-src/himi-branded-lite-feed/index.ts +4 -3
  181. package/templates/nonprofit-cause/tier5-src/himi-branded-lite-group-about/index.ts +243 -0
  182. package/templates/nonprofit-cause/tier5-src/himi-branded-lite-notifsettings/index.ts +173 -0
  183. package/templates/nonprofit-cause/tier5-src/himi-branded-lite-plans/index.ts +2 -1
  184. package/templates/nonprofit-cause/tier5-src/himi-events-detail/index.ts +12 -86
  185. package/templates/nonprofit-cause/tier5-src/himi-events-list/index.ts +47 -6
  186. package/templates/nonprofit-cause/tier5-src/wix-spaces-plan-detail/index.ts +2 -1
  187. package/templates/nonprofit-cause/tier5-src/wix-spaces-whats-new/index.ts +2 -1
  188. package/templates/nonprofit-cause-owner/dev/index.ts +85 -65
  189. package/templates/nonprofit-cause-owner/tier5-src/_shared/collection-contract.ts +19 -3
  190. package/templates/nonprofit-cause-owner/tier5-src/_shared/owner-rich-guard.ts +27 -0
  191. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-event/index.ts +16 -8
  192. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-event-form/index.ts +16 -7
  193. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-events/index.ts +4 -2
  194. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-post/index.ts +7 -0
  195. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-service/index.ts +38 -7
  196. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-service-form/index.ts +53 -7
  197. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-services/index.ts +4 -2
  198. package/templates/owner-lite/dev/index.ts +132 -66
  199. package/templates/owner-lite/tier5-src/_shared/collection-contract.ts +19 -3
  200. package/templates/owner-lite/tier5-src/himi-owner-lite-event/index.ts +16 -8
  201. package/templates/owner-lite/tier5-src/himi-owner-lite-event-form/index.ts +16 -7
  202. package/templates/owner-lite/tier5-src/himi-owner-lite-events/index.ts +4 -2
  203. package/templates/owner-lite/tier5-src/himi-owner-lite-post/index.ts +7 -0
  204. package/templates/owner-lite/tier5-src/himi-owner-lite-product/index.ts +39 -6
  205. package/templates/owner-lite/tier5-src/himi-owner-lite-product-form/index.ts +14 -8
  206. package/templates/owner-lite/tier5-src/himi-owner-lite-products/index.ts +7 -4
  207. package/templates/owner-lite/tier5-src/himi-owner-lite-service/index.ts +38 -7
  208. package/templates/owner-lite/tier5-src/himi-owner-lite-service-form/index.ts +53 -7
  209. package/templates/owner-lite/tier5-src/himi-owner-lite-services/index.ts +4 -2
  210. package/templates/podcast-creator/config.ts +27 -1
  211. package/templates/podcast-creator/dev/index.ts +1051 -158
  212. package/templates/podcast-creator/himalaya.content.json +3 -0
  213. package/templates/podcast-creator/tier5-src/_shared/branded-lite-hosted.ts +1 -1
  214. package/templates/podcast-creator/tier5-src/_shared/collection-contract.ts +19 -3
  215. package/templates/podcast-creator/tier5-src/_shared/event-registration.ts +86 -0
  216. package/templates/podcast-creator/tier5-src/_shared/himi-restaurants.ts +2 -1
  217. package/templates/podcast-creator/tier5-src/himi-blog-post/index.ts +21 -8
  218. package/templates/podcast-creator/tier5-src/himi-branded-lite-feed/index.ts +4 -3
  219. package/templates/podcast-creator/tier5-src/himi-branded-lite-notifsettings/index.ts +173 -0
  220. package/templates/podcast-creator/tier5-src/himi-branded-lite-plans/index.ts +2 -1
  221. package/templates/podcast-creator/tier5-src/himi-branded-lite-podcasts/index.ts +2 -1
  222. package/templates/podcast-creator/tier5-src/himi-events-detail/index.ts +12 -86
  223. package/templates/podcast-creator/tier5-src/himi-events-list/index.ts +47 -6
  224. package/templates/podcast-creator/tier5-src/wix-spaces-plan-detail/index.ts +2 -1
  225. package/templates/podcast-creator/tier5-src/wix-spaces-whats-new/index.ts +2 -1
  226. package/templates/podcast-creator-owner/dev/index.ts +53 -1
  227. package/templates/podcast-creator-owner/tier5-src/_shared/collection-contract.ts +19 -3
  228. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-event/index.ts +16 -8
  229. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-event-form/index.ts +16 -7
  230. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-events/index.ts +4 -2
  231. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-post/index.ts +7 -0
  232. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-product/index.ts +39 -6
  233. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-product-form/index.ts +14 -8
  234. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-products/index.ts +7 -4
  235. package/templates/portfolio-creative/config.ts +27 -1
  236. package/templates/portfolio-creative/dev/index.ts +1305 -468
  237. package/templates/portfolio-creative/himalaya.content.json +3 -0
  238. package/templates/portfolio-creative/tier5-src/_shared/branded-lite-hosted.ts +1 -1
  239. package/templates/portfolio-creative/tier5-src/_shared/collection-contract.ts +19 -3
  240. package/templates/portfolio-creative/tier5-src/_shared/event-registration.ts +86 -0
  241. package/templates/portfolio-creative/tier5-src/_shared/himi-restaurants.ts +2 -1
  242. package/templates/portfolio-creative/tier5-src/_shared/owner-editor-value.ts +164 -0
  243. package/templates/portfolio-creative/tier5-src/_shared/store-product-info.ts +50 -0
  244. package/templates/portfolio-creative/tier5-src/himi-blog-post/index.ts +21 -8
  245. package/templates/portfolio-creative/tier5-src/himi-branded-lite-category/index.ts +3 -2
  246. package/templates/portfolio-creative/tier5-src/himi-branded-lite-notifsettings/index.ts +173 -0
  247. package/templates/portfolio-creative/tier5-src/himi-branded-lite-portfolio/index.ts +2 -1
  248. package/templates/portfolio-creative/tier5-src/himi-branded-lite-portfolio-project/index.ts +3 -2
  249. package/templates/portfolio-creative/tier5-src/himi-events-detail/index.ts +12 -86
  250. package/templates/portfolio-creative/tier5-src/himi-events-list/index.ts +47 -6
  251. package/templates/portfolio-creative/tier5-src/himi-store-product/index.ts +14 -3
  252. package/templates/portfolio-creative/tier5-src/wix-spaces-whats-new/index.ts +2 -1
  253. package/templates/portfolio-creative-owner/dev/index.ts +129 -66
  254. package/templates/portfolio-creative-owner/tier5-src/_shared/collection-contract.ts +19 -3
  255. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-post/index.ts +7 -0
  256. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-product/index.ts +39 -6
  257. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-product-form/index.ts +14 -8
  258. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-products/index.ts +7 -4
  259. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-service/index.ts +38 -7
  260. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-service-form/index.ts +53 -7
  261. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-services/index.ts +4 -2
  262. package/templates/restaurant/config.ts +27 -1
  263. package/templates/restaurant/dev/index.ts +1051 -158
  264. package/templates/restaurant/himalaya.content.json +3 -0
  265. package/templates/restaurant/tier5-src/_shared/branded-lite-hosted.ts +1 -1
  266. package/templates/restaurant/tier5-src/_shared/collection-contract.ts +19 -3
  267. package/templates/restaurant/tier5-src/_shared/event-registration.ts +86 -0
  268. package/templates/restaurant/tier5-src/_shared/himi-restaurants.ts +2 -1
  269. package/templates/restaurant/tier5-src/himi-blog-post/index.ts +21 -8
  270. package/templates/restaurant/tier5-src/himi-branded-lite-notifsettings/index.ts +173 -0
  271. package/templates/restaurant/tier5-src/himi-events-detail/index.ts +12 -86
  272. package/templates/restaurant/tier5-src/himi-events-list/index.ts +47 -6
  273. package/templates/restaurant/tier5-src/wix-spaces-whats-new/index.ts +2 -1
  274. package/templates/restaurant-owner/dev/index.ts +132 -66
  275. package/templates/restaurant-owner/tier5-src/_shared/collection-contract.ts +19 -3
  276. package/templates/restaurant-owner/tier5-src/himi-owner-lite-event/index.ts +16 -8
  277. package/templates/restaurant-owner/tier5-src/himi-owner-lite-event-form/index.ts +16 -7
  278. package/templates/restaurant-owner/tier5-src/himi-owner-lite-events/index.ts +4 -2
  279. package/templates/restaurant-owner/tier5-src/himi-owner-lite-post/index.ts +7 -0
  280. package/templates/restaurant-owner/tier5-src/himi-owner-lite-product/index.ts +39 -6
  281. package/templates/restaurant-owner/tier5-src/himi-owner-lite-product-form/index.ts +14 -8
  282. package/templates/restaurant-owner/tier5-src/himi-owner-lite-products/index.ts +7 -4
  283. package/templates/restaurant-owner/tier5-src/himi-owner-lite-service/index.ts +38 -7
  284. package/templates/restaurant-owner/tier5-src/himi-owner-lite-service-form/index.ts +53 -7
  285. package/templates/restaurant-owner/tier5-src/himi-owner-lite-services/index.ts +4 -2
  286. package/templates/retail-store/config.ts +27 -1
  287. package/templates/retail-store/dev/index.ts +597 -191
  288. package/templates/retail-store/himalaya.content.json +3 -0
  289. package/templates/retail-store/tier5-src/_shared/branded-lite-hosted.ts +1 -1
  290. package/templates/retail-store/tier5-src/_shared/collection-contract.ts +19 -3
  291. package/templates/retail-store/tier5-src/_shared/himi-restaurants.ts +2 -1
  292. package/templates/retail-store/tier5-src/_shared/owner-editor-value.ts +164 -0
  293. package/templates/retail-store/tier5-src/_shared/store-product-info.ts +50 -0
  294. package/templates/retail-store/tier5-src/himi-blog-post/index.ts +21 -8
  295. package/templates/retail-store/tier5-src/himi-branded-lite-category/index.ts +3 -2
  296. package/templates/retail-store/tier5-src/himi-branded-lite-notifsettings/index.ts +173 -0
  297. package/templates/retail-store/tier5-src/himi-store-product/index.ts +13 -3
  298. package/templates/retail-store/tier5-src/wix-spaces-whats-new/index.ts +2 -1
  299. package/templates/retail-store-owner/dev/index.ts +50 -1
  300. package/templates/retail-store-owner/tier5-src/_shared/collection-contract.ts +19 -3
  301. package/templates/retail-store-owner/tier5-src/himi-owner-lite-post/index.ts +7 -0
  302. package/templates/retail-store-owner/tier5-src/himi-owner-lite-product/index.ts +39 -6
  303. package/templates/retail-store-owner/tier5-src/himi-owner-lite-product-form/index.ts +14 -8
  304. package/templates/retail-store-owner/tier5-src/himi-owner-lite-products/index.ts +7 -4
  305. package/templates/yoga-studio/config.ts +27 -1
  306. package/templates/yoga-studio/dev/index.ts +2996 -877
  307. package/templates/yoga-studio/himalaya.content.json +3 -0
  308. package/templates/yoga-studio/tier5-src/_shared/booking-location.ts +147 -0
  309. package/templates/yoga-studio/tier5-src/_shared/booking-session.ts +222 -0
  310. package/templates/yoga-studio/tier5-src/_shared/branded-lite-hosted.ts +1 -1
  311. package/templates/yoga-studio/tier5-src/_shared/collection-contract.ts +19 -3
  312. package/templates/yoga-studio/tier5-src/_shared/event-registration.ts +86 -0
  313. package/templates/yoga-studio/tier5-src/_shared/himi-restaurants.ts +2 -1
  314. package/templates/yoga-studio/tier5-src/himi-blog-post/index.ts +21 -8
  315. package/templates/yoga-studio/tier5-src/himi-booking-service/index.ts +277 -14
  316. package/templates/yoga-studio/tier5-src/himi-booking-services/index.ts +351 -92
  317. package/templates/yoga-studio/tier5-src/himi-booking-time/index.ts +25 -5
  318. package/templates/yoga-studio/tier5-src/himi-branded-lite-agenda/index.ts +219 -220
  319. package/templates/yoga-studio/tier5-src/himi-branded-lite-notifsettings/index.ts +173 -0
  320. package/templates/yoga-studio/tier5-src/himi-branded-lite-plans/index.ts +2 -1
  321. package/templates/yoga-studio/tier5-src/himi-branded-lite-program/facts.ts +52 -0
  322. package/templates/yoga-studio/tier5-src/himi-branded-lite-program/index.ts +21 -11
  323. package/templates/yoga-studio/tier5-src/himi-events-detail/index.ts +12 -86
  324. package/templates/yoga-studio/tier5-src/himi-events-list/index.ts +47 -6
  325. package/templates/yoga-studio/tier5-src/wix-spaces-plan-detail/index.ts +2 -1
  326. package/templates/yoga-studio/tier5-src/wix-spaces-whats-new/index.ts +2 -1
  327. package/templates/yoga-studio-owner/dev/index.ts +85 -65
  328. package/templates/yoga-studio-owner/tier5-src/_shared/collection-contract.ts +19 -3
  329. package/templates/yoga-studio-owner/tier5-src/_shared/owner-rich-guard.ts +27 -0
  330. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-event/index.ts +16 -8
  331. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-event-form/index.ts +16 -7
  332. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-events/index.ts +4 -2
  333. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-post/index.ts +7 -0
  334. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-service/index.ts +38 -7
  335. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-service-form/index.ts +53 -7
  336. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-services/index.ts +4 -2
@@ -1,3 +1,6 @@
1
+ import { descriptionBody } from "../_shared/rich-body.js";
2
+ import { htmlIsTrivial, htmlPreviewText } from "../_shared/owner-rich-guard.js";
3
+ import { parseRicosJson } from "@himalaya/wix-rich-content";
1
4
  // Tier-5 bundle: __HIMI_APP_NAME__ — edit Bookings service (the CRUD "U").
2
5
  // Opened from the service detail ("Edit"). EDIT-ONLY — the Bookings v2
3
6
  // service-create needs a full nested structure the generated client doesn't
@@ -31,6 +34,10 @@ interface ServiceFormState {
31
34
  heading: string;
32
35
  name: string;
33
36
  description: string;
37
+ originalDescription: unknown;
38
+ descriptionProtected: boolean;
39
+ descriptionEditable: boolean;
40
+ descriptionNote: string;
34
41
  category: string;
35
42
  status: "idle" | "loading" | "saving" | "saved" | "error";
36
43
  writeBusy: boolean;
@@ -79,6 +86,16 @@ function categoryName(s: WixService): string {
79
86
  return "";
80
87
  }
81
88
 
89
+ function descriptionFields(value: unknown, known = true) {
90
+ const body = descriptionBody(value);
91
+ const protectedBody = !known || (value != null && (typeof value !== "string" || !!parseRicosJson(value)
92
+ || !htmlIsTrivial(value) || (!!htmlPreviewText(value).trim() && !body.bodyText)));
93
+ return { description: body.bodyText, originalDescription: known ? value ?? "" : undefined, descriptionProtected: protectedBody,
94
+ descriptionEditable: !protectedBody, descriptionNote: protectedBody
95
+ ? known ? copyParam("ownerServiceForm.richDescriptionNote", "This description has formatting or media. Edit it in your site dashboard to keep that content intact; the name can be changed here.")
96
+ : copyParam("ownerServiceForm.descriptionNotLoaded", "The description is not available yet. The name can be changed here.") : "" };
97
+ }
98
+
82
99
  function shape(s: Partial<ServiceFormState>): ServiceFormState {
83
100
  const id = typeof s.id === "string" ? s.id : "";
84
101
  const savedId = typeof s.savedId === "string" ? s.savedId : id;
@@ -89,6 +106,10 @@ function shape(s: Partial<ServiceFormState>): ServiceFormState {
89
106
  heading: s.heading ?? copyParam("ownerServiceForm.headingEdit", "Edit service"),
90
107
  name: s.name ?? "",
91
108
  description: s.description ?? "",
109
+ originalDescription: s.originalDescription,
110
+ descriptionProtected: s.descriptionProtected ?? true,
111
+ descriptionEditable: s.descriptionProtected === false,
112
+ descriptionNote: s.descriptionNote ?? copyParam("ownerServiceForm.descriptionNotLoaded", "The description is not available yet. The name can be changed here."),
92
113
  category: s.category ?? "",
93
114
  status: s.status ?? "idle",
94
115
  writeBusy: s.writeBusy ?? false,
@@ -117,6 +138,8 @@ const svc = defineService<ServiceFormState, {
117
138
  submit: (s: ServiceFormState, values?: Record<string, unknown>) => Promise<ServiceFormState>;
118
139
  }>("himiOwnerLiteServiceForm", {
119
140
  state: shape({ id: initialId }),
141
+ notHydrated: ["originalDescription", "descriptionProtected", "descriptionEditable", "descriptionNote"],
142
+ perVisit: ["originalDescription", "descriptionProtected", "descriptionEditable", "descriptionNote"],
120
143
  actions: {
121
144
  load: async (s, arg): Promise<ServiceFormState | undefined> => landsOnLive(svc, s, await (async () => {
122
145
  stashCopy(arg); // absorb the descriptor's onAppear copy-pack param
@@ -130,7 +153,7 @@ const svc = defineService<ServiceFormState, {
130
153
  if (d) {
131
154
  return shape({
132
155
  ...s, id, heading: copyParam("ownerServiceForm.headingEdit", "Edit service"),
133
- name: d.name, description: d.description, category: d.category,
156
+ name: d.name, ...descriptionFields(d.description), category: d.category,
134
157
  status: "idle", error: "", savedMessage: "", demoNote: copyParam("ownerCommon.demoNote", DEMO_NOTE),
135
158
  });
136
159
  }
@@ -144,7 +167,7 @@ const svc = defineService<ServiceFormState, {
144
167
  ...s, id, heading: copyParam("ownerServiceForm.headingEdit", "Edit service"),
145
168
  revision: String((svcObj as any).revision ?? ""),
146
169
  name: (svcObj as any).name ?? "",
147
- description: (svcObj as any).description ?? "",
170
+ ...descriptionFields((svcObj as any).description),
148
171
  category: categoryName(svcObj),
149
172
  status: "idle", error: "", savedMessage: "",
150
173
  });
@@ -155,7 +178,7 @@ const svc = defineService<ServiceFormState, {
155
178
  return shape({
156
179
  ...s, id, heading: "Edit service",
157
180
  name: String(cached.name ?? cached.title ?? ""),
158
- description: String(cached.description ?? ""),
181
+ ...descriptionFields(cached.description, Object.hasOwn(cached, "description")),
159
182
  category: String(cached.category ?? ""),
160
183
  status: "idle", error: "", savedMessage: "",
161
184
  });
@@ -165,7 +188,7 @@ const svc = defineService<ServiceFormState, {
165
188
  if (d) {
166
189
  return shape({
167
190
  ...s, id, heading: copyParam("ownerServiceForm.headingEdit", "Edit service"),
168
- name: d.name, description: d.description, category: d.category,
191
+ name: d.name, ...descriptionFields(d.description), category: d.category,
169
192
  status: "idle", error: "", savedMessage: "", demoNote: copyParam("ownerCommon.demoNote", DEMO_NOTE),
170
193
  });
171
194
  }
@@ -177,25 +200,42 @@ const svc = defineService<ServiceFormState, {
177
200
  if (isOwnerPreviewDemo() || s.demoNote) return demoRefusal(s);
178
201
  const v = values ?? {};
179
202
  const targetId = s.id || (typeof v.id === "string" ? v.id : "");
203
+ const cached = !s.id && targetId ? await cacheGet(targetId) : null;
204
+ // Legacy queued payloads arrive without a loaded form. Read the current body before
205
+ // accepting their text, so replay cannot replace a rich description blindly.
206
+ if (!s.id && targetId) {
207
+ try {
208
+ const service = (await getService(targetId)).service;
209
+ if (!service?.id) return shape({ ...s, status: "error", error: copyParam("ownerServiceForm.errorNotFound", "Service not found") });
210
+ s = shape({ ...s, id: targetId, revision: String(service.revision ?? ""),
211
+ ...descriptionFields(service.description), category: categoryName(service) || String(cached?.category ?? "") });
212
+ } catch (error) {
213
+ return shape({ ...s, status: "error", error: ownerWriteError(error), savedMessage: "" });
214
+ }
215
+ }
180
216
  const name = String(v.name ?? s.name).trim();
181
217
  const description = String(v.description ?? s.description).trim();
218
+ const descriptionEdited = description !== descriptionBody(s.originalDescription).bodyText.trim();
219
+ if (s.descriptionProtected && descriptionEdited) return shape({ ...s, status: "error", error: s.descriptionNote, savedMessage: "" });
182
220
  if (!name) return shape({ ...s, status: "error", error: copyParam("ownerServiceForm.nameRequired", "Name is required"), savedMessage: "" });
183
221
  if (!targetId) return shape({ ...s, status: "error", error: copyParam("ownerServiceForm.errorNoService", "No service to edit."), savedMessage: "" });
184
222
 
185
- const cached = !s.id ? await cacheGet(targetId) : null;
186
- const localRow: DbEntity = { ...(cached ?? {}), id: targetId, name, title: name, description, category: s.category || String(cached?.category ?? "") };
223
+ const localRow: DbEntity = { ...(cached ?? {}), id: targetId, name, title: name,
224
+ ...(descriptionEdited || s.originalDescription !== undefined ? { description: descriptionEdited ? description : s.originalDescription } : {}),
225
+ category: s.category || String(cached?.category ?? "") };
187
226
  try {
188
227
  // v2 PATCH is a masked update requiring the current `revision` (optimistic
189
228
  // concurrency), captured from the getService on load. The response wraps
190
229
  // the UPDATED entity ({ service }) with its bumped revision — carry it
191
230
  // into state, or the SECOND consecutive save would send the stale
192
231
  // load-time revision and reject.
193
- const res = await updateService(targetId, { name, ...(description ? { description } : {}), ...(s.revision ? { revision: s.revision } : {}) });
232
+ const res = await updateService(targetId, { name, ...(!s.descriptionProtected && descriptionEdited ? { description } : {}), ...(s.revision ? { revision: s.revision } : {}) });
194
233
  const bumped = String((res?.service as { revision?: unknown } | undefined)?.revision ?? "");
195
234
  // The local row follows only what Wix confirmed.
196
235
  await cachePut(localRow);
197
236
  return shape({
198
237
  ...s, id: targetId, name, description,
238
+ originalDescription: descriptionEdited ? description : s.originalDescription,
199
239
  revision: bumped || s.revision,
200
240
  status: "saved", error: "", savedMessage: copyParam("ownerServiceForm.savedMessage", "Service saved."),
201
241
  savedId: targetId,
@@ -211,4 +251,10 @@ const svc = defineService<ServiceFormState, {
211
251
  },
212
252
  });
213
253
 
254
+ // Older binaries ignore notHydrated. Their restored preview must also stay read-only until load.
255
+ if (!(globalThis as { himalaya?: { hydrationOptOut?: boolean } }).himalaya?.hydrationOptOut) {
256
+ Object.assign(svc.getState(), { originalDescription: undefined, descriptionProtected: true, descriptionEditable: false,
257
+ descriptionNote: copyParam("ownerServiceForm.descriptionNotLoaded", "The description is not available yet. The name can be changed here.") });
258
+ }
259
+
214
260
  export { svc };
@@ -8,7 +8,7 @@ import { queryServices, type WixService } from "@himalaya/wix-bookings";
8
8
  import { ownerLoadError, isOwnerPreviewDemo, ownerDemoFallback } from "../_shared/owner-load-error.js";
9
9
  import { DEMO_SERVICES, DEMO_NOTE } from "../_shared/owner-preview-demo.js";
10
10
  import { copyParam } from "../_shared/himi-copy.js";
11
- import { getAll, upsert, type DbEntity } from "../_shared/owner-local-db.js";
11
+ import { get, getAll, upsert, type DbEntity } from "../_shared/owner-local-db.js";
12
12
 
13
13
  // Last-synced rows are an explicitly incomplete fallback for an unfiltered
14
14
  // request during an outage. Filtered pages never claim this cache is complete.
@@ -17,8 +17,10 @@ const ENTITY = "owner_services";
17
17
  async function readCachedRows(): Promise<ServiceRow[]> {
18
18
  try { return (await getAll(ENTITY)) as unknown as ServiceRow[]; } catch { return []; }
19
19
  }
20
+ // A list row carries no description. Merge it over the stored row so a normal refresh keeps the
21
+ // rich body the service form cached, as Products and Events do.
20
22
  async function writeCachedRows(rows: ServiceRow[]): Promise<void> {
21
- try { for (const r of rows) await upsert(ENTITY, r as unknown as DbEntity); } catch { /* capability not granted → online-only */ }
23
+ try { for (const r of rows) await upsert(ENTITY, { ...await get(ENTITY, r.id), ...r } as unknown as DbEntity); } catch { /* capability not granted → online-only */ }
22
24
  }
23
25
 
24
26
  interface ServiceRow {
@@ -85225,6 +85225,35 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
85225
85225
  }
85226
85226
  }
85227
85227
  },
85228
+ {
85229
+ "id": "service_form.description_note",
85230
+ "body": {
85231
+ "package": "himalaya",
85232
+ "type": "Text",
85233
+ "props": {
85234
+ "text": "$service:himiOwnerLiteServiceForm.descriptionNote",
85235
+ "style": "footnote",
85236
+ "color": "textSecondary",
85237
+ "collapseWhenEmpty": true
85238
+ }
85239
+ }
85240
+ },
85241
+ {
85242
+ "id": "service_form.description_preview",
85243
+ "body": {
85244
+ "package": "himalaya",
85245
+ "type": "Text",
85246
+ "props": {
85247
+ "text": "$service:himiOwnerLiteServiceForm.description",
85248
+ "style": "body",
85249
+ "maxLines": 8,
85250
+ "collapseWhenEmpty": true
85251
+ }
85252
+ },
85253
+ "modifiers": {
85254
+ "hiddenPath": "$service:himiOwnerLiteServiceForm.descriptionEditable"
85255
+ }
85256
+ },
85228
85257
  {
85229
85258
  "id": "service_form.form",
85230
85259
  "body": {
@@ -85269,6 +85298,9 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
85269
85298
  "multilineMaxLines": 3
85270
85299
  }
85271
85300
  }
85301
+ },
85302
+ "modifiers": {
85303
+ "hiddenPath": "$service:himiOwnerLiteServiceForm.descriptionProtected"
85272
85304
  }
85273
85305
  }
85274
85306
  ],
@@ -87649,6 +87681,51 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
87649
87681
  }
87650
87682
  }
87651
87683
  },
87684
+ {
87685
+ "id": "product_body",
87686
+ "body": {
87687
+ "package": "himalaya",
87688
+ "type": "RichContent",
87689
+ "props": {
87690
+ "documentJsonPath": "$service:himiOwnerLiteProduct.bodyJson",
87691
+ "onLink": {
87692
+ "actionId": "tier5.himiOwnerLiteProduct.openLink"
87693
+ },
87694
+ "fallback": {
87695
+ "id": "",
87696
+ "body": {
87697
+ "package": "himalaya",
87698
+ "type": "Text",
87699
+ "props": {
87700
+ "text": "$service:himiOwnerLiteProduct.bodyText",
87701
+ "style": "body",
87702
+ "color": "textPrimary",
87703
+ "collapseWhenEmpty": true
87704
+ }
87705
+ }
87706
+ }
87707
+ }
87708
+ },
87709
+ "modifiers": {
87710
+ "hiddenPath": "$service:himiOwnerLiteProduct.noBodyJson"
87711
+ }
87712
+ },
87713
+ {
87714
+ "id": "product_body_text",
87715
+ "body": {
87716
+ "package": "himalaya",
87717
+ "type": "Text",
87718
+ "props": {
87719
+ "text": "$service:himiOwnerLiteProduct.bodyText",
87720
+ "style": "body",
87721
+ "color": "textPrimary",
87722
+ "collapseWhenEmpty": true
87723
+ }
87724
+ },
87725
+ "modifiers": {
87726
+ "hiddenPath": "$service:himiOwnerLiteProduct.hasBodyJson"
87727
+ }
87728
+ },
87652
87729
  {
87653
87730
  "id": "product_info_card",
87654
87731
  "body": {
@@ -88070,7 +88147,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
88070
88147
  "contentType": "application/javascript+ts-bundle",
88071
88148
  "declaredCapabilities": [
88072
88149
  "wix_api",
88073
- "local_database"
88150
+ "local_database",
88151
+ "open_url"
88074
88152
  ],
88075
88153
  "minBinaryVersion": "0.1.0",
88076
88154
  "bundleVersion": "0.0.1"
@@ -88650,6 +88728,51 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
88650
88728
  }
88651
88729
  }
88652
88730
  },
88731
+ {
88732
+ "id": "service_body",
88733
+ "body": {
88734
+ "package": "himalaya",
88735
+ "type": "RichContent",
88736
+ "props": {
88737
+ "documentJsonPath": "$service:himiOwnerLiteService.bodyJson",
88738
+ "onLink": {
88739
+ "actionId": "tier5.himiOwnerLiteService.openLink"
88740
+ },
88741
+ "fallback": {
88742
+ "id": "",
88743
+ "body": {
88744
+ "package": "himalaya",
88745
+ "type": "Text",
88746
+ "props": {
88747
+ "text": "$service:himiOwnerLiteService.bodyText",
88748
+ "style": "body",
88749
+ "color": "textPrimary",
88750
+ "collapseWhenEmpty": true
88751
+ }
88752
+ }
88753
+ }
88754
+ }
88755
+ },
88756
+ "modifiers": {
88757
+ "hiddenPath": "$service:himiOwnerLiteService.noBodyJson"
88758
+ }
88759
+ },
88760
+ {
88761
+ "id": "service_body_text",
88762
+ "body": {
88763
+ "package": "himalaya",
88764
+ "type": "Text",
88765
+ "props": {
88766
+ "text": "$service:himiOwnerLiteService.bodyText",
88767
+ "style": "body",
88768
+ "color": "textPrimary",
88769
+ "collapseWhenEmpty": true
88770
+ }
88771
+ },
88772
+ "modifiers": {
88773
+ "hiddenPath": "$service:himiOwnerLiteService.hasBodyJson"
88774
+ }
88775
+ },
88653
88776
  {
88654
88777
  "id": "service_info_card",
88655
88778
  "body": {
@@ -88837,70 +88960,6 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
88837
88960
  "modifiers": {
88838
88961
  "hiddenPath": "$service:himiOwnerLiteService.capacityBlank"
88839
88962
  }
88840
- },
88841
- {
88842
- "id": "",
88843
- "body": {
88844
- "package": "himalaya",
88845
- "type": "Divider",
88846
- "props": {}
88847
- },
88848
- "modifiers": {
88849
- "hiddenPath": "$service:himiOwnerLiteService.descriptionNoDivider"
88850
- }
88851
- },
88852
- {
88853
- "id": "service_row_description",
88854
- "body": {
88855
- "package": "himalaya",
88856
- "type": "HStack",
88857
- "props": {
88858
- "spacing": 0,
88859
- "children": [
88860
- {
88861
- "id": "",
88862
- "body": {
88863
- "package": "himalaya",
88864
- "type": "Text",
88865
- "props": {
88866
- "text": "Description",
88867
- "style": "footnote",
88868
- "color": "textSecondary"
88869
- }
88870
- },
88871
- "modifiers": {
88872
- "padding": {
88873
- "trailing": 10
88874
- }
88875
- }
88876
- },
88877
- {
88878
- "id": "",
88879
- "body": {
88880
- "package": "himalaya",
88881
- "type": "Spacer",
88882
- "props": {}
88883
- }
88884
- },
88885
- {
88886
- "id": "",
88887
- "body": {
88888
- "package": "himalaya",
88889
- "type": "Text",
88890
- "props": {
88891
- "text": "$service:himiOwnerLiteService.description",
88892
- "style": "bodyEmphasis",
88893
- "maxLines": 1,
88894
- "collapseWhenEmpty": true
88895
- }
88896
- }
88897
- }
88898
- ]
88899
- }
88900
- },
88901
- "modifiers": {
88902
- "hiddenPath": "$service:himiOwnerLiteService.descriptionBlank"
88903
- }
88904
88963
  }
88905
88964
  ]
88906
88965
  }
@@ -89020,7 +89079,8 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
89020
89079
  "contentType": "application/javascript+ts-bundle",
89021
89080
  "declaredCapabilities": [
89022
89081
  "wix_api",
89023
- "local_database"
89082
+ "local_database",
89083
+ "open_url"
89024
89084
  ],
89025
89085
  "minBinaryVersion": "0.1.0",
89026
89086
  "bundleVersion": "0.0.1"
@@ -89485,6 +89545,9 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
89485
89545
  }
89486
89546
  }
89487
89547
  }
89548
+ },
89549
+ "modifiers": {
89550
+ "hiddenPath": "$service:himiOwnerLiteEvent.noBodyJson"
89488
89551
  }
89489
89552
  },
89490
89553
  {
@@ -90493,6 +90556,9 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
90493
90556
  }
90494
90557
  }
90495
90558
  }
90559
+ },
90560
+ "modifiers": {
90561
+ "hiddenPath": "$service:himiOwnerLitePost.noBodyJson"
90496
90562
  }
90497
90563
  },
90498
90564
  {
@@ -19,6 +19,8 @@ export interface CollectionConfig {
19
19
  /** Numeric 0–5 row field rendered as a Rating (accessible "N out of 5") instead of
20
20
  * folding a "★★★★☆" glyph string into the metadata line, so screen readers get a value. */
21
21
  rating?: string;
22
+ /** Domain-provided calendar text and its unavailable flag, kept separate from media. */
23
+ dateBadge?: { text: string; hidden: string };
22
24
  sectioned?: boolean;
23
25
  view: 'list' | 'grid';
24
26
  backendQuery?: boolean;
@@ -38,7 +40,13 @@ export interface CollectionConfig {
38
40
  /** The card's primary verb, shown as a visible button beside the overflow.
39
41
  * `screenId` opens that screen with the row id; without it the verb reuses the
40
42
  * row's own tap action (the detail screen that owns the verb). */
41
- primaryVerb?: { label: string; screenId?: string };
43
+ primaryVerb?: { label: string; screenId?: string;
44
+ /** A row field holding THIS row's verb label (Register, RSVP, Buy Tickets…); `label` stays the fallback copy. */
45
+ labelPath?: string;
46
+ /** A row boolean that hides the verb on rows that offer no action (an event with no registration). */
47
+ hiddenPath?: string };
48
+ /** The worker action that shares a row (`tier5.<service>.<name>` with `{ id }`): adds Share to the card's overflow menu. */
49
+ shareAction?: string;
42
50
  /** A TIME-BOUND entity (an event, a booking, a reservation): the boolean row field the
43
51
  * DOMAIN sets once the record has finished — computed by the same rule as the row's own
44
52
  * "Past" label, in the same place, so the two cannot disagree. A finished
@@ -73,7 +81,7 @@ export const COLLECTIONS: Record<string, CollectionConfig> = {
73
81
  himiBookingBookings: { rows: 'rows', title: 'title', subtitle: 'subtitle', metadata: ['status'], view: 'list', backendQuery: true,
74
82
  defaultFilter: 'value:Upcoming', searchPlaceholder: 'Search by booking ID', countNoun: ['booking', 'bookings'], filterValues: ['Upcoming', 'Past', 'Cancelled'],
75
83
  sortLabels: { default: 'Soonest', az: 'Oldest', za: 'Latest' } },
76
- himiEvents: { rows: 'results', title: 'title', subtitle: 'dateLine', image: 'image', view: 'grid', backendQuery: true, defaultFilter: 'value:Upcoming', searchPlaceholder: 'Search events', countNoun: ['event', 'events'], filterValues: ['Upcoming', 'Past'], sortLabels: { default: 'Date', az: 'Title A–Z', za: 'Title Z–A' }, primaryVerb: { label: 'Register' }, endedWhen: 'isPast' },
84
+ himiEvents: { rows: 'results', title: 'title', subtitle: 'dateLine', image: 'image', dateBadge: { text: 'dateBadge', hidden: 'noDateBadge' }, gridColumns: 1, view: 'grid', backendQuery: true, defaultFilter: 'value:Upcoming', searchPlaceholder: 'Search events', countNoun: ['event', 'events'], filterValues: ['Upcoming', 'Past'], sortLabels: { default: 'Date', az: 'Title A–Z', za: 'Title Z–A' }, primaryVerb: { label: 'Register', labelPath: 'actionLabel', hiddenPath: 'noAction' }, shareAction: 'share', endedWhen: 'isPast' },
77
85
  himiBlogFeed: { rows: 'posts', title: 'title', subtitle: 'excerpt', image: 'image', filter: 'category', filterValuesFrom: 'categories', view: 'grid', narrowedBy: 'selectedCategoryId' },
78
86
  himiOwnerLiteProducts: { rows: 'products', title: 'name', subtitle: 'price', image: 'image', view: 'grid', backendQuery: true, countNoun: ['product', 'products'] },
79
87
  himiOwnerModules: { instanceInput: 'module', rows: 'rows', title: 'title', subtitle: 'subtitle', image: 'image', filter: 'statusLabel', view: 'list', paged: true, reviewAction: 'prepareRecord', reviewSelectedAction: 'prepareSelected' },
@@ -208,7 +216,15 @@ export function projectCollection(source: CollectionRow[], config: CollectionCon
208
216
  ...(config.endedWhen ? (() => {
209
217
  const ended = row[config.endedWhen] === true || (config.endedWhen === 'isPast' && row.statusLabel === 'Past');
210
218
  return { collectionEnded: ended, collectionNotEnded: !ended };
211
- })() : {}) })),
219
+ })() : {}),
220
+ // A row restored from state saved by an older build has no badge flag. An unset hidden flag
221
+ // fails open and would paint an empty chip, so it reads as "no badge" until a refresh.
222
+ ...(config.dateBadge && typeof row[config.dateBadge.hidden] !== 'boolean'
223
+ ? { [config.dateBadge.text]: '', [config.dateBadge.hidden]: true } : {}),
224
+ // Same for a per-row verb: an unset hidden flag fails open and would show a verb with an unresolved
225
+ // label, so a row without the flag offers no action until a refresh establishes one.
226
+ ...(config.primaryVerb?.hiddenPath && typeof row[config.primaryVerb.hiddenPath] !== 'boolean'
227
+ ? { ...(config.primaryVerb.labelPath ? { [config.primaryVerb.labelPath]: '' } : {}), [config.primaryVerb.hiddenPath]: true } : {}) })),
212
228
  filters, loaded: rows.length,
213
229
  };
214
230
  }
@@ -12,7 +12,7 @@ import { ownerLoadError, isOwnerPreviewDemo, ownerDemoFallback, ownerWriteError,
12
12
  import { DEMO_EVENTS, DEMO_NOTE, DEMO_SAVE_NOTE } from "../_shared/owner-preview-demo.js";
13
13
  import { stashCopy, copyParam } from "../_shared/himi-copy.js";
14
14
  import { openRichLink } from "../_shared/rich-content-link.js";
15
- import { richBody } from "../_shared/rich-body.js";
15
+ import { descriptionBody } from "../_shared/rich-body.js";
16
16
  import { get as dbGet, upsert as dbUpsert, remove as dbRemove, type DbEntity } from "../_shared/owner-local-db.js";
17
17
  import { blankFlags } from "../_shared/detail-facts.js";
18
18
 
@@ -41,6 +41,7 @@ interface EventState {
41
41
  bodyJson: string;
42
42
  /** bodyJson !== "" — gates the plain text, because RichContent draws nothing for "". */
43
43
  hasBodyJson: boolean;
44
+ noBodyJson: boolean;
44
45
  /** The description's plain text (the document's own text, else the legacy description). */
45
46
  bodyText: string;
46
47
  initial: string;
@@ -68,15 +69,15 @@ interface EventState {
68
69
  }
69
70
 
70
71
  /* eslint-disable @typescript-eslint/no-explicit-any */
71
- /** [rico] #3499 — keep the description's plain text with the event's cached row, so the offline detail shows it.
72
+ /** [rico] #3499 — keep the description pair with the event's cached row, so the offline detail shows it.
72
73
  * Merged into the row the events list (or the form) wrote rather than replacing it; with no row yet, the
73
74
  * loaded detail's own fields become one. */
74
75
  async function cacheBodyText(s: EventState): Promise<void> {
75
76
  if (s.status !== "ready" || !s.id) return;
76
77
  const prev = await cacheGet(s.id);
77
- await cachePut(prev ? { ...prev, bodyText: s.bodyText } : {
78
+ await cachePut(prev ? { ...prev, bodyText: s.bodyText, bodyJson: s.bodyJson } : {
78
79
  id: s.id, title: s.title, subtitle: s.subtitle, image: s.image, dateLine: s.dateLine, location: s.location,
79
- statusLabel: s.statusLabel, registration: s.registration, bodyText: s.bodyText,
80
+ statusLabel: s.statusLabel, registration: s.registration, bodyText: s.bodyText, bodyJson: s.bodyJson,
80
81
  });
81
82
  }
82
83
  function idFrom(arg: unknown, fallback = ""): string {
@@ -132,6 +133,7 @@ function shapeFields(s: Partial<EventState>): EventState {
132
133
  summary: s.summary ?? "",
133
134
  bodyJson: s.bodyJson ?? "",
134
135
  hasBodyJson: !!s.bodyJson,
136
+ noBodyJson: !s.bodyJson,
135
137
  bodyText: s.bodyText ?? "",
136
138
  initial: s.initial ?? "?",
137
139
  image,
@@ -186,6 +188,7 @@ function cachedDetail(s: EventState, row: DbEntity): EventState {
186
188
  const title = String(row.title ?? row.name ?? "");
187
189
  const dateLine = String(row.dateLine ?? row.when ?? "");
188
190
  const location = String(row.location ?? "");
191
+ const body = descriptionBody(row.bodyJson || row.description, descriptionBody(row.bodyText ?? row.summary).bodyText);
189
192
  return shape({
190
193
  ...s,
191
194
  id: String(row.id),
@@ -193,8 +196,8 @@ function cachedDetail(s: EventState, row: DbEntity): EventState {
193
196
  title,
194
197
  subtitle: String(row.subtitle ?? [dateLine, location].filter((x) => x && x !== "—").join(" · ")),
195
198
  summary: "",
196
- bodyJson: "",
197
- bodyText: String(row.bodyText ?? row.summary ?? row.description ?? ""),
199
+ bodyJson: body.bodyJson,
200
+ bodyText: body.bodyText,
198
201
  initial: String(row.initial ?? (title[0] || "?")).slice(0, 1).toUpperCase(),
199
202
  image: String(row.image ?? ""),
200
203
  dateLine: dateLine || "—",
@@ -216,9 +219,9 @@ async function refresh(prev: EventState, id: string): Promise<EventState> {
216
219
  }
217
220
  const row = normalizeEvent(ev); // reuses date/location/status normalization
218
221
  const image = /^https?:\/\//.test(row.image) ? row.image : "";
219
- const { bodyJson, bodyText } = richBody((ev as unknown as { description?: unknown }).description, (eventDescription(ev) || "").trim());
222
+ const { bodyJson, bodyText } = descriptionBody((ev as unknown as { description?: unknown }).description, descriptionBody(eventDescription({ ...ev, description: undefined })).bodyText);
220
223
  // The teaser stays above the body only when it says something the body does not.
221
- const teaser = String((ev as any).shortDescription ?? "").trim();
224
+ const teaser = descriptionBody((ev as any).shortDescription).bodyText;
222
225
  return shape({
223
226
  ...prev,
224
227
  id,
@@ -358,4 +361,9 @@ if ((globalThis as { himalaya?: { hydrationOptOut?: unknown } }).himalaya?.hydra
358
361
  if (booted && typeof booted === "object") Object.assign(booted, { deletePending: false, noDeleteConfirmation: true });
359
362
  }
360
363
 
364
+ // Hydration shallow-merges older snapshots over defaults; derive both body gates from
365
+ // the restored document before the first paint, without waiting for a load action.
366
+ const bootedBody = svc.getState();
367
+ Object.assign(bootedBody, { hasBodyJson: !!bootedBody.bodyJson, noBodyJson: !bootedBody.bodyJson });
368
+
361
369
  export { svc };
@@ -1,3 +1,4 @@
1
+ import { descriptionBody } from "../_shared/rich-body.js";
1
2
  // Tier-5 bundle: __HIMI_APP_NAME__ — Events event EDIT form (the CRUD "U" only).
2
3
  // Modeled on himi-blog-owner-editor. Opened from the event detail ("Edit").
3
4
  //
@@ -222,12 +223,16 @@ const svc = defineService<EventFormState, {
222
223
  // this form never writes, so showing them here would invite an edit that lands elsewhere.
223
224
  ...(() => {
224
225
  const raw = (ev as unknown as { description?: unknown }).description;
225
- const doc = raw && typeof raw === "object" && Array.isArray((raw as { nodes?: unknown }).nodes) ? raw as Parameters<typeof postBodyText>[0] : null;
226
- const text = doc ? postBodyText(doc) : typeof raw === "string" ? raw.trim() : "";
226
+ const doc = parseRicosJson(raw);
227
+ const text = descriptionBody(raw).bodyText;
227
228
  // Edited in the RichContentEditor, seeded with the event's own document byte for byte (never
228
229
  // re-encoded); a legacy string seeds as paragraphs, and none seeds an empty editor.
229
- return { ...DESCRIPTION_LOADED, description: text, originalDescription: text, descriptionMode: "editor" as const,
230
- descriptionJson: doc ? JSON.stringify(raw) : text ? docJson(plainPostBody(text)) : "" };
230
+ // A description that looks like a serialized document but does not read as one (malformed JSON,
231
+ // or an object that is not a document) is locked, as on the Product form: an empty editor would
232
+ // let a save replace it. A blank or tag-only string stays editable so the owner can write the first one.
233
+ const unreadable = !doc && !text && raw != null && (typeof raw !== "string" || /^\s*[{[]/.test(raw));
234
+ return { ...DESCRIPTION_LOADED, description: text, originalDescription: text, descriptionMode: unreadable ? "locked" as const : "editor" as const,
235
+ descriptionJson: unreadable ? "" : doc ? JSON.stringify(doc) : text ? docJson(plainPostBody(text)) : "" };
231
236
  })(),
232
237
  when: row.dateLine || "—",
233
238
  location: row.location || "—",
@@ -239,14 +244,18 @@ const svc = defineService<EventFormState, {
239
244
  // Offline: prefill from the last-synced local cache before the demo/error fallbacks.
240
245
  const cached = await cacheGet(id);
241
246
  if (cached) {
247
+ // Only `descriptionJson` is the document as Wix returned it. The detail's `bodyJson` is the encoder's
248
+ // DISPLAY copy (media resized to urls), so it feeds the preview text and never seeds the editor.
249
+ const doc = parseRicosJson(cached.descriptionJson);
250
+ const description = descriptionBody(doc ?? cached.bodyJson, descriptionBody(cached.description ?? cached.bodyText ?? cached.summary).bodyText).bodyText;
242
251
  return shape({
243
252
  ...s, mode, id, heading: "Edit event",
244
253
  title: String(cached.title ?? cached.name ?? ""),
245
- description: String(cached.description ?? ""),
246
- originalDescription: String(cached.description ?? ""), ...DESCRIPTION_LOADED,
254
+ description,
255
+ originalDescription: description, ...DESCRIPTION_LOADED,
247
256
  // A row cached with its document reopens in the editor. An older row has none, so its verdict
248
257
  // decides: plain when it was plain, else locked (it carries no verdict either: fail closed).
249
- ...(cached.descriptionJson ? { descriptionMode: "editor" as const, descriptionJson: String(cached.descriptionJson) }
258
+ ...(doc ? { descriptionMode: "editor" as const, descriptionJson: JSON.stringify(doc) }
250
259
  : { descriptionMode: cached.descriptionProtected === "false" ? "plain" as const : "locked" as const, descriptionJson: "" }),
251
260
  when: String(cached.when ?? cached.dateLine ?? "—"),
252
261
  location: String(cached.location ?? "—"),
@@ -9,7 +9,7 @@ import { normalizeEvent, type EventRow } from "../_shared/himi-events.js";
9
9
  import { ownerLoadError, isOwnerPreviewDemo, ownerDemoFallback } from "../_shared/owner-load-error.js";
10
10
  import { DEMO_EVENTS, DEMO_NOTE } from "../_shared/owner-preview-demo.js";
11
11
  import { copyParam } from "../_shared/himi-copy.js";
12
- import { getAll, upsert, type DbEntity } from "../_shared/owner-local-db.js";
12
+ import { get, getAll, upsert, type DbEntity } from "../_shared/owner-local-db.js";
13
13
 
14
14
  // Last-synced rows are an explicitly incomplete fallback for an unfiltered
15
15
  // request during an outage. Filtered pages never claim this cache is complete.
@@ -19,7 +19,9 @@ async function readCachedRows(): Promise<EventRow[]> {
19
19
  try { return (await getAll(ENTITY)) as unknown as EventRow[]; } catch { return []; }
20
20
  }
21
21
  async function writeCachedRows(rows: EventRow[]): Promise<void> {
22
- try { for (const r of rows) await upsert(ENTITY, r as unknown as DbEntity); } catch { /* capability not granted → online-only */ }
22
+ try {
23
+ for (const r of rows) await upsert(ENTITY, { ...await get(ENTITY, r.id), ...r } as unknown as DbEntity);
24
+ } catch { /* capability not granted → online-only */ }
23
25
  }
24
26
 
25
27
  interface EventsState {