@wix/agent-skills 1.23.0 → 1.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +64 -50
- package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +4 -3
- package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +28 -25
- package/skills/wix-app/references/editor-react-component/BRANDED-COMPONENTS.md +8 -2
- package/skills/wix-app/references/editor-react-component/COMPONENT-CONTRACT.md +12 -14
- package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +4 -3
- package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +66 -9
- package/skills/wix-app/references/editor-react-component/EDITOR-EXTENSION-CONFIGURATION.md +25 -0
- package/skills/wix-app/references/editor-react-component/OVERFLOW.md +146 -0
- package/skills/wix-app/references/editor-react-component/PARTS.md +6 -0
- package/skills/wix-app/scripts/scan-a11y-eslint.cjs +25 -1
- package/skills/{wix-headless-fast → wix-headless-kit}/SKILL.md +79 -60
- package/skills/{wix-headless-fast → wix-headless-kit}/cold-start/bootstrap.mjs +2 -2
- package/skills/{wix-headless-fast → wix-headless-kit}/cold-start/cold-start.md +26 -35
- package/skills/wix-headless-kit/guides/capabilities.md +76 -0
- package/skills/wix-headless-kit/guides/feedback.md +98 -0
- package/skills/{wix-headless-fast → wix-headless-kit}/guides/migration.md +20 -9
- package/skills/{wix-headless-fast → wix-headless-kit}/install/AGENTS.md +3 -0
- package/skills/{wix-headless-fast → wix-headless-kit}/install/attach.mjs +5 -2
- package/skills/{wix-headless-fast → wix-headless-kit}/install/check.mjs +1 -1
- package/skills/wix-headless-kit/install/context.mjs +169 -0
- package/skills/{wix-headless-fast → wix-headless-kit}/install/deploy.mjs +17 -4
- package/skills/{wix-headless-fast → wix-headless-kit}/install/setup.mjs +89 -55
- package/skills/{wix-headless-fast → wix-headless-kit}/install/templates.mjs +1 -1
- package/skills/wix-manage/references/cms/cms-dashboard-navigation.md +2 -2
- package/skills/wix-manage/references/cms/cms-data-items-crud.md +16 -16
- package/skills/wix-manage/references/cms/cms-publishing-flow.md +15 -15
- package/skills/wix-manage/references/cms/cms-schema-management.md +6 -6
- package/skills/wix-manage/references/sites/query-sites.md +1 -8
- package/skills/wix-auth/SKILL.md +0 -12
- package/skills/wix-auth/references/device-flow.md +0 -140
- package/skills/wix-headless-fast/install/context.mjs +0 -126
- /package/skills/{wix-headless-fast → wix-headless-kit}/guides/existing-site.md +0 -0
- /package/skills/{wix-headless-fast → wix-headless-kit}/guides/reference-mode.md +0 -0
- /package/skills/{wix-headless-fast → wix-headless-kit}/install/agents-md.mjs +0 -0
- /package/skills/{wix-headless-fast → wix-headless-kit}/install/lock.mjs +0 -0
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
# Device Flow
|
|
2
|
-
|
|
3
|
-
Implements the OAuth 2.0 Device Authorization Grant (RFC 8628). The user approves in a browser while the agent polls for tokens.
|
|
4
|
-
|
|
5
|
-
Produces two kinds of token:
|
|
6
|
-
- **Account token** — works for account-level APIs (e.g. list sites). Expires in ~4 hours.
|
|
7
|
-
- **Site token** — required for any site-specific API (contacts, products, bookings, …). Derived on demand from the account `refreshToken` + a `siteId`. Expires in ~15 minutes.
|
|
8
|
-
|
|
9
|
-
## Constants
|
|
10
|
-
|
|
11
|
-
```
|
|
12
|
-
BASE_URL = https://manage.wix.com
|
|
13
|
-
CLIENT_ID = 6f95cec8-3e98-48b9-b4e5-1fb92fcd9973
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
Required headers on every request:
|
|
17
|
-
|
|
18
|
-
```
|
|
19
|
-
X-XSRF-TOKEN: nocheck
|
|
20
|
-
Cookie: XSRF-TOKEN=nocheck
|
|
21
|
-
User-Agent: wix-cli
|
|
22
|
-
Content-Type: application/json (on POST requests)
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Step 1 — Request a device code
|
|
26
|
-
|
|
27
|
-
```
|
|
28
|
-
GET /oauth2/device/code?clientId=CLIENT_ID
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
Response:
|
|
32
|
-
|
|
33
|
-
```json
|
|
34
|
-
{ "deviceCode": "…", "userCode": "XXXXXXXX", "verificationUri": "https://users.wix.com/login/device-login", "expiresIn": 600 }
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Step 2 — Ask the user to authorize
|
|
38
|
-
|
|
39
|
-
Show the user this URL and code:
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
URL: {verificationUri}?color=developer&studio=true
|
|
43
|
-
Code: {userCode}
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Make sure the user has copied or noted the code **before** opening the link — they'll need to enter it on the page. Present the URL as a clickable link that opens in a new tab if your interface supports it.
|
|
47
|
-
|
|
48
|
-
## Step 3 — Poll for the token
|
|
49
|
-
|
|
50
|
-
Every 3 seconds, POST:
|
|
51
|
-
|
|
52
|
-
```
|
|
53
|
-
POST /oauth2/token
|
|
54
|
-
{ "clientId": "CLIENT_ID", "grantType": "urn:ietf:params:oauth:grant-type:device_code", "scope": "offline_access", "deviceCode": "{deviceCode}" }
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
- While waiting: server returns `400` with `{ "error": "authorization_pending" }` or `{ "message": "Device code is not yet verified" }` — keep polling.
|
|
58
|
-
- On approval: `200` with `{ "access_token": "…", "refresh_token": "…", "expires_in": 14400 }`.
|
|
59
|
-
- Stop polling after `expiresIn` seconds total.
|
|
60
|
-
|
|
61
|
-
## Step 4 — Fetch user info
|
|
62
|
-
|
|
63
|
-
```
|
|
64
|
-
GET /_serverless/wix-cli-userinfo/userinfo
|
|
65
|
-
Authorization: Bearer {access_token}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
Response: `{ "userId": "…", "email": "…" }`
|
|
69
|
-
|
|
70
|
-
## Step 5 — Persist
|
|
71
|
-
|
|
72
|
-
At this point you already hold all the values in memory — store them securely to whatever credential store your platform provides (file, secrets manager, environment variables, etc.), without asking the user to enter them manually. **Treat these as secrets: never print them in the conversation, never include them in logs, and never send them to any service other than the Wix APIs.**
|
|
73
|
-
|
|
74
|
-
```
|
|
75
|
-
accessToken string
|
|
76
|
-
refreshToken string
|
|
77
|
-
expiresIn number (seconds)
|
|
78
|
-
issuedAt number (Unix timestamp in seconds, recorded at the moment tokens were received)
|
|
79
|
-
userInfo { userId, email }
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
## Getting a valid token on subsequent calls
|
|
83
|
-
|
|
84
|
-
**Account token**
|
|
85
|
-
|
|
86
|
-
1. Load stored credentials. If missing → run the device flow above.
|
|
87
|
-
2. Check validity: `issuedAt + expiresIn - 600 > now` (10-min buffer).
|
|
88
|
-
3. If expired → refresh silently:
|
|
89
|
-
|
|
90
|
-
```
|
|
91
|
-
POST /oauth2/token
|
|
92
|
-
{ "clientId": "CLIENT_ID", "grantType": "refresh_token", "refreshToken": "{refreshToken}" }
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
Same response shape as Step 3. Persist the new tokens with a fresh `issuedAt`.
|
|
96
|
-
|
|
97
|
-
4. If refresh returns `400 invalid_grant` → session revoked; run the device flow again.
|
|
98
|
-
|
|
99
|
-
**Site token**
|
|
100
|
-
|
|
101
|
-
The account token returns `403` on site-level endpoints. Derive a site token on demand:
|
|
102
|
-
|
|
103
|
-
```
|
|
104
|
-
POST /oauth2/token
|
|
105
|
-
{ "clientId": "CLIENT_ID", "grantType": "refresh_token", "refreshToken": "{refreshToken}", "siteId": "{siteId}" }
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
Response: `{ "access_token": "…", "refresh_token": "…", "expires_in": 900 }`
|
|
109
|
-
|
|
110
|
-
Re-derive on each use rather than caching — it expires in 15 minutes.
|
|
111
|
-
|
|
112
|
-
## Examples
|
|
113
|
-
|
|
114
|
-
**List sites (account token)**
|
|
115
|
-
|
|
116
|
-
```
|
|
117
|
-
POST https://www.wixapis.com/site-list/v2/sites/query
|
|
118
|
-
Authorization: Bearer {accountToken}
|
|
119
|
-
{ "query": { "filter": { "namespace": { "$in": ["WIX", "HEADLESS"] } }, "cursorPaging": { "limit": 100 } } }
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
Returns `{ sites: [{ id, displayName, namespace, … }] }` — the `id` is the `siteId` for site-scoped calls.
|
|
123
|
-
|
|
124
|
-
> Without the `namespace` filter, headless sites are silently excluded from results.
|
|
125
|
-
|
|
126
|
-
**List contacts (site token)**
|
|
127
|
-
|
|
128
|
-
```
|
|
129
|
-
POST https://www.wixapis.com/contacts/v4/contacts/query
|
|
130
|
-
Authorization: Bearer {siteToken}
|
|
131
|
-
{ "query": { "paging": { "limit": 10 } } }
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
Returns `{ contacts: […] }`.
|
|
135
|
-
|
|
136
|
-
---
|
|
137
|
-
|
|
138
|
-
For the full Wix REST API reference — endpoints, request/response shapes, and field details — see [https://www.wix.com/skills/docs](https://www.wix.com/skills/docs).
|
|
139
|
-
|
|
140
|
-
For REST API recipes covering common management operations (stores, bookings, contacts, CMS, and more) — see [https://www.wix.com/skills/manage](https://www.wix.com/skills/manage).
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
// The site context of a project folder — the one place that says which site a call targets.
|
|
2
|
-
//
|
|
3
|
-
// node <SKILL_ROOT>/install/context.mjs [--refresh] [--no-pull] (prints one JSON object)
|
|
4
|
-
//
|
|
5
|
-
// Two identities live in a Wix project and are the same site almost always:
|
|
6
|
-
// deploy — `wix.config.json` (`siteId`, `appId`): where `wix release` uploads. The CLI's business.
|
|
7
|
-
// content — `.env.local` (`WIX_CLIENT_ID`, what `wix env pull` writes): the app the SDK client
|
|
8
|
-
// runs as, on every stack (the Astro integration reads WIX_CLIENT_ID from the env and
|
|
9
|
-
// never the config; the other stacks get it copied into src/wix/config.ts by deploy.mjs).
|
|
10
|
-
// They differ on a MIGRATION PREVIEW: a project whose config points at a fresh site created only to
|
|
11
|
-
// host the deployment, while `.env.local` carries the credentials of the site being migrated (the
|
|
12
|
-
// parent) and says so. Then every admin, discovery and seed call targets the parent, the SDK client
|
|
13
|
-
// is the parent's, and only the release goes to the child. Completing the migration is a CLI step
|
|
14
|
-
// that does not exist yet; this module only reads the state.
|
|
15
|
-
//
|
|
16
|
-
// `env pull` runs here when `.env.local` is missing (or --refresh): it is the source of the content
|
|
17
|
-
// identity, and the Astro build refuses to run without it. Non-interactive (CI=1); a failure is
|
|
18
|
-
// reported in `pullError` and the config's ids stand in, so a caller can still work offline.
|
|
19
|
-
import { spawnSync } from "node:child_process";
|
|
20
|
-
import { copyFileSync, existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
21
|
-
import { tmpdir } from "node:os";
|
|
22
|
-
import { join } from "node:path";
|
|
23
|
-
|
|
24
|
-
// The variables `wix env pull` writes for a migration preview. The names are the platform's and are
|
|
25
|
-
// spelled once, here.
|
|
26
|
-
export const ENV = {
|
|
27
|
-
clientId: "WIX_CLIENT_ID",
|
|
28
|
-
parentSiteId: "WIX_MIGRATION_PARENT_SITE_ID",
|
|
29
|
-
migration: "WIX_MIGRATION",
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
/** KEY=value lines of a dotenv file, quotes stripped; null when the file is absent. */
|
|
33
|
-
export function readEnvFile(file) {
|
|
34
|
-
if (!existsSync(file)) return null;
|
|
35
|
-
const out = {};
|
|
36
|
-
for (const raw of readFileSync(file, "utf8").split(/\r?\n/)) {
|
|
37
|
-
const line = raw.trim();
|
|
38
|
-
if (!line || line.startsWith("#")) continue;
|
|
39
|
-
const eq = line.indexOf("=");
|
|
40
|
-
if (eq === -1) continue;
|
|
41
|
-
const key = line.slice(0, eq).trim().replace(/^export\s+/, "");
|
|
42
|
-
let value = line.slice(eq + 1).trim();
|
|
43
|
-
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
44
|
-
value = value.slice(1, -1).replace(/\\"/g, '"');
|
|
45
|
-
}
|
|
46
|
-
out[key] = value;
|
|
47
|
-
}
|
|
48
|
-
return out;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function readWixConfig(cwd) {
|
|
52
|
-
const file = join(cwd, "wix.config.json");
|
|
53
|
-
if (!existsSync(file)) return null;
|
|
54
|
-
try { return JSON.parse(readFileSync(file, "utf8")); } catch { return null; }
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const truthy = (v) => typeof v === "string" && /^(1|true|yes|on)$/i.test(v.trim());
|
|
58
|
-
|
|
59
|
-
const ENV_PULL = ["-y", "@wix/cli@latest", "env", "pull"];
|
|
60
|
-
const runPull = (dir) => spawnSync("npx", ENV_PULL, { cwd: dir, env: { ...process.env, CI: "1" }, encoding: "utf8", timeout: 180_000 });
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* `wix env pull` into `cwd/.env.local`. The CLI mounts `env` only once the folder reads as an Astro
|
|
64
|
-
* project (an astro.config.* file, or `site.outputDirectory` in the config); a folder that holds just
|
|
65
|
-
* the downloaded `wix.config.json` gets "unknown command 'env'". Then the pull runs in a temp folder
|
|
66
|
-
* holding a copy of the config and an empty astro.config.mjs, and the `.env.local` comes back here.
|
|
67
|
-
*/
|
|
68
|
-
export function pullEnv(cwd) {
|
|
69
|
-
const envFile = join(cwd, ".env.local");
|
|
70
|
-
let r = runPull(cwd);
|
|
71
|
-
if (r.status === 0 && existsSync(envFile)) return { ok: true, via: "in place" };
|
|
72
|
-
const notAProjectYet = /unknown command 'env'/.test(`${r.stderr}${r.stdout}`);
|
|
73
|
-
if (notAProjectYet) {
|
|
74
|
-
const tmp = mkdtempSync(join(tmpdir(), "wix-env-pull-"));
|
|
75
|
-
try {
|
|
76
|
-
copyFileSync(join(cwd, "wix.config.json"), join(tmp, "wix.config.json"));
|
|
77
|
-
writeFileSync(join(tmp, "astro.config.mjs"), "");
|
|
78
|
-
r = runPull(tmp);
|
|
79
|
-
if (r.status === 0 && existsSync(join(tmp, ".env.local"))) {
|
|
80
|
-
copyFileSync(join(tmp, ".env.local"), envFile);
|
|
81
|
-
return { ok: true, via: "stub project" };
|
|
82
|
-
}
|
|
83
|
-
} finally {
|
|
84
|
-
rmSync(tmp, { recursive: true, force: true });
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
return { ok: false, error: (r.stderr || r.stdout || "env pull produced no .env.local — is the Wix CLI logged in? (npx @wix/cli@latest whoami)").trim().slice(-400) };
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* `{ deploy: { siteId, appId }, content: { siteId, clientId }, migration: { active, parentSiteId },
|
|
92
|
-
* env: { file, present, pulled }, pullError?, warnings: [] }`.
|
|
93
|
-
* `pull`: "auto" (default) pulls when `.env.local` is missing; true always; false never.
|
|
94
|
-
*/
|
|
95
|
-
export function siteContext({ cwd = process.cwd(), pull = "auto" } = {}) {
|
|
96
|
-
const config = readWixConfig(cwd) ?? {};
|
|
97
|
-
const deploy = { siteId: config.siteId ?? config.projectId ?? null, appId: config.appId ?? null };
|
|
98
|
-
const envFile = join(cwd, ".env.local");
|
|
99
|
-
let pulled = false, pullError;
|
|
100
|
-
if (deploy.siteId && (pull === true || (pull === "auto" && !existsSync(envFile)))) {
|
|
101
|
-
const r = pullEnv(cwd);
|
|
102
|
-
if (r.ok) pulled = r.via;
|
|
103
|
-
else pullError = r.error;
|
|
104
|
-
}
|
|
105
|
-
const env = readEnvFile(envFile) ?? {};
|
|
106
|
-
const parentSiteId = env[ENV.parentSiteId] || null;
|
|
107
|
-
const active = !!parentSiteId && (truthy(env[ENV.migration]) || env[ENV.migration] === undefined);
|
|
108
|
-
const migration = { active, parentSiteId: active ? parentSiteId : null };
|
|
109
|
-
const clientId = env[ENV.clientId] || deploy.appId;
|
|
110
|
-
const content = { siteId: active ? parentSiteId : deploy.siteId, clientId };
|
|
111
|
-
const warnings = [];
|
|
112
|
-
if (env[ENV.clientId] && deploy.appId && env[ENV.clientId] !== deploy.appId && !active) {
|
|
113
|
-
warnings.push(`.env.local ${ENV.clientId} differs from wix.config.json appId and no migration is declared — the SDK client runs as the env's app, the release goes to the config's site`);
|
|
114
|
-
}
|
|
115
|
-
if (active && migration.parentSiteId === deploy.siteId) {
|
|
116
|
-
warnings.push("the migration's parent site is the deploy site itself — nothing is being migrated");
|
|
117
|
-
}
|
|
118
|
-
return { deploy, content, migration, env: { file: envFile, present: Object.keys(env).length > 0, pulled }, ...(pullError ? { pullError } : {}), warnings };
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// ---- CLI ----------------------------------------------------------------------------------------
|
|
122
|
-
if (process.argv[1] && /context\.mjs$/.test(process.argv[1])) {
|
|
123
|
-
const argv = process.argv.slice(2);
|
|
124
|
-
const pull = argv.includes("--no-pull") ? false : argv.includes("--refresh") ? true : "auto";
|
|
125
|
-
console.log(JSON.stringify(siteContext({ pull }), null, 2));
|
|
126
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|