@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
@@ -8,7 +8,7 @@ description: "SEASONAL sub-flow — load [Goal: Seasonal Revenue] FIRST (it owns
8
8
  >
9
9
  > This flow is a sub-step, not a direct entry point. If you have not yet called `ReadFullDocsArticle` on [Goal: Seasonal Revenue](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/goal-seasonal-revenue) in this conversation, **stop and load it now**. The goal skill owns the SEASONAL classification rule, the time-window presentation requirement, and the priority rule that gates access to this flow.
10
10
  >
11
- > **Before executing this flow**, also 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).
11
+ > **Before executing this flow**, also 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).
12
12
 
13
13
  Creates event-driven promotional discounts tied to holidays, shopping events, or seasonal milestones. The flow identifies upcoming events based on the site's country and current date, calculates optimal campaign start/end windows, and targets event-relevant product categories with appropriately sized discounts.
14
14
 
@@ -6,7 +6,7 @@ description: "Stock-mover clearance sub-flow — load [Goal: Clear Inventory] FI
6
6
 
7
7
  > **Routing rule (READ FIRST).** This recipe is a sub-step of [Goal: Clear Inventory](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/goal-clear-inventory). If you arrived here directly from the WixREADME index, load the goal recipe NOW before executing — it owns the velocity scoring, classification cues, and the per-recommendation presentation rules (including the **margin-floor guardrail** surfacing requirement).
8
8
  >
9
- > **Then** 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).
9
+ > **Then** 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).
10
10
 
11
11
  Creates a discount targeting slow-moving inventory — products with high stock levels and low sales velocity. The discount depth is proportional to how overstocked the product is, with deeper discounts for the most stagnant items. Margin protection guardrails are especially important here since clearance discounts tend to push closer to cost.
12
12
 
@@ -99,7 +99,7 @@ If scope is CATEGORY, call `getCategoryIds` to convert category names to GUIDs.
99
99
 
100
100
  ## Step 6: Run guardrail checks
101
101
 
102
- **Run the pre-create guardrails in [Create Discount Rule](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/pricing-create-discount-rule) → "Guardrails" before creating the rule** (conflict/stacking, %-sanity, margin floor). Clearance is the **most margin-sensitive** case: discounts push closest to cost, so the margin-floor check (effective margin ≥ 15% unless the merchant overrides) is the one most likely to fire here — verify it per candidate product.
102
+ **Run the pre-create guardrails in [Create Discount Rule](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/pricing-create-discount-rule) → "Guardrails" before creating the rule** (conflict/stacking, %-plausibility, margin floor). Clearance is the **most margin-sensitive** case: discounts push closest to cost, so the margin-floor check (effective margin ≥ 15% unless the merchant overrides) is the one most likely to fire here — verify it per candidate product.
103
103
 
104
104
  ---
105
105
 
@@ -4,7 +4,7 @@ description: "UPSELL_BOOST sub-flow — load [Goal: Increase AOV] FIRST (it owns
4
4
  ---
5
5
  # Flow: Upsell Boost 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 incentivizes customers to spend more per order by setting a minimum subtotal threshold above the store's current AOV. The discount percentage is scaled to the store's average profit margin, and the scope targets high-margin categories or products.
10
10
 
@@ -29,7 +29,7 @@ Catalog analytics and product data are already in conversation context — do NO
29
29
  - `siteData.aov` — site-level AOV (revenue / ordersCount). Loaded by eCommerce Load Context.
30
30
 
31
31
  Extract from context:
32
- - `effective_aov` — use `siteData.aov`; run AOV sanity check: if AOV < price_p25, override with price_p50 as effective AOV
32
+ - `effective_aov` — use `siteData.aov`; run AOV plausibility check: if AOV < price_p25, override with price_p50 as effective AOV
33
33
  - `avg_profit_margin` — from the "All Products" group in `siteData.catalogAnalytics`
34
34
  - `price_p50`, `price_p75`, `price_p90` — from quantiles in `siteData.catalogAnalytics`
35
35
  - Top products by price and order volume — from `siteData.productCatalogData`
@@ -90,7 +90,7 @@ Max 3 categoryIds per discount rule.
90
90
 
91
91
  ## Step 6: Run guardrail checks
92
92
 
93
- **Run the pre-create guardrails in [Create Discount Rule](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/pricing-create-discount-rule) → "Guardrails" before creating the rule** — conflict/stacking (scope, time, coupon cross-stacking), the 25% cap, the 15% margin floor, and %-sanity. Present any warnings to the merchant and get confirmation before proceeding.
93
+ **Run the pre-create guardrails in [Create Discount Rule](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/pricing-create-discount-rule) → "Guardrails" before creating the rule** — conflict/stacking (scope, time, coupon cross-stacking), the 25% cap, the 15% margin floor, and %-plausibility. Present any warnings to the merchant and get confirmation before proceeding.
94
94
 
95
95
  ---
96
96
 
@@ -8,7 +8,7 @@ description: Creates a free shipping option with an AOV-calibrated threshold to
8
8
 
9
9
  > **Before executing this skill**, read [Setup: Shipping Rates](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/shipping-set-up-rates) with `ReadFullDocsArticle` for the rate-object mechanics.
10
10
 
11
- ## Rate pricing sanity (inline guardrail)
11
+ ## Rate pricing plausibility (inline guardrail)
12
12
 
13
13
  Validate every rate you create or update against the store's AOV; flag any that fail:
14
14
 
@@ -101,7 +101,7 @@ If the threshold needs adjustment, update the shipping option via PATCH (see Ste
101
101
 
102
102
  ---
103
103
 
104
- ## Step 3: Run AOV sanity check
104
+ ## Step 3: Run AOV plausibility check
105
105
 
106
106
  Before calculating a threshold, validate that AOV is reliable by comparing it against catalog price distribution.
107
107
 
@@ -263,7 +263,7 @@ Report to the merchant:
263
263
  | `deliveryRegionId is not a valid GUID` | Used `deliveryRegionIds` (plural) instead of `deliveryRegionId` (singular) | Use the singular `deliveryRegionId` field |
264
264
  | `SHIPPING_OPTION_NOT_FOUND` | Option ID doesn't exist when trying to update | Re-query shipping options to get current IDs |
265
265
  | `REVISION_MISMATCH` | Revision doesn't match the current version when updating | Re-fetch the option for the latest revision, then retry |
266
- | Threshold seems unreasonable | AOV data is unreliable (too few orders, data anomaly) | Run the AOV sanity check (Step 3) and use `effective_aov` instead of raw AOV |
266
+ | Threshold seems unreasonable | AOV data is unreliable (too few orders, data anomaly) | Run the AOV plausibility check (Step 3) and use `effective_aov` instead of raw AOV |
267
267
  | Free shipping not visible at checkout | Region linked to the option has `active=false` | Check region active status and activate if intended |
268
268
 
269
269
  ## References
@@ -6,7 +6,7 @@ description: Analyzes catalog price distribution and current rate structure to r
6
6
 
7
7
  > **Routing rule:** BEFORE taking any action, call `ReadFullDocsArticle` on [Shipping API Reference](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/shipping-api-reference). The Query Shipping Options and Update/Create Shipping Option endpoints used in Steps 2–4 live there. Do NOT query or modify any shipping options without loading it first.
8
8
 
9
- ## Rate pricing sanity (inline guardrail)
9
+ ## Rate pricing plausibility (inline guardrail)
10
10
 
11
11
  Validate every rate you create or update against the store's AOV; flag any that fail:
12
12
 
@@ -1,10 +1,10 @@
1
1
  ---
2
2
  name: "Shipping: Set Up Rates"
3
- description: Configures shipping option rates — rate types (flat, tiered, free), condition types and operators, free shipping threshold calibration, AOV sanity check, per-item penalty avoidance, and tier gap detection.
3
+ description: Configures shipping option rates — rate types (flat, tiered, free), condition types and operators, free shipping threshold calibration, AOV plausibility check, per-item penalty avoidance, and tier gap detection.
4
4
  ---
5
5
  # Shipping Rates
6
6
 
7
- ## AOV Sanity Check
7
+ ## AOV Plausibility Check
8
8
 
9
9
  **MANDATORY before any threshold calculation that references AOV.** Raw AOV can be misleading due to data issues or bulk purchases.
10
10
 
@@ -80,6 +80,6 @@ When ALL of the following are true, flat rate is optimal and no change is needed
80
80
 
81
81
  Sort all conditions by value and look for gaps between ranges. Gaps mean some cart totals have no matching rate, which can cause checkout failures.
82
82
 
83
- ## Shipping Cost Sanity Check
83
+ ## Shipping Cost Plausibility Check
84
84
 
85
85
  Any rate `amount > AOV x 0.15` (15% of average order value) should be flagged as a cart abandonment risk.
@@ -16,7 +16,7 @@ Five ways to get the files live; what you have decides which are open to you.
16
16
  | Option | Needs | Carries | The user ends up with |
17
17
  | --- | --- | --- | --- |
18
18
  | **A.** `curl` + CLI token → [into the account](#publish-into-the-users-account) | A shell; a Wix CLI login | Anything on disk | A site in their account, final URL |
19
- | **B.** `ExecuteWixAPI` → [into the account](#publish-into-the-users-account) | The Wix MCP | Small text files already in the conversation | A site in their account, final URL |
19
+ | **B.** `ExecuteWixAPI` → [into the account](#publish-into-the-users-account) | The Wix MCP | Files already in the conversation — text as is, small binaries as base64 — and anything downloaded from the site | A site in their account, final URL |
20
20
  | **C.** `curl` → [anonymous](#publish-anonymously) | A shell | Anything on disk | A live site for one hour; kept by a [claim](#claim-it-into-the-users-account) (through the Wix MCP or a CLI token) or the save link |
21
21
  | **D.** [The drop page](#the-drop-page) | Nothing | Whatever the user uploads | The same, after they upload it themselves |
22
22
  | **E.** [The headless skill](#keep-building-add-a-backend-when-you-need-one) | A shell; Node; a Wix CLI login | A project folder, source included (built for you) | A site in their account as a Wix Headless project, released with the Wix CLI, ready for Wix Business Solutions |
@@ -30,8 +30,13 @@ What sets them apart:
30
30
  byte is written out inside the call. That costs nothing extra for a page you
31
31
  generated or the user pasted (it's already in the conversation); for files on
32
32
  disk it means reading them in and writing them back out, and each change
33
- resends all of it. A string body is sent as UTF-8, so binary files (PNG, JPG,
34
- fonts, zips) arrive corrupted; link images by absolute URL.
33
+ resends all of it. Files travel in the tool's `files` param — text raw, a
34
+ binary file (PNG, JPG, fonts) as base64 — and `wix.multipart()` builds the
35
+ upload body (below). Base64 costs about a third more than the file and every
36
+ byte is tokens, so it suits small assets (an icon, a logo, a font) and files
37
+ you downloaded from the site to change; a photo goes in by absolute URL
38
+ (`<img src="https://…">`) or with `curl` from a shell. The bundle is capped at
39
+ 4M characters.
35
40
  - **A CLI login** is one approval by the user in the browser: run
36
41
  `npx @wix/cli login` and have them approve; `npx @wix/cli token` then prints a
37
42
  token (see [Before the calls](#before-the-calls)). It also unlocks later
@@ -43,8 +48,8 @@ What sets them apart:
43
48
  the only one that takes framework source as is and leaves a project ready for a
44
49
  backend. A drop site can still move to it [later](#keep-building-add-a-backend-when-you-need-one).
45
50
 
46
- So: a small page already in the conversation, with the Wix MCP connected — B,
47
- shell or not. Static files on disk — A with a CLI login, else C (claimed through
51
+ So: a site already in the conversation — pages, styles, a logo — with the Wix
52
+ MCP connected — B, shell or not. Static files on disk — A with a CLI login, else C (claimed through
48
53
  the Wix MCP when it's connected). A framework project (a `package.json`), or a
49
54
  site that needs stores, bookings, a CMS or members from the start — E. Files out
50
55
  of your reach, or nothing above fits — D.
@@ -108,8 +113,27 @@ curl -sS -X POST \
108
113
  "siteUrl": "https://headless-zjfqzddjtww-northwind-1406.wix-site-host.com" }
109
114
  ```
110
115
 
111
- Option B — the same two calls as one `ExecuteWixAPI` script, for small text files
112
- already in the conversation:
116
+ Option B — the same two calls as one `ExecuteWixAPI` script, for files already
117
+ in the conversation. The files go in the tool's **`files` param**, not in
118
+ `code`: one bundle, each file introduced by a line `=== FILE: <path> ===` and
119
+ followed by its raw text, `<path>` relative to the site root. A binary file is
120
+ introduced by `=== FILE: <path> base64 ===` and followed by its base64. Nothing
121
+ in it is escaped, so quotes, backticks, `${}` and backslashes arrive as written.
122
+
123
+ ```
124
+ === FILE: index.html ===
125
+ <!doctype html><html><head><title>Northwind Studio</title>
126
+ <link rel="stylesheet" href="assets/styles.css"></head><body><h1>Northwind Studio</h1><img src="assets/logo.png"></body></html>
127
+ === FILE: assets/styles.css ===
128
+ body { font-family: sans-serif; margin: 0; padding: 4rem; }
129
+ === FILE: assets/logo.png base64 ===
130
+ iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==
131
+ ```
132
+
133
+ In `code`, the bundle is the `files` global (`[{ path, content, encoding? }]`,
134
+ `encoding: 'base64'` on the binary entries) and `wix.multipart()` turns it into
135
+ the upload body: one part named `files` per file, the path as its filename, a
136
+ content type guessed from the extension, base64 entries decoded to their bytes.
113
137
 
114
138
  ```javascript
115
139
  async function run() {
@@ -117,31 +141,21 @@ async function run() {
117
141
  url: 'https://www.wixapis.com/headless-business-setup/v1/headless-business/provision',
118
142
  body: { origin: 'drop', newMetasite: { namingStrategy: { metaSiteName: 'Northwind Studio' }, seedOptions: [] },
119
143
  synchronousSteps: ['SET_METASITE_NAME', 'CONFIGURE_HEADLESS_APP'] } });
120
- // path → text content, as template literals. Escape \ as \\ first, then ` as \` and ${ as \${
121
- // (an unescaped \ is dropped or reinterpreted: /\d+/ would arrive as /d+/).
122
- const files = {
123
- 'index.html': `<!doctype html><html><head><title>Northwind Studio</title>
124
- <link rel="stylesheet" href="assets/styles.css"></head><body><h1>Northwind Studio</h1></body></html>`,
125
- 'assets/styles.css': `body { font-family: sans-serif; margin: 0; padding: 4rem; }`,
126
- };
127
- const boundary = '----wixdropboundary';
128
- const body = Object.entries(files).flatMap(([path, text]) => [
129
- '--' + boundary,
130
- `Content-Disposition: form-data; name="files"; filename="${path}"`,
131
- '', text,
132
- ]).concat('--' + boundary + '--', '').join('\r\n');
144
+ const mp = wix.multipart(); // the `files` param; or pass [{ path, content | base64 | bytes }]
133
145
  return await wix.request({ scope: 'account', method: 'POST',
134
146
  url: `https://www.wixapis.com/headless-business-setup/v1/headless-business/${created.data.metaSiteId}/drop`,
135
- headers: { 'Content-Type': 'multipart/form-data; boundary=' + boundary },
136
- body }); // a string body is sent verbatim
147
+ headers: { 'Content-Type': mp.contentType },
148
+ body: mp.body });
137
149
  }
138
150
  ```
139
151
 
140
152
  `wix.request` returns `{ status, data }`; read a response's fields from `data`
141
- (`created.data.metaSiteId`). Keep the body's shape exactly. It's a string; an
142
- object is sent as JSON and rejected. Lines end in `\r\n`, the body ends with
143
- `--<boundary>--`, and the header names the same boundary the body uses. Break any of these and the drop
144
- fails with a bare `500`.
153
+ (`created.data.metaSiteId`). Don't build the multipart body by hand — a missing
154
+ `\r\n` or a boundary mismatch is a bare `500` — and don't put file text inside
155
+ `code` as string literals: that second layer of escaping is what corrupts
156
+ backslashes and `${}`. Don't put image bytes in `code` either — they're a
157
+ `base64` entry in `files`. The one thing `files` cannot carry is a file with a
158
+ line that reads exactly `=== FILE: … ===`.
145
159
 
146
160
  `siteUrl` is the site's final address — it's already in the user's account. Give
147
161
  the user two links: `siteUrl`, and its dashboard at
@@ -169,24 +183,28 @@ unzip -o current.zip -d current # the site's files + wix.config.json
169
183
  ```
170
184
 
171
185
  In an `ExecuteWixAPI` script, request the same URL with `responseType: 'base64'`
172
- and read the zip in memory. Entries are stored (method 0) or deflated (method 8):
186
+ and unzip it in memory with `wix.unzip()`. Each entry is `{ path, bytes, text() }`:
187
+ `bytes` is the file as stored, `text()` decodes it when it's text. Don't decode
188
+ every entry — an image run through a text decoder is corrupted.
173
189
 
174
190
  ```javascript
175
191
  const r = await wix.request({ scope: 'account', method: 'GET', responseType: 'base64',
176
192
  url: `https://www.wix.com/_api/wixstro-deployments/v1/instant-sites/${metaSiteId}/download.zip` });
177
- const z = Uint8Array.from(atob(r.data), (c) => c.charCodeAt(0));
178
- const u16 = (o) => z[o] | (z[o + 1] << 8), u32 = (o) => (u16(o) | (u16(o + 2) << 16)) >>> 0;
179
- let e = z.length - 22; while (u32(e) !== 0x06054b50) e--; // end of central directory
180
- const files = {};
181
- for (let i = 0, p = u32(e + 16); i < u16(e + 10); i++) { // one central-directory entry each
182
- const name = new TextDecoder().decode(z.slice(p + 46, p + 46 + u16(p + 28)));
183
- const at = u32(p + 42), start = at + 30 + u16(at + 26) + u16(at + 28);
184
- const raw = z.slice(start, start + u32(p + 20));
185
- files[name] = u16(p + 10) === 0 ? new TextDecoder().decode(raw)
186
- : await new Response(new Blob([raw]).stream().pipeThrough(new DecompressionStream('deflate-raw'))).text();
187
- p += 46 + u16(p + 28) + u16(p + 30) + u16(p + 32);
188
- }
189
- // files: { 'index.html': '…', 'assets/styles.css': '…', 'wix.config.json': '…' }
193
+ const entries = await wix.unzip(r.data);
194
+ // entries: [{ path: 'index.html', bytes, text() }, { path: 'assets/logo.png', bytes, text() }, { path: 'wix.config.json', … }]
195
+ ```
196
+
197
+ Edit in memory — text through `text()`, binaries left as they are — then drop
198
+ the full set back in the same script, leaving `wix.config.json` out. Entries go
199
+ to `wix.multipart()` as they are; an edited file replaces its entry with
200
+ `{ path, content }`:
201
+
202
+ ```javascript
203
+ const edited = entries.filter((e) => e.path !== 'wix.config.json').map((e) =>
204
+ e.path === 'index.html' ? { path: e.path, content: e.text().replace('Northwind Studio', 'Northwind Studio — Est. 1998') } : e);
205
+ const mp = wix.multipart(edited);
206
+ await wix.request({ scope: 'account', method: 'POST', headers: { 'Content-Type': mp.contentType }, body: mp.body,
207
+ url: `https://www.wixapis.com/headless-business-setup/v1/headless-business/${metaSiteId}/drop` });
190
208
  ```
191
209
 
192
210
  The live URL itself (`*.wix-site-host.com`) can't be read from a script; this
@@ -219,7 +237,8 @@ Keep both: `metaSiteId` addresses the site, `projectId` builds the save link.
219
237
  ### 2. Upload the files
220
238
 
221
239
  Same multipart shape as the [drop](#2-drop-the-files--the-site-goes-live), to the
222
- upload path, with the attribution parameters:
240
+ upload path, with the attribution parameters (in a script: `wix.multipart()` with
241
+ the `files` param, posted to this URL):
223
242
 
224
243
  ```bash
225
244
  curl -sS -X POST \
@@ -323,7 +342,7 @@ Failures come back as HTTP 400 with a code in `details.applicationError.code`:
323
342
  - **`403 PERMISSION_DENIED` on a drop** — the token expired or is missing (see
324
343
  [Before the calls](#before-the-calls)), or the site isn't the caller's. A site
325
344
  that's still anonymous is changed by upload + release, not by a drop.
326
- - **`500` on a drop or upload** — the multipart body is malformed (see the shape
345
+ - **`500` on a drop or upload** — the multipart body was built by hand and is malformed (see the shape
327
346
  above). Rebuild it from the example; sending it again unchanged fails the
328
347
  same way.
329
348
  - **`404` on the anonymous route after step 1** — the hour passed or the site was
@@ -1624,7 +1624,7 @@ function normalizeV5Contact(contact = {}) {
1624
1624
  return normalized;
1625
1625
  }
1626
1626
  // Legacy V4-style `info` payloads (pre-GA generated transforms) convert through this
1627
- // STRICT whitelist: unknown keys throw instead of silently dropping source data.
1627
+ // STRICT allowlist: unknown keys throw instead of silently dropping source data.
1628
1628
  // `extendedFields` and `labelKeys` throw because they have no mechanical V5 equivalent —
1629
1629
  // V5 custom fields live under extendedFields.namespaces (Data Extension Schema) and
1630
1630
  // labels became tags (Tags API); both need a setup-time decision, not a converter guess.
@@ -326,7 +326,7 @@ async function enableOnlineReservations(ctx, reservationLocationId, revision) {
326
326
  }
327
327
 
328
328
  // ══ EXPERIENCES (setup-restaurant-experiences.md) ══════════════════════════════════════════════════
329
- // An experience is a reservation that IS a curated dining occasion (wine tasting, chef's table). Feature
329
+ // An experience is a reservation that IS a curated dining occasion (chef's table, tasting menu). Feature
330
330
  // of the Table Reservations app — no separate install. Created against a reservationLocationId (from
331
331
  // listReservationLocations). The full create payload lives in the live docs (fields evolve) — build each
332
332
  // `experience` from the Create-Experience doc; this only wires the loop. Set configuration.visible:true.