@wix/agent-skills 1.18.2 → 1.19.1
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 +1 -1
- package/skills/wix-app/SKILL.md +42 -40
- package/skills/wix-app/references/BACKEND_API.md +151 -152
- package/skills/wix-app/references/DASHBOARD_PAGE.md +6 -10
- package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +16 -7
- package/skills/wix-app/references/EXTENSION_REGISTRATION.md +12 -8
- package/skills/wix-app/references/WIX_PATTERNS_DOCS.md +53 -131
- package/skills/wix-app/references/dashboard-page/UX_SUCCESS_MODEL.md +1 -2
- package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +83 -73
- package/skills/wix-app/references/editor-react-component/COMPONENT-CONTRACT.md +3 -2
- package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +9 -0
- package/skills/wix-app/references/editor-react-component/PARTS.md +5 -2
- package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +1 -1
- package/skills/wix-app/scripts/pkg-root.cjs +73 -0
- package/skills/wix-app/scripts/scan-a11y-code.cjs +310 -40
- package/skills/wix-app/scripts/scan-a11y-eslint.cjs +118 -24
- package/skills/wix-app/scripts/scan-a11y-render.cjs +551 -0
- package/skills/wix-app/scripts/scan-a11y-review.cjs +373 -0
- package/skills/wix-base44-connector/SKILL.md +24 -22
- package/skills/wix-base44-connector/scripts/utils.cjs +39 -3
- package/skills/wix-docs/SKILL.md +47 -20
- package/skills/wix-headless/entry/bootstrap.mjs +106 -50
- package/skills/wix-headless/entry/skill.md +5 -3
- package/skills/wix-headless/references/managed/AUTHENTICATION.md +25 -5
- package/skills/wix-headless-fast/SKILL.md +25 -7
- package/skills/wix-headless-fast/entry/skill.md +23 -14
- package/skills/wix-headless-fast/install/fast-path.mjs +48 -5
- package/skills/wix-headless-fast/install/pin-agents-md.mjs +57 -0
- package/skills/wix-headless-fast/references/shared/CUSTOM_OPERATIONS.md +3 -3
- package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +204 -35
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +146 -36
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-store.ts +8 -2
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +95 -20
- package/skills/wix-headless-fast/references/storefront/seed/SEED.md +21 -2
- package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +104 -18
- package/skills/wix-manage/SKILL.md +14 -8
- package/skills/wix-manage/references/bookings/booking-service-policy-setup.md +59 -33
- package/skills/wix-manage/references/bookings/bookings-staff-setup.md +45 -22
- package/skills/wix-manage/references/bookings/multi-resource-service-creation.md +70 -12
- package/skills/wix-manage/references/calendar/configure-default-business-hours.md +53 -17
- package/skills/wix-manage/references/google-ads/billing-and-payment.md +3 -3
- package/skills/wix-manage/references/google-ads/create-performance-max-campaign.md +8 -8
- package/skills/wix-manage/references/google-ads/get-campaign-suggestions.md +4 -4
- package/skills/wix-manage/references/google-ads/google-ads-dashboard-navigation.md +1 -1
- package/skills/wix-manage/references/google-ads/install-and-create-account.md +9 -9
- package/skills/wix-manage/references/google-ads/query-campaign-analytics.md +7 -7
- package/skills/wix-manage/references/seo/manage-content-plan.md +181 -135
- package/skills/wix-manage/references/seo/manage-google-search-console.md +272 -0
- package/skills/wix-manage/references/sites/upload-static-site.md +53 -0
- package/skills/wix-manage/references/stores/change-store-currency.md +1 -1
- package/skills/wix-manage/references/stores/create-product-catalog-v3.md +17 -1
- package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed-with-install.md +12 -9
- package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed.md +12 -9
- package/skills/wix-vibe-headless/platforms/base44-ecom-light.md +1 -1
- package/skills/wix-vibe-headless/platforms/base44.md +11 -3
- package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +5 -1
- package/skills/wix-vibe-headless/references/storefront/seed/SEED.md +5 -4
- package/skills/wix-vibe-headless/references/storefront/seed/seed-store.cjs +33 -5
- package/skills/wix-app/references/dashboard-page/COLLECTION_TOOLKIT.md +0 -80
- package/skills/wix-app/references/dashboard-page/ENTITY_PAGE_TOOLKIT.md +0 -140
- package/skills/wix-app/references/dashboard-page/PATTERNS_BUNDLE_READING.md +0 -112
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductCard.tsx +0 -100
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductDetailView.tsx +0 -130
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductGrid.tsx +0 -48
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ShopView.tsx +0 -66
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/VariantPicker.tsx +0 -103
- package/skills/wix-headless-fast/references/storefront/app-astro/pages/products/[slug].astro +0 -56
- package/skills/wix-headless-fast/references/storefront/app-astro/pages/shop.astro +0 -23
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "Manage Google Search Console for a Wix Site"
|
|
3
|
+
description: "Connect a Wix site to Google Search Console and drive its setup through the public GSC Connection and Site Readiness APIs: check connection and readiness, start the Google authorization, verify ownership, add the property, submit the sitemap, request indexing, read search performance, run URL inspection, recover a stale connection, or disconnect. The site owner authorizes in their own browser via a single-use connect URL."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Manage Google Search Console for a Wix Site
|
|
7
|
+
|
|
8
|
+
The **GSC Connection API** links a Google account to the site. The **GSC Site
|
|
9
|
+
Readiness API** acts through that account: verifies ownership, adds the Search
|
|
10
|
+
Console property, submits the sitemap, requests indexing, reads search performance
|
|
11
|
+
and URL inspection. Both select the site from the caller's authorization context
|
|
12
|
+
and take no site ID. Use the site already selected in the environment. If none is
|
|
13
|
+
selected, list the available sites. Select the only site automatically; if several
|
|
14
|
+
are available, ask the user to choose by name before making site-specific calls.
|
|
15
|
+
Never invent a site ID or ask the user to type one.
|
|
16
|
+
|
|
17
|
+
All endpoints are under `https://www.wixapis.com`: Connection calls under
|
|
18
|
+
`/gsc/connection/v1`, everything else under `/gsc/v1`.
|
|
19
|
+
|
|
20
|
+
## Start every task with two reads
|
|
21
|
+
|
|
22
|
+
Both are side-effect free. Do them before describing the site's state.
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
GET https://www.wixapis.com/gsc/connection/v1/connection
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{ "connection": { "status": "VALID", "connectedEmailMasking": "m*******@gmail.com", "ownedByCaller": true } }
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
GET https://www.wixapis.com/gsc/v1/site-readiness
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{ "siteReadiness": { "status": "NOT_READY", "blockingReason": "SITE_OWNER_NOT_VERIFIED" } }
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Read them together:
|
|
41
|
+
|
|
42
|
+
| `connection.status` | `siteReadiness` | Meaning | Next |
|
|
43
|
+
|---|---|---|---|
|
|
44
|
+
| `NOT_CONNECTED` | `NOT_READY` / `SITE_OWNER_NOT_VERIFIED` | No Google account linked | Connect (below) |
|
|
45
|
+
| `PENDING` | any | An authorization attempt is open | Ask the user to finish it in their browser, do not start another |
|
|
46
|
+
| `VALID` | `READY` | Connected and verified | Property steps if the user wants them |
|
|
47
|
+
| `VALID` | `NOT_READY` / `SITE_OWNER_NOT_VERIFIED` | Connected, not verified | Verify Site |
|
|
48
|
+
| `INVALID` | `NOT_READY` / `TOKEN_INVALID` | Credentials rejected by Google | Reconnect |
|
|
49
|
+
| `VALID` | `NOT_READY` / `DOMAIN_MISSING` | No connected domain | User connects a domain first |
|
|
50
|
+
|
|
51
|
+
`blockingReason` is `UNKNOWN_BLOCKING_REASON` when the status is `READY`; not an
|
|
52
|
+
error. Treat an unrecognized reason as "not ready, no known next action".
|
|
53
|
+
|
|
54
|
+
`READY` covers connection and verification only. Whether the property was added,
|
|
55
|
+
the sitemap submitted, or indexing requested comes from **List Events**.
|
|
56
|
+
|
|
57
|
+
## `VALID` can be stale, and `MISSING_TOKEN` means reconnect
|
|
58
|
+
|
|
59
|
+
`INVALID` is only written when a real call to Google is rejected, so a site nobody
|
|
60
|
+
has queried since its credentials broke keeps reporting `VALID`. The tell arrives
|
|
61
|
+
on the first Google-facing call:
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{ "message": "FAILED_PRECONDITION: Missing Token", "details": { "applicationError": { "code": "MISSING_TOKEN" } } }
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The reference describes `MISSING_TOKEN` as "no Google account is connected"; it
|
|
68
|
+
also fires when the stored credentials are gone while Get Connection still said
|
|
69
|
+
`VALID`. Either way: the Google account must be reconnected. Do not retry, and do
|
|
70
|
+
not tell the user the site is connected.
|
|
71
|
+
|
|
72
|
+
## Connect a Google account
|
|
73
|
+
|
|
74
|
+
Get Connect URL is `GET`, but it **writes**: every call starts a new single-use
|
|
75
|
+
authorization attempt (two-hour expiry) and Get Connection reports `PENDING` while
|
|
76
|
+
it is open. Use Get Connection to check connection status. Call Get Connect URL
|
|
77
|
+
when starting a connection or reconnection attempt; while the user completes that
|
|
78
|
+
attempt, use Get Connection for status checks. Request a new URL when a new attempt
|
|
79
|
+
is needed, such as after expiry. On an already-connected site it is allowed: the
|
|
80
|
+
same Google account refreshes the credentials, a different one replaces the
|
|
81
|
+
connection. Say which before you do it.
|
|
82
|
+
|
|
83
|
+
1. Read Get Connection. If `VALID`, stop unless the user wants to reconnect.
|
|
84
|
+
2. Call [Get Connect URL](https://dev.wix.com/docs/api-reference/business-management/seo/google-search-console/connection-v1/get-connect-url). The request takes no parameters or body.
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
GET https://www.wixapis.com/gsc/connection/v1/connect-url
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{ "connectUrl": "https://accounts.google.com/o/oauth2/v2/auth?client_id=407408718192.apps.googleusercontent.com&redirect_uri=https%3A%2F%2Fwww.wixapis.com%2Fgsc%2Fconnection%2Fv1%2Fconnect-callback&response_type=code&scope=openid%20email%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fwebmasters&state=EXAMPLE_STATE" }
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The response above is illustrative. Wix generates the authorization URL,
|
|
95
|
+
including its OAuth query parameters. Give the user the exact returned
|
|
96
|
+
`connectUrl`; do not construct, modify, or reuse the example URL.
|
|
97
|
+
|
|
98
|
+
3. Give the URL to the user and ask them to tell you when they have finished. Wix
|
|
99
|
+
completes the exchange server-side; there is no code to send back.
|
|
100
|
+
4. When the user says they are done, read Get Connection once and confirm `VALID`.
|
|
101
|
+
Do not poll while waiting. If it is still `PENDING`, the user has not finished;
|
|
102
|
+
if the attempt expired (two hours), request a fresh URL only after they agree.
|
|
103
|
+
|
|
104
|
+
## Writes need a published, indexable site with a connected domain
|
|
105
|
+
|
|
106
|
+
Get Connect URL, Verify Site, Add Site, and Submit Sitemap fail with
|
|
107
|
+
`FAILED_PRECONDITION` until the site is published, has a connected (premium)
|
|
108
|
+
domain, and allows indexing. The code names the first failing check:
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{ "message": "FAILED_PRECONDITION: The site has no connected domain. Connect a domain before connecting the site to Google Search Console",
|
|
112
|
+
"details": { "applicationError": { "code": "DOMAIN_NOT_CONNECTED" } } }
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Codes: `SITE_NOT_PUBLISHED`, `DOMAIN_NOT_CONNECTED`, `SITE_NOT_INDEXABLE`. A free
|
|
116
|
+
site on a `wixsite.com` address cannot complete these writes. Report the missing
|
|
117
|
+
prerequisite and stop. When listing sites to find one that qualifies, filter for
|
|
118
|
+
premium sites with a connected domain.
|
|
119
|
+
|
|
120
|
+
## Set the site up in Search Console
|
|
121
|
+
|
|
122
|
+
Run the steps the user asked for, in this order, confirming before each write.
|
|
123
|
+
Bodies are empty unless shown.
|
|
124
|
+
|
|
125
|
+
| Step | Call | Notes |
|
|
126
|
+
|---|---|---|
|
|
127
|
+
| Verify ownership | `POST /gsc/v1/verify-site` with `{ "method": "META" }` | Synchronous against Google, allow up to 60 s. Idempotent. Wix already places the meta tag. |
|
|
128
|
+
| Add the property | `POST /gsc/v1/add-site` | Requires a verified site. |
|
|
129
|
+
| Submit the sitemap | `POST /gsc/v1/submit-sitemap` | Wix hosts and generates the sitemap. Google processes it asynchronously. |
|
|
130
|
+
| Request indexing | `POST /gsc/v1/request-site-indexing` | Success means Google accepted the request, not that the site is indexed. |
|
|
131
|
+
| Request one page | `POST /gsc/v1/request-page-indexing` with `{ "url": "https://www.example.com/about" }` | Full URL of a page on this site. |
|
|
132
|
+
|
|
133
|
+
All succeed with `{}`. Re-read Get Site Readiness after each step and act on the
|
|
134
|
+
current `blockingReason`. Verify Site on an already-verified site returns `{}` and
|
|
135
|
+
re-stamps the `SITE_VERIFIED` event date: safe, but not a change to report.
|
|
136
|
+
|
|
137
|
+
Two Google-side failures are retryable. `RESOURCE_EXHAUSTED` (`GOOGLE_QUOTA_EXCEEDED`):
|
|
138
|
+
the quota is daily, tell the user to retry tomorrow. `UNAVAILABLE`
|
|
139
|
+
(`GOOGLE_UNAVAILABLE`): retry once after a few seconds. On any other error your next
|
|
140
|
+
message is the final response: name the step that failed and the error code, and
|
|
141
|
+
make no further Search Console calls.
|
|
142
|
+
|
|
143
|
+
## Check what was done: List Events and List Sitemaps
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
GET https://www.wixapis.com/gsc/v1/events
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
```json
|
|
150
|
+
{ "events": [
|
|
151
|
+
{ "eventType": "ACCOUNT_CONNECTED", "occurredDate": "2025-10-29T11:10:15.869Z" },
|
|
152
|
+
{ "eventType": "SITE_VERIFIED", "occurredDate": "2026-09-07T11:39:31.992Z" },
|
|
153
|
+
{ "eventType": "SITE_ADDED", "occurredDate": "2025-10-29T11:07:39.050Z" } ] }
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
One entry per event type with the date it **last** occurred, **not sorted by
|
|
157
|
+
date**: never read the last entry as the latest event. Types: `ACCOUNT_CONNECTED`,
|
|
158
|
+
`SITE_VERIFIED`, `SITE_ADDED`, `SITEMAP_SUBMITTED`, `SITE_INDEXING_REQUESTED`,
|
|
159
|
+
`PAGE_INDEXING_REQUESTED`. A missing type means that step never happened.
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
GET https://www.wixapis.com/gsc/v1/sitemaps
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
{ "sitemaps": [ { "url": "https://www.example.com/blog-posts-sitemap.xml", "type": "sitemap", "pending": false,
|
|
167
|
+
"lastDownloadedDate": "2026-09-05T15:14:47.210Z", "errorCount": "0", "warningCount": "0",
|
|
168
|
+
"contents": [ { "type": "web", "submittedCount": "1", "indexedCount": "1" } ] } ] }
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Wix submits several sitemaps, typically one per content type. `pending: true` with
|
|
172
|
+
an empty `type` means Google has not processed it yet. Counts are strings.
|
|
173
|
+
|
|
174
|
+
## Read search performance
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
GET https://www.wixapis.com/gsc/v1/search-analytics?startDate=2026-08-01&endDate=2026-08-31&dimensions=query&rowLimit=5
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
```json
|
|
181
|
+
{ "results": [ { "keys": ["best of santorini"], "clicks": 0, "impressions": 3, "ctr": 0, "position": 36 } ] }
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
- `startDate` and `endDate` are required, `YYYY-MM-DD`, end inclusive.
|
|
185
|
+
- `dimensions` repeats: `date`, `query`, `page`, `country`, `device`,
|
|
186
|
+
`searchAppearance`; omit for one aggregate row. `keys` follow your order.
|
|
187
|
+
- `type`: `web` (default), `image`, `video`, `news`. Page with `rowLimit`/`startRow`.
|
|
188
|
+
- It is Google's own report: the latest days are usually missing, and there is no
|
|
189
|
+
history from before the property was added. Empty `results` is a real answer.
|
|
190
|
+
|
|
191
|
+
## Inspect pages
|
|
192
|
+
|
|
193
|
+
Page IDs are Wix static-page IDs, not URLs. Discover them with
|
|
194
|
+
[List Item SEO Tags](https://dev.wix.com/docs/api-reference/business-management/seo/item-seo-tags-v1/list-item-seo-tags)
|
|
195
|
+
for `STATIC_PAGE`. The request has no body:
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
GET https://www.wixapis.com/promote/seo/v1/item-seo-tags/STATIC_PAGE
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Relevant response fields (unrelated SEO fields omitted; IDs are illustrative):
|
|
202
|
+
|
|
203
|
+
```json
|
|
204
|
+
{ "itemSeoTags": [ { "id": "STATIC_PAGE:c1dmp", "itemType": "STATIC_PAGE", "itemId": "c1dmp" } ],
|
|
205
|
+
"pagingMetadata": { "count": 1, "hasNext": false, "cursors": {} } }
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
If `pagingMetadata.hasNext` is `true`, pass `pagingMetadata.cursors.next` back as
|
|
209
|
+
`paging.cursor` in the next request's query string, URL-encoded. Continue until
|
|
210
|
+
`hasNext` is `false`. The optional `paging.limit` controls the page size; omit the
|
|
211
|
+
cursor on the first request. Treat cursors as opaque.
|
|
212
|
+
|
|
213
|
+
Use each selected entry's `itemId` as a `pageIds` entry for Inspect URLs. Do not
|
|
214
|
+
use the composite `id` (`STATIC_PAGE:c1dmp`) or a page URL, and never invent an ID.
|
|
215
|
+
The example below assumes discovery returned `c1dmp` for the selected page.
|
|
216
|
+
|
|
217
|
+
```
|
|
218
|
+
POST https://www.wixapis.com/gsc/v1/inspect-urls
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
```json
|
|
222
|
+
{ "pageIds": ["c1dmp"], "updateResults": true }
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
```json
|
|
226
|
+
{ "results": [ { "page": { "pageId": "c1dmp", "name": "Home", "path": "/", "itemType": "STATIC_PAGE" },
|
|
227
|
+
"status": "OK", "createdDate": "2026-09-07T12:09:55.301Z",
|
|
228
|
+
"data": { "inspectionResultLink": "https://search.google.com/search-console/inspect?resource_id=https%3A%2F%2Fwww.example.com%2F&id=EXAMPLE_INSPECTION_ID",
|
|
229
|
+
"indexStatusResult": { "verdict": "PASS", "coverageState": "Submitted and indexed",
|
|
230
|
+
"indexingState": "INDEXING_ALLOWED", "lastCrawlTime": "2026-08-16T11:39:45Z",
|
|
231
|
+
"googleCanonical": "https://www.example.com/", "userCanonical": "https://www.example.com/" } } } ],
|
|
232
|
+
"status": "COMPLETE", "remainingPageCount": 0 }
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
- `data.inspectionResultLink` is returned by Google. The complete URL above is
|
|
236
|
+
illustrative; use the actual returned link unchanged, including its query
|
|
237
|
+
parameters. Do not construct a link from the example values.
|
|
238
|
+
- Each page spends one unit of the account's Google quota (2,000 per property per
|
|
239
|
+
day): confirm the page list first. Sites over 2,000 pages fail with
|
|
240
|
+
`SITE_EXCEEDS_INSPECTION_LIMIT`.
|
|
241
|
+
- The site stores **one** inspection; without `updateResults: true` a new call
|
|
242
|
+
replaces it. Prefer `true` unless the user wants a clean run.
|
|
243
|
+
- `ONGOING`: poll `GET https://www.wixapis.com/gsc/v1/inspection` every few
|
|
244
|
+
seconds until `COMPLETE` or `ERROR` (same shape plus `updatedDate`).
|
|
245
|
+
- `remainingPageCount > 0` on `COMPLETE` means quota ran out. Name the missing
|
|
246
|
+
pages; do not call it done.
|
|
247
|
+
- `data` is Google's raw URL Inspection payload: read `indexStatusResult.verdict`
|
|
248
|
+
(`PASS`, `PARTIAL`, `FAIL`, `NEUTRAL`) and `coverageState`; text is English only.
|
|
249
|
+
`UNKNOWN_INSPECTION_STATUS` with empty `results` means never inspected.
|
|
250
|
+
|
|
251
|
+
## Disconnect and clear
|
|
252
|
+
|
|
253
|
+
Two different removals; confirm which one the user wants.
|
|
254
|
+
|
|
255
|
+
| Call | Removes | Keeps |
|
|
256
|
+
|---|---|---|
|
|
257
|
+
| `POST /gsc/connection/v1/disconnect` | Stored Google credentials | Verification tag, Search Console property |
|
|
258
|
+
| `POST /gsc/v1/clear-verification` | Verification tag, verification state, **and** credentials | Search Console property |
|
|
259
|
+
|
|
260
|
+
Neither removes the site from Search Console or revokes Wix's access on Google's
|
|
261
|
+
side. Disconnect with no stored credentials returns `NOT_FOUND`
|
|
262
|
+
(`CONNECTION_NOT_FOUND`).
|
|
263
|
+
|
|
264
|
+
## When a call fails
|
|
265
|
+
|
|
266
|
+
- `403` or `PERMISSION_DENIED`: stop after the first and report the missing SEO
|
|
267
|
+
permission (reads need view access to SEO settings, writes need manage access).
|
|
268
|
+
Do not try another site, path, or method.
|
|
269
|
+
- `FAILED_PRECONDITION`: act on `details.applicationError.code` as above. Do not
|
|
270
|
+
retry the same call.
|
|
271
|
+
- Get Connect URL is a recovery step only for `MISSING_TOKEN`, `INVALID`, or
|
|
272
|
+
`TOKEN_INVALID`, and only after the user agrees to reconnect.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "Upload a Website or HTML Files"
|
|
3
|
+
description: Get a user's ready-made website live on Wix when they already have the site files — an index.html, a zip, or a static build exported from an AI builder or any other tool — by sending them to the Wix Headless drop page, where they upload the files and instantly get a live hosted site they can claim into their account. Use whenever the user wants to upload, publish, or host their own HTML/CSS/JS files as a NEW site. 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.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Upload a Website or HTML Files
|
|
7
|
+
|
|
8
|
+
The user already has a finished website as files — hand-written HTML, a zip
|
|
9
|
+
export, or the output of an AI site builder — and wants it live on Wix as a
|
|
10
|
+
new site. There is no API call to make. Send them to the upload page and
|
|
11
|
+
explain the flow:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
https://www.wix.com/headless/drop?utm_campaign=mcp
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**Always give the URL exactly as written above, including the
|
|
18
|
+
`utm_campaign=mcp` query parameter.** It attributes the visit to an
|
|
19
|
+
assistant/MCP referral; dropping or rewriting it breaks that attribution.
|
|
20
|
+
|
|
21
|
+
## What happens on that page
|
|
22
|
+
|
|
23
|
+
1. The user drags in their files (or a zip) — no login needed.
|
|
24
|
+
2. Wix hosts them immediately on a live URL they can open and share.
|
|
25
|
+
|
|
26
|
+
## Tell the user before they upload
|
|
27
|
+
|
|
28
|
+
Share the requirements that match their situation — these are the common
|
|
29
|
+
reasons an upload fails:
|
|
30
|
+
|
|
31
|
+
- The upload must contain an **HTML file at the top level of the site's
|
|
32
|
+
files**. It does not need to be named `index.html` — a single HTML file of
|
|
33
|
+
any name is served as the homepage — and a zip or folder that wraps
|
|
34
|
+
everything in one top-level folder (e.g. `my-site/index.html`) is unwrapped
|
|
35
|
+
automatically.
|
|
36
|
+
- Size limits: **3 MB per file, 20 MB total.**
|
|
37
|
+
- **Static files only** — HTML, CSS, JavaScript, and assets. If the user has
|
|
38
|
+
framework source code that needs a build step (a `package.json`, React/Vue
|
|
39
|
+
source, etc.), they must run their build first and upload the build output
|
|
40
|
+
folder's contents, not the source.
|
|
41
|
+
|
|
42
|
+
## Route the request correctly
|
|
43
|
+
|
|
44
|
+
| The user has… | Do this |
|
|
45
|
+
|---|---|
|
|
46
|
+
| Site files on their machine (HTML/zip/AI-builder export), wants a new site | This recipe — send them to the drop URL above |
|
|
47
|
+
| A live site or store on another platform (a URL), or CSV/TSV exports, and wants content/products migrated | [Site Import](site-import.md) |
|
|
48
|
+
| An existing Wix site they want to add HTML, an embed, or custom code into | Not this recipe — that's embedding custom code in the site editor |
|
|
49
|
+
| Images, videos, or documents to add to a site | [Upload Media to Wix](../media/upload-media-to-wix.md) — media goes to the site's media files, not a new site |
|
|
50
|
+
|
|
51
|
+
Do not try to perform the upload for the user through an API, and do not
|
|
52
|
+
create a site for them with other site-creation tools instead — the drop page
|
|
53
|
+
is the flow.
|
|
@@ -5,6 +5,6 @@ description: "Changes the store's payment currency through Site Properties and e
|
|
|
5
5
|
|
|
6
6
|
# Change Store Currency
|
|
7
7
|
|
|
8
|
-
Use the [Site Properties
|
|
8
|
+
Use the [Change a Site's Regional Properties (Currency, Time Zone, Language) via Site Properties API](../site-properties/change-payment-currency-site-properties.md) recipe to set the requested payment currency and read it back. Confirm the change with the user before updating it.
|
|
9
9
|
|
|
10
10
|
Catalog product responses may temporarily show the previous currency after carts and checkout use the new one. Allow time for propagation, then recheck.
|
|
@@ -83,9 +83,22 @@ If any product is missing a price, **do not call the API**. Ask for the missing
|
|
|
83
83
|
|
|
84
84
|
## Build each product
|
|
85
85
|
|
|
86
|
+
> [!WARNING]
|
|
87
|
+
> **Hard requirement before every create call:** If `productType` is `"PHYSICAL"`, the request MUST include `physicalProperties` on the product and on every variant:
|
|
88
|
+
>
|
|
89
|
+
> ```json
|
|
90
|
+
> {
|
|
91
|
+
> "productType": "PHYSICAL",
|
|
92
|
+
> "physicalProperties": {},
|
|
93
|
+
> "variantsInfo": {"variants": [{"physicalProperties": {}}]}
|
|
94
|
+
> }
|
|
95
|
+
> ```
|
|
96
|
+
>
|
|
97
|
+
> Put supplied physical fields such as weight or dimensions inside those objects; use `{}` when none were supplied. Never invent them, and never execute or retry a physical-product request when either object is absent.
|
|
98
|
+
|
|
86
99
|
| Concern | Rule |
|
|
87
100
|
|---|---|
|
|
88
|
-
| Type | `PHYSICAL`
|
|
101
|
+
| Type | `PHYSICAL` requires both `productType: "PHYSICAL"` and product-level `physicalProperties`, plus both `productType: "PHYSICAL"` and variant-level `physicalProperties` on every variant. `DIGITAL` omits physical properties and carries `inventoryItem.inStock` plus `digitalProperties.digitalFile` on each variant. |
|
|
89
102
|
| Variants | Include at least one. Price, SKU, barcode, inventory, and digital file are variant-level fields. |
|
|
90
103
|
| Price | Use a string in `price.actualPrice.amount`; add `compareAtPrice` only when supplied. |
|
|
91
104
|
| SKU | Preserve supplied strings exactly, including `#`, punctuation, and leading zeroes. Keep variant SKUs unique unless explicitly requested otherwise. |
|
|
@@ -221,6 +234,8 @@ The first is for single endpoints; the second is for bulk endpoints. If the user
|
|
|
221
234
|
|
|
222
235
|
For one product when the user supplied no quantity, stock state, or inventory-tracking request, the complete direct path is `POST /stores/v3/products` with `{"product": PRODUCT}`. Do not infer `inStock: true`, add `inventoryItem`, or choose `/products-with-inventory`; physical product type does not imply inventory. If it has ready images, add `"fields": ["MEDIA_ITEMS_INFO"]` to the same no-inventory request.
|
|
223
236
|
|
|
237
|
+
For a physical product on either create endpoint, never send `productType: "PHYSICAL"` by itself. Include `physicalProperties: {}` on the product and `physicalProperties: {}` on every physical variant (or populate those objects with the supplied physical dimensions/weight). The API validates these as aligned one-of pairs and returns 400 if either corresponding field is missing.
|
|
238
|
+
|
|
224
239
|
For one physical product with inventory, the complete direct path is one `POST /stores/v3/products-with-inventory` call with `{"product": PRODUCT}`. Put `inventoryItem` on its priced variant. If it has ready images, add `"fields": ["MEDIA_ITEMS_INFO"]` to that same request. The product shape, envelope, endpoint, and validation paths are complete here: do not search another recipe or schema, probe an alternate endpoint, or make a post-create read unless the projected create response does not prove requested media.
|
|
225
240
|
|
|
226
241
|
### Request projected media when validating images
|
|
@@ -300,4 +315,5 @@ Retry only failed transient items, not successful products. If a requested field
|
|
|
300
315
|
- `variantsInfo must not be empty`: include at least one priced variant per product.
|
|
301
316
|
- Option/variant mismatch: create every requested combination and reference every option once per variant.
|
|
302
317
|
- Media not visible: use the uploaded `wixstatic.com` URL in `media.itemsInfo.items`; do not set `media.main`.
|
|
318
|
+
- `productType` alignment 400 (`product is invalid: productType and the corresponding physical_properties field must be passed together`): pair `productType: "PHYSICAL"` with `physicalProperties` on the product and on every physical variant. The API validates these as aligned one-of pairs, so do not retry with only one level populated. Pair `productType: "DIGITAL"` with the digital variant fields instead.
|
|
303
319
|
- Digital product rejected at add-to-cart: `ITEM_NOT_FOUND_IN_CATALOG` means the variant has no `digitalProperties.digitalFile`; `exceeds available inventory` means it has no `inventoryItem.inStock`. Both read back as a healthy product.
|
|
@@ -11,7 +11,8 @@ or configuration changes are needed.
|
|
|
11
11
|
**Banner disabled for this entry flow:** do not add `<WixManageBanner/>`; skip the shared
|
|
12
12
|
storefront instructions' optional banner integration.
|
|
13
13
|
|
|
14
|
-
Follow STEPs 1–4 below exactly
|
|
14
|
+
Follow STEPs 1–4 below exactly. Fire product image generations first, then build the client
|
|
15
|
+
(STEP 2), and seed (STEP 3) **after** the client is built — generation finishes while you build.
|
|
15
16
|
|
|
16
17
|
## STEP 1 — Install the Wix skills and deploy the storefront vertical to the app
|
|
17
18
|
|
|
@@ -89,17 +90,19 @@ Inline via exec_tool, `base44` is already declared — use it directly; do **not
|
|
|
89
90
|
`@base44/sdk`, re-declare it, or call `createClient()` (that's for standalone `.js` files only;
|
|
90
91
|
inline it throws *"Identifier 'base44' has already been declared."*).
|
|
91
92
|
|
|
92
|
-
**Product images.**
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
from the
|
|
97
|
-
call
|
|
98
|
-
|
|
93
|
+
**Product images.** Fire every `generate_image` **before you build the client**, and seed **after**
|
|
94
|
+
it — generation finishes while you build, so by the time you write the seed call your images are
|
|
95
|
+
ready: each finished result now reads `status: "completed"` with its final
|
|
96
|
+
`https://media.base44.com/...` url. Read every `imageUrl` from the results **as they read at that
|
|
97
|
+
moment** — not from what they said when you called the tool — and pass them in the single
|
|
98
|
+
`setupStore` call. A result without a final url by then (still running, or failed) → seed that
|
|
99
|
+
product **without** `imageUrl` and attach it afterwards with `attachProductImages`.
|
|
99
100
|
|
|
100
101
|
## STEP 4 — Wrap up
|
|
101
102
|
|
|
102
|
-
###
|
|
103
|
+
### Verify
|
|
104
|
+
|
|
105
|
+
Verify **once, after the seed** — home, shop, and a product page against the populated catalog.
|
|
103
106
|
|
|
104
107
|
Images that are still generating may show `/__generating__/…` placeholders;
|
|
105
108
|
the platform replaces these automatically at turn end, with a stock fallback if generation
|
|
@@ -24,7 +24,8 @@ No installation, deployment, or AGENTS.md update is needed.
|
|
|
24
24
|
The deployed implementation and configuration files do not need to be read; use the build and seed
|
|
25
25
|
guides below for their contracts and usage. Continue with STEP 1.
|
|
26
26
|
|
|
27
|
-
Follow STEPs 1–3 below exactly
|
|
27
|
+
Follow STEPs 1–3 below exactly. Fire product image generations first, then build the client
|
|
28
|
+
(STEP 1), and seed (STEP 2) **after** the client is built — generation finishes while you build.
|
|
28
29
|
|
|
29
30
|
## STEP 1 — Build the client
|
|
30
31
|
|
|
@@ -74,17 +75,19 @@ Inline via exec_tool, `base44` is already declared — use it directly; do **not
|
|
|
74
75
|
`@base44/sdk`, re-declare it, or call `createClient()` (that's for standalone `.js` files only;
|
|
75
76
|
inline it throws *"Identifier 'base44' has already been declared."*).
|
|
76
77
|
|
|
77
|
-
**Product images.**
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
from the
|
|
82
|
-
call
|
|
83
|
-
|
|
78
|
+
**Product images.** Fire every `generate_image` **before you build the client**, and seed **after**
|
|
79
|
+
it — generation finishes while you build, so by the time you write the seed call your images are
|
|
80
|
+
ready: each finished result now reads `status: "completed"` with its final
|
|
81
|
+
`https://media.base44.com/...` url. Read every `imageUrl` from the results **as they read at that
|
|
82
|
+
moment** — not from what they said when you called the tool — and pass them in the single
|
|
83
|
+
`setupStore` call. A result without a final url by then (still running, or failed) → seed that
|
|
84
|
+
product **without** `imageUrl` and attach it afterwards with `attachProductImages`.
|
|
84
85
|
|
|
85
86
|
## STEP 3 — Wrap up
|
|
86
87
|
|
|
87
|
-
###
|
|
88
|
+
### Verify
|
|
89
|
+
|
|
90
|
+
Verify **once, after the seed** — home, shop, and a product page against the populated catalog.
|
|
88
91
|
|
|
89
92
|
Images that are still generating may show `/__generating__/…` placeholders;
|
|
90
93
|
the platform replaces these automatically at turn end, with a stock fallback if generation
|
|
@@ -62,7 +62,7 @@ need to diagnose and fix it.
|
|
|
62
62
|
|
|
63
63
|
**No seeding in this flow** — the client is the only deliverable. Do not seed, populate, or write data to Wix.
|
|
64
64
|
|
|
65
|
-
###
|
|
65
|
+
### Verify
|
|
66
66
|
|
|
67
67
|
Images that are still generating may show `/__generating__/…` placeholders;
|
|
68
68
|
the platform replaces these automatically at turn end, with a stock fallback if generation
|
|
@@ -11,7 +11,8 @@ only), safe in the frontend; use it directly for the Wix client setup.
|
|
|
11
11
|
**Banner enabled for this entry flow:** mount `<WixManageBanner/>` once in the Layout, above
|
|
12
12
|
the header in the fixed top region, per the vertical instructions. It is preview-only.
|
|
13
13
|
|
|
14
|
-
Follow STEPs 1–5 below exactly (run STEP 4 in parallel with STEP 3 — **except `forms`**, see
|
|
14
|
+
Follow STEPs 1–5 below exactly (run STEP 4 in parallel with STEP 3 — **except `forms`**, see
|
|
15
|
+
STEP 3, and **except a seed that attaches entity images**, which runs after the build; see STEP 4).
|
|
15
16
|
|
|
16
17
|
## STEP 1 — Install the Wix skills locally
|
|
17
18
|
|
|
@@ -98,8 +99,15 @@ rejects the write. Wire routes/imports in with `find_replace`, leave the rest as
|
|
|
98
99
|
|
|
99
100
|
Seed by calling your vertical's ready-made seed module — read
|
|
100
101
|
`.agents/skills/wix-vibe-headless/references/<vertical>/seed/SEED.md` and follow it (the loader
|
|
101
|
-
snippet, admin connector token,
|
|
102
|
-
|
|
102
|
+
snippet, admin connector token, and every field shape are there). Gaps or an unexpected shape → the
|
|
103
|
+
documentation skill available in your environment.
|
|
104
|
+
|
|
105
|
+
**Entity images:** fire every image generation **before you build the client**, and run an
|
|
106
|
+
image-carrying seed **after** the build — generation finishes while you build, and each finished
|
|
107
|
+
result then reads `status: "completed"` with its final `https://media.base44.com/...` url. Read
|
|
108
|
+
every image url from the results **as they read at that moment**, not from what they said when you
|
|
109
|
+
called the tool. No final url by then (still running, or failed) → seed without that image and
|
|
110
|
+
attach it afterwards per the vertical's `SEED.md`.
|
|
103
111
|
Seeding is **admin-only** — not part of the client, which is built solely per the `wix-vibe-headless` skill.
|
|
104
112
|
|
|
105
113
|
- **Additive only:** never delete or overwrite the user's content, even apparent sample data; ask first if a cleanup truly seems needed.
|
|
@@ -9,7 +9,7 @@ or configuration changes are needed to build the UI. Never mock products or hand
|
|
|
9
9
|
`/checkout` URL; the shipped cart uses the eCom redirect session.
|
|
10
10
|
|
|
11
11
|
## Prerequisites
|
|
12
|
-
- The site's **Wix Stores** catalog is the read/cart target. It
|
|
12
|
+
- The site's **Wix Stores** catalog is the read/cart target. It may be empty while the client is being built — render the empty state cleanly. Flows that seed do so after the client is built; verify the storefront once the catalog is populated, not against the empty state.
|
|
13
13
|
|
|
14
14
|
## Already installed in `src/`
|
|
15
15
|
Successful deployment verified these files are in place; use this map without needing to read their source (`@/` → `src/`).
|
|
@@ -336,6 +336,10 @@ wire these exactly as shown below.
|
|
|
336
336
|
When adding storefront routes and providers to `src/App.jsx`, preserve the existing platform
|
|
337
337
|
authentication setup, including `AuthProvider`, `useAuth`, and their `@/lib/AuthContext` imports.
|
|
338
338
|
Do not remove or replace that authentication logic.
|
|
339
|
+
The shipped commerce flow needs no login: shoppers browse, cart, and check out on the Wix visitor
|
|
340
|
+
session, which is separate from platform user auth. Whether the storefront is public or members-only
|
|
341
|
+
is the brief's call — default to public, and gate routes behind platform auth only when the brief
|
|
342
|
+
asks for it. Neither choice affects the commerce flow.
|
|
339
343
|
- Wrap the routed tree in `<CartProvider>` (from `@/context/CartContext`).
|
|
340
344
|
- Put your **header + footer in a `Layout`** that renders `<Outlet/>` between them, and nest every
|
|
341
345
|
route under one pathless `<Route element={<Layout/>}>`. Your brand chrome then wraps **every** page
|
|
@@ -19,9 +19,7 @@ const ctx = { token: accessToken };
|
|
|
19
19
|
// ONE call: install (+ wait for V3) → create products → categories → attach images, ids kept
|
|
20
20
|
// in memory (no hand-threading). Categories map name -> product NAMES. Pass an imageUrl per product
|
|
21
21
|
// to attach its image; omit it to skip images.
|
|
22
|
-
// imageUrl
|
|
23
|
-
// result — not a still-generating /__generating__/<id>.png placeholder (Wix can't fetch that).
|
|
24
|
-
// generate_image runs in the background while you build, so the urls are ready by seed time.
|
|
22
|
+
// imageUrl: a public, fetchable https:// url — Wix copies the image bytes at attach time.
|
|
25
23
|
const result = await seed.setupStore(ctx, {
|
|
26
24
|
currency: "EUR", // Pass only if the user asked for a currency or it's obvious for the store; else omit this line.
|
|
27
25
|
products: [
|
|
@@ -38,6 +36,8 @@ const result = await seed.setupStore(ctx, {
|
|
|
38
36
|
categories: { "Legends": ["The Glam Rocker"], "Rising Stars": [] }, // omit if the brief names none
|
|
39
37
|
});
|
|
40
38
|
// result: { products:[{id,slug,revision,name}], categories:[{id,name}], imagesAttached,
|
|
39
|
+
// imagesSkipped (product names whose imageUrl was not an absolute https:// url — attach those afterwards),
|
|
40
|
+
// productsWithoutImages (product names seeded with no imageUrl — attach afterwards once urls exist),
|
|
41
41
|
// currency: { requested, actual, status, warnings } }
|
|
42
42
|
```
|
|
43
43
|
|
|
@@ -112,6 +112,8 @@ enrolls in — is **Pricing Plans**, not a Stores product, so it isn't seeded he
|
|
|
112
112
|
download — uploaded and created with both the file and stock, which is what the cart requires
|
|
113
113
|
(`quantity` is ignored). It's also the only way in: a file-less digital product is created
|
|
114
114
|
successfully, reads back healthy, and is then rejected at add-to-cart as `ITEM_NOT_FOUND_IN_CATALOG`.
|
|
115
|
+
No real, fetchable file in hand → seed the product as **physical** with `inStock: true` and tell the
|
|
116
|
+
user; swap it to a digital download once a real file exists.
|
|
115
117
|
|
|
116
118
|
Two things this module does **not** seed, so don't try:
|
|
117
119
|
|
|
@@ -138,7 +140,6 @@ const products = await seed.bulkCreateProducts(ctx, [ // → [{i
|
|
|
138
140
|
]);
|
|
139
141
|
const cats = await seed.createCategories(ctx, ["Legends"]); // sequential → [{id,name}]
|
|
140
142
|
await seed.addProductsToCategories(ctx, { [cats[0].id]: [products[0].id] });
|
|
141
|
-
// images: use the FINAL https://media.base44.com/... url only (never a /__generating__/ placeholder)
|
|
142
143
|
await seed.attachProductImages(ctx, products.map((p, i) => ({ id: p.id, url: imageUrls[i], altText: p.slug })));
|
|
143
144
|
```
|
|
144
145
|
|
|
@@ -257,7 +257,8 @@ async function uploadDigitalFile(ctx, url, fileName) {
|
|
|
257
257
|
if (!mimeType) throw new Error(`digitalFileName needs one of these extensions (${Object.keys(FILE_MIME).join(", ")}): ${fileName}`);
|
|
258
258
|
const { uploadUrl } = await req(ctx, "/site-media/v1/files/generate-upload-url", { body: { mimeType, fileName } });
|
|
259
259
|
const src = await fetch(url);
|
|
260
|
-
if (!src.ok) throw new Error(`digitalFileUrl ${url} -> ${src.status}`
|
|
260
|
+
if (!src.ok) throw new Error(`digitalFileUrl ${url} -> ${src.status}. A digital product needs a real, ` +
|
|
261
|
+
`fetchable file — with none at hand, seed this product as physical with inStock: true and tell the user.`);
|
|
261
262
|
const res = await fetch(uploadUrl, {
|
|
262
263
|
method: "PUT", headers: { "Content-Type": mimeType }, body: Buffer.from(await src.arrayBuffer()),
|
|
263
264
|
});
|
|
@@ -416,9 +417,17 @@ async function addProductsToCategories(ctx, mapping) {
|
|
|
416
417
|
// caller never manages a revision token — attach any number of times, in any pass. Wix re-hosts the
|
|
417
418
|
// image from the url server-side; the re-hosted media can take a little while to appear on read-back
|
|
418
419
|
// (propagation) — that's normal, not a failure, so we don't block on it.
|
|
420
|
+
// Wix imports the image bytes server-side, so an attach needs an absolute, publicly fetchable url.
|
|
421
|
+
const isFetchableImageUrl = (url) => typeof url === "string" && /^https:\/\//.test(url);
|
|
422
|
+
|
|
419
423
|
async function attachProductImages(ctx, items) {
|
|
420
424
|
if (!items?.length) return;
|
|
421
425
|
if (items.some((it) => !it.id)) throw new Error("Image attachment requires a product ID for every item; no image request was sent.");
|
|
426
|
+
const unfetchable = items.filter((it) => !isFetchableImageUrl(it.url));
|
|
427
|
+
if (unfetchable.length) throw new Error(
|
|
428
|
+
`Image url(s) for [${unfetchable.map((it) => it.altText || it.id).join(", ")}] are not absolute ` +
|
|
429
|
+
`https:// urls, and Wix copies the image bytes at attach time. Re-call attachProductImages once each ` +
|
|
430
|
+
`image has its final url. No image request was sent; products are unaffected.`);
|
|
422
431
|
const ids = items.map((it) => it.id);
|
|
423
432
|
const q = await req(ctx, "/stores/v3/products/query", { body: { query: { filter: { id: { $in: ids } }, paging: { limit: ids.length } } } });
|
|
424
433
|
const revById = new Map((q.products ?? []).map((p) => [p.id, p.revision]));
|
|
@@ -475,7 +484,8 @@ async function configureCurrency(ctx, requested) {
|
|
|
475
484
|
* digitalFileUrl?, digitalFileName? }],
|
|
476
485
|
* categories?: { [categoryName]: string[] }, // map of category name -> product NAMES in it
|
|
477
486
|
* }}
|
|
478
|
-
* @returns { products: [{id,slug,revision,name}], categories: [{id,name}], imagesAttached: number,
|
|
487
|
+
* @returns { products: [{id,slug,revision,name}], categories: [{id,name}], imagesAttached: number,
|
|
488
|
+
* imagesSkipped?: string[], note?: string, currency: {requested,actual,status,warnings} }
|
|
479
489
|
*/
|
|
480
490
|
async function setupStore(ctx, { products = [], categories = {}, currency } = {}) {
|
|
481
491
|
validateProducts(products);
|
|
@@ -498,11 +508,29 @@ async function setupStore(ctx, { products = [], categories = {}, currency } = {}
|
|
|
498
508
|
}
|
|
499
509
|
|
|
500
510
|
const imageItems = withNames
|
|
501
|
-
.map((p, i) => ({ id: p.id, url: products[i]?.imageUrl, altText: products[i]?.altText ?? p.slug }))
|
|
511
|
+
.map((p, i) => ({ id: p.id, url: products[i]?.imageUrl, altText: products[i]?.altText ?? p.slug, name: p.name }))
|
|
502
512
|
.filter((it) => it.url);
|
|
503
|
-
|
|
513
|
+
// A url Wix cannot fetch would fail the attach: seed the product imageless and report it,
|
|
514
|
+
// so the caller attaches once the final url exists.
|
|
515
|
+
const readyItems = imageItems.filter((it) => isFetchableImageUrl(it.url));
|
|
516
|
+
const skipped = imageItems.filter((it) => !isFetchableImageUrl(it.url)).map((it) => it.name);
|
|
517
|
+
if (readyItems.length) await attachProductImages(ctx, readyItems);
|
|
504
518
|
|
|
505
|
-
|
|
519
|
+
const withoutImages = withNames.filter((p, i) => !products[i]?.imageUrl).map((p) => p.name);
|
|
520
|
+
return {
|
|
521
|
+
products: withNames, categories: cats, imagesAttached: readyItems.length,
|
|
522
|
+
...(skipped.length && {
|
|
523
|
+
imagesSkipped: skipped,
|
|
524
|
+
note: "these products' image urls were not absolute https:// urls — attach them with " +
|
|
525
|
+
"attachProductImages once each image has its final url",
|
|
526
|
+
}),
|
|
527
|
+
...(withoutImages.length && !skipped.length && {
|
|
528
|
+
productsWithoutImages: withoutImages,
|
|
529
|
+
note: "these products were seeded without an image — once their images have final urls, " +
|
|
530
|
+
"attach them with attachProductImages",
|
|
531
|
+
}),
|
|
532
|
+
currency: currencyResult,
|
|
533
|
+
};
|
|
506
534
|
}
|
|
507
535
|
|
|
508
536
|
module.exports = {
|