@wix/agent-skills 1.19.2 → 1.20.1

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 (215) hide show
  1. package/package.json +1 -1
  2. package/skills/wix-app/references/SERVICE_PLUGIN.md +14 -1
  3. package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +7 -6
  4. package/skills/wix-app/references/service-plugin/ADDITIONAL-FEES.md +4 -0
  5. package/skills/wix-app/references/service-plugin/AVAILABILITY-TIME-SLOTS-CONFIGURATION.md +118 -0
  6. package/skills/wix-app/references/service-plugin/BOOKING-POLICY.md +65 -0
  7. package/skills/wix-app/references/service-plugin/BOOKINGS-PRICING.md +71 -0
  8. package/skills/wix-app/references/service-plugin/BOOKINGS-STAFF-SORTING.md +11 -3
  9. package/skills/wix-app/references/service-plugin/BOOKINGS-VALIDATION.md +137 -0
  10. package/skills/wix-app/references/service-plugin/DISCOUNT-TRIGGERS.md +23 -16
  11. package/skills/wix-app/references/service-plugin/GIFT-CARDS.md +4 -0
  12. package/skills/wix-app/references/service-plugin/PAYMENT-SETTINGS.md +4 -2
  13. package/skills/wix-app/references/service-plugin/REALTIME-PERMISSIONS.md +45 -0
  14. package/skills/wix-app/references/service-plugin/SHIPPING-RATES.md +15 -0
  15. package/skills/wix-app/references/service-plugin/TOOLS_PROVIDER.md +4 -0
  16. package/skills/wix-app/references/service-plugin/VALIDATIONS.md +4 -0
  17. package/skills/wix-headless/references/CAPABILITIES.md +2 -2
  18. package/skills/wix-headless/references/inline-recipes/experience-store.md +4 -3
  19. package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +98 -18
  20. package/skills/wix-headless/references/managed/DEPLOYMENT.md +8 -8
  21. package/skills/wix-headless-fast/SKILL.md +200 -34
  22. package/skills/wix-headless-fast/entry/skill.md +10 -2
  23. package/skills/wix-headless-fast/install/attach.mjs +253 -0
  24. package/skills/wix-headless-fast/install/deploy.mjs +109 -9
  25. package/skills/wix-headless-fast/install/fast-path.mjs +28 -31
  26. package/skills/wix-headless-fast/references/blog/INSTRUCTIONS.md +224 -60
  27. package/skills/wix-headless-fast/references/blog/app/components/blog/BlogFeedView.tsx +2 -3
  28. package/skills/wix-headless-fast/references/blog/app/components/blog/PostView.tsx +2 -3
  29. package/skills/wix-headless-fast/references/blog/app/hooks/blog/useBlogFeed.ts +24 -116
  30. package/skills/wix-headless-fast/references/blog/app/hooks/blog/usePost.ts +16 -64
  31. package/skills/wix-headless-fast/references/blog/app/wix/blog/blog-feed-store.ts +137 -0
  32. package/skills/wix-headless-fast/references/blog/app/wix/blog/post-store.ts +78 -0
  33. package/skills/wix-headless-fast/references/blog/app/wix/blog/posts-core.ts +117 -0
  34. package/skills/wix-headless-fast/references/blog/app/wix/blog/posts.ts +13 -60
  35. package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy-core.ts +47 -0
  36. package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy.ts +10 -28
  37. package/skills/wix-headless-fast/references/blog/app-astro/pages/blog/[...slug].astro +2 -4
  38. package/skills/wix-headless-fast/references/blog/rest/posts.ts +42 -0
  39. package/skills/wix-headless-fast/references/blog/rest/taxonomy.ts +62 -0
  40. package/skills/wix-headless-fast/references/blog/seed/SEED.md +9 -0
  41. package/skills/wix-headless-fast/references/bookings/INSTRUCTIONS.md +179 -33
  42. package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServiceBookingView.tsx +2 -1
  43. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useBookingFlow.ts +26 -132
  44. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useServices.ts +18 -49
  45. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-core.ts +218 -0
  46. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-flow-store.ts +169 -0
  47. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking.ts +57 -142
  48. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-core.ts +92 -0
  49. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-store.ts +90 -0
  50. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services.ts +22 -61
  51. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/types.ts +3 -1
  52. package/skills/wix-headless-fast/references/bookings/rest/booking.ts +113 -0
  53. package/skills/wix-headless-fast/references/bookings/rest/services.ts +55 -0
  54. package/skills/wix-headless-fast/references/bookings/seed/SEED.md +10 -0
  55. package/skills/wix-headless-fast/references/cms/INSTRUCTIONS.md +236 -62
  56. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useCollection.ts +19 -52
  57. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useItem.ts +16 -36
  58. package/skills/wix-headless-fast/references/cms/app/wix/cms/collection-store.ts +158 -0
  59. package/skills/wix-headless-fast/references/cms/app/wix/cms/item-store.ts +93 -0
  60. package/skills/wix-headless-fast/references/cms/app/wix/cms/items-core.ts +177 -0
  61. package/skills/wix-headless-fast/references/cms/app/wix/cms/items.ts +13 -41
  62. package/skills/wix-headless-fast/references/cms/rest/items.ts +125 -0
  63. package/skills/wix-headless-fast/references/cms/seed/SEED.md +9 -0
  64. package/skills/wix-headless-fast/references/events/INSTRUCTIONS.md +239 -83
  65. package/skills/wix-headless-fast/references/events/app/components/events/EventConfirmationView.tsx +1 -1
  66. package/skills/wix-headless-fast/references/events/app/components/events/EventRegistrationView.tsx +7 -5
  67. package/skills/wix-headless-fast/references/events/app/components/events/EventsView.tsx +2 -2
  68. package/skills/wix-headless-fast/references/events/app/hooks/events/useEventRegistration.ts +28 -110
  69. package/skills/wix-headless-fast/references/events/app/hooks/events/useEvents.ts +19 -54
  70. package/skills/wix-headless-fast/references/events/app/wix/events/events-core.ts +130 -0
  71. package/skills/wix-headless-fast/references/events/app/wix/events/events-store.ts +97 -0
  72. package/skills/wix-headless-fast/references/events/app/wix/events/events.ts +13 -94
  73. package/skills/wix-headless-fast/references/events/app/wix/events/registration-core.ts +113 -0
  74. package/skills/wix-headless-fast/references/events/app/wix/events/registration-store.ts +156 -0
  75. package/skills/wix-headless-fast/references/events/app/wix/events/registration.ts +38 -69
  76. package/skills/wix-headless-fast/references/events/rest/events.ts +57 -0
  77. package/skills/wix-headless-fast/references/events/rest/registration.ts +83 -0
  78. package/skills/wix-headless-fast/references/events/seed/SEED.md +9 -0
  79. package/skills/wix-headless-fast/references/forms/INSTRUCTIONS.md +214 -26
  80. package/skills/wix-headless-fast/references/forms/app/hooks/forms/useWixForm.ts +35 -267
  81. package/skills/wix-headless-fast/references/forms/app/wix/forms/form-store.ts +332 -0
  82. package/skills/wix-headless-fast/references/forms/app/wix/forms/forms-core.ts +238 -0
  83. package/skills/wix-headless-fast/references/forms/app/wix/forms/forms.ts +28 -243
  84. package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions-core.ts +216 -0
  85. package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions.ts +32 -204
  86. package/skills/wix-headless-fast/references/forms/rest/forms.ts +34 -0
  87. package/skills/wix-headless-fast/references/forms/rest/submissions.ts +56 -0
  88. package/skills/wix-headless-fast/references/forms/seed/SEED.md +8 -0
  89. package/skills/wix-headless-fast/references/forms/seed/seed-forms.mjs +15 -8
  90. package/skills/wix-headless-fast/references/members/INSTRUCTIONS.md +314 -63
  91. package/skills/wix-headless-fast/references/members/app/components/members/LoginForm.tsx +1 -1
  92. package/skills/wix-headless-fast/references/members/app/wix/members/auth-core.ts +105 -0
  93. package/skills/wix-headless-fast/references/members/app/wix/members/auth.ts +36 -65
  94. package/skills/wix-headless-fast/references/members/app/wix/members/client.ts +1 -1
  95. package/skills/wix-headless-fast/references/members/app/wix/members/members-core.ts +43 -0
  96. package/skills/wix-headless-fast/references/members/app/wix/members/members.ts +11 -32
  97. package/skills/wix-headless-fast/references/members/rest/auth.ts +215 -0
  98. package/skills/wix-headless-fast/references/members/rest/members.ts +26 -0
  99. package/skills/wix-headless-fast/references/portfolio/INSTRUCTIONS.md +238 -59
  100. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionProjectsView.tsx +2 -2
  101. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionsView.tsx +2 -2
  102. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/GalleryMedia.tsx +35 -0
  103. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/ProjectDetailView.tsx +8 -38
  104. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollectionProjects.ts +23 -50
  105. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollections.ts +16 -34
  106. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useProjectDetail.ts +22 -49
  107. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collection-projects-store.ts +82 -0
  108. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collections-store.ts +58 -0
  109. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio-core.ts +177 -0
  110. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio.ts +31 -118
  111. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/project-detail-store.ts +81 -0
  112. package/skills/wix-headless-fast/references/portfolio/rest/portfolio.ts +75 -0
  113. package/skills/wix-headless-fast/references/portfolio/seed/SEED.md +8 -0
  114. package/skills/wix-headless-fast/references/pricing-plans/INSTRUCTIONS.md +212 -51
  115. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlanDetailView.tsx +9 -20
  116. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlansView.tsx +7 -32
  117. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/SubscribeButton.tsx +41 -0
  118. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlanPurchase.ts +12 -33
  119. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlans.ts +17 -34
  120. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plan-purchase-store.ts +54 -0
  121. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-core.ts +106 -0
  122. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-store.ts +64 -0
  123. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans.ts +7 -55
  124. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase-core.ts +43 -0
  125. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase.ts +11 -34
  126. package/skills/wix-headless-fast/references/pricing-plans/rest/plans.ts +31 -0
  127. package/skills/wix-headless-fast/references/pricing-plans/rest/purchase.ts +20 -0
  128. package/skills/wix-headless-fast/references/pricing-plans/seed/SEED.md +8 -0
  129. package/skills/wix-headless-fast/references/restaurants/INSTRUCTIONS.md +240 -47
  130. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/MenuView.tsx +2 -2
  131. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartDrawer.tsx +2 -2
  132. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useMenus.ts +14 -35
  133. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useReservation.ts +28 -171
  134. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-core.ts +155 -0
  135. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-store.ts +89 -0
  136. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu.ts +23 -117
  137. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering-core.ts +124 -0
  138. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering.ts +45 -114
  139. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservation-store.ts +193 -0
  140. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations-core.ts +94 -0
  141. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations.ts +15 -87
  142. package/skills/wix-headless-fast/references/restaurants/rest/menu.ts +60 -0
  143. package/skills/wix-headless-fast/references/restaurants/rest/ordering.ts +169 -0
  144. package/skills/wix-headless-fast/references/restaurants/rest/reservations.ts +68 -0
  145. package/skills/wix-headless-fast/references/restaurants/seed/SEED.md +8 -0
  146. package/skills/wix-headless-fast/references/shared/SUPPLIED-CONTENT.md +23 -0
  147. package/skills/wix-headless-fast/references/shared/app/wix/media.ts +55 -1
  148. package/skills/wix-headless-fast/references/shared/app/wix/sdk.ts +13 -0
  149. package/skills/wix-headless-fast/references/shared/rest/client.ts +155 -0
  150. package/skills/wix-headless-fast/references/shared/rest/config.ts +3 -0
  151. package/skills/wix-headless-fast/references/shared/rest/media.ts +65 -0
  152. package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +371 -81
  153. package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartDrawer.tsx +37 -3
  154. package/skills/wix-headless-fast/references/storefront/app/components/storefront/FilterPanel.tsx +266 -0
  155. package/skills/wix-headless-fast/references/storefront/app/components/storefront/OptionPicker.tsx +95 -0
  156. package/skills/wix-headless-fast/references/storefront/app/components/storefront/QuickAdd.tsx +136 -0
  157. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useProductDetail.ts +29 -130
  158. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +26 -182
  159. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-core.ts +121 -0
  160. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart.ts +53 -136
  161. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog-core.ts +309 -0
  162. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +73 -230
  163. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/product-detail-store.ts +147 -0
  164. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/shop-store.ts +289 -0
  165. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/types.ts +62 -4
  166. package/skills/wix-headless-fast/references/storefront/app-astro/layouts/SiteLayout.astro +21 -2
  167. package/skills/wix-headless-fast/references/storefront/rest/cart.ts +132 -0
  168. package/skills/wix-headless-fast/references/storefront/rest/catalog.ts +123 -0
  169. package/skills/wix-headless-fast/references/storefront/seed/SEED.md +25 -5
  170. package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +24 -0
  171. package/skills/wix-manage/SKILL.md +4 -1
  172. package/skills/wix-manage/references/ecommerce/ecom-shipping.md +1 -1
  173. package/skills/wix-manage/references/events/create-wix-event.md +46 -0
  174. package/skills/wix-manage/references/events/manage-wix-events.md +51 -1
  175. package/skills/wix-manage/references/google-ads/manage-campaign-lifecycle.md +6 -6
  176. package/skills/wix-manage/references/seo/manage-seo-suggestions.md +351 -0
  177. package/skills/wix-vibe-headless/install/deploy.cjs +33 -2
  178. package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed-with-install.md +1 -1
  179. package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed.md +13 -4
  180. package/skills/wix-vibe-headless/platforms/base44-ecom-light.md +1 -1
  181. package/skills/wix-vibe-headless/platforms/base44.md +19 -4
  182. package/skills/wix-vibe-headless/platforms/generic.md +6 -0
  183. package/skills/wix-vibe-headless/references/_shared/nav/nav.tanstack.js +30 -0
  184. package/skills/wix-vibe-headless/references/_shared/routing.md +86 -0
  185. package/skills/wix-vibe-headless/references/blog/INSTRUCTIONS.md +44 -0
  186. package/skills/wix-vibe-headless/references/blog/app/components/PostCard.jsx +1 -1
  187. package/skills/wix-vibe-headless/references/blog/app/components/PostChips.jsx +1 -1
  188. package/skills/wix-vibe-headless/references/blog/app/pages/CategoryPage.jsx +1 -1
  189. package/skills/wix-vibe-headless/references/blog/app/pages/PostDetail.jsx +1 -1
  190. package/skills/wix-vibe-headless/references/blog/app/pages/TagPage.jsx +1 -1
  191. package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +42 -0
  192. package/skills/wix-vibe-headless/references/bookings/app/components/ServiceCard.jsx +1 -1
  193. package/skills/wix-vibe-headless/references/bookings/app/pages/ServiceDetail.jsx +1 -1
  194. package/skills/wix-vibe-headless/references/events/INSTRUCTIONS.md +42 -0
  195. package/skills/wix-vibe-headless/references/events/app/components/EventCard.jsx +1 -1
  196. package/skills/wix-vibe-headless/references/events/app/pages/EventDetail.jsx +1 -1
  197. package/skills/wix-vibe-headless/references/members/INSTRUCTIONS.md +42 -0
  198. package/skills/wix-vibe-headless/references/members/app/components/MemberMenu.jsx +1 -1
  199. package/skills/wix-vibe-headless/references/members/app/components/RequireAuth.jsx +1 -1
  200. package/skills/wix-vibe-headless/references/members/app/pages/Login.jsx +1 -1
  201. package/skills/wix-vibe-headless/references/portfolio/INSTRUCTIONS.md +43 -0
  202. package/skills/wix-vibe-headless/references/portfolio/app/components/CollectionCard.jsx +1 -1
  203. package/skills/wix-vibe-headless/references/portfolio/app/components/ProjectCard.jsx +1 -1
  204. package/skills/wix-vibe-headless/references/portfolio/app/pages/CollectionPage.jsx +1 -1
  205. package/skills/wix-vibe-headless/references/portfolio/app/pages/ProjectDetail.jsx +1 -1
  206. package/skills/wix-vibe-headless/references/pricing-plans/INSTRUCTIONS.md +43 -0
  207. package/skills/wix-vibe-headless/references/pricing-plans/app/components/PlanCard.jsx +1 -1
  208. package/skills/wix-vibe-headless/references/pricing-plans/app/pages/PlanDetail.jsx +1 -1
  209. package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +36 -0
  210. package/skills/wix-vibe-headless/references/shared/app/lib/nav.js +9 -0
  211. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +42 -41
  212. package/skills/wix-vibe-headless/references/storefront/app/hooks/useProductCard.js +7 -1
  213. package/skills/wix-vibe-headless/references/storefront/seed/SEED.md +3 -0
  214. package/skills/wix-vibe-headless/references/storefront/seed/seed-store.cjs +6 -0
  215. package/skills/wix-headless-fast/install/pin-agents-md.mjs +0 -57
@@ -0,0 +1,113 @@
1
+ // Registration rules and DTO mapping — transport-agnostic, imported by both ./registration.ts
2
+ // (SDK) and the REST twin in references/events/rest/registration.ts (fetch). Tier mapping, the
3
+ // reservation line items, the payment gate, the checkout callbacks, and the RSVP body live HERE,
4
+ // once. Raw ticket definitions carry `_id` (SDK) or `id` (REST). Type-only imports so a strip
5
+ // to JS emits none.
6
+ import type { EventDetail, RegistrationResult, TicketTier } from "./types";
7
+ import type { Raw } from "./events-core";
8
+
9
+ const tierId = (raw: Raw | undefined | null): string => raw?._id ?? raw?.id ?? "";
10
+
11
+ export function formatTierPrice(price: Raw | undefined): string {
12
+ const value = price?.amount ?? price?.value;
13
+ if (value == null || value === "") return "";
14
+ try {
15
+ return new Intl.NumberFormat(undefined, { style: "currency", currency: price?.currency || "USD" }).format(Number(value));
16
+ } catch {
17
+ return `${value} ${price?.currency ?? ""}`.trim();
18
+ }
19
+ }
20
+
21
+ export function toTier(raw: Raw): TicketTier {
22
+ const free = raw.free === true || Number(raw.price?.amount ?? raw.price?.value ?? 0) === 0;
23
+ return {
24
+ id: tierId(raw),
25
+ name: raw.name ?? "",
26
+ description: raw.description ?? "",
27
+ price: free ? "Free" : formatTierPrice(raw.price),
28
+ free,
29
+ limitPerCheckout: raw.limitPerCheckout ?? 20,
30
+ saleStatus: (raw.saleStatus ?? "SALE_STARTED") as TicketTier["saleStatus"],
31
+ };
32
+ }
33
+
34
+ /** Tiers in display order (orderIndex), skipping any without an id. */
35
+ export function toTiers(definitions: Raw[] | undefined): TicketTier[] {
36
+ return (definitions ?? [])
37
+ .slice()
38
+ .sort((a, b) => (a.orderIndex ?? 0) - (b.orderIndex ?? 0))
39
+ .map(toTier)
40
+ .filter((t) => t.id);
41
+ }
42
+
43
+ /** The reservation's line items from the picker's selections; throws when nothing is picked. */
44
+ export function reservationTickets(selections: { tierId: string; quantity: number }[]): { ticketDefinitionId: string; quantity: number }[] {
45
+ const tickets = selections
46
+ .filter((s) => s.quantity > 0)
47
+ .map((s) => ({ ticketDefinitionId: s.tierId, quantity: s.quantity }));
48
+ if (!tickets.length) throw new Error("Pick at least one ticket first.");
49
+ return tickets;
50
+ }
51
+
52
+ /**
53
+ * The real gate on paid tickets: until the site has a premium plan AND a configured payment
54
+ * method, reserving fails 403 NO_PAYMENT_METHOD_CONFIGURED. Not a permissions bug — don't
55
+ * elevate (that just creates an unpayable order); surface it softly.
56
+ */
57
+ export function reservationError(e: unknown): Error {
58
+ const msg = e instanceof Error ? e.message : String(e);
59
+ if (/payment method|not configured|premium/i.test(msg)) {
60
+ return new Error("Ticket sales aren't switched on yet — the organizer needs to connect a payment method in the dashboard.");
61
+ }
62
+ return e instanceof Error ? e : new Error(msg);
63
+ }
64
+
65
+ /** The reservation id out of either transport's response; throws when the hold didn't happen. */
66
+ export function reservationId(reservation: Raw | null | undefined): string {
67
+ const id = tierId(reservation);
68
+ if (!id) throw new Error("Those tickets couldn't be reserved — they may have just sold out.");
69
+ return id;
70
+ }
71
+
72
+ /** Where the hosted checkout returns to. Defaults are the Astro routes; a static site passes its file paths. */
73
+ export interface CheckoutPaths {
74
+ /** Success landing — Wix appends `?orderNumber=&eventId=`. Default `/event-confirmation`. */
75
+ confirmation?: string;
76
+ /** Back here on abandon. Default `/events/<slug>`. */
77
+ event?: string;
78
+ }
79
+
80
+ /**
81
+ * The redirect session's callbacks. `origin` is the published https host (window.location.origin
82
+ * in a browser) — an http or server-derived origin isn't on the redirect allowlist and 403s the
83
+ * return; {} when unknown (SSR).
84
+ */
85
+ export function checkoutCallbacks(origin: string, slug: string, paths: CheckoutPaths = {}): Raw {
86
+ if (!origin) return {};
87
+ return {
88
+ thankYouPageUrl: `${origin}${paths.confirmation ?? "/event-confirmation"}`,
89
+ postFlowUrl: `${origin}${paths.event ?? `/events/${slug}`}`,
90
+ };
91
+ }
92
+
93
+ /** The redirect result; throws when Wix returned no URL. */
94
+ export function redirectResult(session: Raw | null | undefined): RegistrationResult {
95
+ const url = session?.redirectSession?.fullUrl;
96
+ if (!url) throw new Error("Checkout couldn't start — please try again.");
97
+ return { kind: "redirect", url };
98
+ }
99
+
100
+ /**
101
+ * The RSVP body: the built-in form is exactly firstName + lastName + email — never a fetched
102
+ * schema, never extra fields. "NO" only when the event's rsvpResponseType is "YES_AND_NO".
103
+ */
104
+ export function rsvpBody(eventId: string, guest: { firstName: string; lastName: string; email: string }, status: "YES" | "NO"): Raw {
105
+ return { eventId, firstName: guest.firstName, lastName: guest.lastName, email: guest.email, status };
106
+ }
107
+
108
+ /** A full event with a waitlist answers status "WAITLIST" — tell the guest they're waitlisted, not confirmed. */
109
+ export function rsvpResult(rsvp: Raw | null | undefined, sent: "YES" | "NO"): RegistrationResult {
110
+ return { kind: "rsvpConfirmed", status: (rsvp?.status ?? sent) as "YES" | "NO" | "WAITLIST" };
111
+ }
112
+
113
+ export type CheckoutEvent = Pick<EventDetail, "id" | "slug">;
@@ -0,0 +1,156 @@
1
+ // The registration flow for one event as a framework-free store — the logic behind
2
+ // useEventRegistration, usable from React (the hook wraps it), from a static page's event view,
3
+ // from Vue/Svelte, or as the specification for a port. Branched on event.registrationType:
4
+ // TICKETING loads the tier picker and checkout() reserves → redirects to Wix's hosted checkout;
5
+ // RSVP is the built-in name+email form submitted in place. All correctness (the visitor-public
6
+ // tier read, the reservation payload, the redirect callbacks, rsvpV2) lives in the data layer —
7
+ // this store orchestrates; the page owns how it looks.
8
+ //
9
+ // One store per event surface: createRegistrationStore(event), not a singleton. A static site
10
+ // passes `paths` so the hosted checkout returns to its files (`event-confirmation.html`).
11
+ import { fetchTicketTiers, startTicketCheckout, submitRsvp, type CheckoutPaths } from "./registration";
12
+ import type { EventDetail, RegistrationResult, TicketTier } from "./types";
13
+
14
+ export type RsvpField = "firstName" | "lastName" | "email";
15
+
16
+ export interface RegistrationStoreOptions {
17
+ /** Where the hosted checkout returns to; defaults are the Astro routes. */
18
+ paths?: CheckoutPaths;
19
+ }
20
+
21
+ export interface RegistrationState {
22
+ /** TICKETING: tiers for the picker — null while loading (skeletons), [] honest empty. Other types: []. */
23
+ tiers: TicketTier[] | null;
24
+ /** Selected quantity per tier id (0 when untouched). */
25
+ quantities: Record<string, number>;
26
+ ticketCount: number;
27
+ /** True when ≥ 1 ticket is selected — gate the checkout CTA on this. */
28
+ canCheckout: boolean;
29
+ /** RSVP form state — the built-in fields, exactly these. */
30
+ rsvpValues: { firstName: string; lastName: string; email: string };
31
+ /** True when every RSVP field is filled — gate the RSVP CTA on this. */
32
+ canRsvp: boolean;
33
+ submitting: boolean;
34
+ /** Set after an RSVP completes (kind "rsvpConfirmed"; status may be "WAITLIST"). */
35
+ confirmed: RegistrationResult | null;
36
+ error: string | null;
37
+ }
38
+
39
+ export interface RegistrationStore {
40
+ getState(): RegistrationState;
41
+ subscribe(listener: () => void): () => void;
42
+ /** Load the tiers of a TICKETING event. Call once when mounted (a browser). */
43
+ start(): void;
44
+ /** Stop reacting; drop a late response. */
45
+ stop(): void;
46
+ /** Clamped to 0..limitPerCheckout; ignored for tiers not on sale (saleStatus gate). */
47
+ setQuantity(tierId: string, quantity: number): void;
48
+ setRsvpValue(field: RsvpField, value: string): void;
49
+ /** Reserves + redirects to the Wix-hosted checkout. On "redirect" the browser is navigating. Throws (and sets .error) on refusal. */
50
+ checkout(): Promise<RegistrationResult>;
51
+ /** attending=false only when event.rsvpResponseType is "YES_AND_NO". Throws (and sets .error) on refusal. */
52
+ rsvp(attending?: boolean): Promise<RegistrationResult>;
53
+ }
54
+
55
+ export function createRegistrationStore(event: EventDetail, { paths }: RegistrationStoreOptions = {}): RegistrationStore {
56
+ const ticketed = event.registrationType === "TICKETING";
57
+ let tiers: TicketTier[] | null = ticketed ? null : [];
58
+ let quantities: Record<string, number> = {};
59
+ let rsvpValues = { firstName: "", lastName: "", email: "" };
60
+ let submitting = false;
61
+ let confirmed: RegistrationResult | null = null;
62
+ let error: string | null = null;
63
+ let started = false;
64
+ const listeners = new Set<() => void>();
65
+ let snapshot: RegistrationState | null = null;
66
+ const emit = () => {
67
+ snapshot = null;
68
+ for (const fn of listeners) fn();
69
+ };
70
+
71
+ function getState(): RegistrationState {
72
+ if (snapshot) return snapshot;
73
+ const ticketCount = Object.values(quantities).reduce((sum, q) => sum + q, 0);
74
+ snapshot = {
75
+ tiers,
76
+ quantities,
77
+ ticketCount,
78
+ canCheckout: ticketCount > 0,
79
+ rsvpValues,
80
+ canRsvp: (["firstName", "lastName", "email"] as const).every((f) => rsvpValues[f].trim().length > 0),
81
+ submitting,
82
+ confirmed,
83
+ error,
84
+ };
85
+ return snapshot;
86
+ }
87
+
88
+ async function run(op: () => Promise<RegistrationResult>): Promise<RegistrationResult> {
89
+ submitting = true;
90
+ error = null;
91
+ emit();
92
+ try {
93
+ const result = await op();
94
+ if (result.kind === "redirect") {
95
+ if (typeof window !== "undefined") window.location.href = result.url;
96
+ } else {
97
+ confirmed = result;
98
+ }
99
+ return result;
100
+ } catch (e) {
101
+ error = e instanceof Error ? e.message : String(e);
102
+ throw e;
103
+ } finally {
104
+ submitting = false;
105
+ emit();
106
+ }
107
+ }
108
+
109
+ return {
110
+ getState,
111
+ subscribe(fn) {
112
+ listeners.add(fn);
113
+ return () => listeners.delete(fn);
114
+ },
115
+ start() {
116
+ if (started) return;
117
+ started = true;
118
+ if (!ticketed) return;
119
+ fetchTicketTiers(event.id)
120
+ .then((t) => {
121
+ if (!started) return;
122
+ tiers = t;
123
+ emit();
124
+ })
125
+ .catch((e) => {
126
+ if (!started) return;
127
+ tiers = [];
128
+ error = e instanceof Error ? e.message : String(e);
129
+ emit();
130
+ });
131
+ },
132
+ stop() {
133
+ started = false;
134
+ },
135
+ setQuantity(tierId, quantity) {
136
+ const tier = (tiers ?? []).find((t) => t.id === tierId);
137
+ if (!tier || tier.saleStatus !== "SALE_STARTED") return;
138
+ const clamped = Math.max(0, Math.min(quantity, tier.limitPerCheckout || 20));
139
+ quantities = { ...quantities, [tierId]: clamped };
140
+ emit();
141
+ },
142
+ setRsvpValue(field, value) {
143
+ rsvpValues = { ...rsvpValues, [field]: value };
144
+ emit();
145
+ },
146
+ checkout: () =>
147
+ run(() =>
148
+ startTicketCheckout(
149
+ event,
150
+ Object.entries(quantities).map(([tierId, quantity]) => ({ tierId, quantity })),
151
+ paths,
152
+ ),
153
+ ),
154
+ rsvp: (attending = true) => run(() => submitRsvp(event.id, rsvpValues, attending ? "YES" : "NO")),
155
+ };
156
+ }
@@ -1,7 +1,8 @@
1
- // Ticket tiers, the reserve → hosted-checkout redirect, and RSVP. The payload shapes here
2
- // are exact and easy to get subtly wrong — copy as-is; extend by calling these exports,
3
- // never by editing them. Failures are loud. Everything runs as the anonymous VISITOR —
4
- // no server route, no elevation, anywhere.
1
+ // Ticket tiers, the reserve → hosted-checkout redirect, and RSVP over the SDK. Rules and mappers
2
+ // live in ./registration-core (shared with the REST twin in references/events/rest/); this file is
3
+ // the transport only. The payload shapes are exact and easy to get subtly wrong — copy as-is;
4
+ // extend by calling these exports, never by editing them. Failures are loud. Everything runs as
5
+ // the anonymous VISITOR — no server route, no elevation, anywhere.
5
6
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/events/registration/ticketing/orders/query-available-tickets.md
6
7
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/events/registration/ticketing/ticket-reservations/create-ticket-reservation.md
7
8
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/events/registration/rsvp-v2/create-rsvp.md
@@ -9,38 +10,28 @@
9
10
  import { orders, rsvpV2, ticketReservations } from "@wix/events";
10
11
  import { redirects as redirectsModule } from "@wix/redirects";
11
12
  import { wixModule } from "../sdk";
12
- import type { EventDetail, RegistrationResult, TicketTier } from "./types";
13
+ import {
14
+ checkoutCallbacks,
15
+ redirectResult,
16
+ reservationError,
17
+ reservationId,
18
+ reservationTickets,
19
+ rsvpBody,
20
+ rsvpResult,
21
+ toTiers,
22
+ type CheckoutEvent,
23
+ type CheckoutPaths,
24
+ } from "./registration-core";
25
+ import type { Raw } from "./events-core";
26
+ import type { RegistrationResult, TicketTier } from "./types";
27
+
28
+ export { type CheckoutPaths };
13
29
 
14
30
  const availableTickets = wixModule(orders);
15
31
  const reservations = wixModule(ticketReservations);
16
32
  const rsvps = wixModule(rsvpV2);
17
33
  const redirects = wixModule(redirectsModule);
18
34
 
19
- type Raw = Record<string, any>;
20
-
21
- function formatTierPrice(price: Raw | undefined): string {
22
- const value = price?.amount ?? price?.value;
23
- if (value == null || value === "") return "";
24
- try {
25
- return new Intl.NumberFormat(undefined, { style: "currency", currency: price?.currency || "USD" }).format(Number(value));
26
- } catch {
27
- return `${value} ${price?.currency ?? ""}`.trim();
28
- }
29
- }
30
-
31
- function toTier(raw: Raw): TicketTier {
32
- const free = raw.free === true || Number(raw.price?.amount ?? raw.price?.value ?? 0) === 0;
33
- return {
34
- id: raw._id ?? "", // _id, never .id
35
- name: raw.name ?? "",
36
- description: raw.description ?? "",
37
- price: free ? "Free" : formatTierPrice(raw.price),
38
- free,
39
- limitPerCheckout: raw.limitPerCheckout ?? 20,
40
- saleStatus: (raw.saleStatus ?? "SALE_STARTED") as TicketTier["saleStatus"],
41
- };
42
- }
43
-
44
35
  /**
45
36
  * Ticket tiers for a TICKETING event, in display order. Reads the VISITOR-public storefront
46
37
  * endpoint (orders.queryAvailableTickets) — never ticketDefinitions*.queryTicketDefinitions:
@@ -50,20 +41,17 @@ function toTier(raw: Raw): TicketTier {
50
41
  export async function fetchTicketTiers(eventId: string): Promise<TicketTier[]> {
51
42
  // limit is REQUIRED: it defaults to 0, which returns metadata only — zero tiers, no error.
52
43
  const res: Raw = await availableTickets.queryAvailableTickets({ filter: { eventId }, limit: 100 });
53
- return (res.definitions ?? [])
54
- .slice()
55
- .sort((a: Raw, b: Raw) => (a.orderIndex ?? 0) - (b.orderIndex ?? 0))
56
- .map((d: Raw) => toTier(d))
57
- .filter((t: TicketTier) => t.id);
44
+ return toTiers(res.definitions);
58
45
  }
59
46
 
60
47
  /**
61
48
  * RSVP to a free (RSVP-type) event — completes fully client-side: no reservation, no
62
49
  * redirect, no payment. The registration form is BUILT-IN: exactly firstName + lastName +
63
50
  * email; never fetch a form schema or add fields. Send "NO" only when the event's
64
- * rsvpResponseType is "YES_AND_NO". Throws on closed registration / duplicate email —
65
- * surface the message. A full event with a waitlist returns status "WAITLIST" — tell the
66
- * guest they're waitlisted, not confirmed.
51
+ * rsvpResponseType is "YES_AND_NO". Throws on closed registration, a guest limit, or an
52
+ * invalid email — surface the message (a repeat email is accepted by default; the organizer's
53
+ * settings decide). A full event with a waitlist returns status "WAITLIST" — tell the guest
54
+ * they're waitlisted, not confirmed.
67
55
  */
68
56
  export async function submitRsvp(
69
57
  eventId: string,
@@ -72,8 +60,8 @@ export async function submitRsvp(
72
60
  ): Promise<RegistrationResult> {
73
61
  // rsvpV2 takes the rsvp object DIRECTLY as the first arg (never wrapped in { rsvp: … }),
74
62
  // and only rsvpV2 works for visitors — the legacy v1 `rsvp` module 400s on these fields.
75
- const res: Raw = await rsvps.createRsvp({ eventId, ...guest, status } as any);
76
- return { kind: "rsvpConfirmed", status: (res?.status ?? status) as "YES" | "NO" | "WAITLIST" };
63
+ const res: Raw = await rsvps.createRsvp(rsvpBody(eventId, guest, status) as any);
64
+ return rsvpResult(res, status);
77
65
  }
78
66
 
79
67
  /**
@@ -84,45 +72,26 @@ export async function submitRsvp(
84
72
  * server-derived origin isn't on the redirect allowlist and 403s the return), and
85
73
  * createRedirectSession must run as the visitor (it embeds the headless OAuth client and
86
74
  * rejects admin/elevated tokens). Never hand-build the checkout URL — the Wix-site
87
- * `…/ticket-form?reservationId=` path 404s on a headless site.
75
+ * `…/ticket-form?reservationId=` path 404s on a headless site. `paths` overrides the return
76
+ * routes (a static site's `event-confirmation.html`).
88
77
  */
89
78
  export async function startTicketCheckout(
90
- event: Pick<EventDetail, "id" | "slug">,
79
+ event: CheckoutEvent,
91
80
  selections: { tierId: string; quantity: number }[],
81
+ paths: CheckoutPaths = {},
92
82
  ): Promise<RegistrationResult> {
93
- const tickets = selections
94
- .filter((s) => s.quantity > 0)
95
- .map((s) => ({ ticketDefinitionId: s.tierId, quantity: s.quantity }));
96
- if (!tickets.length) throw new Error("Pick at least one ticket first.");
97
-
83
+ const tickets = reservationTickets(selections);
98
84
  let reservation: Raw;
99
85
  try {
100
86
  reservation = await reservations.createTicketReservation({ tickets } as any);
101
87
  } catch (e) {
102
- // The real gate on paid tickets: until the site has a premium plan AND a configured
103
- // payment method, reserving fails 403 "No payment method configured". Not a permissions
104
- // bug — don't elevate (that just creates an unpayable order); surface it softly.
105
- const msg = e instanceof Error ? e.message : String(e);
106
- if (/payment method|not configured|premium/i.test(msg)) {
107
- throw new Error(
108
- "Ticket sales aren't switched on yet — the organizer needs to connect a payment method in the dashboard.",
109
- );
110
- }
111
- throw e;
88
+ throw reservationError(e);
112
89
  }
113
- const reservationId: string | undefined = reservation?._id; // _id, never .id
114
- if (!reservationId) throw new Error("Those tickets couldn't be reserved — they may have just sold out.");
115
-
116
90
  const origin = typeof window !== "undefined" ? window.location.origin : "";
117
91
  const session: Raw = await redirects.createRedirectSession({
118
- eventsCheckout: { reservationId, eventSlug: event.slug },
119
- callbacks: {
120
- // Wix appends ?orderNumber=&eventId= — the shipped /event-confirmation page reads them.
121
- thankYouPageUrl: origin ? `${origin}/event-confirmation` : undefined,
122
- postFlowUrl: origin ? `${origin}/events/${event.slug}` : undefined, // back here on abandon
123
- },
92
+ eventsCheckout: { reservationId: reservationId(reservation), eventSlug: event.slug },
93
+ // Wix appends ?orderNumber=&eventId= to the thank-you URL — the shipped /event-confirmation page reads them.
94
+ callbacks: checkoutCallbacks(origin, event.slug, paths),
124
95
  });
125
- const url = session?.redirectSession?.fullUrl;
126
- if (!url) throw new Error("Checkout couldn't start — please try again.");
127
- return { kind: "redirect", url };
96
+ return redirectResult(session);
128
97
  }
@@ -0,0 +1,57 @@
1
+ // Event reads over REST — the twin of app/wix/events/events.ts. Same exports, same DTOs; the rules
2
+ // and mappers come from events-core (the SAME file the SDK transport uses, deployed flat next to
3
+ // this one by deploy.mjs --stack static), so this file is only the transport: one fetch with a
4
+ // literal body per function. Every call here is safe from a browser with a visitor token.
5
+ // Porting: keep the paths, keep the bodies, port the core once.
6
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/events/event-management/events-v3/query-events.md
7
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/events/event-management/events-v3/get-event-by-slug.md
8
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/events/event-management/events-v3/get-event.md
9
+ import { WixApiError, wixRequest } from "./client.js";
10
+ import { imgSrc } from "./media.js";
11
+ import { DETAIL_FIELDS, EVENTS_APP_ID, LIST_FIELDS, listQuery, rawId, toDetail, toSummary, type Raw } from "./events-core.js";
12
+ import type { EventDetail, EventSummary } from "./types.js";
13
+
14
+ export { EVENTS_APP_ID };
15
+
16
+ const notFound = (e: unknown): boolean => e instanceof WixApiError && e.status === 404;
17
+
18
+ /**
19
+ * Live (UPCOMING/STARTED) events, soonest first. The limit is always sent: `paging.limit`
20
+ * defaults to 0 and a bare query answers `total: N, events: []` with no error.
21
+ * POST /events/v3/events/query { query: { filter: { status: { $in } }, sort, paging: { limit } }, fields }
22
+ */
23
+ export async function fetchEvents({ limit = 100 } = {}): Promise<EventSummary[]> {
24
+ const res = await wixRequest<Raw>("/events/v3/events/query", { body: { query: listQuery({ limit }), fields: LIST_FIELDS } });
25
+ return ((res?.events ?? []) as Raw[]).map((e) => toSummary(e, imgSrc));
26
+ }
27
+
28
+ /**
29
+ * One event by URL slug; null when the slug doesn't resolve (EVENT_NOT_FOUND, 404) — a real 404,
30
+ * never a fallback to another event. The response is WRAPPED: { event }.
31
+ * GET /events/v3/events/slug/{slug}?fields=DETAILS&fields=TEXTS&fields=REGISTRATION&fields=URLS&fields=CATEGORIES
32
+ */
33
+ export async function fetchEventBySlug(slug: string): Promise<EventDetail | null> {
34
+ try {
35
+ const res = await wixRequest<Raw>(`/events/v3/events/slug/${encodeURIComponent(slug)}`, { method: "GET", query: { fields: DETAIL_FIELDS } });
36
+ return res?.event ? toDetail(res.event, imgSrc) : null;
37
+ } catch (e) {
38
+ if (notFound(e)) return null;
39
+ throw e;
40
+ }
41
+ }
42
+
43
+ /**
44
+ * One event by id — the post-checkout confirmation read (the thank-you URL carries
45
+ * `?orderNumber=&eventId=`). On REST this response is WRAPPED too: { event } (the SDK's getEvent
46
+ * is the unwrapped one). GET /events/v3/events/{eventId}?fields=…
47
+ */
48
+ export async function fetchEventById(eventId: string): Promise<EventDetail | null> {
49
+ try {
50
+ const res = await wixRequest<Raw>(`/events/v3/events/${encodeURIComponent(eventId)}`, { method: "GET", query: { fields: DETAIL_FIELDS } });
51
+ const raw: Raw | undefined = res?.event;
52
+ return raw && rawId(raw) ? toDetail(raw, imgSrc) : null;
53
+ } catch (e) {
54
+ if (notFound(e)) return null;
55
+ throw e;
56
+ }
57
+ }
@@ -0,0 +1,83 @@
1
+ // Ticket tiers, the reserve → hosted-checkout redirect, and RSVP over REST — the twin of
2
+ // app/wix/events/registration.ts. Same exports, same DTOs; rules and mappers from
3
+ // registration-core (the SAME file the SDK transport uses, deployed flat next to this one). The
4
+ // request shapes are exact and rewriting them is how registrations break. Failures are loud.
5
+ // All calls run with the visitor token — the reservation and the RSVP are the token's.
6
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/events/registration/ticketing/orders/query-available-tickets.md
7
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/events/registration/ticketing/ticket-reservations/create-ticket-reservation.md
8
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/events/registration/rsvp-v2/create-rsvp.md
9
+ // docs: https://dev.wix.com/docs/api-reference/business-management/headless/redirects/create-redirect-session.md
10
+ import { wixRequest } from "./client.js";
11
+ import {
12
+ checkoutCallbacks,
13
+ redirectResult,
14
+ reservationError,
15
+ reservationId,
16
+ reservationTickets,
17
+ rsvpBody,
18
+ rsvpResult,
19
+ toTiers,
20
+ type CheckoutEvent,
21
+ type CheckoutPaths,
22
+ } from "./registration-core.js";
23
+ import type { Raw } from "./events-core.js";
24
+ import type { RegistrationResult, TicketTier } from "./types.js";
25
+
26
+ export { type CheckoutPaths };
27
+
28
+ /**
29
+ * Ticket tiers for a TICKETING event, in display order — the VISITOR-public storefront read, never
30
+ * the ticket-definitions management API (403 for a visitor). `limit` is REQUIRED: it defaults to 0
31
+ * and returns metadata only. POST /events/v1/checkout/available-tickets/query { filter: { eventId }, limit }
32
+ */
33
+ export async function fetchTicketTiers(eventId: string): Promise<TicketTier[]> {
34
+ const res = await wixRequest<Raw>("/events/v1/checkout/available-tickets/query", { body: { filter: { eventId }, limit: 100 } });
35
+ return toTiers(res?.definitions);
36
+ }
37
+
38
+ /**
39
+ * RSVP to a free (RSVP-type) event — completes fully client-side: no reservation, no redirect, no
40
+ * payment. The form is BUILT-IN: exactly firstName + lastName + email. "NO" only when the event's
41
+ * rsvpResponseType is "YES_AND_NO". Throws on closed registration, a guest limit, or an invalid
42
+ * email — surface the message (a repeat email is accepted by default). A full event with a waitlist
43
+ * answers "WAITLIST".
44
+ * POST /events/v2/rsvps { rsvp: { eventId, firstName, lastName, email, status } } → { rsvp: { id, status } }
45
+ */
46
+ export async function submitRsvp(
47
+ eventId: string,
48
+ guest: { firstName: string; lastName: string; email: string },
49
+ status: "YES" | "NO" = "YES",
50
+ ): Promise<RegistrationResult> {
51
+ const res = await wixRequest<Raw>("/events/v2/rsvps", { body: { rsvp: rsvpBody(eventId, guest, status) } });
52
+ return rsvpResult(res?.rsvp, status);
53
+ }
54
+
55
+ /**
56
+ * Ticketed checkout, the exact sequence: reserve the selected tiers (a PENDING hold that
57
+ * auto-expires), then mint the Wix-hosted checkout redirect and return its URL — the caller
58
+ * navigates the FULL document to it; Wix collects guest details + payment and emails the tickets.
59
+ * `origin` must be the site's real https origin as registered on the OAuth app's allowed domains
60
+ * (browser: window.location.origin). Never hand-build the checkout URL. `paths` overrides the
61
+ * return routes — a static site passes `{ confirmation: "/event-confirmation.html", event: "/event.html?slug=…" }`.
62
+ * POST /events/v1/ticket-reservations { ticketReservation: { tickets: [{ ticketDefinitionId, quantity }] } } → { ticketReservation: { id, status: "PENDING", expirationDate } }
63
+ * POST /headless/v1/redirect-session { eventsCheckout: { reservationId, eventSlug }, callbacks: { thankYouPageUrl, postFlowUrl } }
64
+ */
65
+ export async function startTicketCheckout(
66
+ event: CheckoutEvent,
67
+ selections: { tierId: string; quantity: number }[],
68
+ paths: CheckoutPaths = {},
69
+ origin: string = typeof window !== "undefined" ? window.location.origin : "",
70
+ ): Promise<RegistrationResult> {
71
+ const tickets = reservationTickets(selections);
72
+ let reservation: Raw | undefined;
73
+ try {
74
+ // Until the site has a premium plan AND a payment method this is a 403 NO_PAYMENT_METHOD_CONFIGURED — a business gate, not a bug.
75
+ reservation = (await wixRequest<Raw>("/events/v1/ticket-reservations", { body: { ticketReservation: { tickets } } }))?.ticketReservation;
76
+ } catch (e) {
77
+ throw reservationError(e);
78
+ }
79
+ const session = await wixRequest<Raw>("/headless/v1/redirect-session", {
80
+ body: { eventsCheckout: { reservationId: reservationId(reservation), eventSlug: event.slug }, callbacks: checkoutCallbacks(origin, event.slug, paths) },
81
+ });
82
+ return redirectResult(session);
83
+ }
@@ -76,6 +76,15 @@ dashboard. That's an owner step, not a seeding failure; relay it.
76
76
  **Seeding is additive — never delete or overwrite existing content**; ask first if a cleanup
77
77
  seems needed.
78
78
 
79
+ ## Supplied content
80
+
81
+ The general rules are in `references/shared/SUPPLIED-CONTENT.md`. For events, each event the user
82
+ lists is one entry. Its title becomes `title`; its date and time become `startDate` and `endDate` in
83
+ ISO with the `timeZoneId` the user stated; the venue and address become `location`; named tickets
84
+ with prices become `ticketTiers` on a `TICKETING` event, and an event with no tickets is `RSVP`; a
85
+ category becomes `category`; their image becomes `imageUrl`. A date without a year or without a
86
+ time zone is a question for the user, never a guess.
87
+
79
88
  ## Escape hatch — individual functions
80
89
  `setupEvents` composes exported steps — `installEventsApp`, `getSiteCurrency`, `createEvent`,
81
90
  `createTicketTiers`, `publishEvent`, `createEventCategories`, `assignEventsToCategory`,