@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.
- package/package.json +2 -2
- package/skills/wix-app/SKILL.md +1 -1
- package/skills/wix-app/references/APP_VALIDATION.md +5 -1
- package/skills/wix-app/references/SDK_MODULE_MAP.md +1 -1
- package/skills/wix-app/references/editor-react-component/PARTS.md +1 -1
- package/skills/wix-app/references/service-plugin/DISCOUNT-TRIGGERS.md +1 -1
- package/skills/wix-app/references/stores/GET_PRODUCT.md +9 -1
- package/skills/wix-app/references/stores/INVENTORY.md +2 -0
- package/skills/wix-app/references/stores/QUERY.md +2 -2
- package/skills/wix-app/references/stores/WRITE.md +1 -1
- package/skills/wix-headless/references/astro.md +1 -1
- package/skills/wix-headless-kit/SKILL.md +4 -0
- package/skills/wix-headless-kit/guides/no-machine.md +115 -0
- package/skills/wix-headless-kit/install/attach.mjs +5 -3
- package/skills/wix-headless-kit/install/bootstrap.mjs +3 -1
- package/skills/wix-headless-kit/install/context.mjs +4 -2
- package/skills/wix-headless-kit/install/deploy.mjs +4 -2
- package/skills/wix-headless-kit/install/pins.json +8 -0
- package/skills/wix-headless-kit/install/setup.mjs +10 -8
- package/skills/wix-headless-kit/install/templates.mjs +18 -8
- package/skills/wix-headless-templates/donations/INSTRUCTIONS.md +8 -9
- package/skills/wix-headless-templates/donations/app/wix/donations/donate.ts +18 -45
- package/skills/wix-headless-templates/donations/app/wix/donations/donations-core.ts +18 -19
- package/skills/wix-headless-templates/donations/project/src/wix/donations/donate.ts +18 -45
- package/skills/wix-headless-templates/donations/project/src/wix/donations/donations-core.ts +18 -19
- package/skills/wix-headless-templates/donations/rest/donate.ts +13 -39
- package/skills/wix-headless-templates/pricing-plans/INSTRUCTIONS.md +4 -2
- package/skills/wix-headless-templates/restaurants/app/wix/restaurants/types.ts +1 -1
- package/skills/wix-headless-templates/restaurants/project/src/wix/restaurants/types.ts +1 -1
- package/skills/wix-headless-templates/restaurants/seed/SEED.md +4 -4
- package/skills/wix-headless-templates/restaurants/seed/seed-restaurants.mjs +1 -1
- package/skills/wix-headless-templates/shared/capabilities/site-search/seed/install.mjs +2 -2
- package/skills/wix-headless-templates/shared/seed/wix-cli.mjs +6 -3
- package/skills/wix-headless-templates/storefront/app/wix/storefront/cart.ts +1 -2
- package/skills/wix-headless-templates/storefront/project/src/wix/storefront/cart.ts +1 -2
- package/skills/wix-manage/references/bookings/diagnose-availability-issues.md +1 -1
- package/skills/wix-manage/references/ecommerce/ecom-shipping.md +2 -2
- package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-create-coupon.md +1 -1
- package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-create-discount-rule.md +2 -2
- package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-bundle-and-save.md +1 -1
- package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-seasonal-promotion.md +1 -1
- package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-stock-mover.md +2 -2
- package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-flow-upsell-boost.md +3 -3
- package/skills/wix-manage/references/ecommerce/shipping/ecom-shipping-free-shipping.md +3 -3
- package/skills/wix-manage/references/ecommerce/shipping/ecom-shipping-optimize-rates.md +1 -1
- package/skills/wix-manage/references/ecommerce/shipping/ecom-shipping-setup-rates.md +3 -3
- package/skills/wix-manage/references/sites/upload-static-site.md +61 -42
- package/skills/wix-replatform/resources/rp-target-wix/lib/wix-writers.js +1 -1
- 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
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
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 {
|
|
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
|
-
|
|
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
|
|
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
|
-
*
|
|
65
|
-
*
|
|
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
|
|
45
|
+
let cartId: string;
|
|
70
46
|
try {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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(
|
|
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
|
|
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
|
-
// ----
|
|
354
|
+
// ---- cart -----------------------------------------------------------------------------------------
|
|
355
355
|
|
|
356
356
|
/**
|
|
357
|
-
* The one
|
|
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
|
-
/**
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
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
|
-
|
|
386
|
-
|
|
380
|
+
cart: { source: { channelType: "WEB" }, ...(input.note ? { note: input.note } : {}) },
|
|
381
|
+
catalogItems: [donationLineItem(campaignId, input)],
|
|
387
382
|
};
|
|
388
383
|
}
|
|
389
384
|
|
|
390
|
-
/**
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
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
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
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 {
|
|
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
|
-
|
|
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
|
|
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
|
-
*
|
|
65
|
-
*
|
|
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
|
|
45
|
+
let cartId: string;
|
|
70
46
|
try {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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(
|
|
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
|
|
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
|
-
// ----
|
|
354
|
+
// ---- cart -----------------------------------------------------------------------------------------
|
|
355
355
|
|
|
356
356
|
/**
|
|
357
|
-
* The one
|
|
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
|
-
/**
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
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
|
-
|
|
386
|
-
|
|
380
|
+
cart: { source: { channelType: "WEB" }, ...(input.note ? { note: input.note } : {}) },
|
|
381
|
+
catalogItems: [donationLineItem(campaignId, input)],
|
|
387
382
|
};
|
|
388
383
|
}
|
|
389
384
|
|
|
390
|
-
/**
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
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
|
|
4
|
-
// payment and donor details.
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// docs: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/
|
|
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
|
-
|
|
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
|
|
40
|
+
let cartId: string;
|
|
64
41
|
try {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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(
|
|
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
|
|
340
|
-
`
|
|
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 ("
|
|
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 ("
|
|
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": "
|
|
49
|
-
{ "name": "
|
|
50
|
-
"variants": [{ "name": "
|
|
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 }` — "
|
|
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 "
|
|
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@
|
|
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@
|
|
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
|
|
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",
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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-
|
|
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
|
|
package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-create-coupon.md
CHANGED
|
@@ -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
|
-
- **%
|
|
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 /
|
|
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
|
-
- **%
|
|
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, %-
|
|
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
|
|