@wix/agent-skills 1.14.0 → 1.15.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 (247) hide show
  1. package/README.md +4 -1
  2. package/package.json +1 -1
  3. package/skills/README.md +23 -0
  4. package/skills/wix-app/SKILL.md +10 -2
  5. package/skills/wix-app/references/AUTO_PATTERNS_DASHBOARD.md +326 -0
  6. package/skills/wix-app/references/CODE_QUALITY.md +1 -0
  7. package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +124 -115
  8. package/skills/wix-app/references/DASHBOARD_PAGE.md +3 -0
  9. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +23 -9
  10. package/skills/wix-app/references/SITE_PLUGIN.md +1 -1
  11. package/skills/wix-app/references/auto-patterns-dashboard/action-cell.md +115 -0
  12. package/skills/wix-app/references/auto-patterns-dashboard/app-config-structure.md +264 -0
  13. package/skills/wix-app/references/auto-patterns-dashboard/app-context.md +37 -0
  14. package/skills/wix-app/references/auto-patterns-dashboard/bulk-actions.md +86 -0
  15. package/skills/wix-app/references/auto-patterns-dashboard/collection-page-actions.md +119 -0
  16. package/skills/wix-app/references/auto-patterns-dashboard/collection-page.md +103 -0
  17. package/skills/wix-app/references/auto-patterns-dashboard/custom-actions-override.md +76 -0
  18. package/skills/wix-app/references/auto-patterns-dashboard/custom-columns-override.md +82 -0
  19. package/skills/wix-app/references/auto-patterns-dashboard/custom-components-override.md +89 -0
  20. package/skills/wix-app/references/auto-patterns-dashboard/custom-header-override.md +124 -0
  21. package/skills/wix-app/references/auto-patterns-dashboard/custom-sections-override.md +91 -0
  22. package/skills/wix-app/references/auto-patterns-dashboard/custom-slots-override.md +71 -0
  23. package/skills/wix-app/references/auto-patterns-dashboard/entity-page-actions.md +70 -0
  24. package/skills/wix-app/references/auto-patterns-dashboard/entity-page-view-actions.md +73 -0
  25. package/skills/wix-app/references/auto-patterns-dashboard/entity-page.md +98 -0
  26. package/skills/wix-app/references/auto-patterns-dashboard/example-patterns.json +278 -0
  27. package/skills/wix-app/references/auto-patterns-dashboard/pages-configuration.md +94 -0
  28. package/skills/wix-app/references/auto-patterns-dashboard/resolved-action.md +43 -0
  29. package/skills/wix-app/references/auto-patterns-dashboard/sdk-utilities.md +66 -0
  30. package/skills/wix-app/references/auto-patterns-dashboard/views.md +76 -0
  31. package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +1 -14
  32. package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +54 -29
  33. package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +2 -2
  34. package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +17 -105
  35. package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +127 -0
  36. package/skills/wix-app/references/editor-react-component/PARTS.md +2 -1
  37. package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +15 -15
  38. package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +25 -53
  39. package/skills/wix-app/scripts/generate-auto-patterns.js +510 -0
  40. package/skills/wix-auth/SKILL.md +12 -0
  41. package/skills/wix-auth/references/device-flow.md +140 -0
  42. package/skills/wix-docs/SKILL.md +188 -0
  43. package/skills/wix-docs/references/API_SPEC_SEARCH.md +213 -0
  44. package/skills/wix-docs/references/EXTRACTING.md +120 -0
  45. package/skills/wix-headless/SKILL.md +84 -130
  46. package/skills/wix-headless/entry/bootstrap.mjs +93 -0
  47. package/skills/wix-headless/entry/skill.md +78 -0
  48. package/skills/wix-headless/references/AI_FEATURES.md +178 -0
  49. package/skills/wix-headless/references/CAPABILITIES.md +84 -0
  50. package/skills/wix-headless/references/DISCOVERY.md +34 -56
  51. package/skills/wix-headless/references/DOC_DISCOVERY.md +37 -0
  52. package/skills/wix-headless/references/FEEDBACK.md +118 -0
  53. package/skills/wix-headless/references/IMAGE_GENERATION.md +69 -0
  54. package/skills/wix-headless/references/SDK_HANDOFF.md +97 -0
  55. package/skills/wix-headless/references/SEED.md +44 -188
  56. package/skills/wix-headless/references/SETUP.md +32 -103
  57. package/skills/wix-headless/references/astro.md +98 -0
  58. package/skills/wix-headless/references/inline-recipes/how-to-code-a-blog.md +196 -0
  59. package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +236 -0
  60. package/skills/wix-headless/references/inline-recipes/how-to-code-bookings.md +279 -0
  61. package/skills/wix-headless/references/inline-recipes/how-to-code-cms.md +163 -0
  62. package/skills/wix-headless/references/inline-recipes/how-to-code-events.md +203 -0
  63. package/skills/wix-headless/references/inline-recipes/how-to-code-forms.md +222 -0
  64. package/skills/wix-headless/references/inline-recipes/how-to-code-members-astro.md +124 -0
  65. package/skills/wix-headless/references/inline-recipes/how-to-code-members-custom-login.md +160 -0
  66. package/skills/wix-headless/references/inline-recipes/how-to-code-members-non-astro.md +118 -0
  67. package/skills/wix-headless/references/inline-recipes/how-to-code-portfolio.md +132 -0
  68. package/skills/wix-headless/references/inline-recipes/how-to-code-pricing-plans.md +124 -0
  69. package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-orders.md +188 -0
  70. package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-reservations.md +173 -0
  71. package/skills/wix-headless/references/inline-recipes/how-to-code-restaurants.md +161 -0
  72. package/skills/wix-headless/references/inline-recipes/setup-blog.md +175 -0
  73. package/skills/wix-headless/references/inline-recipes/setup-bookings.md +228 -0
  74. package/skills/wix-headless/references/inline-recipes/setup-cms.md +200 -0
  75. package/skills/wix-headless/references/inline-recipes/setup-events.md +196 -0
  76. package/skills/wix-headless/references/inline-recipes/setup-forms.md +174 -0
  77. package/skills/wix-headless/references/inline-recipes/setup-online-store.md +176 -0
  78. package/skills/wix-headless/references/inline-recipes/setup-portfolio.md +153 -0
  79. package/skills/wix-headless/references/inline-recipes/setup-pricing-plans.md +229 -0
  80. package/skills/wix-headless/references/inline-recipes/setup-restaurant-orders.md +161 -0
  81. package/skills/wix-headless/references/inline-recipes/setup-restaurant-reservations.md +117 -0
  82. package/skills/wix-headless/references/inline-recipes/setup-restaurants.md +152 -0
  83. package/skills/wix-headless/references/managed/AUTHENTICATION.md +57 -0
  84. package/skills/wix-headless/references/managed/CONNECT.md +74 -0
  85. package/skills/wix-headless/references/managed/CREATE.md +130 -0
  86. package/skills/wix-headless/references/managed/DEPLOYMENT.md +57 -0
  87. package/skills/wix-headless/references/non-astro.md +59 -0
  88. package/skills/wix-headless/references/self-managed/AUTHENTICATION.md +22 -0
  89. package/skills/wix-headless/references/self-managed/DEPLOYMENT.md +7 -0
  90. package/skills/wix-headless/references/stripe/AUTHENTICATION.md +55 -0
  91. package/skills/wix-headless/references/stripe/DEPLOYMENT.md +63 -0
  92. package/skills/wix-manage/SKILL.md +24 -1
  93. package/skills/wix-manage/references/analytics/query-site-analytics.md +241 -0
  94. package/skills/wix-manage/references/bookings/create-and-update-booking-services.md +1 -1
  95. package/skills/wix-manage/references/bookings/diagnose-availability-issues.md +265 -0
  96. package/skills/wix-manage/references/marketing/create-and-publish-social-post.md +436 -0
  97. package/skills/wix-manage/references/marketing/generate-and-publish-marketing-plan.md +209 -0
  98. package/skills/wix-manage/references/rich-content/author-ricos-rich-content.md +249 -0
  99. package/skills/wix-manage/references/stores/create-product-with-options-catalog-v3.md +51 -0
  100. package/skills/wix-vibe-headless/SKILL.md +136 -0
  101. package/skills/wix-vibe-headless/references/blog/INSTRUCTIONS.md +128 -0
  102. package/skills/wix-vibe-headless/references/blog/wix-blog.js +217 -0
  103. package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +153 -0
  104. package/skills/wix-vibe-headless/references/bookings/wix-bookings-checkout.js +147 -0
  105. package/skills/wix-vibe-headless/references/bookings/wix-bookings-services.js +215 -0
  106. package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +154 -0
  107. package/skills/wix-vibe-headless/references/cms/wix-cms.js +186 -0
  108. package/skills/wix-vibe-headless/references/events/INSTRUCTIONS.md +142 -0
  109. package/skills/wix-vibe-headless/references/events/wix-events-browse.js +135 -0
  110. package/skills/wix-vibe-headless/references/events/wix-events-registration.js +187 -0
  111. package/skills/wix-vibe-headless/references/members/INSTRUCTIONS.md +211 -0
  112. package/skills/wix-vibe-headless/references/members/wix-members-auth.js +387 -0
  113. package/skills/wix-vibe-headless/references/portfolio/INSTRUCTIONS.md +111 -0
  114. package/skills/wix-vibe-headless/references/portfolio/wix-portfolio.js +194 -0
  115. package/skills/wix-vibe-headless/references/pricing-plans/INSTRUCTIONS.md +127 -0
  116. package/skills/wix-vibe-headless/references/pricing-plans/wix-pricing-plans.js +157 -0
  117. package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +138 -0
  118. package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-menu.js +224 -0
  119. package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-ordering.js +156 -0
  120. package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-reservations.js +107 -0
  121. package/skills/wix-vibe-headless/references/shared/wix-client.js +186 -0
  122. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +155 -0
  123. package/skills/wix-vibe-headless/references/storefront/wix-store-cart.js +147 -0
  124. package/skills/wix-vibe-headless/references/storefront/wix-store-catalog.js +142 -0
  125. package/skills/wix-headless/references/BUILD-astro.md +0 -253
  126. package/skills/wix-headless/references/BUILD-own-build.md +0 -167
  127. package/skills/wix-headless/references/BUILD.md +0 -105
  128. package/skills/wix-headless/references/DESIGN_SYSTEM.md +0 -165
  129. package/skills/wix-headless/references/DISCOVERY-connect.md +0 -55
  130. package/skills/wix-headless/references/DISCOVERY-create.md +0 -238
  131. package/skills/wix-headless/references/PLAN-connect.md +0 -19
  132. package/skills/wix-headless/references/PLAN-create.md +0 -17
  133. package/skills/wix-headless/references/PLAN.md +0 -92
  134. package/skills/wix-headless/references/astro/blog/BLOG_PAGES.md +0 -300
  135. package/skills/wix-headless/references/astro/blog/BLOG_SETUP.md +0 -218
  136. package/skills/wix-headless/references/astro/bookings/COMPONENTS.md +0 -45
  137. package/skills/wix-headless/references/astro/bookings/SERVICES_PAGES.md +0 -77
  138. package/skills/wix-headless/references/astro/cms/CMS_FOUNDATIONS.md +0 -214
  139. package/skills/wix-headless/references/astro/cms/FAQ_KNOWLEDGE_BASE.md +0 -231
  140. package/skills/wix-headless/references/astro/cms/PORTFOLIO.md +0 -453
  141. package/skills/wix-headless/references/astro/cms/RESOURCE_LIBRARY.md +0 -354
  142. package/skills/wix-headless/references/astro/cms/TEAM_DIRECTORY.md +0 -299
  143. package/skills/wix-headless/references/astro/designer/INSTRUCTIONS.md +0 -351
  144. package/skills/wix-headless/references/astro/ecom/CART_PAGES.md +0 -119
  145. package/skills/wix-headless/references/astro/ecom/CART_WIRING.md +0 -103
  146. package/skills/wix-headless/references/astro/ecom/COMPONENTS_CSS.md +0 -132
  147. package/skills/wix-headless/references/astro/forms/CONTACT_FORM.md +0 -463
  148. package/skills/wix-headless/references/astro/gift-cards/COMPONENTS.md +0 -119
  149. package/skills/wix-headless/references/astro/gift-cards/PAGES.md +0 -129
  150. package/skills/wix-headless/references/astro/stores/BACK_IN_STOCK.md +0 -178
  151. package/skills/wix-headless/references/astro/stores/CATEGORY_PAGES.md +0 -85
  152. package/skills/wix-headless/references/astro/stores/COMPONENTS_CSS.md +0 -129
  153. package/skills/wix-headless/references/astro/stores/HOME_AND_NAV.md +0 -229
  154. package/skills/wix-headless/references/astro/stores/PRODUCT_PAGES.md +0 -215
  155. package/skills/wix-headless/references/astro/stores/SHARED_WIRING.md +0 -165
  156. package/skills/wix-headless/references/astro/templates/Layout.astro +0 -132
  157. package/skills/wix-headless/references/astro/templates/astro.config.mjs +0 -41
  158. package/skills/wix-headless/references/astro/templates/bookings/AvailabilityCalendar.tsx +0 -374
  159. package/skills/wix-headless/references/astro/templates/bookings/BookingForm.tsx +0 -136
  160. package/skills/wix-headless/references/astro/templates/bookings/SeoTags.astro +0 -25
  161. package/skills/wix-headless/references/astro/templates/bookings/ServiceBookingFlow.tsx +0 -71
  162. package/skills/wix-headless/references/astro/templates/bookings/ServiceCard.astro +0 -54
  163. package/skills/wix-headless/references/astro/templates/bookings/booking-confirmation.astro +0 -49
  164. package/skills/wix-headless/references/astro/templates/bookings/bookingDriver.ts +0 -245
  165. package/skills/wix-headless/references/astro/templates/bookings/components-bookings.css +0 -424
  166. package/skills/wix-headless/references/astro/templates/bookings/services/[slug].astro +0 -176
  167. package/skills/wix-headless/references/astro/templates/bookings/services/index.astro +0 -181
  168. package/skills/wix-headless/references/astro/templates/ecom/CartBadge.tsx +0 -84
  169. package/skills/wix-headless/references/astro/templates/ecom/CartView.tsx +0 -543
  170. package/skills/wix-headless/references/astro/templates/ecom/cart.astro +0 -13
  171. package/skills/wix-headless/references/astro/templates/ecom/components-ecom.css +0 -302
  172. package/skills/wix-headless/references/astro/templates/ecom/discounts.ts +0 -71
  173. package/skills/wix-headless/references/astro/templates/ecom/thank-you.astro +0 -24
  174. package/skills/wix-headless/references/astro/templates/gift-cards/GiftCardPurchase.tsx +0 -172
  175. package/skills/wix-headless/references/astro/templates/gift-cards/_home-teaser-snippet.astro +0 -42
  176. package/skills/wix-headless/references/astro/templates/gift-cards/_nav-snippet.astro +0 -11
  177. package/skills/wix-headless/references/astro/templates/gift-cards/components-gift-cards.css +0 -220
  178. package/skills/wix-headless/references/astro/templates/gift-cards/gift-cards.astro +0 -51
  179. package/skills/wix-headless/references/astro/templates/gift-cards/gift-cards.ts +0 -75
  180. package/skills/wix-headless/references/astro/templates/global.css +0 -288
  181. package/skills/wix-headless/references/astro/templates/stores/AddToCartButton.tsx +0 -77
  182. package/skills/wix-headless/references/astro/templates/stores/BackInStockForm.tsx +0 -176
  183. package/skills/wix-headless/references/astro/templates/stores/CategoryRail.astro +0 -69
  184. package/skills/wix-headless/references/astro/templates/stores/ProductCard.astro +0 -79
  185. package/skills/wix-headless/references/astro/templates/stores/ProductPurchase.tsx +0 -397
  186. package/skills/wix-headless/references/astro/templates/stores/SeoTags.astro +0 -21
  187. package/skills/wix-headless/references/astro/templates/stores/back-in-stock.ts +0 -67
  188. package/skills/wix-headless/references/astro/templates/stores/categories.ts +0 -155
  189. package/skills/wix-headless/references/astro/templates/stores/category/[slug].astro +0 -130
  190. package/skills/wix-headless/references/astro/templates/stores/components-stores.css +0 -400
  191. package/skills/wix-headless/references/astro/templates/stores/products/[slug].astro +0 -128
  192. package/skills/wix-headless/references/astro/templates/stores/products/index.astro +0 -101
  193. package/skills/wix-headless/references/blog/BLOG_CONTENT.md +0 -161
  194. package/skills/wix-headless/references/blog/INSTRUCTIONS.md +0 -32
  195. package/skills/wix-headless/references/bookings/FLOW.md +0 -246
  196. package/skills/wix-headless/references/bookings/INSTRUCTIONS.md +0 -95
  197. package/skills/wix-headless/references/bookings/SERVICES_DATA.md +0 -355
  198. package/skills/wix-headless/references/cms/CMS_FOUNDATIONS.md +0 -176
  199. package/skills/wix-headless/references/cms/INSTRUCTIONS.md +0 -71
  200. package/skills/wix-headless/references/commands/known-apps.json +0 -6
  201. package/skills/wix-headless/references/custom/CONNECTION_PLAN.md +0 -142
  202. package/skills/wix-headless/references/custom/INSTRUCTIONS.md +0 -88
  203. package/skills/wix-headless/references/custom/blog/WIRING.md +0 -52
  204. package/skills/wix-headless/references/custom/bookings/WIRING.md +0 -197
  205. package/skills/wix-headless/references/custom/cms/WIRING.md +0 -97
  206. package/skills/wix-headless/references/custom/ecom/WIRING.md +0 -67
  207. package/skills/wix-headless/references/custom/forms/WIRING.md +0 -101
  208. package/skills/wix-headless/references/custom/stores/WIRING.md +0 -80
  209. package/skills/wix-headless/references/ecom/INSTRUCTIONS.md +0 -59
  210. package/skills/wix-headless/references/forms/INSTRUCTIONS.md +0 -43
  211. package/skills/wix-headless/references/gift-cards/INSTRUCTIONS.md +0 -51
  212. package/skills/wix-headless/references/images/INSTRUCTIONS.md +0 -357
  213. package/skills/wix-headless/references/seed-recipes.md +0 -49
  214. package/skills/wix-headless/references/shared/AGENTS_MD.md +0 -47
  215. package/skills/wix-headless/references/shared/AUTHENTICATION.md +0 -108
  216. package/skills/wix-headless/references/shared/BUILD_NOISE.md +0 -8
  217. package/skills/wix-headless/references/shared/DESIGN_MD.md +0 -84
  218. package/skills/wix-headless/references/shared/DOCS_SEARCH.md +0 -41
  219. package/skills/wix-headless/references/shared/IMAGE_GENERATION.md +0 -186
  220. package/skills/wix-headless/references/shared/IMPLEMENTER.md +0 -206
  221. package/skills/wix-headless/references/shared/PRODUCTION_SHARP_EDGES.md +0 -97
  222. package/skills/wix-headless/references/shared/RETURN_CONTRACT.md +0 -143
  223. package/skills/wix-headless/references/shared/STYLING.md +0 -140
  224. package/skills/wix-headless/references/stores/INSTRUCTIONS.md +0 -126
  225. package/skills/wix-headless/references/stores/PRODUCT_CATALOG_DATA.md +0 -252
  226. package/skills/wix-headless/references/verticals/_schema.json +0 -74
  227. package/skills/wix-headless/references/verticals/_schema.md +0 -95
  228. package/skills/wix-headless/references/verticals/blog.md +0 -31
  229. package/skills/wix-headless/references/verticals/bookings.md +0 -41
  230. package/skills/wix-headless/references/verticals/cms.md +0 -30
  231. package/skills/wix-headless/references/verticals/ecom.md +0 -25
  232. package/skills/wix-headless/references/verticals/forms.md +0 -26
  233. package/skills/wix-headless/references/verticals/gift-cards.md +0 -24
  234. package/skills/wix-headless/references/verticals/stores.md +0 -33
  235. package/skills/wix-headless/scripts/check-manifest.mjs +0 -335
  236. package/skills/wix-headless/scripts/compose.mjs +0 -520
  237. package/skills/wix-headless/scripts/emit-design-tokens.mjs +0 -157
  238. package/skills/wix-headless/scripts/flatten.sh +0 -61
  239. package/skills/wix-headless/scripts/generate-images.mjs +0 -242
  240. package/skills/wix-headless/scripts/patch-decorative-slots.mjs +0 -154
  241. package/skills/wix-headless/scripts/plan-entity-image-waves.mjs +0 -190
  242. package/skills/wix-headless/scripts/scaffold.sh +0 -139
  243. package/skills/wix-headless/scripts/seed-utilities.sh +0 -93
  244. package/skills/wix-headless/scripts/write-decorative-json.mjs +0 -62
  245. package/skills/wix-headless/shared-utilities/analytics.ts +0 -40
  246. package/skills/wix-headless/shared-utilities/ricos.ts +0 -179
  247. package/skills/wix-headless/shared-utilities/wix-image.ts +0 -72
@@ -0,0 +1,186 @@
1
+ import { wixApiRequest } from "./wix-client.js";
2
+
3
+ /**
4
+ * Wix CMS (Wix Data) — REST helpers for reading and writing data items in site data collections.
5
+ *
6
+ * COLLECTIONS & PERMISSIONS: A collection (e.g. "Tutorials") is identified by its
7
+ * dataCollectionId — the name set in the dashboard, NOT a GUID. Field keys are also set
8
+ * in the dashboard. This skill runs as an ANONYMOUS VISITOR — a call only succeeds if the
9
+ * collection grants that action to "Anyone" (Read for listing, Insert for forms, etc.).
10
+ * Permission-denied throws HTTP 403 by design. Set permissions in Wix dashboard → CMS → Permissions.
11
+ * https://dev.wix.com/docs/api-reference/business-solutions/cms/collection-management/data-permissions/data-permissions-object.md
12
+ *
13
+ * Data Item — every read helper returns the item's `data` payload:
14
+ * _id {string} — GUID (route key, itemId for get/update/remove),
15
+ * _createdDate, _updatedDate {string} — ISO 8601 (use { "$date": "..." } in filters),
16
+ * _ownerId {string}, ...fields — collection field values keyed by field key
17
+ * Full reference: https://dev.wix.com/docs/api-reference/business-solutions/cms/data-items/data-item-object.md
18
+ *
19
+ * FILTERS & SORT (Wix API Query Language):
20
+ * filter: { field: value } for equality; { field: { $op: value } } for operators:
21
+ * $eq $ne $gt $gte $lt $lte $in $nin $startsWith $exists $isEmpty $hasSome $hasAll
22
+ * Combine with $and / $or / $not. Dates: { "$date": "2026-05-05T00:00:00.000Z" }.
23
+ * sort: [{ fieldName: "publishDate", order: "DESC" }]
24
+ * Full reference: https://dev.wix.com/docs/api-reference/articles/work-with-wix-apis/data-retrieval/about-the-wix-api-query-language.md
25
+ */
26
+
27
+ /**
28
+ * Query one page of items from a collection.
29
+ * Reference: https://dev.wix.com/docs/api-reference/business-solutions/cms/data-items/query-data-items.md
30
+ *
31
+ * Pass `nextCursor` back as `cursor` to load the next page. Define `filter`/`sort`/`fields`
32
+ * on the FIRST request only — on cursor follow-ups Wix reuses the original query and
33
+ * ignores them (so this helper omits them when a cursor is supplied).
34
+ *
35
+ * @param {string} dataCollectionId Collection name (e.g. "Tutorials").
36
+ * @param {{
37
+ * filter?: object,
38
+ * sort?: Array<{ fieldName: string, order?: "ASC"|"DESC" }>,
39
+ * limit?: number,
40
+ * cursor?: string,
41
+ * fields?: string[],
42
+ * includeReferences?: Array<{ field: string, limit?: number }>
43
+ * }} [options]
44
+ * @returns {Promise<{ items: object[], nextCursor: string|null }>} items are `data` payloads (each includes `_id`).
45
+ */
46
+ export async function queryDataItems(dataCollectionId, { filter, sort, limit = 100, cursor, fields, includeReferences } = {}) {
47
+ const query = {
48
+ ...(cursor
49
+ ? {}
50
+ : {
51
+ ...(filter ? { filter } : {}),
52
+ ...(sort ? { sort } : {}),
53
+ ...(fields ? { fields } : {}),
54
+ }),
55
+ cursorPaging: cursor ? { limit, cursor } : { limit },
56
+ };
57
+ const res = await wixApiRequest("/wix-data/v2/items/query", {
58
+ method: "POST",
59
+ body: {
60
+ dataCollectionId,
61
+ query,
62
+ ...(includeReferences ? { includeReferences } : {}),
63
+ },
64
+ });
65
+ return {
66
+ items: (res?.dataItems ?? []).map((d) => d.data),
67
+ nextCursor: res?.pagingMetadata?.cursors?.next ?? null,
68
+ };
69
+ }
70
+
71
+ /**
72
+ * Get a single item by its `_id`. Returns the `data` payload, or null if not found
73
+ * (or not readable by an anonymous visitor — see the permissions note up top).
74
+ * Reference: https://dev.wix.com/docs/api-reference/business-solutions/cms/data-items/get-data-item.md
75
+ *
76
+ * @param {string} dataCollectionId
77
+ * @param {string} itemId The item's `_id`.
78
+ * @returns {Promise<object|null>}
79
+ */
80
+ export async function getDataItem(dataCollectionId, itemId) {
81
+ try {
82
+ const res = await wixApiRequest(`/wix-data/v2/items/${encodeURIComponent(itemId)}`, {
83
+ method: "GET",
84
+ query: { dataCollectionId },
85
+ });
86
+ return res?.dataItem?.data ?? null;
87
+ } catch {
88
+ return null;
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Get the first item whose `fieldKey` equals `value`. Use for slug-style routing —
94
+ * Wix Data has no native get-by-slug, so detail pages keyed off a human-readable field
95
+ * (e.g. a "slug" or "handle" field) resolve through this. Returns the `data` payload or null.
96
+ * Built on Query Data Items: https://dev.wix.com/docs/api-reference/business-solutions/cms/data-items/query-data-items.md
97
+ *
98
+ * @param {string} dataCollectionId
99
+ * @param {string} fieldKey Field to match (e.g. "slug").
100
+ * @param {unknown} value Value to match.
101
+ * @returns {Promise<object|null>}
102
+ */
103
+ export async function getDataItemBy(dataCollectionId, fieldKey, value) {
104
+ const { items } = await queryDataItems(dataCollectionId, { filter: { [fieldKey]: value }, limit: 1 });
105
+ return items[0] ?? null;
106
+ }
107
+
108
+ /**
109
+ * Count items in a collection matching an optional filter. Use for empty-state logic
110
+ * (0 → prompt the user to add items in their Wix dashboard) and result counts.
111
+ * Reference: https://dev.wix.com/docs/api-reference/business-solutions/cms/data-items/count-data-items.md
112
+ *
113
+ * @param {string} dataCollectionId
114
+ * @param {object} [filter] Same filter syntax as queryDataItems.
115
+ * @returns {Promise<number>}
116
+ */
117
+ export async function countDataItems(dataCollectionId, filter) {
118
+ const res = await wixApiRequest("/wix-data/v2/items/count", {
119
+ method: "POST",
120
+ body: { dataCollectionId, ...(filter ? { filter } : {}) },
121
+ });
122
+ return res?.totalCount ?? 0;
123
+ }
124
+
125
+ /**
126
+ * Insert a new item (e.g. a public form submission). The collection's Insert permission
127
+ * must be "Anyone" for this to succeed as a visitor. Returns the inserted `data` payload
128
+ * (including the assigned `_id`). Throws on failure (e.g. permission denied, validation).
129
+ * Reference: https://dev.wix.com/docs/api-reference/business-solutions/cms/data-items/insert-data-item.md
130
+ *
131
+ * @param {string} dataCollectionId
132
+ * @param {object} data Field-keyed values, e.g. { name, email, message }. Omit `_id`
133
+ * to let Wix assign one; supply `_id` only for a custom GUID.
134
+ * @returns {Promise<object>} The inserted item's `data` payload.
135
+ */
136
+ export async function insertDataItem(dataCollectionId, data) {
137
+ const res = await wixApiRequest("/wix-data/v2/items", {
138
+ method: "POST",
139
+ body: { dataCollectionId, dataItem: { data } },
140
+ });
141
+ const inserted = res?.dataItem?.data;
142
+ if (!inserted) throw new Error(`Insert into "${dataCollectionId}" failed (no item returned).`);
143
+ return inserted;
144
+ }
145
+
146
+ /**
147
+ * Update (REPLACE) an existing item by `_id`. Returns the updated `data` payload. Throws
148
+ * if the item doesn't exist or the visitor lacks Update permission (usually admin/author only).
149
+ * Reference: https://dev.wix.com/docs/api-reference/business-solutions/cms/data-items/update-data-item.md
150
+ *
151
+ * ⚠ This is a FULL REPLACE: the new `data` overwrites the whole item, and any field NOT
152
+ * included is dropped. To change a few fields, fetch the item first (getDataItem), spread
153
+ * it, then pass the merged object — or use Patch Data Item for a partial change:
154
+ * https://dev.wix.com/docs/api-reference/business-solutions/cms/data-items/patch-data-item.md
155
+ *
156
+ * @param {string} dataCollectionId
157
+ * @param {string} itemId The item's `_id`.
158
+ * @param {object} data The complete new field set.
159
+ * @returns {Promise<object>} The updated item's `data` payload.
160
+ */
161
+ export async function updateDataItem(dataCollectionId, itemId, data) {
162
+ const res = await wixApiRequest(`/wix-data/v2/items/${encodeURIComponent(itemId)}`, {
163
+ method: "PUT",
164
+ body: { dataCollectionId, dataItem: { id: itemId, data: { ...data, _id: itemId } } },
165
+ });
166
+ const updated = res?.dataItem?.data;
167
+ if (!updated) throw new Error(`Update of "${itemId}" in "${dataCollectionId}" failed (no item returned).`);
168
+ return updated;
169
+ }
170
+
171
+ /**
172
+ * Remove an item by `_id`. Irreversible. Returns the removed `data` payload. Throws if the
173
+ * visitor lacks Delete permission (usually admin/author only).
174
+ * Reference: https://dev.wix.com/docs/api-reference/business-solutions/cms/data-items/remove-data-item.md
175
+ *
176
+ * @param {string} dataCollectionId
177
+ * @param {string} itemId The item's `_id`.
178
+ * @returns {Promise<object|null>} The removed item's `data` payload.
179
+ */
180
+ export async function removeDataItem(dataCollectionId, itemId) {
181
+ const res = await wixApiRequest(`/wix-data/v2/items/${encodeURIComponent(itemId)}`, {
182
+ method: "DELETE",
183
+ query: { dataCollectionId },
184
+ });
185
+ return res?.dataItem?.data ?? null;
186
+ }
@@ -0,0 +1,142 @@
1
+
2
+ # Wix Events Skill
3
+
4
+ > **Source files (in this skill):** the shared transport `references/shared/wix-client.js` and the helper file(s) you need from `references/events/`. All helpers import from `"./wix-client.js"`, so copy them into the same folder (e.g. `src/rest/`).
5
+ >
6
+ > | Need | Copy |
7
+ > |---|---|
8
+ > | Event listing + detail (always) | `wix-events-browse.js` |
9
+ > | RSVP, ticketing, registration | `wix-events-registration.js` |
10
+
11
+ Builds a real, client-only Wix Events site. The browser talks to Wix directly over a
12
+ public `WIX_CLIENT_ID`. Never mock events; never hand-build registration or payment URLs —
13
+ register via the RSVP/ticketing APIs, and complete paid tickets on the official Wix-hosted
14
+ ticket form.
15
+
16
+ ## When to use
17
+ - User wants an events site over Wix Events & Tickets, or asks to "connect Wix Events".
18
+ - Replacing placeholder/mock events with live Wix data.
19
+ - Adding event listings, an event detail page, RSVP, or ticket purchase over existing,
20
+ published Wix events.
21
+
22
+ ## Prerequisites
23
+ 1. A Wix site with **Wix Events & Tickets installed and events already published** (this skill
24
+ does NOT create events — it's read-only over them). Selling **paid** tickets also needs a
25
+ Wix premium plan + a configured payment method; **free** events and RSVP events work without.
26
+ 2. The site's public headless **`WIX_CLIENT_ID`**, provided in the handoff prompt (the Wix
27
+ Business Manager surfaces a copyable prompt with the id filled in — see the router `SKILL.md`). Paste
28
+ it into `src/rest/wix-client.js` in place of the placeholder. It is a visitor-facing
29
+ credential (it only mints anonymous visitor tokens), **not** a secret, so hardcoding/
30
+ committing it is fine.
31
+ 3. For paid tickets the buyer completes payment on the **Wix-hosted ticket form** (the redirect
32
+ target of `getTicketCheckoutUrl`). The deployed app domain may need to be allow-listed on the
33
+ OAuth client for that page to return cleanly — a **separate Wix setup the user completes
34
+ later**, out of this skill's scope. If the return fails before that's done, that's expected;
35
+ flag it and continue.
36
+
37
+ ## The API (copy as-is; do not re-derive it)
38
+ This skill ships only the REST layer — no UI components. Build the events UI however the
39
+ project wants; wire it to these two snippets. Copy them into the app (e.g. `src/api/`) and only
40
+ adjust import paths:
41
+ - `src/rest/wix-client.js` — visitor-token mint/refresh + transport. Set `WIX_CLIENT_ID` to the
42
+ id from the prompt (replace the `<YOUR-CLIENT-ID>` placeholder). The visitor refresh token is
43
+ persisted to localStorage and IS the identity of the visitor's ticket reservation/cart — do
44
+ not re-mint anonymously per load.
45
+ - `src/rest/wix-events-browse.js` — **Browse & discovery:**
46
+ `queryEvents`, `getEventBySlug`, `countUpcomingEvents`, `queryEventCategories`, `listEventsByCategory`
47
+ - `src/rest/wix-events-registration.js` — **RSVP & ticketing:**
48
+ `createRsvp`, `queryTicketDefinitions`, `reserveTickets`, `getTicketCheckoutUrl`, `checkoutTickets`
49
+
50
+ The `Event`, `TicketDefinition`, and `RSVP`/`Order` shapes are documented as JSDoc comments at
51
+ the top of each helper file. Read the relevant file(s) before building the UI — they describe
52
+ the key fields and link to the full API reference for anything not shown.
53
+
54
+ ## How to wire it (UI is the project's choice)
55
+ - **Event grid** — `queryEvents()` lists live (UPCOMING/STARTED) events, soonest first. Render
56
+ `title`, `mainImage.url`, `dateAndTimeSettings.formatted.dateAndTime`, `location.name`, and
57
+ `shortDescription`. Use `offset`/`nextOffset` from the result to page. Link each card by `slug`.
58
+ - **Event detail** — `getEventBySlug(slug)`; returns null on miss — show a not-found state, never
59
+ invent an event.
60
+ - **Description fields:** `event.shortDescription` is a **plain string** (safe teaser). The full
61
+ `event.description` is **Ricos rich content** — an object shaped `{ nodes: [...] }`, **not a string**.
62
+ Render it with a Ricos viewer (`@wix/ricos`) or walk `nodes` to extract text; **never** call string
63
+ methods (`.split`/`.slice`/`.substring`) on it — that crashes the page. When you only need text, use
64
+ `shortDescription`.
65
+ - Branch the registration UI on `event.registration.type`:
66
+ - `"RSVP"` → render the RSVP form (fields from `event.form.controls`).
67
+ - `"TICKETING"` → render the ticket picker.
68
+ - `"EXTERNAL"` → link out to `event.registration.external.url`.
69
+ - `"NONE"` → details only, no registration.
70
+ Only `registration.status` values starting `OPEN_` accept new registrations; otherwise show the
71
+ closed state.
72
+ - **Categories (optional)** — `queryEventCategories()` for a filter menu (`counts.assignedEventsCount`
73
+ per category); `listEventsByCategory(categoryId)` to list a category's events (same card fields
74
+ and paging as `queryEvents`).
75
+ - **RSVP** — `createRsvp(eventId, { firstName, lastName, email, status, additionalGuestNames?, extraFields? })`.
76
+ `status` defaults to `"YES"`; only offer `"NO"` when `registration.rsvp.responseType` is
77
+ `"YES_AND_NO"`. If the event is full with a waitlist enabled, the returned RSVP comes back with
78
+ status `"WAITLIST"` — tell the guest. Completes fully client-side; no redirect.
79
+ - **Ticketing** — show tickets, reserve, then complete on the hosted form:
80
+ 1. `queryTicketDefinitions(eventId)` → render each ticket's `name`, price (`pricing.fixedPrice.amount`
81
+ + `currency` for standard tickets; `free` boolean for free tickets; `pricing.minPrice` for
82
+ donation/"pay what you want"; `pricing.pricingOptions.options` for tiered), and filter on
83
+ `saleStatus === "SALE_STARTED"`. The endpoint already returns only non-hidden, available tickets.
84
+ 2. `reserveTickets([{ ticketDefinitionId, quantity, guestPrice?, pricingOptionId? }])` → holds the
85
+ tickets; returns `{ id, expirationDate }`. Show a countdown to `expirationDate` if you like.
86
+ 3. `window.location.href = getTicketCheckoutUrl(event, reservation.id)` → the Wix-hosted ticket
87
+ form collects guest details + payment and returns the buyer to the event. This is the path for
88
+ **all paid tickets**.
89
+ - **Free tickets only:** you may instead call `checkoutTickets(eventId, { reservationId, buyer, guests })`
90
+ to finish in-app — it returns an order with status `"FREE"`, a `ticketsPdf`, and `tickets[]`. It
91
+ throws for paid orders (status `INITIATED`), telling you to use the hosted form.
92
+ - **Empty state** — if `countUpcomingEvents()` is 0, show an empty state telling the user to publish
93
+ events in their Wix dashboard. Never invent events.
94
+
95
+ ## Hard rules (do not violate)
96
+ - ✅ Complete paid ticket purchases ONLY via `reserveTickets()` → `getTicketCheckoutUrl()` redirect
97
+ (the official Wix-hosted ticket form).
98
+ - ❌ Never hand-build registration, ticket, payment, or checkout URLs — derive the hosted form URL
99
+ from `event.eventPageUrl` via `getTicketCheckoutUrl`.
100
+ - ❌ Never mock events, tickets, or guest counts — render live Wix data or the empty/closed state.
101
+ - ❌ Never invent reviews, ratings, attendee names, or "X spots left" numbers not returned by the API.
102
+ - ✅ Set `WIX_CLIENT_ID` from the prompt's value (public visitor-facing client id — safe to hardcode).
103
+ - ✅ Branch registration UI on `event.registration.type`; respect `registration.status` (only `OPEN_*`
104
+ accepts registrations) and ticket `saleStatus`/`salesDetails.soldOut`.
105
+ - ✅ Pass `guestPrice` for donation/"pay what you want" tickets and `pricingOptionId` for tiered tickets
106
+ to `reserveTickets`.
107
+ - The helpers fail loudly on purpose: `reserveTickets` throws when tickets aren't actually held,
108
+ `createRsvp` throws on closed/full registration, `checkoutTickets` throws when payment is still owed.
109
+ A green path means it really worked — don't swallow these.
110
+
111
+ ## Beyond the snippets
112
+ The snippets cover the common RSVP + ticketing paths. If you hit a use case they don't cover
113
+ (coupons/`discount` at checkout, members/auth, schedule/agenda, seating maps, canceling a
114
+ reservation, a field not in the typedefs), make the call yourself with `wixApiRequest` — but look
115
+ up the exact endpoint, HTTP method, and request body in the **official Wix Events API reference**
116
+ first; never guess:
117
+ - Events API reference: https://dev.wix.com/docs/api-reference/business-solutions/events.md
118
+ - Registration (RSVP + ticketing) overview: https://dev.wix.com/docs/api-reference/business-solutions/events/registration/introduction.md
119
+ - Member login + a "my registrations" account view → the **members** vertical (`references/members/INSTRUCTIONS.md`).
120
+ - Ticketing flow (reservations → orders → tickets): https://dev.wix.com/docs/api-reference/business-solutions/events/registration/ticketing/introduction.md
121
+
122
+ Keep the snippets as the default for everything they already do; reach for the API reference only
123
+ for the gap.
124
+
125
+ ## Point the user to their dashboard
126
+ In some cases, users need to access the Wix dashboard in order to edit the events content for their site. To facilitate this, provide the user with deep links directly to the relevant dashboard pages. For events data those pages are:
127
+ - **Events** — `https://manage.wix.com/dashboard/{metaSiteId}/events` (`Dashboard → Events` → **+ Add Event**; create the event, then set it up as **Ticketed** or **RSVP**; only published events appear in the app)
128
+
129
+ Substitute the site's `metaSiteId` to complete the links (you have it from the handoff / `ListWixSites`). Include the in-dashboard navigation as a fallback.
130
+
131
+ ## Verification checklist (before declaring done)
132
+ - [ ] `WIX_CLIENT_ID` set to the prompt's value (not the `<YOUR-CLIENT-ID>` placeholder)
133
+ - [ ] Visitor token persists across reload (same visitor identity for reservations)
134
+ - [ ] Event grid renders live events; clicking a card opens the detail page by `slug`
135
+ - [ ] Detail page branches correctly on `registration.type` (RSVP form vs. ticket picker vs. external link)
136
+ - [ ] RSVP submit creates a real RSVP (and surfaces a `WAITLIST` result when the event is full)
137
+ - [ ] Ticket purchase reserves tickets, then redirects via `getTicketCheckoutUrl` (no hand-built URL)
138
+ - [ ] Paid checkout lands on the Wix-hosted ticket form; buyer returns to the event afterward
139
+ - [ ] Closed registration / sold-out tickets show a clear state rather than a dead end
140
+ - [ ] Empty state shown when `countUpcomingEvents()` is 0
141
+ - [ ] No mock events, tickets, or attendee data anywhere
142
+ - [ ] Told the user at least once that they can continue setting up their events in the dashboard and provided deep links.
@@ -0,0 +1,135 @@
1
+ import { wixApiRequest } from "./wix-client.js";
2
+
3
+ // Data model reference: see INSTRUCTIONS.md
4
+
5
+ /**
6
+ * Wix Events V3 Event — key fields for list cards and the detail page.
7
+ * Full model: https://dev.wix.com/docs/api-reference/business-solutions/events/event-management/events-v3/event-object.md
8
+ *
9
+ * id {string}, title {string}, slug {string},
10
+ * status {string} — "UPCOMING"|"STARTED"|"ENDED"|"CANCELED"|"DRAFT" (only UPCOMING/STARTED are live),
11
+ * shortDescription {string} — PLAIN-TEXT teaser, safe to render directly (DETAILS fieldset),
12
+ * description {object} — RICH CONTENT (Ricos), shape { nodes: [...] } — NOT a string (TEXTS fieldset,
13
+ * returned by getEventBySlug). Render it with a Ricos viewer (@wix/ricos) or walk `nodes` to extract
14
+ * text; NEVER call string methods (.split/.slice/.substring/.trim) on it — that crashes the page.
15
+ * For a plain-string teaser use shortDescription instead.
16
+ * detailedDescription {string} — legacy plain/HTML description (TEXTS fieldset); prefer description/shortDescription,
17
+ * mainImage {object} — { id, url, width, height, altText } (DETAILS fieldset),
18
+ * dateAndTimeSettings {object}:
19
+ * startDate, endDate {string} — ISO-8601; absent when dateAndTimeTbd is true,
20
+ * timeZoneId {string} — IANA tz,
21
+ * formatted.dateAndTime {string} — ready-to-render human string,
22
+ * location {object}: type "VENUE"|"ONLINE", name {string}, address {object}, locationTbd {boolean},
23
+ * registration {object} (REGISTRATION fieldset):
24
+ * type {string} — "RSVP"|"TICKETING"|"EXTERNAL"|"NONE",
25
+ * status {string} — only OPEN_* statuses accept new registrations,
26
+ * rsvp.responseType — "YES_AND_NO" allows a "NO" reply,
27
+ * tickets.currency, tickets.lowestPrice, tickets.soldOut,
28
+ * external.url — link out when type === "EXTERNAL",
29
+ * eventPageUrl {object} — { base, path } (URLS fieldset) — needed for getTicketCheckoutUrl,
30
+ * form {object} — registration form controls (FORM fieldset),
31
+ * calendarUrls {object} — { google, ics } (DETAILS fieldset)
32
+ *
33
+ * Category: { id, label, slug, counts.assignedEventsCount }
34
+ * Full model: https://dev.wix.com/docs/api-reference/business-solutions/events/event-management/categories
35
+ */
36
+
37
+ const LIST_FIELDS = ["DETAILS", "REGISTRATION", "URLS"];
38
+ const DETAIL_FIELDS = ["DETAILS", "TEXTS", "REGISTRATION", "URLS", "FORM"];
39
+
40
+ /**
41
+ * Query live (UPCOMING/STARTED) events for a listing grid, one page. Sorted soonest first.
42
+ * Uses offset paging — response carries total for empty state and "load more" math.
43
+ * https://dev.wix.com/docs/api-reference/business-solutions/events/event-management/events-v3/query-events.md
44
+ * @param {{ limit?: number, offset?: number, status?: string[] }} [options]
45
+ * @returns {Promise<{ events: object[], total: number, offset: number, nextOffset: number|null }>}
46
+ */
47
+ export async function queryEvents({ limit = 50, offset = 0, status = ["UPCOMING", "STARTED"] } = {}) {
48
+ const res = await wixApiRequest("/events/v3/events/query", {
49
+ method: "POST",
50
+ body: {
51
+ query: {
52
+ filter: { status: { $in: status } },
53
+ sort: [{ fieldName: "dateAndTimeSettings.startDate", order: "ASC" }],
54
+ paging: { limit, offset },
55
+ },
56
+ fields: LIST_FIELDS,
57
+ },
58
+ });
59
+ const events = res?.events ?? [];
60
+ const total = res?.pagingMetadata?.total ?? events.length;
61
+ const nextOffset = offset + events.length < total ? offset + events.length : null;
62
+ return { events, total, offset, nextOffset };
63
+ }
64
+
65
+ /**
66
+ * Fetch a single event by its URL slug, with full detail-page fields (description, form, page URL).
67
+ * Returns null if not found — show a not-found state, never invent an event.
68
+ * https://dev.wix.com/docs/api-reference/business-solutions/events/event-management/events-v3/get-event-by-slug.md
69
+ * @param {string} slug
70
+ * @returns {Promise<object|null>}
71
+ */
72
+ export async function getEventBySlug(slug) {
73
+ try {
74
+ const res = await wixApiRequest(`/events/v3/events/slug/${encodeURIComponent(slug)}`, {
75
+ method: "GET",
76
+ query: { fields: DETAIL_FIELDS },
77
+ });
78
+ return res?.event ?? null;
79
+ } catch {
80
+ return null;
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Total number of live events. Used for empty-state logic (0 → prompt user to publish events).
86
+ * @param {string[]} [status]
87
+ * @returns {Promise<number>}
88
+ */
89
+ export async function countUpcomingEvents(status = ["UPCOMING", "STARTED"]) {
90
+ const res = await wixApiRequest("/events/v3/events/query", {
91
+ method: "POST",
92
+ body: { query: { filter: { status: { $in: status } }, paging: { limit: 1, offset: 0 } } },
93
+ });
94
+ return res?.pagingMetadata?.total ?? 0;
95
+ }
96
+
97
+ /**
98
+ * Query event categories for a category menu/filter. counts.assignedEventsCount tells you
99
+ * how many events are in each category.
100
+ * https://dev.wix.com/docs/api-reference/business-solutions/events/event-management/categories/query-categories.md
101
+ * @param {{ limit?: number, offset?: number }} [options]
102
+ * @returns {Promise<{ categories: object[], total: number }>}
103
+ */
104
+ export async function queryEventCategories({ limit = 100, offset = 0 } = {}) {
105
+ const res = await wixApiRequest("/events/v1/categories/query", {
106
+ method: "POST",
107
+ body: { query: { paging: { limit, offset } }, fieldset: ["COUNTS"] },
108
+ });
109
+ return {
110
+ categories: res?.categories ?? [],
111
+ total: res?.metaData?.total ?? (res?.categories?.length ?? 0),
112
+ };
113
+ }
114
+
115
+ /**
116
+ * List live events assigned to a category, one page. Same card fields as queryEvents.
117
+ * https://dev.wix.com/docs/api-reference/business-solutions/events/event-management/events-v3/list-events-by-category.md
118
+ * @param {string} categoryId Category GUID from queryEventCategories.
119
+ * @param {{ limit?: number, offset?: number }} [options]
120
+ * @returns {Promise<{ events: object[], total: number, offset: number, nextOffset: number|null }>}
121
+ */
122
+ export async function listEventsByCategory(categoryId, { limit = 50, offset = 0 } = {}) {
123
+ const res = await wixApiRequest(`/events/v3/events/category/${encodeURIComponent(categoryId)}`, {
124
+ method: "GET",
125
+ query: {
126
+ fields: LIST_FIELDS,
127
+ "paging.limit": String(limit),
128
+ "paging.offset": String(offset),
129
+ },
130
+ });
131
+ const events = res?.events ?? [];
132
+ const total = res?.pagingMetadata?.total ?? events.length;
133
+ const nextOffset = offset + events.length < total ? offset + events.length : null;
134
+ return { events, total, offset, nextOffset };
135
+ }
@@ -0,0 +1,187 @@
1
+ import { wixApiRequest } from "./wix-client.js";
2
+
3
+ // Data model reference: see INSTRUCTIONS.md
4
+ // Event shape (for getEventBySlug): see wix-events-browse.js
5
+
6
+ /**
7
+ * Wix Events Ticket Definition — a ticket type returned by the checkout/available-tickets endpoint.
8
+ * Full model: https://dev.wix.com/docs/api-reference/business-solutions/events/registration/ticketing/orders/list-available-tickets
9
+ *
10
+ * id {string}, eventId {string}, name {string}, description {string},
11
+ * free {boolean} — true when the ticket is free,
12
+ * price { amount, currency } — the display price (use pricing.* for full detail),
13
+ * pricing ONE-OF:
14
+ * fixedPrice { amount, currency } — same price for everyone,
15
+ * minPrice { amount, currency } — minimum for "pay what you want" (donation); pass chosen amount as ticketInfo.guestPrice,
16
+ * pricingOptions.options [{ id, name, price { amount, currency } }] — tiered; pass chosen option id as ticketInfo.pricingOptionId,
17
+ * pricingType {string} — "STANDARD" | "DONATION" | "OPTIONS",
18
+ * saleStatus {string} — "SALE_STARTED" is the only buyable state,
19
+ * limitPerCheckout {number},
20
+ * orderIndex {number} — display order
21
+ *
22
+ * RSVP: { id, eventId, status ("YES"|"NO"|"WAITLIST"), totalGuests, firstName, lastName, email }
23
+ * status "WAITLIST" when the event is full and waitlist is enabled.
24
+ * Order: { orderNumber, status, totalPrice, ticketsPdf, tickets[] }
25
+ * status "FREE" → confirmed. status "INITIATED" → redirect to getTicketCheckoutUrl.
26
+ */
27
+
28
+ /**
29
+ * Submit an RSVP for an RSVP-type event (registration.type === "RSVP"). Completes client-side.
30
+ *
31
+ * Pass status "NO" only when event.registration.rsvp.responseType is "YES_AND_NO".
32
+ * If the event is full with a waitlist enabled, the RSVP comes back with status "WAITLIST".
33
+ * Throws on closed registration, guest-limit exceeded, duplicate email, or invalid form.
34
+ * https://dev.wix.com/docs/api-reference/business-solutions/events/registration/rsvp-v2/create-rsvp.md
35
+ *
36
+ * @param {string} eventId
37
+ * @param {{ firstName: string, lastName: string, email: string, status?: "YES"|"NO",
38
+ * additionalGuestNames?: string[], extraFields?: Record<string,string|string[]> }} guest
39
+ * @returns {Promise<object>} The created RSVP.
40
+ */
41
+ export async function createRsvp(eventId, { firstName, lastName, email, status = "YES", additionalGuestNames = [], extraFields = {} } = {}) {
42
+ if (!firstName || !lastName || !email) throw new Error("createRsvp requires firstName, lastName, and email.");
43
+
44
+ // The built-in fields go TOP-LEVEL on rsvp — the API rejects them inside form.inputValues
45
+ // (400 "rsvp.firstName must not be empty"). form.inputValues is ONLY for the event's extra
46
+ // custom fields; sending a built-in-only form, or additionalGuestDetails when the event has no
47
+ // guest fields, throws INVALID_FORM_RESPONSE ("input additionalGuests/guestNames is unexpected").
48
+ const rsvp = { eventId, firstName, lastName, email, status };
49
+
50
+ const inputValues = [];
51
+ for (const [inputName, value] of Object.entries(extraFields)) {
52
+ inputValues.push(Array.isArray(value) ? { inputName, values: value } : { inputName, value });
53
+ }
54
+ if (inputValues.length) rsvp.form = { inputValues };
55
+ if (additionalGuestNames.length) {
56
+ rsvp.additionalGuestDetails = { guestCount: additionalGuestNames.length, guestNames: additionalGuestNames };
57
+ }
58
+
59
+ const res = await wixApiRequest("/events/v2/rsvps", { method: "POST", body: { rsvp } });
60
+ return res?.rsvp;
61
+ }
62
+
63
+ /**
64
+ * Query the buyable ticket definitions for a ticketed event (with availability).
65
+ *
66
+ * Uses GET /events/v1/checkout/available-tickets (WIX_EVENTS.READ_CHECKOUT) — the visitor-facing
67
+ * checkout endpoint. The V3 /ticket-definitions/query endpoint requires WIX_EVENTS.READ_TICKET_DEFINITIONS
68
+ * (scope SCOPE.DC-EVENTS.MANAGE-TICKET-DEF), an admin-only scope that anonymous visitor tokens do
69
+ * not carry, so it 403s in a headless SPA context.
70
+ *
71
+ * This endpoint already filters to non-hidden, SALE_STARTED tickets, so the result is ready to
72
+ * render directly. Pass includeSoldOut: false to additionally drop sold-out tiers.
73
+ *
74
+ * https://dev.wix.com/docs/api-reference/business-solutions/events/registration/ticketing/orders/list-available-tickets
75
+ * @param {string} eventId
76
+ * @param {{ includeSoldOut?: boolean }} [options]
77
+ * @returns {Promise<object[]>}
78
+ */
79
+ export async function queryTicketDefinitions(eventId, { includeSoldOut = true } = {}) {
80
+ const res = await wixApiRequest("/events/v1/checkout/available-tickets", {
81
+ method: "GET",
82
+ query: { eventId, limit: "100" },
83
+ });
84
+ let defs = res?.definitions ?? [];
85
+ if (!includeSoldOut) defs = defs.filter((d) => !d.salesDetails?.soldOut);
86
+ return defs;
87
+ }
88
+
89
+ /**
90
+ * Reserve tickets for a limited time (typically 5–30 min) while the buyer completes checkout.
91
+ * Returns a reservation with status "PENDING" and an expirationDate.
92
+ * Throws if the reservation doesn't come back PENDING (e.g. tickets unavailable).
93
+ * https://dev.wix.com/docs/api-reference/business-solutions/events/registration/ticketing/ticket-reservations/create-ticket-reservation.md
94
+ *
95
+ * @param {Array<{ ticketDefinitionId: string, quantity: number, guestPrice?: string, pricingOptionId?: string }>} tickets
96
+ * @returns {Promise<object>} The created reservation (id, expirationDate, tickets[], status).
97
+ */
98
+ export async function reserveTickets(tickets) {
99
+ if (!Array.isArray(tickets) || !tickets.length) throw new Error("reserveTickets requires at least one ticket line.");
100
+
101
+ const lines = tickets.map(({ ticketDefinitionId, quantity, guestPrice, pricingOptionId }) => {
102
+ if (!ticketDefinitionId || !quantity) throw new Error("Each ticket line needs a ticketDefinitionId and quantity.");
103
+ const ticketInfo = {};
104
+ if (guestPrice !== undefined) ticketInfo.guestPrice = String(guestPrice);
105
+ if (pricingOptionId) ticketInfo.pricingOptionId = pricingOptionId;
106
+ const line = { ticketDefinitionId, quantity };
107
+ if (Object.keys(ticketInfo).length) line.ticketInfo = ticketInfo;
108
+ return line;
109
+ });
110
+
111
+ const res = await wixApiRequest("/events/v1/ticket-reservations", {
112
+ method: "POST",
113
+ body: { ticketReservation: { tickets: lines } },
114
+ });
115
+ const reservation = res?.ticketReservation;
116
+ if (!reservation?.id || reservation.status !== "PENDING") {
117
+ throw new Error(`Could not reserve tickets (status: ${reservation?.status ?? "unknown"}). They may be sold out.`);
118
+ }
119
+ return reservation;
120
+ }
121
+
122
+ /**
123
+ * Build the URL of the Wix-hosted ticket form for a reservation. Use this for ALL paid tickets
124
+ * (and free tickets too). The buyer fills in guest details and pays on Wix's page, then returns.
125
+ * Redirect with: window.location.href = getTicketCheckoutUrl(event, reservation.id)
126
+ *
127
+ * event must have been fetched with the URLS fieldset (getEventBySlug already does this).
128
+ * https://dev.wix.com/docs/api-reference/business-solutions/events/registration/ticketing/orders/checkout.md
129
+ *
130
+ * @param {object} event Event from getEventBySlug (needs eventPageUrl).
131
+ * @param {string} reservationId From reserveTickets.
132
+ * @returns {string} Absolute hosted ticket-form URL.
133
+ */
134
+ export function getTicketCheckoutUrl(event, reservationId) {
135
+ const base = event?.eventPageUrl?.base;
136
+ const path = event?.eventPageUrl?.path;
137
+ if (!base || !path) throw new Error("Event is missing eventPageUrl — fetch it with getEventBySlug (URLS fieldset).");
138
+ if (!reservationId) throw new Error("getTicketCheckoutUrl requires a reservationId from reserveTickets.");
139
+ return `${base}${path}/ticket-form?reservationId=${encodeURIComponent(reservationId)}`;
140
+ }
141
+
142
+ /**
143
+ * Check out a reservation via REST — creates the order and assigns guests.
144
+ * Use this ONLY for FREE ticket orders (no redirect needed): the returned order has
145
+ * status "FREE", a ticketsPdf, and generated tickets[].
146
+ *
147
+ * For PAID tickets, this throws and tells you to redirect to getTicketCheckoutUrl instead.
148
+ * https://dev.wix.com/docs/api-reference/business-solutions/events/registration/ticketing/orders/checkout.md
149
+ *
150
+ * @param {string} eventId
151
+ * @param {{ reservationId: string,
152
+ * buyer?: { firstName: string, lastName: string, email: string },
153
+ * guests: Array<{ firstName: string, lastName: string, email: string, extraFields?: Record<string,string|string[]> }> }} details
154
+ * @returns {Promise<object>} The created order (orderNumber, status, ticketsPdf, tickets[]).
155
+ */
156
+ export async function checkoutTickets(eventId, { reservationId, buyer, guests } = {}) {
157
+ if (!eventId || !reservationId) throw new Error("checkoutTickets requires eventId and reservationId.");
158
+ if (!Array.isArray(guests) || !guests.length) throw new Error("checkoutTickets requires at least one guest.");
159
+
160
+ const toForm = ({ firstName, lastName, email, extraFields = {} }) => {
161
+ const inputValues = [
162
+ { inputName: "firstName", value: firstName },
163
+ { inputName: "lastName", value: lastName },
164
+ { inputName: "email", value: email },
165
+ ];
166
+ for (const [inputName, value] of Object.entries(extraFields)) {
167
+ inputValues.push(Array.isArray(value) ? { inputName, values: value } : { inputName, value });
168
+ }
169
+ return { form: { inputValues } };
170
+ };
171
+
172
+ const body = { reservationId, guests: guests.map(toForm) };
173
+ if (buyer) body.buyer = buyer;
174
+
175
+ const res = await wixApiRequest(`/events/v1/events/${encodeURIComponent(eventId)}/tickets/checkout`, {
176
+ method: "POST",
177
+ body,
178
+ });
179
+ const order = res?.order;
180
+ const status = order?.status;
181
+ if (status === "INITIATED" || status === "PENDING") {
182
+ throw new Error(
183
+ `Order ${order?.orderNumber ?? ""} needs payment (status: ${status}). Redirect the buyer to getTicketCheckoutUrl(event, reservationId) to pay on the hosted ticket form.`,
184
+ );
185
+ }
186
+ return order;
187
+ }