@wix/agent-skills 1.27.0 → 1.29.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 (49) hide show
  1. package/package.json +2 -2
  2. package/skills/wix-app/SKILL.md +1 -1
  3. package/skills/wix-app/references/APP_VALIDATION.md +5 -1
  4. package/skills/wix-app/references/SDK_MODULE_MAP.md +1 -1
  5. package/skills/wix-app/references/editor-react-component/PARTS.md +1 -1
  6. package/skills/wix-app/references/service-plugin/DISCOUNT-TRIGGERS.md +1 -1
  7. package/skills/wix-app/references/stores/GET_PRODUCT.md +9 -1
  8. package/skills/wix-app/references/stores/INVENTORY.md +2 -0
  9. package/skills/wix-app/references/stores/QUERY.md +2 -2
  10. package/skills/wix-app/references/stores/WRITE.md +1 -1
  11. package/skills/wix-headless/references/astro.md +1 -1
  12. package/skills/wix-headless-kit/SKILL.md +4 -0
  13. package/skills/wix-headless-kit/guides/no-machine.md +115 -0
  14. package/skills/wix-headless-kit/install/attach.mjs +5 -3
  15. package/skills/wix-headless-kit/install/bootstrap.mjs +3 -1
  16. package/skills/wix-headless-kit/install/context.mjs +4 -2
  17. package/skills/wix-headless-kit/install/deploy.mjs +4 -2
  18. package/skills/wix-headless-kit/install/pins.json +8 -0
  19. package/skills/wix-headless-kit/install/setup.mjs +10 -8
  20. package/skills/wix-headless-kit/install/templates.mjs +18 -8
  21. package/skills/wix-headless-templates/donations/INSTRUCTIONS.md +8 -9
  22. package/skills/wix-headless-templates/donations/app/wix/donations/donate.ts +18 -45
  23. package/skills/wix-headless-templates/donations/app/wix/donations/donations-core.ts +18 -19
  24. package/skills/wix-headless-templates/donations/project/src/wix/donations/donate.ts +18 -45
  25. package/skills/wix-headless-templates/donations/project/src/wix/donations/donations-core.ts +18 -19
  26. package/skills/wix-headless-templates/donations/rest/donate.ts +13 -39
  27. package/skills/wix-headless-templates/pricing-plans/INSTRUCTIONS.md +4 -2
  28. package/skills/wix-headless-templates/restaurants/app/wix/restaurants/types.ts +1 -1
  29. package/skills/wix-headless-templates/restaurants/project/src/wix/restaurants/types.ts +1 -1
  30. package/skills/wix-headless-templates/restaurants/seed/SEED.md +4 -4
  31. package/skills/wix-headless-templates/restaurants/seed/seed-restaurants.mjs +1 -1
  32. package/skills/wix-headless-templates/shared/capabilities/site-search/seed/install.mjs +2 -2
  33. package/skills/wix-headless-templates/shared/seed/wix-cli.mjs +6 -3
  34. package/skills/wix-headless-templates/storefront/app/wix/storefront/cart.ts +1 -2
  35. package/skills/wix-headless-templates/storefront/project/src/wix/storefront/cart.ts +1 -2
  36. package/skills/wix-manage/references/bookings/diagnose-availability-issues.md +1 -1
  37. package/skills/wix-manage/references/ecommerce/ecom-shipping.md +2 -2
  38. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-create-coupon.md +1 -1
  39. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-create-discount-rule.md +2 -2
  40. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-bundle-and-save.md +1 -1
  41. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-seasonal-promotion.md +1 -1
  42. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-stock-mover.md +2 -2
  43. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-upsell-boost.md +3 -3
  44. package/skills/wix-manage/references/ecommerce/shipping/ecom-shipping-free-shipping.md +3 -3
  45. package/skills/wix-manage/references/ecommerce/shipping/ecom-shipping-optimize-rates.md +1 -1
  46. package/skills/wix-manage/references/ecommerce/shipping/ecom-shipping-setup-rates.md +3 -3
  47. package/skills/wix-manage/references/sites/upload-static-site.md +61 -42
  48. package/skills/wix-replatform/resources/rp-target-wix/lib/wix-writers.js +1 -1
  49. package/skills/wix-vibe-headless/references/restaurants/seed/seed-restaurants.cjs +1 -1
@@ -1,29 +1,19 @@
1
- // The donation flow over the SDK: a visitor's choice → an eCom checkout with one donation line →
2
- // the Wix-hosted checkout URL; and the thank-you page's order read. Payment, donor details and
3
- // receipts are Wix's hosted checkout and the eCom order — nothing here creates an order or builds
4
- // a URL by hand. Bodies and result readers live in ./donations-core (shared with the REST twin);
5
- // this file is the transport only. Copy as-is.
6
- //
7
- // Two routes to a checkout id, both kept:
8
- // createDonationCheckout — Create Checkout with the line (a donation never merges into a
9
- // storefront visitor's current cart). The default.
10
- // createDonationCheckoutViaCart — the Wix widget's own sequence: Create Cart → Create Checkout
11
- // from the cart, channelType OTHER_PLATFORM. The fallback when
12
- // the direct route is refused; also reachable by name.
13
- // Whether the Donations catalog plugin prices a line created directly is not yet verified live,
14
- // hence the automatic fallback.
15
- // docs: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/checkout/create-checkout.md
1
+ // The donation flow over the SDK: a visitor's choice → an eCom cart with one donation line → the
2
+ // Wix-hosted checkout URL; and the thank-you page's order read. In Cart V2 there is no separate
3
+ // checkout entity: the cart IS the checkout, so its id is the id the redirect session takes.
4
+ // Payment, donor details and receipts are Wix's hosted checkout and the eCom order — nothing here
5
+ // creates an order or builds a URL by hand. Bodies and result readers live in ./donations-core
6
+ // (shared with the REST twin); this file is the transport only. Copy as-is.
7
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart-v2/create-cart.md
16
8
  // docs: https://dev.wix.com/docs/api-reference/business-management/headless/redirects/create-redirect-session.md
17
9
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/orders/get-order.md
18
- import { cart as cartModule, checkout as checkoutModule, orders as ordersModule } from "@wix/ecom";
10
+ import { cartV2 as cartV2Module, orders as ordersModule } from "@wix/ecom";
19
11
  import { redirects as redirectsModule } from "@wix/redirects";
20
12
  import { wixModule } from "../sdk";
21
13
  import {
22
14
  cartBody,
23
- checkoutBody,
15
+ cartIdOf,
24
16
  checkoutError,
25
- checkoutIdOf,
26
- rawId,
27
17
  redirectBody,
28
18
  redirectUrl,
29
19
  toReceipt,
@@ -34,8 +24,7 @@ import type { DonationInput, DonationReceipt } from "./types";
34
24
 
35
25
  export type { DonatePaths };
36
26
 
37
- const checkoutApi = wixModule(checkoutModule);
38
- const cartApi = wixModule(cartModule);
27
+ const cartV2Api = wixModule(cartV2Module);
39
28
  const ordersApi = wixModule(ordersModule);
40
29
  const redirects = wixModule(redirectsModule);
41
30
 
@@ -46,37 +35,21 @@ export interface DonateOptions {
46
35
  paths?: DonatePaths;
47
36
  }
48
37
 
49
- /** Create Checkout with the donation line → checkout id. */
50
- export async function createDonationCheckout(campaignId: string, input: DonationInput): Promise<string> {
51
- const checkout: Raw = await checkoutApi.createCheckout(checkoutBody(campaignId, input) as any);
52
- return checkoutIdOf(checkout);
53
- }
54
-
55
- /** The Wix widget's route: Create Cart (the note as buyerNote) → Create Checkout from the cart → checkout id. */
56
- export async function createDonationCheckoutViaCart(campaignId: string, input: DonationInput): Promise<string> {
57
- const cart: Raw = await cartApi.createCart(cartBody(campaignId, input) as any);
58
- const res: Raw = await cartApi.createCheckout(rawId(cart), { channelType: "OTHER_PLATFORM" });
59
- return checkoutIdOf(res);
60
- }
61
-
62
38
  /**
63
39
  * Start the hosted checkout for a donation; resolves to the URL to navigate the FULL document to.
64
- * Direct Create Checkout first, the cart route when that is refused, then one redirect session
65
- * whose thank-you callback lands on `/donate/thank-you?orderId=`.
40
+ * One Create Cart (the cart is the checkout) → one redirect session whose thank-you callback lands
41
+ * on `/donate/thank-you?orderId=`.
66
42
  */
67
43
  export async function donationCheckoutUrl(campaignId: string, input: DonationInput, { origin, paths }: DonateOptions = {}): Promise<string> {
68
44
  const site = origin ?? (typeof window !== "undefined" ? window.location.origin : "");
69
- let checkoutId: string;
45
+ let cartId: string;
70
46
  try {
71
- checkoutId = await createDonationCheckout(campaignId, input);
72
- } catch (direct) {
73
- try {
74
- checkoutId = await createDonationCheckoutViaCart(campaignId, input);
75
- } catch {
76
- throw checkoutError(direct);
77
- }
47
+ const cart: Raw = await cartV2Api.createCart(cartBody(campaignId, input) as any);
48
+ cartId = cartIdOf(cart);
49
+ } catch (e) {
50
+ throw checkoutError(e);
78
51
  }
79
- const session: Raw = await redirects.createRedirectSession(redirectBody(checkoutId, campaignId, site, paths) as any);
52
+ const session: Raw = await redirects.createRedirectSession(redirectBody(cartId, campaignId, site, paths) as any);
80
53
  return redirectUrl(session);
81
54
  }
82
55
 
@@ -1,7 +1,7 @@
1
1
  // Donation rules and DTO mapping — transport-agnostic, imported by BOTH transports: ./campaigns.ts
2
2
  // + ./donate.ts (the SDK, managed Astro and React) and the REST twins in templates/donations/rest/
3
3
  // (fetch, a static site or a port to another language). Every rule about amounts, fees, frequency,
4
- // goal math, validation, the checkout line and the redirect body lives HERE, once. A raw campaign
4
+ // goal math, validation, the cart line and the redirect body lives HERE, once. A raw campaign
5
5
  // may come from the SDK (`_id`, coverImage as a `wix:image://` string) or from REST (`id`,
6
6
  // coverImage as { id, url }); the mappers accept both. Has its own formatMoney so it stands alone
7
7
  // when stripped. Imports are type-only so a strip to JS emits no imports.
@@ -351,10 +351,10 @@ export function toInput(options: DonationOptions, sel: DonationSelection): Donat
351
351
  return { amount, frequency: sel.frequency, coverFee: options.askCoverFee && sel.coverFee, note: sel.note.trim() };
352
352
  }
353
353
 
354
- // ---- checkout -------------------------------------------------------------------------------------
354
+ // ---- cart -----------------------------------------------------------------------------------------
355
355
 
356
356
  /**
357
- * The one line item a donation checkout carries. `amount` is a NUMBER and `frequency` the enum
357
+ * The one catalog item a donation cart carries. `amount` is a NUMBER and `frequency` the enum
358
358
  * string; `donorCoveringFees` is sent only when the donor opted in (the Donations catalog plugin
359
359
  * prices the line from these options — never a customLineItem, never a computed price).
360
360
  */
@@ -370,27 +370,26 @@ export function donationLineItem(campaignId: string, input: DonationInput): Raw
370
370
  };
371
371
  }
372
372
 
373
- /** Create Checkout body: the donation line, channelType WEB, the note as the checkout's buyerNote. */
374
- export function checkoutBody(campaignId: string, input: DonationInput): Raw {
375
- return {
376
- lineItems: [donationLineItem(campaignId, input)],
377
- channelType: "WEB",
378
- ...(input.note ? { checkoutInfo: { buyerNote: input.note } } : {}),
379
- };
380
- }
381
-
382
- /** Create Cart body — the Wix widget's own route (fallback): the note as the cart's buyerNote. */
373
+ /**
374
+ * Create Cart body (Cart V2): the single donation catalog item, the WEB channel on the cart's
375
+ * `source`, the donor note as the cart's `note`. In V2 the created cart IS the checkout — its id is
376
+ * the id the redirect session takes; there is no separate Create Checkout step.
377
+ */
383
378
  export function cartBody(campaignId: string, input: DonationInput): Raw {
384
379
  return {
385
- lineItems: [donationLineItem(campaignId, input)],
386
- ...(input.note ? { cartInfo: { buyerNote: input.note } } : {}),
380
+ cart: { source: { channelType: "WEB" }, ...(input.note ? { note: input.note } : {}) },
381
+ catalogItems: [donationLineItem(campaignId, input)],
387
382
  };
388
383
  }
389
384
 
390
- /** The checkout id out of either transport's response for either route. */
391
- export function checkoutIdOf(res: Raw | null | undefined): string {
392
- const id = res?._id ?? res?.id ?? res?.checkoutId ?? res?.checkout?.id ?? res?.checkout?._id ?? "";
393
- if (!id) throw new Error("Checkout couldn't start: no checkout id returned.");
385
+ /**
386
+ * The cart id out of the Create Cart response — the id a V2 donation hands the redirect session
387
+ * (the cart is the checkout). The SDK returns a Cart directly (`_id`); REST wraps it as
388
+ * `{ cart: { id } }`.
389
+ */
390
+ export function cartIdOf(res: Raw | null | undefined): string {
391
+ const id = res?._id ?? res?.id ?? res?.cart?._id ?? res?.cart?.id ?? "";
392
+ if (!id) throw new Error("Checkout couldn't start: no cart id returned.");
394
393
  return String(id);
395
394
  }
396
395
 
@@ -1,29 +1,19 @@
1
- // The donation flow over the SDK: a visitor's choice → an eCom checkout with one donation line →
2
- // the Wix-hosted checkout URL; and the thank-you page's order read. Payment, donor details and
3
- // receipts are Wix's hosted checkout and the eCom order — nothing here creates an order or builds
4
- // a URL by hand. Bodies and result readers live in ./donations-core (shared with the REST twin);
5
- // this file is the transport only. Copy as-is.
6
- //
7
- // Two routes to a checkout id, both kept:
8
- // createDonationCheckout — Create Checkout with the line (a donation never merges into a
9
- // storefront visitor's current cart). The default.
10
- // createDonationCheckoutViaCart — the Wix widget's own sequence: Create Cart → Create Checkout
11
- // from the cart, channelType OTHER_PLATFORM. The fallback when
12
- // the direct route is refused; also reachable by name.
13
- // Whether the Donations catalog plugin prices a line created directly is not yet verified live,
14
- // hence the automatic fallback.
15
- // docs: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/checkout/create-checkout.md
1
+ // The donation flow over the SDK: a visitor's choice → an eCom cart with one donation line → the
2
+ // Wix-hosted checkout URL; and the thank-you page's order read. In Cart V2 there is no separate
3
+ // checkout entity: the cart IS the checkout, so its id is the id the redirect session takes.
4
+ // Payment, donor details and receipts are Wix's hosted checkout and the eCom order — nothing here
5
+ // creates an order or builds a URL by hand. Bodies and result readers live in ./donations-core
6
+ // (shared with the REST twin); this file is the transport only. Copy as-is.
7
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart-v2/create-cart.md
16
8
  // docs: https://dev.wix.com/docs/api-reference/business-management/headless/redirects/create-redirect-session.md
17
9
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/orders/get-order.md
18
- import { cart as cartModule, checkout as checkoutModule, orders as ordersModule } from "@wix/ecom";
10
+ import { cartV2 as cartV2Module, orders as ordersModule } from "@wix/ecom";
19
11
  import { redirects as redirectsModule } from "@wix/redirects";
20
12
  import { wixModule } from "../sdk";
21
13
  import {
22
14
  cartBody,
23
- checkoutBody,
15
+ cartIdOf,
24
16
  checkoutError,
25
- checkoutIdOf,
26
- rawId,
27
17
  redirectBody,
28
18
  redirectUrl,
29
19
  toReceipt,
@@ -34,8 +24,7 @@ import type { DonationInput, DonationReceipt } from "./types";
34
24
 
35
25
  export type { DonatePaths };
36
26
 
37
- const checkoutApi = wixModule(checkoutModule);
38
- const cartApi = wixModule(cartModule);
27
+ const cartV2Api = wixModule(cartV2Module);
39
28
  const ordersApi = wixModule(ordersModule);
40
29
  const redirects = wixModule(redirectsModule);
41
30
 
@@ -46,37 +35,21 @@ export interface DonateOptions {
46
35
  paths?: DonatePaths;
47
36
  }
48
37
 
49
- /** Create Checkout with the donation line → checkout id. */
50
- export async function createDonationCheckout(campaignId: string, input: DonationInput): Promise<string> {
51
- const checkout: Raw = await checkoutApi.createCheckout(checkoutBody(campaignId, input) as any);
52
- return checkoutIdOf(checkout);
53
- }
54
-
55
- /** The Wix widget's route: Create Cart (the note as buyerNote) → Create Checkout from the cart → checkout id. */
56
- export async function createDonationCheckoutViaCart(campaignId: string, input: DonationInput): Promise<string> {
57
- const cart: Raw = await cartApi.createCart(cartBody(campaignId, input) as any);
58
- const res: Raw = await cartApi.createCheckout(rawId(cart), { channelType: "OTHER_PLATFORM" });
59
- return checkoutIdOf(res);
60
- }
61
-
62
38
  /**
63
39
  * Start the hosted checkout for a donation; resolves to the URL to navigate the FULL document to.
64
- * Direct Create Checkout first, the cart route when that is refused, then one redirect session
65
- * whose thank-you callback lands on `/donate/thank-you?orderId=`.
40
+ * One Create Cart (the cart is the checkout) → one redirect session whose thank-you callback lands
41
+ * on `/donate/thank-you?orderId=`.
66
42
  */
67
43
  export async function donationCheckoutUrl(campaignId: string, input: DonationInput, { origin, paths }: DonateOptions = {}): Promise<string> {
68
44
  const site = origin ?? (typeof window !== "undefined" ? window.location.origin : "");
69
- let checkoutId: string;
45
+ let cartId: string;
70
46
  try {
71
- checkoutId = await createDonationCheckout(campaignId, input);
72
- } catch (direct) {
73
- try {
74
- checkoutId = await createDonationCheckoutViaCart(campaignId, input);
75
- } catch {
76
- throw checkoutError(direct);
77
- }
47
+ const cart: Raw = await cartV2Api.createCart(cartBody(campaignId, input) as any);
48
+ cartId = cartIdOf(cart);
49
+ } catch (e) {
50
+ throw checkoutError(e);
78
51
  }
79
- const session: Raw = await redirects.createRedirectSession(redirectBody(checkoutId, campaignId, site, paths) as any);
52
+ const session: Raw = await redirects.createRedirectSession(redirectBody(cartId, campaignId, site, paths) as any);
80
53
  return redirectUrl(session);
81
54
  }
82
55
 
@@ -1,7 +1,7 @@
1
1
  // Donation rules and DTO mapping — transport-agnostic, imported by BOTH transports: ./campaigns.ts
2
2
  // + ./donate.ts (the SDK, managed Astro and React) and the REST twins in templates/donations/rest/
3
3
  // (fetch, a static site or a port to another language). Every rule about amounts, fees, frequency,
4
- // goal math, validation, the checkout line and the redirect body lives HERE, once. A raw campaign
4
+ // goal math, validation, the cart line and the redirect body lives HERE, once. A raw campaign
5
5
  // may come from the SDK (`_id`, coverImage as a `wix:image://` string) or from REST (`id`,
6
6
  // coverImage as { id, url }); the mappers accept both. Has its own formatMoney so it stands alone
7
7
  // when stripped. Imports are type-only so a strip to JS emits no imports.
@@ -351,10 +351,10 @@ export function toInput(options: DonationOptions, sel: DonationSelection): Donat
351
351
  return { amount, frequency: sel.frequency, coverFee: options.askCoverFee && sel.coverFee, note: sel.note.trim() };
352
352
  }
353
353
 
354
- // ---- checkout -------------------------------------------------------------------------------------
354
+ // ---- cart -----------------------------------------------------------------------------------------
355
355
 
356
356
  /**
357
- * The one line item a donation checkout carries. `amount` is a NUMBER and `frequency` the enum
357
+ * The one catalog item a donation cart carries. `amount` is a NUMBER and `frequency` the enum
358
358
  * string; `donorCoveringFees` is sent only when the donor opted in (the Donations catalog plugin
359
359
  * prices the line from these options — never a customLineItem, never a computed price).
360
360
  */
@@ -370,27 +370,26 @@ export function donationLineItem(campaignId: string, input: DonationInput): Raw
370
370
  };
371
371
  }
372
372
 
373
- /** Create Checkout body: the donation line, channelType WEB, the note as the checkout's buyerNote. */
374
- export function checkoutBody(campaignId: string, input: DonationInput): Raw {
375
- return {
376
- lineItems: [donationLineItem(campaignId, input)],
377
- channelType: "WEB",
378
- ...(input.note ? { checkoutInfo: { buyerNote: input.note } } : {}),
379
- };
380
- }
381
-
382
- /** Create Cart body — the Wix widget's own route (fallback): the note as the cart's buyerNote. */
373
+ /**
374
+ * Create Cart body (Cart V2): the single donation catalog item, the WEB channel on the cart's
375
+ * `source`, the donor note as the cart's `note`. In V2 the created cart IS the checkout — its id is
376
+ * the id the redirect session takes; there is no separate Create Checkout step.
377
+ */
383
378
  export function cartBody(campaignId: string, input: DonationInput): Raw {
384
379
  return {
385
- lineItems: [donationLineItem(campaignId, input)],
386
- ...(input.note ? { cartInfo: { buyerNote: input.note } } : {}),
380
+ cart: { source: { channelType: "WEB" }, ...(input.note ? { note: input.note } : {}) },
381
+ catalogItems: [donationLineItem(campaignId, input)],
387
382
  };
388
383
  }
389
384
 
390
- /** The checkout id out of either transport's response for either route. */
391
- export function checkoutIdOf(res: Raw | null | undefined): string {
392
- const id = res?._id ?? res?.id ?? res?.checkoutId ?? res?.checkout?.id ?? res?.checkout?._id ?? "";
393
- if (!id) throw new Error("Checkout couldn't start: no checkout id returned.");
385
+ /**
386
+ * The cart id out of the Create Cart response — the id a V2 donation hands the redirect session
387
+ * (the cart is the checkout). The SDK returns a Cart directly (`_id`); REST wraps it as
388
+ * `{ cart: { id } }`.
389
+ */
390
+ export function cartIdOf(res: Raw | null | undefined): string {
391
+ const id = res?._id ?? res?.id ?? res?.cart?._id ?? res?.cart?.id ?? "";
392
+ if (!id) throw new Error("Checkout couldn't start: no cart id returned.");
394
393
  return String(id);
395
394
  }
396
395
 
@@ -1,19 +1,17 @@
1
1
  // The donation flow over REST — the twin of app/wix/donations/donate.ts. Same exports, same
2
2
  // signatures; the bodies and result readers come from donations-core (the SAME file the SDK
3
- // transport uses). A donation is an eCom checkout with one catalog line; the hosted checkout takes
4
- // payment and donor details. Never create the order yourself, never hand-build a checkout URL.
5
- // Two routes to a checkout id, both kept: Create Checkout directly (default), and the Wix widget's
6
- // Create Cart → Create Checkout from the cart (the fallback when the direct route is refused).
7
- // docs: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/checkout/create-checkout.md
3
+ // transport uses). A donation is an eCom cart with one catalog line; the hosted checkout takes
4
+ // payment and donor details. In Cart V2 the cart IS the checkout — its id is the id the redirect
5
+ // session takes, so there is one route and no separate Create Checkout call. Never create the
6
+ // order yourself, never hand-build a checkout URL.
7
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart-v2/create-cart.md
8
8
  // docs: https://dev.wix.com/docs/api-reference/business-management/headless/redirects/create-redirect-session.md
9
9
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/orders/get-order.md
10
10
  import { wixRequest } from "./client.js";
11
11
  import {
12
12
  cartBody,
13
- checkoutBody,
13
+ cartIdOf,
14
14
  checkoutError,
15
- checkoutIdOf,
16
- rawId,
17
15
  redirectBody,
18
16
  redirectUrl,
19
17
  toReceipt,
@@ -31,46 +29,22 @@ export interface DonateOptions {
31
29
  paths?: DonatePaths;
32
30
  }
33
31
 
34
- /**
35
- * Create Checkout with the donation line → checkout id.
36
- * POST /ecom/v1/checkouts { lineItems: [{ quantity: 1, catalogReference: { appId, catalogItemId, options: { amount, frequency, donorCoveringFees? } } }], channelType: "WEB", checkoutInfo?: { buyerNote } } → { checkout: { id } }
37
- */
38
- export async function createDonationCheckout(campaignId: string, input: DonationInput): Promise<string> {
39
- const res = await wixRequest<Raw>("/ecom/v1/checkouts", { body: checkoutBody(campaignId, input) });
40
- return checkoutIdOf(res);
41
- }
42
-
43
- /**
44
- * The Wix widget's route → checkout id.
45
- * POST /ecom/v1/carts { lineItems, cartInfo?: { buyerNote } } → { cart: { id } }
46
- * POST /ecom/v1/carts/{id}/create-checkout { channelType: "OTHER_PLATFORM" } → { checkoutId }
47
- */
48
- export async function createDonationCheckoutViaCart(campaignId: string, input: DonationInput): Promise<string> {
49
- const created = await wixRequest<Raw>("/ecom/v1/carts", { body: cartBody(campaignId, input) });
50
- const cartId = rawId(created?.cart);
51
- if (!cartId) throw new Error("Checkout couldn't start: no cart id returned.");
52
- const res = await wixRequest<Raw>(`/ecom/v1/carts/${cartId}/create-checkout`, { body: { channelType: "OTHER_PLATFORM" } });
53
- return checkoutIdOf(res);
54
- }
55
-
56
32
  /**
57
33
  * Start the hosted checkout for a donation; resolves to the URL to navigate the FULL document to.
58
34
  * `origin` must be the site's real https origin as registered on the OAuth app's allowed domains.
35
+ * POST /ecom/v2/carts { cart: { source: { channelType: "WEB" }, note? }, catalogItems: [{ quantity: 1, catalogReference: { appId, catalogItemId, options: { amount, frequency, donorCoveringFees? } } }] } → { cart: { id } } (the cart is the checkout)
59
36
  * POST /headless/v1/redirect-session { ecomCheckout: { checkoutId }, callbacks: { postFlowUrl, thankYouPageUrl } } → { redirectSession: { fullUrl } }
60
37
  */
61
38
  export async function donationCheckoutUrl(campaignId: string, input: DonationInput, { origin, paths }: DonateOptions = {}): Promise<string> {
62
39
  const site = origin ?? (typeof window !== "undefined" ? window.location.origin : "");
63
- let checkoutId: string;
40
+ let cartId: string;
64
41
  try {
65
- checkoutId = await createDonationCheckout(campaignId, input);
66
- } catch (direct) {
67
- try {
68
- checkoutId = await createDonationCheckoutViaCart(campaignId, input);
69
- } catch {
70
- throw checkoutError(direct);
71
- }
42
+ const res = await wixRequest<Raw>("/ecom/v2/carts", { body: cartBody(campaignId, input) });
43
+ cartId = cartIdOf(res);
44
+ } catch (e) {
45
+ throw checkoutError(e);
72
46
  }
73
- const session = await wixRequest<Raw>("/headless/v1/redirect-session", { body: redirectBody(checkoutId, campaignId, site, paths) });
47
+ const session = await wixRequest<Raw>("/headless/v1/redirect-session", { body: redirectBody(cartId, campaignId, site, paths) });
74
48
  return redirectUrl(session);
75
49
  }
76
50
 
@@ -336,8 +336,10 @@ other road — an eCom checkout with one PLAN line item (`catalogItemId: plan.id
336
336
  must share one checkout with products (a cart holding a membership and a T-shirt). Both end on a
337
337
  Wix-hosted checkout with coupons, notes, and login handled there. The DTO carries
338
338
  `pricingVariantId` so the eCom path is reachable without touching the DTO if a brief needs it;
339
- building it means `@wix/ecom` `checkout.createCheckout` plus a redirect session with
340
- `ecomCheckout: { checkoutId }` — a new function beside `purchase.ts`, not a change to it.
339
+ building it means adding the plan line (and any product lines) to the current cart with `@wix/ecom`
340
+ `currentCartV2` — in Cart V2 the cart IS the checkout, so the cart's id is the id passed to a
341
+ redirect session with `ecomCheckout: { checkoutId }` — a new function beside `purchase.ts`, not a
342
+ change to it.
341
343
 
342
344
  ## Gated content — requires the `members` vertical
343
345
 
@@ -21,7 +21,7 @@ export interface MenuItemLabel {
21
21
  iconUrl: string;
22
22
  }
23
23
 
24
- /** One price variant of an item ("Glass" / "Bottle"). An item has price OR variants. */
24
+ /** One price variant of an item ("Small" / "Large"). An item has price OR variants. */
25
25
  export interface MenuItemVariant {
26
26
  variantId: string;
27
27
  name: string;
@@ -21,7 +21,7 @@ export interface MenuItemLabel {
21
21
  iconUrl: string;
22
22
  }
23
23
 
24
- /** One price variant of an item ("Glass" / "Bottle"). An item has price OR variants. */
24
+ /** One price variant of an item ("Small" / "Large"). An item has price OR variants. */
25
25
  export interface MenuItemVariant {
26
26
  variantId: string;
27
27
  name: string;
@@ -45,9 +45,9 @@ size, or a `modifierGroups` entry) when the restaurant takes orders, so the dish
45
45
  { "name": "Branzino", "description": "Whole roasted sea bass, lemon, herbs.",
46
46
  "price": 28, "imageUrl": "https://…" }
47
47
  ] },
48
- { "name": "Vino", "items": [
49
- { "name": "Chianti Classico", "description": "Sangiovese, Tuscany.",
50
- "variants": [{ "name": "Glass", "price": 11 }, { "name": "Bottle", "price": 44 }], "imageUrl": "https://…" }
48
+ { "name": "Pizze", "items": [
49
+ { "name": "Margherita", "description": "San Marzano tomato, fior di latte, basil.",
50
+ "variants": [{ "name": "Small", "price": 14 }, { "name": "Large", "price": 22 }], "imageUrl": "https://…" }
51
51
  ] },
52
52
  { "name": "Dolci", "items": [
53
53
  { "name": "Tiramisù", "description": "Espresso-soaked ladyfingers, mascarpone.",
@@ -65,7 +65,7 @@ size, or a `modifierGroups` entry) when the restaurant takes orders, so the dish
65
65
  ```
66
66
 
67
67
  - `price` — a number; stored as a decimal string in the **site currency** (never send one per item).
68
- An item has `price` OR `variants` (each `{ name, price }` — "Glass" / "Bottle"), never both; an
68
+ An item has `price` OR `variants` (each `{ name, price }` — "Small" / "Large"), never both; an
69
69
  item with neither renders as "Market price" and can't be ordered online.
70
70
  - `modifierGroups` — per item: `{ name, required?, min?, max?, modifiers: [{ name, price?, preSelected?, inStock? }] }`.
71
71
  `required: true, min: 1, max: 1` is a single choice (radios); `max` alone is "choose up to";
@@ -166,7 +166,7 @@ export async function createModifierGroups(ctx, groups) {
166
166
  }
167
167
 
168
168
  /**
169
- * Bulk-create price variants (the reusable "Glass" / "Bottle" names; the price per item lives on
169
+ * Bulk-create price variants (the reusable "Small" / "Large" names; the price per item lives on
170
170
  * the item's priceVariants reference). Returns ids in input order.
171
171
  * docs: https://dev.wix.com/docs/api-reference/business-solutions/restaurants/menus/items/item-variants/bulk-create-variants.md
172
172
  */
@@ -29,9 +29,9 @@ if (!siteId) {
29
29
  console.log(JSON.stringify({ error: "no site: pass --site <siteId> or run in a folder with wix.config.json" }));
30
30
  process.exit(1);
31
31
  }
32
- const token = execFileSync("npx", ["-y", "@wix/cli@latest", "token", "--site", siteId], { encoding: "utf8" }).trim();
32
+ const token = execFileSync("npx", ["-y", "@wix/cli@1.1.258", "token", "--site", siteId], { encoding: "utf8" }).trim();
33
33
  if (!token) {
34
- console.log(JSON.stringify({ error: "the Wix CLI returned no token — run `npx @wix/cli@latest login` first" }));
34
+ console.log(JSON.stringify({ error: "the Wix CLI returned no token — run `npx @wix/cli@1.1.258 login` first" }));
35
35
  process.exit(1);
36
36
  }
37
37
  try {
@@ -1,12 +1,15 @@
1
1
  // The Wix CLI the seeds call for a site token and for `wix env pull`.
2
2
  //
3
3
  // Order: the project's own copy (node_modules/.bin/wix, installed with the template's lock), then
4
- // a `wix` on PATH, then `npx -y @wix/cli@latest` — which installs the CLI before running it, 20 to
4
+ // a `wix` on PATH, then `npx -y @wix/cli@<pinned>` — which installs the CLI before running it, 20 to
5
5
  // 60 s and a wall of npm output on a fresh machine. The first two take under two seconds.
6
6
  import { existsSync } from "node:fs";
7
7
  import { delimiter, join } from "node:path";
8
8
  import { execFileSync, spawnSync } from "node:child_process";
9
9
 
10
+ // The CLI version the fallback installs; equal to `@wix/cli` in wix-headless-kit/install/pins.json.
11
+ const WIX_CLI_VERSION = "1.1.258";
12
+
10
13
  export function resolveWixCli(cwd = process.cwd()) {
11
14
  const bin = process.platform === "win32" ? "wix.cmd" : "wix";
12
15
  const local = join(cwd, "node_modules", ".bin", bin);
@@ -19,7 +22,7 @@ export function resolveWixCli(cwd = process.cwd()) {
19
22
  for (const dir of (process.env.PATH ?? "").split(delimiter)) {
20
23
  if (dir && existsSync(join(dir, bin))) return { file: join(dir, bin), prefix: [] };
21
24
  }
22
- return { file: "npx", prefix: ["-y", "@wix/cli@latest"] };
25
+ return { file: "npx", prefix: ["-y", `@wix/cli@${WIX_CLI_VERSION}`] };
23
26
  }
24
27
 
25
28
  /**
@@ -33,7 +36,7 @@ export function wixToken(siteId, cwd = process.cwd()) {
33
36
  // An older CLI starts its "update available" box on the token's own line, so a line split is
34
37
  // not enough: the token is the first long run of token characters.
35
38
  const token = out.match(/[A-Za-z0-9._-]{40,}/)?.[0];
36
- if (!token) throw new Error("The Wix CLI returned no token — run `wix login` (or `npx @wix/cli@latest login`) first.");
39
+ if (!token) throw new Error(`The Wix CLI returned no token — run \`wix login\` (or \`npx @wix/cli@${WIX_CLI_VERSION} login\`) first.`);
37
40
  return token;
38
41
  }
39
42
 
@@ -167,8 +167,7 @@ export async function setNote(note: string): Promise<Cart> {
167
167
  /**
168
168
  * Start the Wix-hosted checkout for the current cart and return the URL to navigate to.
169
169
  * The cart's id IS the checkout id — no separate checkout-creation call (Wix's own storefront
170
- * does the same; `createCheckoutFromCurrentCart` is the alternative when a checkout must exist
171
- * before redirecting).
170
+ * does the same).
172
171
  * Call from the browser: the return origin must be the site's real https origin
173
172
  * (window.location.origin), never a server-derived request origin.
174
173
  */
@@ -167,8 +167,7 @@ export async function setNote(note: string): Promise<Cart> {
167
167
  /**
168
168
  * Start the Wix-hosted checkout for the current cart and return the URL to navigate to.
169
169
  * The cart's id IS the checkout id — no separate checkout-creation call (Wix's own storefront
170
- * does the same; `createCheckoutFromCurrentCart` is the alternative when a checkout must exist
171
- * before redirecting).
170
+ * does the same).
172
171
  * Call from the browser: the return origin must be the site's real https origin
173
172
  * (window.location.origin), never a server-derived request origin.
174
173
  */
@@ -64,7 +64,7 @@ Interpret the result:
64
64
 
65
65
  > **The hidden-service trap.** A service that's **hidden** from the site, or has **online booking turned off**, can still list slots here — so bookable slots do **not** prove customers can book it. When the complaint is "customers can't book / can't find this service" (as opposed to "the calendar is empty"), **run [Step 2](#step-2--rule-out-service-level-blockers-visibility--online-booking) before trusting the slot count** — it's the single most common cause and neither `ListAvailabilityTimeSlots` nor `DiagnoseAvailability` detects it.
66
66
 
67
- If **no slots come back at all**, also sanity-check the inputs before concluding "no availability": the queried window isn't entirely in the past, and any `locations` filter is actually offered by the service.
67
+ If **no slots come back at all**, also double-check the inputs before concluding "no availability": the queried window isn't entirely in the past, and any `locations` filter is actually offered by the service.
68
68
 
69
69
  ---
70
70
 
@@ -39,7 +39,7 @@ Set up and tune how a store ships — what rates to charge, which regions are co
39
39
 
40
40
  ### Troubleshoot
41
41
 
42
- > - [Shipping rate incorrect (customer charged wrong shipping)](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/shipping-optimize-rates) — tags: `[intent:rate-incorrect]` · priority 0 · *audit rates via the Rate Pricing Sanity guardrail, then correct the rate structure*
42
+ > - [Shipping rate incorrect (customer charged wrong shipping)](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/shipping-optimize-rates) — tags: `[intent:rate-incorrect]` · priority 0 · *audit rates via the Rate Pricing Plausibility guardrail, then correct the rate structure*
43
43
 
44
44
  ## Tag matching
45
45
 
@@ -53,7 +53,7 @@ The agent matches the merchant's natural-language query to an `intent:*` tag (cu
53
53
  | "How much should I charge for shipping?" | any | `ecom-shipping-setup-rates` via `[intent:setup-rates]` |
54
54
  | "I want customers to pick up from my shop" | any | `ecom-shipping-setup-pickup` via `[intent:setup-pickup]` |
55
55
  | "Some regions have no shipping option" | any | `ecom-shipping-fix-coverage` via `[intent:fix-coverage]` |
56
- | "A customer was charged the wrong shipping" | any | `ecom-shipping-optimize-rates` via `[intent:rate-incorrect]` (runs rate-sanity guardrail first) |
56
+ | "A customer was charged the wrong shipping" | any | `ecom-shipping-optimize-rates` via `[intent:rate-incorrect]` (runs rate-plausibility guardrail first) |
57
57
 
58
58
  ## Base recipe (fallback)
59
59
 
@@ -68,7 +68,7 @@ Check for: duplicate codes, overlapping scopes with active coupons, and cross-me
68
68
 
69
69
  - **Duplicate / conflicting code** — reject a code already in use.
70
70
  - **Cross-mechanism stacking** — coupons stack with automatic discount rules at checkout. Query active discount rules on overlapping scope; if found, warn with the combined effective discount ("a 20% coupon during a 20% automatic sale = ~36% off"). Only one coupon applies per checkout, but automatic rules are unlimited.
71
- - **% sanity** — > 50% warn (show a $100 → $(100−pct) example); = 100% block unless confirmed; > 100% always block.
71
+ - **% plausibility** — > 50% warn (show a $100 → $(100−pct) example); = 100% block unless confirmed; > 100% always block.
72
72
  - **Margin** — if cost data is available, ensure the discount doesn't push price below cost; otherwise warn for > 40%.
73
73
  - **User override** — explicit merchant values override these caps; document the override in your reasoning.
74
74
 
@@ -129,10 +129,10 @@ These checks guard every discount creation (rule **or** coupon). Run them before
129
129
  - **Time overlap** — overlapping `activeTimeInfo` on the same scope (`existingStart < newEnd AND existingEnd > newStart`) → warn about the overlap window.
130
130
  - **Cross-mechanism (automatic + coupon)** — automatic discounts and coupons both apply at checkout. If creating a rule, query active coupons on overlapping scope (and vice-versa); warn with the combined effective discount. (Only one coupon per checkout, but automatic rules are unlimited.)
131
131
 
132
- **Margin / sanity:**
132
+ **Margin / plausibility:**
133
133
  - **Global cap** — default max discount **25%**; flag anything higher (proceed only on explicit request).
134
134
  - **Minimum margin** — default floor **15%**; if cost data is available, `effective_margin = (price − cost − discount_amount) / price × 100` must stay ≥ 15% (block + explain otherwise).
135
- - **% sanity** — > 50% warn (show a $100 → $(100−pct) example); = 100% block unless confirmed ("makes the product free"); > 100% always block.
135
+ - **% plausibility** — > 50% warn (show a $100 → $(100−pct) example); = 100% block unless confirmed ("makes the product free"); > 100% always block.
136
136
  - **Stacking margin** — when a new discount overlaps existing active ones, evaluate the *combined* discount against the cap and margin floor, not just the new one in isolation.
137
137
 
138
138
  | Scenario | Action |
@@ -4,7 +4,7 @@ description: "BUNDLE_AND_SAVE sub-flow — load [Goal: Drive Cross-Sells] FIRST
4
4
  ---
5
5
  # Flow: Bundle & Save Campaign
6
6
 
7
- > **Before executing this skill**, read [Create Discount Rule](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/pricing-create-discount-rule) with `ReadFullDocsArticle` — it contains the discount-rule mechanics **and** the pre-create guardrails (conflict/stacking, margin floor, %-sanity).
7
+ > **Before executing this skill**, read [Create Discount Rule](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/pricing-create-discount-rule) with `ReadFullDocsArticle` — it contains the discount-rule mechanics **and** the pre-create guardrails (conflict/stacking, margin floor, %-plausibility).
8
8
 
9
9
  Creates a discount that rewards customers for purchasing multiple items, encouraging product discovery and cross-selling. The discount activates when the cart contains a minimum number of items, and targets categories or products where bundling makes strategic sense.
10
10