@wix/agent-skills 1.31.1 → 1.31.2

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 (90) hide show
  1. package/package.json +1 -1
  2. package/skills/wix-app/references/STORES_VERSIONING.md +1 -1
  3. package/skills/wix-headless-kit/SKILL.md +16 -7
  4. package/skills/wix-headless-kit/guides/api-run.md +81 -51
  5. package/skills/wix-headless-kit/guides/existing-site.md +6 -0
  6. package/skills/wix-headless-kit/install/AGENTS.md +3 -2
  7. package/skills/wix-headless-kit/install/attach.mjs +32 -27
  8. package/skills/wix-headless-kit/install/background.mjs +32 -0
  9. package/skills/wix-headless-kit/install/bootstrap.mjs +28 -11
  10. package/skills/wix-headless-kit/install/check.mjs +2 -2
  11. package/skills/wix-headless-kit/install/context.mjs +49 -5
  12. package/skills/wix-headless-kit/install/deploy.mjs +33 -8
  13. package/skills/wix-headless-kit/install/env-ignore.mjs +16 -0
  14. package/skills/wix-headless-kit/install/install.mjs +95 -0
  15. package/skills/wix-headless-kit/install/pins.json +1 -1
  16. package/skills/wix-headless-kit/install/proc.mjs +46 -0
  17. package/skills/wix-headless-kit/install/setup.mjs +16 -25
  18. package/skills/wix-headless-kit/install/templates.mjs +2 -2
  19. package/skills/wix-headless-templates/blog/app/components/blog/RichContent.tsx +3 -2
  20. package/skills/wix-headless-templates/blog/project/package-lock.json +1287 -1299
  21. package/skills/wix-headless-templates/blog/project/package.json +1 -1
  22. package/skills/wix-headless-templates/blog/project/src/components/blog/RichContent.tsx +3 -2
  23. package/skills/wix-headless-templates/blog/rest/authors.ts +5 -5
  24. package/skills/wix-headless-templates/blog/rest/comments.ts +4 -4
  25. package/skills/wix-headless-templates/blog/rest/post-likes.ts +3 -3
  26. package/skills/wix-headless-templates/blog/rest/posts.ts +4 -4
  27. package/skills/wix-headless-templates/blog/rest/taxonomy.ts +5 -5
  28. package/skills/wix-headless-templates/blog/seed/seed-blog.mjs +2 -1
  29. package/skills/wix-headless-templates/bookings/rest/booking.ts +4 -4
  30. package/skills/wix-headless-templates/bookings/rest/services.ts +4 -4
  31. package/skills/wix-headless-templates/bookings/seed/seed-bookings.mjs +2 -1
  32. package/skills/wix-headless-templates/cms/rest/collections.ts +3 -3
  33. package/skills/wix-headless-templates/cms/rest/items.ts +4 -4
  34. package/skills/wix-headless-templates/cms/seed/seed-cms.mjs +2 -1
  35. package/skills/wix-headless-templates/donations/rest/campaigns.ts +4 -4
  36. package/skills/wix-headless-templates/donations/rest/donate.ts +3 -3
  37. package/skills/wix-headless-templates/donations/seed/seed-donations.mjs +2 -1
  38. package/skills/wix-headless-templates/events/rest/events.ts +4 -4
  39. package/skills/wix-headless-templates/events/rest/orders.ts +4 -4
  40. package/skills/wix-headless-templates/events/rest/registration.ts +4 -4
  41. package/skills/wix-headless-templates/events/seed/seed-events.mjs +2 -1
  42. package/skills/wix-headless-templates/faq/rest/faq.ts +4 -4
  43. package/skills/wix-headless-templates/faq/seed/seed-faq.mjs +2 -1
  44. package/skills/wix-headless-templates/forms/rest/forms.ts +4 -4
  45. package/skills/wix-headless-templates/forms/rest/submissions.ts +4 -4
  46. package/skills/wix-headless-templates/forms/seed/seed-forms.mjs +2 -1
  47. package/skills/wix-headless-templates/members/rest/auth.ts +3 -3
  48. package/skills/wix-headless-templates/members/rest/members.ts +4 -4
  49. package/skills/wix-headless-templates/members/seed/seed-members.mjs +2 -1
  50. package/skills/wix-headless-templates/portfolio/rest/portfolio.ts +4 -4
  51. package/skills/wix-headless-templates/portfolio/seed/seed-portfolio.mjs +2 -1
  52. package/skills/wix-headless-templates/pricing-plans/rest/plan-access.ts +3 -3
  53. package/skills/wix-headless-templates/pricing-plans/rest/plans.ts +4 -4
  54. package/skills/wix-headless-templates/pricing-plans/rest/purchase.ts +3 -3
  55. package/skills/wix-headless-templates/pricing-plans/seed/seed-pricing-plans.mjs +2 -1
  56. package/skills/wix-headless-templates/rentals/rest/rentals.ts +4 -4
  57. package/skills/wix-headless-templates/rentals/seed/seed-rentals.mjs +2 -1
  58. package/skills/wix-headless-templates/restaurants/rest/menu.ts +4 -4
  59. package/skills/wix-headless-templates/restaurants/rest/ordering.ts +5 -5
  60. package/skills/wix-headless-templates/restaurants/rest/reservations.ts +4 -4
  61. package/skills/wix-headless-templates/restaurants/seed/seed-restaurants.mjs +2 -1
  62. package/skills/wix-headless-templates/shared/capabilities/site-search/rest/search.ts +4 -4
  63. package/skills/wix-headless-templates/shared/capabilities/site-search/seed/install.mjs +6 -4
  64. package/skills/wix-headless-templates/shared/seed/main.mjs +15 -0
  65. package/skills/wix-headless-templates/shared/seed/wix-cli.mjs +43 -11
  66. package/skills/wix-headless-templates/storefront/INSTRUCTIONS.md +1 -1
  67. package/skills/wix-headless-templates/storefront/rest/cart.ts +5 -5
  68. package/skills/wix-headless-templates/storefront/rest/catalog.ts +5 -5
  69. package/skills/wix-headless-templates/storefront/seed/SEED.md +27 -9
  70. package/skills/wix-headless-templates/storefront/seed/seed-store.mjs +2 -1
  71. package/skills/wix-manage/SKILL.md +3 -3
  72. package/skills/wix-manage/references/app-installation/install-wix-apps.md +5 -1
  73. package/skills/wix-manage/references/app-installation/list-installed-apps.md +19 -9
  74. package/skills/wix-manage/references/bookings/booking-service-policy-setup.md +3 -0
  75. package/skills/wix-manage/references/bookings/external-calendar-integration.md +3 -0
  76. package/skills/wix-manage/references/bookings/multi-resource-service-creation.md +3 -0
  77. package/skills/wix-manage/references/cms/cms-data-items-crud.md +11 -2
  78. package/skills/wix-manage/references/cms/cms-publishing-flow.md +63 -16
  79. package/skills/wix-manage/references/forms/update-form.md +3 -0
  80. package/skills/wix-manage/references/pricing-plans/create-and-update-pricing-plans.md +3 -0
  81. package/skills/wix-manage/references/restaurants/wix-restaurants-setup.md +3 -0
  82. package/skills/wix-manage/references/sites/create-headless-site.md +7 -50
  83. package/skills/wix-manage/references/sites/manage-oauth-apps.md +4 -4
  84. package/skills/wix-manage/references/sites/read-site-context.md +4 -0
  85. package/skills/wix-manage/references/sites/upload-static-site.md +67 -31
  86. package/skills/wix-manage/references/stores/add-store-pages-to-site.md +3 -0
  87. package/skills/wix-manage/references/stores/change-store-currency.md +3 -0
  88. package/skills/wix-manage/references/stores/create-product-catalog-v3.md +3 -0
  89. package/skills/wix-manage/references/stores/find-products-query-and-search-catalog-v3.md +3 -0
  90. package/skills/wix-manage/references/stores/update-product-with-options.md +192 -22
@@ -5,10 +5,10 @@
5
5
  // A plan without a numeric price is malformed and never returned (plans-core `planAmount`).
6
6
  // Porting: keep the path, keep the body, port the core once.
7
7
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/pricing-plans/plans-v3/query-plans.md
8
- import { wixRequest } from "./client.js";
9
- import { imgSrc } from "./media.js";
10
- import { plansQuery, toDetail, toSummaries, type FormatOptions, type Raw } from "./plans-core.js";
11
- import type { PlanDetail, PlanSummary } from "./types.js";
8
+ import { wixRequest } from "../../shared/rest/client.js";
9
+ import { imgSrc } from "../../shared/rest/media.js";
10
+ import { plansQuery, toDetail, toSummaries, type FormatOptions, type Raw } from "../app/wix/pricing-plans/plans-core.js";
11
+ import type { PlanDetail, PlanSummary } from "../app/wix/pricing-plans/types.js";
12
12
 
13
13
  export type { FormatOptions };
14
14
 
@@ -4,9 +4,9 @@
4
4
  // order form, and payment itself, so a visitor token starts it. Never create the order yourself,
5
5
  // never hand-build a checkout URL.
6
6
  // docs: https://dev.wix.com/docs/api-reference/business-management/headless/redirects/create-redirect-session.md
7
- import { wixRequest } from "./client.js";
8
- import { purchaseBody, redirectUrl, type PurchaseOptions } from "./purchase-core.js";
9
- import type { Raw } from "./plans-core.js";
7
+ import { wixRequest } from "../../shared/rest/client.js";
8
+ import { purchaseBody, redirectUrl, type PurchaseOptions } from "../app/wix/pricing-plans/purchase-core.js";
9
+ import type { Raw } from "../app/wix/pricing-plans/plans-core.js";
10
10
 
11
11
  export type { PurchaseOptions };
12
12
 
@@ -23,6 +23,7 @@
23
23
  import { setSiteCurrency } from "../../shared/seed/site.mjs";
24
24
  import { seedSiteId } from "../../shared/seed/site-context.mjs";
25
25
  import { wixToken } from "../../shared/seed/wix-cli.mjs";
26
+ import { isMain } from "../../shared/seed/main.mjs";
26
27
  import { readFileSync } from "node:fs";
27
28
  import { randomUUID } from "node:crypto";
28
29
 
@@ -283,7 +284,7 @@ export async function setupPricingPlans(ctx, { plans = [], currency } = {}) {
283
284
 
284
285
  // ---- CLI entry ----------------------------------------------------------------------------------
285
286
 
286
- const invokedDirectly = process.argv[1] && import.meta.url.endsWith(process.argv[1].split("/").pop());
287
+ const invokedDirectly = isMain(import.meta.url);
287
288
  if (invokedDirectly) {
288
289
  const planPath = process.argv[2];
289
290
  if (!planPath) {
@@ -10,8 +10,8 @@
10
10
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/bookings/bookings/bookings-writer-v2/create-booking.md
11
11
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart-v2/create-cart.md
12
12
  // docs: https://dev.wix.com/docs/api-reference/business-management/headless/redirects/create-redirect-session.md
13
- import { wixRequest } from "./client.js";
14
- import { imgSrc } from "./media.js";
13
+ import { wixRequest } from "../../shared/rest/client.js";
14
+ import { imgSrc } from "../../shared/rest/media.js";
15
15
  import {
16
16
  FALLBACK_FIELDS,
17
17
  RENTALS_APP_ID,
@@ -42,8 +42,8 @@ import {
42
42
  toSummary,
43
43
  type Raw,
44
44
  type StartWindow,
45
- } from "./rentals-core.js";
46
- import type { EndOption, RentalDetail, RentalFormField, RentalQuote, RentalResult, RentalSummary, StartOption } from "./types.js";
45
+ } from "../app/wix/rentals/rentals-core.js";
46
+ import type { EndOption, RentalDetail, RentalFormField, RentalQuote, RentalResult, RentalSummary, StartOption } from "../app/wix/rentals/types.js";
47
47
 
48
48
  export { RENTALS_APP_ID, RENTALS_FORM_ID, RENTALS_PAGE_SIZE, dailyEndOptions, defaultTimeZone };
49
49
 
@@ -26,6 +26,7 @@ import { readFileSync } from "node:fs";
26
26
  import { resolveItemImages } from "../../shared/seed/images.mjs";
27
27
  import { seedSiteId } from "../../shared/seed/site-context.mjs";
28
28
  import { wixToken } from "../../shared/seed/wix-cli.mjs";
29
+ import { isMain } from "../../shared/seed/main.mjs";
29
30
 
30
31
  const API = "https://www.wixapis.com";
31
32
  /** The Wix Rentals app: the service's immutable appId, the catalog filter, the cart's appId. */
@@ -301,7 +302,7 @@ export async function setupRentals(ctx, { resourceTypes = [], rentals = [], curr
301
302
 
302
303
  // ---- CLI entry ----------------------------------------------------------------------------------
303
304
 
304
- const invokedDirectly = process.argv[1] && import.meta.url.endsWith(process.argv[1].split("/").pop());
305
+ const invokedDirectly = isMain(import.meta.url);
305
306
  if (invokedDirectly) {
306
307
  const planPath = process.argv[2];
307
308
  if (!planPath) {
@@ -7,8 +7,8 @@
7
7
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/restaurants/menus/menus/list-menus.md
8
8
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/restaurants/menus/items/items/list-items.md
9
9
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/ecommerce-settings/get-ecommerce-settings.md
10
- import { wixRequest } from "./client.js";
11
- import { imgSrc } from "./media.js";
10
+ import { wixRequest } from "../../shared/rest/client.js";
11
+ import { imgSrc } from "../../shared/rest/media.js";
12
12
  import {
13
13
  anyLabels,
14
14
  assembleMenus,
@@ -19,8 +19,8 @@ import {
19
19
  nextCursor,
20
20
  toSiteMoney,
21
21
  type Raw,
22
- } from "./menu-core.js";
23
- import type { MenuData, SiteMoney } from "./types.js";
22
+ } from "../app/wix/restaurants/menu-core.js";
23
+ import type { MenuData, SiteMoney } from "../app/wix/restaurants/types.js";
24
24
 
25
25
  const get = (path: string, query?: Record<string, string | readonly string[]>) => wixRequest<Raw>(path, { method: "GET", query });
26
26
 
@@ -12,10 +12,10 @@
12
12
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/restaurants/online-orders/fulfillment-methods/list-fulfillment-methods.md
13
13
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart-v2/add-line-items-to-current-cart.md
14
14
  // docs: https://dev.wix.com/docs/api-reference/business-management/headless/redirects/create-redirect-session.md
15
- import { WixApiError, wixRequest } from "./client.js";
16
- import { imgSrc } from "./media.js";
15
+ import { WixApiError, wixRequest } from "../../shared/rest/client.js";
16
+ import { imgSrc } from "../../shared/rest/media.js";
17
17
  import { fetchSiteMoney } from "./menu.js";
18
- import { initialSelection, nextCursor, validateSelection, type Raw } from "./menu-core.js";
18
+ import { initialSelection, nextCursor, validateSelection, type Raw } from "../app/wix/restaurants/menu-core.js";
19
19
  import {
20
20
  RESTAURANTS_ORDERS_APP_ID,
21
21
  assertOrderAdded,
@@ -29,8 +29,8 @@ import {
29
29
  toFulfillmentMethods,
30
30
  toMenuOrderingMap,
31
31
  toOrderCart,
32
- } from "./ordering-core.js";
33
- import type { FulfillmentMethodInfo, MenuItem, MenuOrderingInfo, OrderCart, OrderSelection, OrderingStatus } from "./types.js";
32
+ } from "../app/wix/restaurants/ordering-core.js";
33
+ import type { FulfillmentMethodInfo, MenuItem, MenuOrderingInfo, OrderCart, OrderSelection, OrderingStatus } from "../app/wix/restaurants/types.js";
34
34
 
35
35
  export { RESTAURANTS_ORDERS_APP_ID };
36
36
 
@@ -9,9 +9,9 @@
9
9
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/restaurants/reservations/reservations/create-held-reservation.md
10
10
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/restaurants/reservations/reservations/reserve-reservation.md
11
11
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/restaurants/reservations/reservations/create-reservation.md
12
- import { wixRequest } from "./client.js";
13
- import { availableSlots, reservationBody, reserveeBody, toConfirmation, toHold, toLocations } from "./reservations-core.js";
14
- import type { Raw } from "./menu-core.js";
12
+ import { wixRequest } from "../../shared/rest/client.js";
13
+ import { availableSlots, reservationBody, reserveeBody, toConfirmation, toHold, toLocations } from "../app/wix/restaurants/reservations-core.js";
14
+ import type { Raw } from "../app/wix/restaurants/menu-core.js";
15
15
  import type {
16
16
  ReservationConfirmation,
17
17
  ReservationFormConfig,
@@ -19,7 +19,7 @@ import type {
19
19
  ReservationLocationInfo,
20
20
  ReservationReservee,
21
21
  ReservationSlot,
22
- } from "./types.js";
22
+ } from "../app/wix/restaurants/types.js";
23
23
 
24
24
  const RESERVATIONS = "/table-reservations/reservations/v1";
25
25
 
@@ -28,6 +28,7 @@ import { readFileSync } from "node:fs";
28
28
  import { resolveItemImages } from "../../shared/seed/images.mjs";
29
29
  import { seedSiteId } from "../../shared/seed/site-context.mjs";
30
30
  import { wixToken } from "../../shared/seed/wix-cli.mjs";
31
+ import { isMain } from "../../shared/seed/main.mjs";
31
32
 
32
33
  const API = "https://www.wixapis.com";
33
34
  const MENUS_APP_ID = "b278a256-2757-4f19-9313-c05c783bec92";
@@ -560,7 +561,7 @@ export async function setupRestaurants(ctx, plan) {
560
561
 
561
562
  // ---- CLI entry ----------------------------------------------------------------------------------
562
563
 
563
- const invokedDirectly = process.argv[1] && import.meta.url.endsWith(process.argv[1].split("/").pop());
564
+ const invokedDirectly = isMain(import.meta.url);
564
565
  if (invokedDirectly) {
565
566
  const planPath = process.argv[2];
566
567
  if (!planPath) {
@@ -4,8 +4,8 @@
4
4
  // a literal body per function. Every call here answers a visitor token (observed live). Porting:
5
5
  // keep the paths, keep the bodies, port the core once.
6
6
  // docs: https://dev.wix.com/docs/api-reference/business-management/site-search/wix-site-search/search.md
7
- import { wixRequest } from "./client.js";
8
- import { imgSrc } from "./media.js";
7
+ import { wixRequest } from "../../../rest/client.js";
8
+ import { imgSrc } from "../../../rest/media.js";
9
9
  import { siteSearchPlan } from "./site-search-config.generated.js";
10
10
  import {
11
11
  GROUP_LIMIT,
@@ -23,8 +23,8 @@ import {
23
23
  toSearchAll,
24
24
  toSuggestGroups,
25
25
  type Raw,
26
- } from "./search-core.js";
27
- import type { SearchAllResult, SearchOptions, SearchPage, SiteSearchConfig, SuggestGroup } from "./types.js";
26
+ } from "../app/wix/site-search/search-core.js";
27
+ import type { SearchAllResult, SearchOptions, SearchPage, SiteSearchConfig, SuggestGroup } from "../app/wix/site-search/types.js";
28
28
 
29
29
  /** The plan's siteSearch entry resolved — types in order, routes, labels. */
30
30
  export const config: SiteSearchConfig = resolveConfig(siteSearchPlan);
@@ -11,10 +11,10 @@
11
11
  // (searchAll("<a seeded title word>")) and expect a non-empty group before wiring the UI. Zero
12
12
  // documents after a minute means the app is not installed or the content is not visible to the
13
13
  // index (hidden products, drafts), not that the query is wrong.
14
- import { execFileSync } from "node:child_process";
15
14
  import { seedSiteId } from "../../../seed/site-context.mjs";
16
15
  import { existsSync, readFileSync } from "node:fs";
17
16
  import { installSiteSearch } from "../../../seed/site.mjs";
17
+ import { wixToken } from "../../../seed/wix-cli.mjs";
18
18
 
19
19
  function flag(name) {
20
20
  const i = process.argv.indexOf(`--${name}`);
@@ -29,9 +29,11 @@ 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@1.1.258", "token", "--site", siteId], { encoding: "utf8" }).trim();
33
- if (!token) {
34
- console.log(JSON.stringify({ error: "the Wix CLI returned no token — run `npx @wix/cli@1.1.258 login` first" }));
32
+ let token;
33
+ try {
34
+ token = wixToken(siteId);
35
+ } catch (e) {
36
+ console.log(JSON.stringify({ error: String(e.message).slice(0, 400) }));
35
37
  process.exit(1);
36
38
  }
37
39
  try {
@@ -0,0 +1,15 @@
1
+ // Whether a seed module is the script node was started with (`node seed-<vertical>.mjs plan.json`)
2
+ // rather than imported. Compares real paths, so Windows backslashes, relative invocations and
3
+ // symlinked folders all match (node reports the module's real path in import.meta.url).
4
+ import { realpathSync } from "node:fs";
5
+ import { resolve } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ export function isMain(moduleUrl) {
9
+ if (!process.argv[1]) return false;
10
+ try {
11
+ return realpathSync(resolve(process.argv[1])) === realpathSync(fileURLToPath(moduleUrl));
12
+ } catch {
13
+ return false;
14
+ }
15
+ }
@@ -1,28 +1,60 @@
1
1
  // The Wix CLI the seeds call for a site token and for `wix env pull`.
2
2
  //
3
- // Order: the project's own copy (node_modules/.bin/wix, installed with the template's lock), then
3
+ // Order: the project's own copy (node_modules/@wix/cli, installed with the template's lock), then
4
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
- import { existsSync } from "node:fs";
7
- import { delimiter, join } from "node:path";
6
+ //
7
+ // On Windows `wix` and `npx` are .cmd shims, which Node starts only through a shell (ENOENT
8
+ // without one, EINVAL for an explicit .cmd since Node 20.12). There the CLI's own JS entry, and
9
+ // npm's npx entry beside node.exe, run through node directly.
10
+ import { existsSync, readFileSync } from "node:fs";
11
+ import { delimiter, dirname, join } from "node:path";
8
12
  import { execFileSync, spawnSync } from "node:child_process";
9
13
 
10
14
  // The CLI version the fallback installs; equal to `@wix/cli` in wix-headless-kit/install/pins.json.
11
15
  const WIX_CLI_VERSION = "1.1.258";
16
+ const isWin = process.platform === "win32";
17
+
18
+ // The JS file a @wix/cli install runs (package.json `bin`), or null.
19
+ function cliEntry(pkgDir) {
20
+ try {
21
+ const { bin } = JSON.parse(readFileSync(join(pkgDir, "package.json"), "utf8"));
22
+ const rel = typeof bin === "string" ? bin : bin?.wix;
23
+ return rel && existsSync(join(pkgDir, rel)) ? join(pkgDir, rel) : null;
24
+ } catch {
25
+ return null;
26
+ }
27
+ }
28
+
29
+ function viaNpx() {
30
+ const pkg = `@wix/cli@${WIX_CLI_VERSION}`;
31
+ if (!isWin) return { file: "npx", prefix: ["-y", pkg] };
32
+ const js = join(dirname(process.execPath), "node_modules", "npm", "bin", "npx-cli.js");
33
+ if (existsSync(js)) return { file: process.execPath, prefix: [js, "-y", pkg] };
34
+ return { file: "npx.cmd", prefix: ["-y", pkg], shell: true };
35
+ }
12
36
 
13
37
  export function resolveWixCli(cwd = process.cwd()) {
14
- const bin = process.platform === "win32" ? "wix.cmd" : "wix";
15
- const local = join(cwd, "node_modules", ".bin", bin);
16
38
  // The project's copy counts only once its install has finished: the seed runs beside a detached
17
39
  // npm install, and mid-install the .bin shim can exist before the package it points at does
18
40
  // (seen live: "Cannot find module node_modules/.bin/wix"). npm writes node_modules/.package-lock.json
19
41
  // last, the same marker the kit's install step syncs on.
20
- const installed = existsSync(join(cwd, "node_modules", ".package-lock.json")) && existsSync(join(cwd, "node_modules", "@wix", "cli", "package.json"));
21
- if (installed && existsSync(local)) return { file: local, prefix: [] };
42
+ const pkgDir = join(cwd, "node_modules", "@wix", "cli");
43
+ const installed = existsSync(join(cwd, "node_modules", ".package-lock.json")) && existsSync(join(pkgDir, "package.json"));
44
+ if (installed) {
45
+ const local = join(cwd, "node_modules", ".bin", "wix");
46
+ if (!isWin && existsSync(local)) return { file: local, prefix: [] };
47
+ const entry = isWin && cliEntry(pkgDir);
48
+ if (entry) return { file: process.execPath, prefix: [entry] };
49
+ }
22
50
  for (const dir of (process.env.PATH ?? "").split(delimiter)) {
23
- if (dir && existsSync(join(dir, bin))) return { file: join(dir, bin), prefix: [] };
51
+ if (!dir) continue;
52
+ if (!isWin && existsSync(join(dir, "wix"))) return { file: join(dir, "wix"), prefix: [] };
53
+ // A global npm install on Windows: wix.cmd in the prefix, the package beside it.
54
+ const entry = isWin && existsSync(join(dir, "wix.cmd")) && cliEntry(join(dir, "node_modules", "@wix", "cli"));
55
+ if (entry) return { file: process.execPath, prefix: [entry] };
24
56
  }
25
- return { file: "npx", prefix: ["-y", `@wix/cli@${WIX_CLI_VERSION}`] };
57
+ return viaNpx();
26
58
  }
27
59
 
28
60
  /**
@@ -32,7 +64,7 @@ export function resolveWixCli(cwd = process.cwd()) {
32
64
  */
33
65
  export function wixToken(siteId, cwd = process.cwd()) {
34
66
  const cli = resolveWixCli(cwd);
35
- const out = execFileSync(cli.file, [...cli.prefix, "token", "--site", siteId], { encoding: "utf8", cwd });
67
+ const out = execFileSync(cli.file, [...cli.prefix, "token", "--site", siteId], { encoding: "utf8", cwd, shell: cli.shell, windowsHide: true });
36
68
  // An older CLI starts its "update available" box on the token's own line, so a line split is
37
69
  // not enough: the token is the first long run of token characters.
38
70
  const token = out.match(/[A-Za-z0-9._-]{40,}/)?.[0];
@@ -43,5 +75,5 @@ export function wixToken(siteId, cwd = process.cwd()) {
43
75
  /** Runs a Wix CLI command synchronously; same return shape as spawnSync. */
44
76
  export function runWix(args, { cwd = process.cwd(), ...opts } = {}) {
45
77
  const cli = resolveWixCli(cwd);
46
- return spawnSync(cli.file, [...cli.prefix, ...args], { cwd, ...opts });
78
+ return spawnSync(cli.file, [...cli.prefix, ...args], { cwd, shell: cli.shell, windowsHide: true, ...opts });
47
79
  }
@@ -264,7 +264,7 @@ import { seoTags } from "@wix/seo";
264
264
  export const wixMetadata = {
265
265
  appDefId: WIX_APPS.checkoutAndOrders.id,
266
266
  pageIdentifier: WIX_APPS.checkoutAndOrders.categoryPageMetadata.pageIdentifier,
267
- identifiers: { slug: WIX_APPS.checkoutAndOrders.categoryPageMetadata.identifiers.handle },
267
+ identifiers: { slug: WIX_APPS.checkoutAndOrders.categoryPageMetadata.identifiers.collection },
268
268
  };
269
269
 
270
270
  const slug = Astro.params.slug!;
@@ -6,11 +6,11 @@
6
6
  // All calls run with the visitor token: the cart is the token's (see ../shared/client).
7
7
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart-v2/add-line-items-to-current-cart.md
8
8
  // docs: https://dev.wix.com/docs/api-reference/business-management/headless/redirects/create-redirect-session.md
9
- import { WixApiError, wixRequest } from "./client.js";
10
- import { imgSrc } from "./media.js";
11
- import { EMPTY_TOTALS, WIX_STORES_APP_ID, addOptions, assertAdded, assertCheckoutable, cartErrorMessage, rawId, summaryTotals, toCart } from "./cart-core.js";
12
- import type { Raw } from "./catalog-core.js";
13
- import type { Cart } from "./types.js";
9
+ import { WixApiError, wixRequest } from "../../shared/rest/client.js";
10
+ import { imgSrc } from "../../shared/rest/media.js";
11
+ import { EMPTY_TOTALS, WIX_STORES_APP_ID, addOptions, assertAdded, assertCheckoutable, cartErrorMessage, rawId, summaryTotals, toCart } from "../app/wix/storefront/cart-core.js";
12
+ import type { Raw } from "../app/wix/storefront/catalog-core.js";
13
+ import type { Cart } from "../app/wix/storefront/types.js";
14
14
 
15
15
  const CART = "/ecom/v2/carts/current";
16
16
 
@@ -5,8 +5,8 @@
5
5
  // Porting: keep the paths, keep the bodies, port the core once.
6
6
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/products-v3/search-products.md
7
7
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/categories/get-category-by-slug.md
8
- import { WixApiError, wixRequest } from "./client.js";
9
- import { imgSrc, mediaKey } from "./media.js";
8
+ import { WixApiError, wixRequest } from "../../shared/rest/client.js";
9
+ import { imgSrc, mediaKey } from "../../shared/rest/media.js";
10
10
  import {
11
11
  CATALOG_SORTS,
12
12
  DETAIL_FIELDS,
@@ -29,9 +29,9 @@ import {
29
29
  type CatalogSort,
30
30
  type FacetSelection,
31
31
  type Raw,
32
- } from "./catalog-core.js";
33
- import { WIX_STORES_APP_ID } from "./cart-core.js";
34
- import type { Category, Facet, FacetData, ProductDetail, ProductSummary, VariantInventory } from "./types.js";
32
+ } from "../app/wix/storefront/catalog-core.js";
33
+ import { WIX_STORES_APP_ID } from "../app/wix/storefront/cart-core.js";
34
+ import type { Category, Facet, FacetData, ProductDetail, ProductSummary, VariantInventory } from "../app/wix/storefront/types.js";
35
35
 
36
36
  export { CATALOG_SORTS, choiceAvailability, resolveVariant, sellingPrice, type CatalogSearchOptions, type CatalogSort, type FacetSelection };
37
37
 
@@ -99,7 +99,7 @@ to a file if you want it later). `.seed-exit` and `seed-result.json` are written
99
99
  create only; an existing category keeps what it has.
100
100
  - `quantity` — tracked stock, a non-negative integer. For stock that isn't counted (made to
101
101
  order, print on demand, unlimited) use `"inStock": true` **instead** of `quantity`; sending
102
- both is rejected.
102
+ both is rejected. A product with no stock given, drafted or the user's own, is `"inStock": true`.
103
103
  Right after the bulk create, a product's own stock summary can still read `OUT_OF_STOCK`
104
104
  while its inventory items are already stocked; the items are what a buyer's add is checked
105
105
  against. A product **without options** can still end up with no item (a create that ran while
@@ -107,16 +107,18 @@ to a file if you want it later). `.seed-exit` and `seed-result.json` are written
107
107
  Inventory Items call (`productId`, its single `variantId`, and `inStock: true` or the
108
108
  `quantity`), where `ALREADY_EXISTS` means the item is already there. A seed made call by call
109
109
  reads the items (Query Inventory Items) and creates only the missing ones.
110
- - `currency` — 3-letter ISO code. Set it **only when the brief names one**: a sentence about
111
- currency ("prices in euros") or a price written with its unit ("9 dollars", "$9", "€20"). Do **not** infer it from a language, a country, or an address
112
- — an unrequested switch silently reprices the whole catalog. The seed applies it before
113
- creating anything, because a product's price is stored in the site currency at create time.
114
- For a few seconds afterwards product reads can still report the old currency; that lag is
110
+ - `currency` — 3-letter ISO code. Set it **only when the user names one**, in the brief or on their
111
+ own pages: a sentence about currency ("prices in euros") or a price written with its unit ("9
112
+ dollars", "$9", "€20"). On a site this run created it is set without asking; a store the user
113
+ already runs is asked first. Do **not** infer it from a language, a country, or an address — an
114
+ unrequested switch silently reprices the whole catalog. The seed applies it before creating
115
+ anything, because a product's price is stored in the site currency at create time. For a few
116
+ seconds afterwards product reads can still report the old currency; that lag is
115
117
  expected and self-resolves, so don't re-verify it or retry.
116
118
 
117
119
  **Default to 3 products** when you draft the catalog yourself — the seed shows the shape, not a
118
- full inventory; the owner adds the rest in the dashboard. **Make those 3 exercise the shipped
119
- UI**: give at least one product a color option and put one product on sale — truthfully to the
120
+ full inventory; the owner adds the rest in the dashboard. The closing names drafted products as
121
+ placeholders. **Make those 3 exercise the shipped UI**: give at least one product a color option and put one product on sale — truthfully to the
120
122
  business (a ceramics studio has glaze colors; a bakery doesn't). When the brief mentions gift
121
123
  wrap, engraving, a message card, pre-orders, or "coming soon" stock, seed ONE product with that
122
124
  modifier and ONE pre-order item so the surfaces exist to design against; never add them to a
@@ -143,7 +145,8 @@ a new site (a dozen products: "Baseball Cap", "Ceramic Flower Vase", "Crew T-Shi
143
145
  live shop lists them next to the owner's, so they are never silent: the result's `preexisting[]` names
144
146
  every product the plan did not name (`{ id, name, slug }`), and the closing message says so with the
145
147
  Manage products link (`dashboardProductsUrl` in the result) so the owner removes them there if they
146
- want to. Categories are idempotent by name — a re-run reuses "Donuts" instead of creating a second one.
148
+ want to. After a currency change their prices keep the same numbers in the new currency, and the
149
+ closing says so. Categories are idempotent by name — a re-run reuses "Donuts" instead of creating a second one.
147
150
 
148
151
  **Images are confirmed, not assumed.** `imagesAttached` counts the attaches the API reported as
149
152
  successful; `imageFailures: [{ name, error }]` names the products left without an image and why.
@@ -161,6 +164,8 @@ duplicated. Never hand-patch ids to "fill the gap".
161
164
 
162
165
  Two things this module does not seed (dashboard-only — tell the merchant): **SKUs** and
163
166
  **subscription plans** (the storefront renders them when the merchant adds them).
167
+ Shipping isn't seeded either; when the brief asks for it, `wix-manage`'s
168
+ `references/ecommerce/ecom-shipping.md` sets it up.
164
169
 
165
170
  ## Escape hatch — individual functions
166
171
 
@@ -169,6 +174,19 @@ ordering: `installStoresApp`, `readAllProducts`, `bulkCreateProducts`,
169
174
  `createCategories(ctx, names, details?)`, `addProductsToCategories`, `attachProductImages` — plus
170
175
  `makeCtx()` for the auth context.
171
176
 
177
+ A seed made call by call sends the body `bulkCreateProducts` builds
178
+ (`POST /stores/v3/bulk/products-with-inventory/create`); the description is rich-text nodes, as
179
+ `mkDesc` turns them out:
180
+
181
+ ```json
182
+ { "returnEntity": true, "products": [{
183
+ "name": "Hearth Candle", "productType": "PHYSICAL", "physicalProperties": {},
184
+ "description": { "nodes": [{ "type": "PARAGRAPH", "id": "d0", "paragraphData": {},
185
+ "nodes": [{ "type": "TEXT", "id": "", "textData": { "text": "Hand-poured soy wax.", "decorations": [] } }] }] },
186
+ "variantsInfo": { "variants": [{ "price": { "actualPrice": { "amount": "28" } },
187
+ "physicalProperties": {}, "inventoryItem": { "inStock": true } }] } }] }
188
+ ```
189
+
172
190
  ## Reference
173
191
 
174
192
  If a call returns an unexpected shape or you need an operation this module doesn't cover, read
@@ -32,6 +32,7 @@ import { readFileSync } from "node:fs";
32
32
  import { resolveItemImages, resolveItemImagesDetailed } from "../../shared/seed/images.mjs";
33
33
  import { seedSiteId } from "../../shared/seed/site-context.mjs";
34
34
  import { wixToken } from "../../shared/seed/wix-cli.mjs";
35
+ import { isMain } from "../../shared/seed/main.mjs";
35
36
 
36
37
  const API = "https://www.wixapis.com";
37
38
  const STORES_APP_ID = "215238eb-22a5-4c36-9e7b-e7c08025e04e";
@@ -854,7 +855,7 @@ export async function setupStore(ctx, { products = [], categories = {}, category
854
855
 
855
856
  // ---- CLI entry ----------------------------------------------------------------------------------
856
857
 
857
- const invokedDirectly = process.argv[1] && import.meta.url.endsWith(process.argv[1].split("/").pop());
858
+ const invokedDirectly = isMain(import.meta.url);
858
859
  if (invokedDirectly) {
859
860
  const planPath = process.argv[2];
860
861
  if (!planPath) {
@@ -396,7 +396,7 @@ Authoritative recipe for hand-authoring valid Ricos rich-content JSON (the richC
396
396
  Creates new Wix sites from templates using account-level APIs. Covers template search, site creation, and publishing. Not for headless sites.
397
397
 
398
398
  ### [Create Headless Site](references/sites/create-headless-site.md)
399
- Creates a Wix Headless site (headless business) with one account-level API call — site, Wix Business Solution apps, and a configured OAuth client.
399
+ Creates a Wix Headless website: a site in the user's Wix account whose frontend is files uploaded to Wix hosting, with the Wix business backend behind it through APIs. Creating, uploading, updating and connecting a backend are one flow, in Upload a Website or HTML Files.
400
400
 
401
401
  ### [Manage OAuth Apps](references/sites/manage-oauth-apps.md)
402
402
  Create, read, update, and query OAuth apps for a Wix headless site. Each OAuth app's id is the client_id a frontend uses to mint anonymous visitor tokens and call Wix APIs.
@@ -417,7 +417,7 @@ Drive the Wix Site Import agent to migrate an existing store or site from anothe
417
417
  "Builds direct links to the account-level sites pages on manage.wix.com — the My Sites list (all sites in the account) and each site's own dashboard. Pairs the site list with the Query Sites read API. Use when the user asks where something is in the Wix dashboard, wants a direct link to a dashboard page, or you need a dashboard URL to include with the result of an API operation."
418
418
 
419
419
  ### [Upload a Website or HTML Files](references/sites/upload-static-site.md)
420
- Publish a user's ready-made website — an index.html, a static build, or a zip exported from an AI builder or any other tool — as a live Wix site. Covers every way to get there — publishing straight into the user's Wix account when you hold their identity, publishing anonymously with a save link when you don't, and handing the user the Wix Headless drop page, or releasing it as a Wix Headless project — and how to get the user's identity through the Wix CLI. Use whenever the user wants to upload, publish, deploy, or host their own HTML/CSS/JS as a NEW site, including files generated for them earlier in the conversation, or to update a site published this way (replace its files on the same site and URL). Not for migrating a live store/site from another platform by URL or from CSV exports (use Site Import), not for adding HTML or custom code into an existing Wix site, and not for uploading images or documents to a site's media files.
420
+ Create and update a Wix Headless website by uploading its files — an index.html, a static build, a zip exported from an AI builder or any other tool, or pages you write for the user — as a live site in the user's Wix account. Covers every route: uploading with the user's identity (curl with a Wix CLI token, or the Wix MCP), publishing anonymously with a save link when you don't hold it, and the Wix Headless drop page; then updating the same site and URL, and connecting a Wix backend (stores, bookings, forms) through the headless skill. Use when the user wants to upload, publish, deploy or host HTML/CSS/JS as a new Wix site, their own or written for them, or to change a site published this way. Not for migrating a live store/site from another platform by URL or from CSV exports (use Site Import), not for adding HTML or custom code into an existing Wix site, and not for uploading images or documents to a site's media files.
421
421
 
422
422
  ---
423
423
 
@@ -445,7 +445,7 @@ Query and list products from a Wix Store using the Catalog V1 Query Products end
445
445
  Manages pre-order settings for product variants using V3 Inventory API. Covers enabling/disabling pre-orders, setting messages, configuring limits, and handling trackQuantity requirements.
446
446
 
447
447
  ### [Update Product with Options (Catalog V3)](references/stores/update-product-with-options.md)
448
- Modifies existing products and variants using Catalog V3 Products API. Covers adding/removing option choices, variant-specific pricing, product visibility (hide, unhide, or show a product in the storefront — a product-level `visible` update, never a delete), and revision-based updates to prevent conflicts.
448
+ Start here for existing Catalog V3 product updates, including digital products that fail at add-to-cart with ITEM_NOT_FOUND_IN_CATALOG. Includes name lookup, Get Product, and PATCH in one flow, plus importing a supplied PDF and attaching it to the existing variant. Covers options, variant prices and SKUs, product visibility (hide/unhide through `visible`, never delete), description edits that preserve Rich Content, and revision-based updates. Read another recipe only for a field or operation this flow does not cover.
449
449
 
450
450
  ### [Stores Dashboard Navigation](references/stores/stores-dashboard-navigation.md)
451
451
  "Builds direct links to Wix Stores and eCommerce dashboard pages on manage.wix.com — products list, edit a specific product, categories, inventory, orders list, a specific order, abandoned checkouts, gift cards, shipping and tax settings. Pairs each main Stores/eCommerce entity with its read API so you can fetch an entity and hand back a 'view it in your dashboard' link. Use when the user asks where something is in the Wix dashboard, wants a direct link to a dashboard page, or you need a dashboard URL to include with the result of an API operation."
@@ -92,7 +92,7 @@ curl -X POST \
92
92
 
93
93
  Before installing, refer to the [Apps Created by Wix](https://dev.wix.com/docs/api-reference/articles/work-with-wix-apis/platform/about-apps-created-by-wix) documentation to find the correct `appDefId` for the app you want to install.
94
94
 
95
- Some common apps:
95
+ Some common apps (`appDefId`; [List Installed Apps](list-installed-apps.md) shows which of them a site already has):
96
96
  | App | appDefId |
97
97
  |-----|----------|
98
98
  | Wix Stores | `215238eb-22a5-4c36-9e7b-e7c08025e04e` |
@@ -102,6 +102,10 @@ Some common apps:
102
102
  | Wix Multilingual | `14d84998-ae09-1abf-c6fc-3f3cace5bf19` |
103
103
  | Wix Pricing Plans | `1522827f-c56c-a5c9-2ac9-00f9e6ae12d3` |
104
104
  | Wix CMS | `e593b0bd-b783-45b8-97c2-873d42aacaf4` |
105
+ | Wix Forms | `225dd912-7dea-4738-8688-4b8c6955ffc2` |
106
+ | Wix Restaurants Menus | `b278a256-2757-4f19-9313-c05c783bec92` |
107
+ | Wix Restaurants Orders (online ordering) | `9a5d83fd-8570-482e-81ab-cfa88942ee60` |
108
+ | Wix Table Reservations | `f9c07de2-5341-40c6-b096-8eb39de391fb` |
105
109
 
106
110
  ### IMPORTANT NOTES:
107
111
  - NEVER guess the `appDefId`. For Wix-built apps, use the table above. For any other app, resolve the ID using Step 0 (Search Market Listings).
@@ -8,7 +8,10 @@ This recipe guides you through listing all installed apps on a Wix site using th
8
8
 
9
9
  ## Prerequisites
10
10
 
11
- - Site ID for the site you want to check
11
+ - A token scoped to the site: the call takes no site parameter and answers for the site the token is
12
+ for. With the Wix CLI, `npx @wix/cli@latest token --site <siteId>`; through the Wix MCP, `ExecuteWixAPI`
13
+ with `scope: 'site'` and the `siteId`. An account token, with or without a `wix-site-id` header, answers
14
+ an empty list, which looks like a site with no apps.
12
15
 
13
16
  ## Required APIs
14
17
 
@@ -18,7 +21,10 @@ This recipe guides you through listing all installed apps on a Wix site using th
18
21
 
19
22
  ## Step 1: Query Installed Apps
20
23
 
21
- Use the Get Installed Apps endpoint to retrieve all apps installed on a site.
24
+ Use the Get Installed Apps endpoint to retrieve all apps installed on a site. It returns every app
25
+ instance, including the dozens of platform apps every site carries, as ids only: the response has no
26
+ names; match them against the table in Step 2. [Read Account or Site Context](../sites/read-site-context.md)
27
+ has the names, but its list can lag an install by many minutes; this call is immediate.
22
28
 
23
29
  **Endpoint**: `GET https://www.wixapis.com/apps-installer-service/v1/app-instances`
24
30
 
@@ -26,7 +32,7 @@ Use the Get Installed Apps endpoint to retrieve all apps installed on a site.
26
32
  ```bash
27
33
  curl -X GET \
28
34
  'https://www.wixapis.com/apps-installer-service/v1/app-instances' \
29
- -H 'Authorization: <AUTH>' \
35
+ -H "Authorization: $(npx @wix/cli@latest token --site <SITE_ID>)" \
30
36
  -H 'Content-Type: application/json'
31
37
  ```
32
38
 
@@ -36,8 +42,7 @@ curl -X GET \
36
42
  "appInstances": [
37
43
  {
38
44
  "id": "instance-id-1",
39
- "appDefId": "1380b703-ce81-ff05-f115-39571d94dfcd",
40
- "version": "^0.0.0",
45
+ "appDefId": "215238eb-22a5-4c36-9e7b-e7c08025e04e",
41
46
  "enabled": true,
42
47
  "status": "UNKNOWN"
43
48
  },
@@ -61,12 +66,17 @@ Match the `appDefId` values from the response against known Wix app IDs.
61
66
 
62
67
  | App | appDefId |
63
68
  |-----|----------|
64
- | Wix Stores | `1380b703-ce81-ff05-f115-39571d94dfcd` |
69
+ | Wix Stores | `215238eb-22a5-4c36-9e7b-e7c08025e04e` |
70
+ | Wix Checkout & Orders (installed with Stores) | `1380b703-ce81-ff05-f115-39571d94dfcd` |
65
71
  | Wix Bookings | `13d21c63-b5ec-5912-8397-c3a5ddb27a97` |
66
72
  | Wix Blog | `14bcded7-0066-7c35-14d7-466cb3f09103` |
67
73
  | Wix Events | `140603ad-af8d-84a5-2c80-a0f60cb47351` |
68
74
  | Wix Pricing Plans | `1522827f-c56c-a5c9-2ac9-00f9e6ae12d3` |
69
- | Wix Restaurants | `13e8d036-5516-6f75-e025-2aca3b5d7930` |
75
+ | Wix CMS (Wix Data) | `e593b0bd-b783-45b8-97c2-873d42aacaf4` |
76
+ | Wix Forms | `225dd912-7dea-4738-8688-4b8c6955ffc2` |
77
+ | Wix Restaurants Menus | `b278a256-2757-4f19-9313-c05c783bec92` |
78
+ | Wix Restaurants Orders (online ordering) | `9a5d83fd-8570-482e-81ab-cfa88942ee60` |
79
+ | Wix Table Reservations | `f9c07de2-5341-40c6-b096-8eb39de391fb` |
70
80
 
71
81
  For a complete list, see [Apps Created by Wix](https://dev.wix.com/docs/api-reference/articles/work-with-wix-apis/platform/about-apps-created-by-wix).
72
82
 
@@ -111,8 +121,8 @@ If you receive `401 Unauthorized` or `403 Forbidden` errors from Wix APIs:
111
121
  - Check that the token has `APP-MARKET.VIEW-INSTALLED-APP` permission
112
122
 
113
123
  ### Empty Response
114
- - The site may have no additional apps installed beyond core Wix functionality
115
- - This is normal for new or minimal sites
124
+ - Every site carries dozens of platform app instances, so an empty list means the token was not scoped to
125
+ the site (an account token answers empty), not a site with no apps. Mint a site token and call again.
116
126
 
117
127
  ---
118
128