@lacneu/wix-openclaw 0.0.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/CHANGELOG.md +68 -0
- package/LICENSE +21 -0
- package/README.md +483 -0
- package/dist/config.d.ts +19 -0
- package/dist/config.js +60 -0
- package/dist/config.js.map +1 -0
- package/dist/hooks/approval.d.ts +29 -0
- package/dist/hooks/approval.js +65 -0
- package/dist/hooks/approval.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +97 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/_factory.d.ts +40 -0
- package/dist/tools/_factory.js +69 -0
- package/dist/tools/_factory.js.map +1 -0
- package/dist/tools/blog.d.ts +140 -0
- package/dist/tools/blog.js +191 -0
- package/dist/tools/blog.js.map +1 -0
- package/dist/tools/bookings.d.ts +116 -0
- package/dist/tools/bookings.js +97 -0
- package/dist/tools/bookings.js.map +1 -0
- package/dist/tools/contacts.d.ts +216 -0
- package/dist/tools/contacts.js +128 -0
- package/dist/tools/contacts.js.map +1 -0
- package/dist/tools/data.d.ts +114 -0
- package/dist/tools/data.js +129 -0
- package/dist/tools/data.js.map +1 -0
- package/dist/tools/design.d.ts +32 -0
- package/dist/tools/design.js +165 -0
- package/dist/tools/design.js.map +1 -0
- package/dist/tools/events.d.ts +66 -0
- package/dist/tools/events.js +70 -0
- package/dist/tools/events.js.map +1 -0
- package/dist/tools/faq.d.ts +98 -0
- package/dist/tools/faq.js +90 -0
- package/dist/tools/faq.js.map +1 -0
- package/dist/tools/forms.d.ts +46 -0
- package/dist/tools/forms.js +63 -0
- package/dist/tools/forms.js.map +1 -0
- package/dist/tools/media.d.ts +50 -0
- package/dist/tools/media.js +75 -0
- package/dist/tools/media.js.map +1 -0
- package/dist/tools/multilingual.d.ts +38 -0
- package/dist/tools/multilingual.js +48 -0
- package/dist/tools/multilingual.js.map +1 -0
- package/dist/tools/reviews.d.ts +62 -0
- package/dist/tools/reviews.js +72 -0
- package/dist/tools/reviews.js.map +1 -0
- package/dist/tools/site.d.ts +36 -0
- package/dist/tools/site.js +94 -0
- package/dist/tools/site.js.map +1 -0
- package/dist/types.d.ts +58 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/dist/wix-client.d.ts +66 -0
- package/dist/wix-client.js +194 -0
- package/dist/wix-client.js.map +1 -0
- package/openclaw.plugin.json +95 -0
- package/package.json +72 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- `wix_site_url_get` now reads `viewUrl` from the Site List API response
|
|
12
|
+
rather than calling the legacy `/urls-server/v2/published-site-urls`
|
|
13
|
+
endpoint, which returns 403 for headless API keys even when the
|
|
14
|
+
"Read Site URLs" permission is granted. The "Read Site URLs"
|
|
15
|
+
permission is no longer required.
|
|
16
|
+
- Forms submission tools migrated from `/form-submissions/v1/...` to
|
|
17
|
+
`/form-submission-service/v4/submissions/namespace/query`. The query
|
|
18
|
+
filter now uses the canonical `{ namespace: { $eq: "..." } }` shape
|
|
19
|
+
enforced by Wix.
|
|
20
|
+
- Multilingual tools migrated from `/multilingual/v1/sitetranslatables/...`
|
|
21
|
+
to the current `/locales/v2/locale/query` and
|
|
22
|
+
`/translation-schema/v1/schemas/site` endpoints. `wix_multilingual_get_translation`
|
|
23
|
+
removed in favour of `wix_multilingual_list_schemas`.
|
|
24
|
+
- Sites + business info endpoints corrected:
|
|
25
|
+
`wix_sites_list` → `POST /site-list/v2/sites/query`,
|
|
26
|
+
`wix_business_info_get` → `GET /site-properties/v4/properties`.
|
|
27
|
+
- Documented the per-app installation requirements that gate certain
|
|
28
|
+
tool families (Velo for `wix_data_*`, Wix Events / Reviews / FAQ /
|
|
29
|
+
Multilingual for their respective tool groups).
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
- `scripts/smoke-test.mjs` + `npm run smoke-test` — live read-only
|
|
33
|
+
endpoint validation against a real Wix account using `.env.smoketest`
|
|
34
|
+
credentials. Generates `smoke-test-report.md`.
|
|
35
|
+
|
|
36
|
+
## [0.1.0] - 2026-04-28
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
- Initial release of `@lacneu/wix-openclaw`.
|
|
40
|
+
- ~50 tools spanning Wix Blog, Site Media, Sites, CMS Data, Forms, Contacts,
|
|
41
|
+
Bookings, Events, Reviews, FAQ, and Multilingual (read-only).
|
|
42
|
+
- `wix_design_brief` tool — pure prompt structurer that turns a loose textual
|
|
43
|
+
brief into a markdown artefact (palette, typography, recommended sections,
|
|
44
|
+
copy starters, prompts for image-generation tools). Does not call the Wix API.
|
|
45
|
+
- Authenticated `WixClient` with the Wix-specific header convention
|
|
46
|
+
(`Authorization: <key>` raw — no `Bearer ` prefix), automatic injection of
|
|
47
|
+
`wix-account-id` and `wix-site-id`, retry on 429/5xx with exponential
|
|
48
|
+
backoff, and JSON serialisation.
|
|
49
|
+
- **Site whitelist**: every site-scoped call is checked against
|
|
50
|
+
`allowedSiteIds` before any HTTP request is built. Calls to a site outside
|
|
51
|
+
the list throw `WixSiteNotAllowedError` and surface as a tool failure.
|
|
52
|
+
- **Approval gating** via the `before_tool_call` hook: every destructive
|
|
53
|
+
operation (publish, delete, cancel, moderate) returns a `requireApproval`
|
|
54
|
+
directive with severity `critical`, 10-minute timeout, and `deny` as the
|
|
55
|
+
timeout fallback.
|
|
56
|
+
- TypeScript build with strict mode (`noImplicitAny`, `noUnusedLocals`,
|
|
57
|
+
`noUnusedParameters`, `noImplicitReturns`, `noFallthroughCasesInSwitch`).
|
|
58
|
+
- TypeBox-based parameter schemas — the agent sees fully typed params
|
|
59
|
+
consistent with the rest of the OpenClaw tool surface.
|
|
60
|
+
- Test suite (`node:test`) covering the security-critical paths:
|
|
61
|
+
whitelist enforcement, header injection, 429 retry, approval matching,
|
|
62
|
+
and a smoke test on two blog tools.
|
|
63
|
+
- CI workflow on Node.js 22 + 24.
|
|
64
|
+
- Release workflow using **npm Trusted Publishing (OIDC)** — no `NPM_TOKEN`
|
|
65
|
+
secret required, provenance attached automatically.
|
|
66
|
+
|
|
67
|
+
[Unreleased]: https://github.com/OlivierNeu/wix-openclaw-plugin/compare/v0.1.0...HEAD
|
|
68
|
+
[0.1.0]: https://github.com/OlivierNeu/wix-openclaw-plugin/releases/tag/v0.1.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 OlivierNeu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
# wix-openclaw-plugin
|
|
2
|
+
|
|
3
|
+
> **Wix REST API plugin for OpenClaw**
|
|
4
|
+
> Manage blog, CMS data, forms, bookings, contacts, events, FAQ on a single
|
|
5
|
+
> Wix site — with **site_id whitelist** and **approval gating** on every
|
|
6
|
+
> destructive operation.
|
|
7
|
+
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
[](https://github.com/openclaw/openclaw)
|
|
10
|
+
[](https://www.npmjs.com/package/@lacneu/wix-openclaw)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Overview
|
|
15
|
+
|
|
16
|
+
`wix-openclaw` is an OpenClaw plugin that lets your agent operate a Wix site
|
|
17
|
+
through the official Wix REST API. It registers ~50 tools split across a dozen
|
|
18
|
+
Wix products (Blog, CMS Data, Forms, Bookings, Contacts, Events, Reviews, FAQ,
|
|
19
|
+
Multilingual, Sites, Site Media), plus a `wix_design_brief` helper that turns
|
|
20
|
+
loose textual briefs into structured markdown artefacts.
|
|
21
|
+
|
|
22
|
+
Every tool funnels through a single authenticated HTTP client that:
|
|
23
|
+
|
|
24
|
+
1. Injects the correct headers (`Authorization`, `wix-account-id`,
|
|
25
|
+
`wix-site-id`)
|
|
26
|
+
2. Refuses any call to a site UUID not in `allowedSiteIds` — **before** the
|
|
27
|
+
network round trip
|
|
28
|
+
3. Retries on 429/5xx with exponential backoff
|
|
29
|
+
4. Maps non-retryable errors to clean tool failures (`WixApiError`)
|
|
30
|
+
|
|
31
|
+
Destructive operations (publish, delete, cancel, moderate) trigger a
|
|
32
|
+
`before_tool_call` approval prompt that the operator must accept in the
|
|
33
|
+
Control UI / Telegram before the call goes through.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Why a whitelist?
|
|
38
|
+
|
|
39
|
+
Wix accounts can host many sites. The `wix-site-id` header is the only thing
|
|
40
|
+
between an agent and "we just published a draft on the wrong site".
|
|
41
|
+
|
|
42
|
+
`allowedSiteIds` is enforced in the client itself, **before** any HTTP request
|
|
43
|
+
is built. If the LLM hallucinates a site UUID, the call fails locally — no
|
|
44
|
+
traffic is generated and no Wix logs are polluted. This is the same reason
|
|
45
|
+
`google_workspace` enforces a domain allowlist: prompt injection should never
|
|
46
|
+
reach the wrong tenant.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
### Requirements
|
|
53
|
+
|
|
54
|
+
- OpenClaw `>= v2026.4.0`
|
|
55
|
+
- A Wix REST API key with the **minimum required permissions** (see
|
|
56
|
+
[Wix API Key permissions](#wix-api-key-permissions) below)
|
|
57
|
+
- The Wix account UUID and at least one site UUID
|
|
58
|
+
|
|
59
|
+
### Install via OpenClaw CLI
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
openclaw plugins install @lacneu/wix-openclaw
|
|
63
|
+
openclaw plugins inspect @lacneu/wix-openclaw
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Configuration
|
|
67
|
+
|
|
68
|
+
Add the entry to your `openclaw.json`:
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"plugins": {
|
|
73
|
+
"allow": ["wix-openclaw", "openclaw-knowledge", "telegram"],
|
|
74
|
+
"entries": {
|
|
75
|
+
"wix-openclaw": {
|
|
76
|
+
"enabled": true,
|
|
77
|
+
"config": {
|
|
78
|
+
"apiKey": "${WIX_API_KEY}",
|
|
79
|
+
"accountId": "${WIX_ACCOUNT_ID}",
|
|
80
|
+
"allowedSiteIds": ["${WIX_SITE_ID_ATARAXIS}"],
|
|
81
|
+
"defaultSiteId": "${WIX_SITE_ID_ATARAXIS}",
|
|
82
|
+
"logLevel": "info"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Add the secrets to your `.env`:
|
|
91
|
+
|
|
92
|
+
```dotenv
|
|
93
|
+
WIX_API_KEY=<your-wix-api-key>
|
|
94
|
+
WIX_ACCOUNT_ID=<your-wix-account-uuid>
|
|
95
|
+
WIX_SITE_ID_ATARAXIS=<your-target-site-uuid>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Restart the gateway:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
openclaw gateway restart
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Configuration reference
|
|
107
|
+
|
|
108
|
+
| Field | Type | Default | Description |
|
|
109
|
+
|---|---|---|---|
|
|
110
|
+
| `enabled` | boolean | `true` | Master switch — disables all `wix_*` tools when false |
|
|
111
|
+
| `apiKey` | string | — | Wix REST API key. Sent **raw** in `Authorization` (no `Bearer ` prefix). Supports `${ENV_VAR}` |
|
|
112
|
+
| `accountId` | string | — | Wix account UUID. Sent as `wix-account-id`. Supports `${ENV_VAR}` |
|
|
113
|
+
| `allowedSiteIds` | string[] | `[]` | Whitelist of Wix site UUIDs. Calls to other sites are rejected before the network round trip |
|
|
114
|
+
| `defaultSiteId` | string | first of `allowedSiteIds` | Site UUID injected when a tool does not explicitly specify one |
|
|
115
|
+
| `approvalRequired` | string[] | (every destructive tool) | Tool names that trigger a `before_tool_call` approval prompt |
|
|
116
|
+
| `logLevel` | enum | `info` | `debug` / `info` / `warn` / `error`. `debug` logs request bodies (mind PII) |
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Authentication header convention
|
|
121
|
+
|
|
122
|
+
Wix REST APIs use a slightly non-standard auth pattern: the API key goes raw
|
|
123
|
+
in the `Authorization` header — **without** the `Bearer ` prefix.
|
|
124
|
+
|
|
125
|
+
```http
|
|
126
|
+
Authorization: <wix-api-key>
|
|
127
|
+
wix-account-id: <wix-account-uuid>
|
|
128
|
+
wix-site-id: <wix-site-uuid>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
This plugin handles that for you; you only need to provide the three values.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Wix API Key permissions
|
|
136
|
+
|
|
137
|
+
A Wix REST API key has **account-wide reach** by design — it can target any
|
|
138
|
+
of the sites under the Wix account it belongs to. Wix does **not** let you
|
|
139
|
+
scope a key to a single site at creation time. The plugin compensates with
|
|
140
|
+
its `allowedSiteIds` whitelist (cf. [Why a whitelist?](#why-a-whitelist)),
|
|
141
|
+
but the API key permission set itself remains your most important defense
|
|
142
|
+
against accidental — or malicious — over-reach. Treat it as a
|
|
143
|
+
least-privilege configuration exercise.
|
|
144
|
+
|
|
145
|
+
> **Where to configure them**
|
|
146
|
+
> Wix Dashboard → **Settings** → **Headless Settings** → **API Keys** →
|
|
147
|
+
> click your key → **Edit API Key** → **Permissions**.
|
|
148
|
+
|
|
149
|
+
### Minimum required (for the V1 toolset shipped here)
|
|
150
|
+
|
|
151
|
+
Tick **only** the following permissions on your API key. Everything else
|
|
152
|
+
should stay unticked.
|
|
153
|
+
|
|
154
|
+
#### Basic permissions
|
|
155
|
+
- [x] **Get Sites List** — required to discover and validate site UUIDs
|
|
156
|
+
|
|
157
|
+
#### Site permissions
|
|
158
|
+
- [x] **Wix Blog** — drafts, posts, categories, tags
|
|
159
|
+
- [x] **Manage Site Media** — upload images for blog cover & rich content
|
|
160
|
+
- [x] **Business Info** — name, address, hours, timezone
|
|
161
|
+
- [x] **Wix Data** — custom CMS collections (read & write)
|
|
162
|
+
- [x] **Wix Forms** — read submitted forms
|
|
163
|
+
- [x] **Manage Form Submissions** — read leads / contact requests
|
|
164
|
+
- [x] **Wix Contacts & Members** — CRM contacts + members
|
|
165
|
+
- [x] **Wix Bookings** — services, sessions, bookings
|
|
166
|
+
- [x] **Wix Events** — events, RSVPs, guests
|
|
167
|
+
- [x] **Wix Reviews** — list & moderate reviews
|
|
168
|
+
- [x] **Manage FAQ** — FAQ categories and questions
|
|
169
|
+
- [x] **Multilingual Translation Schema Read** — read site translations
|
|
170
|
+
- [x] **List Marketing Tags** — read-only marketing/analytics tags
|
|
171
|
+
|
|
172
|
+
### Optional, depending on the business model
|
|
173
|
+
|
|
174
|
+
Tick these only if the corresponding Wix product is actually in use on
|
|
175
|
+
the target site:
|
|
176
|
+
|
|
177
|
+
- [ ] **Pricing Plans** — if you sell subscription packages
|
|
178
|
+
- [ ] **Wix Stores** + **Wix eCommerce** — if you sell physical/digital
|
|
179
|
+
products. Without these, the `wix_*` tools that touch e-commerce
|
|
180
|
+
resources (none in V1) cannot run.
|
|
181
|
+
|
|
182
|
+
### Permissions to **never** tick (defense in depth)
|
|
183
|
+
|
|
184
|
+
The plugin does **not** need any of the following, and granting them
|
|
185
|
+
needlessly amplifies the blast radius if the key ever leaks. Audit your
|
|
186
|
+
key periodically and keep these unticked:
|
|
187
|
+
|
|
188
|
+
| Permission | Why it's dangerous |
|
|
189
|
+
|---|---|
|
|
190
|
+
| `Manage Sites` | Allows site **deletion** |
|
|
191
|
+
| `Manage Domains` | Allows transferring your domain away |
|
|
192
|
+
| `Publish Metasite` | Allows un-publishing the entire site |
|
|
193
|
+
| `Manage Embedded Scripts` | Allows arbitrary JavaScript injection on every page |
|
|
194
|
+
| `OAuth Apps` | Allows creating persistent OAuth apps that survive key revocation |
|
|
195
|
+
| `Manage Functions` / `Manage Your App` | Arbitrary server-side code |
|
|
196
|
+
| `Connect Wix Payments Account` / `Wix Payments` / `Wix Cashier` | Reroutes customer payments |
|
|
197
|
+
| `Manage Email Marketing` / `Manage Email Subscriptions` | Mass-email spam & subscription tampering |
|
|
198
|
+
| `Server Sign On for Members` | Lets the holder impersonate any member |
|
|
199
|
+
| `Manage Roles` / `Manage Site Members` | Account take-over |
|
|
200
|
+
| `Wix CLI - Git Integration` | Modify deployed code |
|
|
201
|
+
| `Multilingual Translation Schema Write` | Tamper with on-site copy across languages |
|
|
202
|
+
| `Manage Notifications` | Push spam to members |
|
|
203
|
+
| `Invoke AI Models` | Bills your account for arbitrary LLM usage |
|
|
204
|
+
| `Manage Wixel Projects` / `Manage Site Branches` | Layout/structure mutation |
|
|
205
|
+
| Any **All account permissions** master toggle | Unties every account-wide capability above |
|
|
206
|
+
|
|
207
|
+
### Mapping: tool group → required permission
|
|
208
|
+
|
|
209
|
+
Use this table to figure out which permission a given group of tools
|
|
210
|
+
relies on. If you want a slimmer key (e.g. blog-only first), drop entire
|
|
211
|
+
columns and remove the matching tools from your agent's allow-list.
|
|
212
|
+
|
|
213
|
+
| Tool group | Wix permission | Required if you use… |
|
|
214
|
+
|---|---|---|
|
|
215
|
+
| `wix_sites_list`, `wix_site_url_get` | Get Sites List | Always (used internally — `wix_site_url_get` reads `viewUrl` from the Site object, no separate "Read Site URLs" permission needed) |
|
|
216
|
+
| `wix_business_info_get` | Business Info | `wix_business_info_get` |
|
|
217
|
+
| `wix_blog_*` | Wix Blog | Any blog tool |
|
|
218
|
+
| `wix_media_*` | Manage Site Media | Any media tool, **and** rich-content blog drafts |
|
|
219
|
+
| `wix_data_*` | Wix Data | Any CMS collection tool |
|
|
220
|
+
| `wix_forms_*` | Wix Forms + Manage Form Submissions | Lead reading |
|
|
221
|
+
| `wix_contacts_*` | Wix Contacts & Members | CRM tooling |
|
|
222
|
+
| `wix_bookings_*` | Wix Bookings | Booking tooling |
|
|
223
|
+
| `wix_events_*` | Wix Events | Event tooling |
|
|
224
|
+
| `wix_reviews_*` | Wix Reviews | Reviews moderation |
|
|
225
|
+
| `wix_faq_*` | Manage FAQ | FAQ tooling |
|
|
226
|
+
| `wix_multilingual_*` | Multilingual Translation Schema Read | Translation reads |
|
|
227
|
+
| `wix_design_brief` | _(none — no API call)_ | Always |
|
|
228
|
+
|
|
229
|
+
### Wix app installation requirements
|
|
230
|
+
|
|
231
|
+
Some Wix REST endpoints only exist when the corresponding **Wix app** is
|
|
232
|
+
installed on the target site. The plugin ships them all generically —
|
|
233
|
+
they will simply return a clean error when the app is missing, and start
|
|
234
|
+
working as soon as the app is installed (no plugin upgrade needed).
|
|
235
|
+
|
|
236
|
+
| Tool group | Wix app required | Error returned when missing |
|
|
237
|
+
|---|---|---|
|
|
238
|
+
| `wix_blog_*` | Wix Blog | `404` |
|
|
239
|
+
| `wix_data_*` | Velo / Wix Code (enable in Editor) | `400 WDE0110: Wix Code not enabled` |
|
|
240
|
+
| `wix_forms_*` | Wix Forms | `404` |
|
|
241
|
+
| `wix_bookings_*` | Wix Bookings | `404` |
|
|
242
|
+
| `wix_events_*` | Wix Events | `428 WIX_EVENTS_APP_NOT_INSTALLED` |
|
|
243
|
+
| `wix_reviews_*` | Wix Reviews | `428 APP_NOT_INSTALLED` |
|
|
244
|
+
| `wix_faq_*` | Wix FAQ | `400 App is not installed` |
|
|
245
|
+
| `wix_multilingual_*` | Wix Multilingual | `403` |
|
|
246
|
+
| `wix_contacts_*`, `wix_media_*`, `wix_sites_list`, `wix_site_url_get`, `wix_business_info_get` | (always available) | — |
|
|
247
|
+
|
|
248
|
+
To install a Wix app on your site: Wix Dashboard → **App Market** → search
|
|
249
|
+
for the app → **Add to Site**. It is free in most cases and takes effect
|
|
250
|
+
immediately for API calls.
|
|
251
|
+
|
|
252
|
+
### Rotating the key
|
|
253
|
+
|
|
254
|
+
Wix keys can be revoked at any time from the same **API Keys** page. If
|
|
255
|
+
a key leaks, or if you need to ship a temporary smoke-test key with
|
|
256
|
+
narrower scope:
|
|
257
|
+
|
|
258
|
+
1. Generate a new key with the desired scope.
|
|
259
|
+
2. Update `WIX_API_KEY` in your environment.
|
|
260
|
+
3. Restart the OpenClaw gateway.
|
|
261
|
+
4. Revoke the old key.
|
|
262
|
+
|
|
263
|
+
The plugin reads the key on each request through the resolved config —
|
|
264
|
+
no in-memory caching beyond the gateway lifecycle, so a restart fully
|
|
265
|
+
flushes the previous credential.
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## Tools
|
|
270
|
+
|
|
271
|
+
### Blog
|
|
272
|
+
|
|
273
|
+
| Tool | What it does | Approval |
|
|
274
|
+
|---|---|---|
|
|
275
|
+
| `wix_blog_list_drafts` | List draft posts | — |
|
|
276
|
+
| `wix_blog_get_draft` | Fetch a draft by id | — |
|
|
277
|
+
| `wix_blog_create_draft` | Create a new draft | — |
|
|
278
|
+
| `wix_blog_update_draft` | Patch a draft | — |
|
|
279
|
+
| `wix_blog_publish_draft` | Publish a draft | required |
|
|
280
|
+
| `wix_blog_list_published` | List published posts | — |
|
|
281
|
+
| `wix_blog_get_post` | Fetch a published post | — |
|
|
282
|
+
| `wix_blog_unpublish` | Move post to trash (reversible) | required |
|
|
283
|
+
| `wix_blog_delete_draft` | Permanently delete a draft | required |
|
|
284
|
+
| `wix_blog_list_categories` | List blog categories | — |
|
|
285
|
+
| `wix_blog_list_tags` | List blog tags | — |
|
|
286
|
+
|
|
287
|
+
### Media
|
|
288
|
+
|
|
289
|
+
| Tool | What it does | Approval |
|
|
290
|
+
|---|---|---|
|
|
291
|
+
| `wix_media_upload` | Import image into Site Media by URL | — |
|
|
292
|
+
| `wix_media_list` | List files in the media library | — |
|
|
293
|
+
|
|
294
|
+
The `wix_media_upload` tool returns the Wix file metadata, including the
|
|
295
|
+
`id`. Pass that id back into `wix_blog_create_draft` as
|
|
296
|
+
`coverMedia.imageId` or embed it into a Ricos rich-content node — see
|
|
297
|
+
the tool description for the contract the LLM should follow.
|
|
298
|
+
|
|
299
|
+
### Site
|
|
300
|
+
|
|
301
|
+
| Tool | What it does | Approval |
|
|
302
|
+
|---|---|---|
|
|
303
|
+
| `wix_sites_list` | List sites under the account (account-scoped) | — |
|
|
304
|
+
| `wix_site_url_get` | Get published URL of a site | — |
|
|
305
|
+
| `wix_business_info_get` | Read business info (name, address, hours) | — |
|
|
306
|
+
|
|
307
|
+
### CMS Data
|
|
308
|
+
|
|
309
|
+
| Tool | What it does | Approval |
|
|
310
|
+
|---|---|---|
|
|
311
|
+
| `wix_data_list_collections` | List CMS collections + schemas | — |
|
|
312
|
+
| `wix_data_query_items` | Mongo-style filter on a collection | — |
|
|
313
|
+
| `wix_data_get_item` | Fetch one item by id | — |
|
|
314
|
+
| `wix_data_insert_item` | Insert a new item | — |
|
|
315
|
+
| `wix_data_update_item` | Update an item | — |
|
|
316
|
+
| `wix_data_remove_item` | Delete an item | required |
|
|
317
|
+
|
|
318
|
+
### Forms
|
|
319
|
+
|
|
320
|
+
| Tool | What it does | Approval |
|
|
321
|
+
|---|---|---|
|
|
322
|
+
| `wix_forms_list_submissions` | List submissions / leads | — |
|
|
323
|
+
| `wix_forms_get_submission` | Fetch a single submission | — |
|
|
324
|
+
|
|
325
|
+
### Contacts
|
|
326
|
+
|
|
327
|
+
| Tool | What it does | Approval |
|
|
328
|
+
|---|---|---|
|
|
329
|
+
| `wix_contacts_query` | Search contacts | — |
|
|
330
|
+
| `wix_contacts_get` | Get one contact | — |
|
|
331
|
+
| `wix_contacts_create` | Create a contact | — |
|
|
332
|
+
| `wix_contacts_update` | Update a contact | — |
|
|
333
|
+
| `wix_contacts_label_add` | Add labels to a contact | — |
|
|
334
|
+
| `wix_contacts_delete` | Delete a contact | required |
|
|
335
|
+
|
|
336
|
+
### Bookings
|
|
337
|
+
|
|
338
|
+
| Tool | What it does | Approval |
|
|
339
|
+
|---|---|---|
|
|
340
|
+
| `wix_bookings_services_list` | List bookable services | — |
|
|
341
|
+
| `wix_bookings_query_bookings` | Query existing bookings | — |
|
|
342
|
+
| `wix_bookings_get_booking` | Fetch one booking | — |
|
|
343
|
+
| `wix_bookings_create` | Create a booking | — |
|
|
344
|
+
| `wix_bookings_reschedule` | Move to a different slot | required |
|
|
345
|
+
| `wix_bookings_cancel` | Cancel a booking | required |
|
|
346
|
+
|
|
347
|
+
### Events
|
|
348
|
+
|
|
349
|
+
| Tool | What it does | Approval |
|
|
350
|
+
|---|---|---|
|
|
351
|
+
| `wix_events_list` | List events | — |
|
|
352
|
+
| `wix_events_get` | Fetch one event | — |
|
|
353
|
+
| `wix_events_list_guests` | List guests / RSVPs / orders | — |
|
|
354
|
+
|
|
355
|
+
### Reviews
|
|
356
|
+
|
|
357
|
+
| Tool | What it does | Approval |
|
|
358
|
+
|---|---|---|
|
|
359
|
+
| `wix_reviews_list` | List reviews | — |
|
|
360
|
+
| `wix_reviews_get` | Fetch one review | — |
|
|
361
|
+
| `wix_reviews_moderate` | Approve / reject a pending review | required |
|
|
362
|
+
|
|
363
|
+
### FAQ
|
|
364
|
+
|
|
365
|
+
| Tool | What it does | Approval |
|
|
366
|
+
|---|---|---|
|
|
367
|
+
| `wix_faq_list_categories` | List FAQ categories | — |
|
|
368
|
+
| `wix_faq_list_questions` | List questions (filterable by category) | — |
|
|
369
|
+
| `wix_faq_create_question` | Create a question | — |
|
|
370
|
+
| `wix_faq_update_question` | Update a question | — |
|
|
371
|
+
| `wix_faq_delete_question` | Delete a question | required |
|
|
372
|
+
|
|
373
|
+
### Multilingual (read-only in V1)
|
|
374
|
+
|
|
375
|
+
| Tool | What it does | Approval |
|
|
376
|
+
|---|---|---|
|
|
377
|
+
| `wix_multilingual_list_languages` | List configured languages | — |
|
|
378
|
+
| `wix_multilingual_get_translation` | Read a translation by key | — |
|
|
379
|
+
|
|
380
|
+
### Design
|
|
381
|
+
|
|
382
|
+
| Tool | What it does | Approval |
|
|
383
|
+
|---|---|---|
|
|
384
|
+
| `wix_design_brief` | Turn a loose textual brief into a structured markdown artefact (palette, typography, sections, image-gen prompts). **Does NOT call the Wix API.** | — |
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
## Approval flow
|
|
389
|
+
|
|
390
|
+
When the LLM calls a destructive tool, the plugin's `before_tool_call` hook
|
|
391
|
+
fires and returns a `requireApproval` directive:
|
|
392
|
+
|
|
393
|
+
```json
|
|
394
|
+
{
|
|
395
|
+
"requireApproval": {
|
|
396
|
+
"title": "Wix: confirm wix_blog_publish_draft",
|
|
397
|
+
"description": "Tool `wix_blog_publish_draft` is about to run with the following parameters:\n\n```json\n{ \"draftPostId\": \"abc-123\" }\n```\n...",
|
|
398
|
+
"severity": "critical",
|
|
399
|
+
"timeoutMs": 600000,
|
|
400
|
+
"timeoutBehavior": "deny"
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
OpenClaw surfaces this to whichever channel/UI the operator is using
|
|
406
|
+
(Telegram inline buttons, Control UI badge, etc.). If no decision is made
|
|
407
|
+
within 10 minutes, the call is denied automatically.
|
|
408
|
+
|
|
409
|
+
You can override the gated set via `approvalRequired` in the plugin config —
|
|
410
|
+
use an empty array to disable gating entirely (not recommended in production).
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## Development
|
|
415
|
+
|
|
416
|
+
### Project layout
|
|
417
|
+
|
|
418
|
+
```
|
|
419
|
+
wix-openclaw-plugin/
|
|
420
|
+
├── src/
|
|
421
|
+
│ ├── index.ts # Entry point + tool collection
|
|
422
|
+
│ ├── config.ts # resolveEnv + default resolution
|
|
423
|
+
│ ├── wix-client.ts # Authenticated HTTP client + whitelist
|
|
424
|
+
│ ├── types.ts # Shared interfaces
|
|
425
|
+
│ ├── hooks/
|
|
426
|
+
│ │ └── approval.ts # before_tool_call approval gating
|
|
427
|
+
│ └── tools/
|
|
428
|
+
│ ├── _factory.ts # defineWixTool helper
|
|
429
|
+
│ ├── blog.ts
|
|
430
|
+
│ ├── media.ts
|
|
431
|
+
│ ├── site.ts
|
|
432
|
+
│ ├── data.ts
|
|
433
|
+
│ ├── forms.ts
|
|
434
|
+
│ ├── contacts.ts
|
|
435
|
+
│ ├── bookings.ts
|
|
436
|
+
│ ├── events.ts
|
|
437
|
+
│ ├── reviews.ts
|
|
438
|
+
│ ├── faq.ts
|
|
439
|
+
│ ├── multilingual.ts
|
|
440
|
+
│ └── design.ts
|
|
441
|
+
├── test/
|
|
442
|
+
│ ├── wix-client.test.ts
|
|
443
|
+
│ ├── manifest.test.ts
|
|
444
|
+
│ ├── hooks/approval.test.ts
|
|
445
|
+
│ └── tools/blog.test.ts
|
|
446
|
+
├── tsconfig.json
|
|
447
|
+
├── tsconfig.test.json
|
|
448
|
+
├── tsconfig.test-build.json
|
|
449
|
+
├── openclaw.plugin.json
|
|
450
|
+
└── package.json
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### Build and test
|
|
454
|
+
|
|
455
|
+
```bash
|
|
456
|
+
npm install
|
|
457
|
+
npm run typecheck # strict TS check (src + test)
|
|
458
|
+
npm test # compile tests + run node:test
|
|
459
|
+
npm run build # compile src/ → dist/
|
|
460
|
+
npm run clean # remove dist + dist-test
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
### Release process
|
|
464
|
+
|
|
465
|
+
1. Update `CHANGELOG.md` with a new `## [x.y.z] - YYYY-MM-DD` section
|
|
466
|
+
2. Commit
|
|
467
|
+
3. Tag and push:
|
|
468
|
+
```bash
|
|
469
|
+
git tag v0.1.0
|
|
470
|
+
git push origin v0.1.0
|
|
471
|
+
```
|
|
472
|
+
4. GitHub Actions will:
|
|
473
|
+
- Run typecheck, tests, build on Node.js 24
|
|
474
|
+
- Stamp the version into `package.json` and `openclaw.plugin.json`
|
|
475
|
+
- Publish to npm via **Trusted Publishing (OIDC)** — no `NPM_TOKEN`
|
|
476
|
+
secret needed
|
|
477
|
+
- Create a GitHub Release with the changelog excerpt
|
|
478
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
481
|
+
## License
|
|
482
|
+
|
|
483
|
+
MIT — see [LICENSE](LICENSE)
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ResolvedWixConfig, WixPluginConfig } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Expand `${VAR_NAME}` patterns in a config string against `process.env`.
|
|
4
|
+
* Non-string values are returned untouched so the helper can be used on any
|
|
5
|
+
* raw config field without type narrowing at the call site. Missing env vars
|
|
6
|
+
* become empty strings to avoid leaking `undefined` into downstream code.
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveEnv<T>(value: T): T;
|
|
9
|
+
/**
|
|
10
|
+
* Apply defaults and env substitution to the raw plugin config.
|
|
11
|
+
*
|
|
12
|
+
* - `enabled` is true unless explicitly set to `false`.
|
|
13
|
+
* - `defaultSiteId`, when blank, falls back to the first `allowedSiteIds`
|
|
14
|
+
* entry. This keeps single-site setups (the typical case) one field
|
|
15
|
+
* shorter without surprising whitelist behaviour.
|
|
16
|
+
* - `approvalRequired` defaults to every destructive operation; pass an
|
|
17
|
+
* empty array to disable gating entirely.
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveConfig(cfg?: WixPluginConfig): ResolvedWixConfig;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Plugin configuration helpers.
|
|
2
|
+
//
|
|
3
|
+
// These helpers are the only place that touches `process.env`, keeping the
|
|
4
|
+
// rest of the plugin easy to test with deterministic values.
|
|
5
|
+
/**
|
|
6
|
+
* Expand `${VAR_NAME}` patterns in a config string against `process.env`.
|
|
7
|
+
* Non-string values are returned untouched so the helper can be used on any
|
|
8
|
+
* raw config field without type narrowing at the call site. Missing env vars
|
|
9
|
+
* become empty strings to avoid leaking `undefined` into downstream code.
|
|
10
|
+
*/
|
|
11
|
+
export function resolveEnv(value) {
|
|
12
|
+
if (typeof value !== "string")
|
|
13
|
+
return value;
|
|
14
|
+
return value.replace(/\$\{(\w+)\}/g, (_, name) => {
|
|
15
|
+
return process.env[name] ?? "";
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
const DEFAULT_APPROVAL_REQUIRED = [
|
|
19
|
+
"wix_blog_publish_draft",
|
|
20
|
+
"wix_blog_unpublish",
|
|
21
|
+
"wix_blog_delete_draft",
|
|
22
|
+
"wix_data_remove_item",
|
|
23
|
+
"wix_contacts_delete",
|
|
24
|
+
"wix_bookings_reschedule",
|
|
25
|
+
"wix_bookings_cancel",
|
|
26
|
+
"wix_reviews_moderate",
|
|
27
|
+
"wix_faq_delete_question",
|
|
28
|
+
];
|
|
29
|
+
const VALID_LOG_LEVELS = ["debug", "info", "warn", "error"];
|
|
30
|
+
/**
|
|
31
|
+
* Apply defaults and env substitution to the raw plugin config.
|
|
32
|
+
*
|
|
33
|
+
* - `enabled` is true unless explicitly set to `false`.
|
|
34
|
+
* - `defaultSiteId`, when blank, falls back to the first `allowedSiteIds`
|
|
35
|
+
* entry. This keeps single-site setups (the typical case) one field
|
|
36
|
+
* shorter without surprising whitelist behaviour.
|
|
37
|
+
* - `approvalRequired` defaults to every destructive operation; pass an
|
|
38
|
+
* empty array to disable gating entirely.
|
|
39
|
+
*/
|
|
40
|
+
export function resolveConfig(cfg = {}) {
|
|
41
|
+
const apiKey = resolveEnv(cfg.apiKey ?? "");
|
|
42
|
+
const accountId = resolveEnv(cfg.accountId ?? "");
|
|
43
|
+
const allowedSiteIds = (cfg.allowedSiteIds ?? []).map((id) => resolveEnv(id));
|
|
44
|
+
const explicitDefault = resolveEnv(cfg.defaultSiteId ?? "");
|
|
45
|
+
const defaultSiteId = explicitDefault || (allowedSiteIds[0] ?? "");
|
|
46
|
+
const approvalRequired = cfg.approvalRequired ?? DEFAULT_APPROVAL_REQUIRED;
|
|
47
|
+
const logLevel = VALID_LOG_LEVELS.includes(cfg.logLevel)
|
|
48
|
+
? cfg.logLevel
|
|
49
|
+
: "info";
|
|
50
|
+
return {
|
|
51
|
+
enabled: cfg.enabled !== false,
|
|
52
|
+
apiKey,
|
|
53
|
+
accountId,
|
|
54
|
+
allowedSiteIds,
|
|
55
|
+
defaultSiteId,
|
|
56
|
+
approvalRequired: new Set(approvalRequired),
|
|
57
|
+
logLevel,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,EAAE;AACF,2EAA2E;AAC3E,6DAA6D;AAQ7D;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAI,KAAQ;IACpC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,OAAO,KAAK,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE,IAAY,EAAE,EAAE;QACvD,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACjC,CAAC,CAAiB,CAAC;AACrB,CAAC;AAED,MAAM,yBAAyB,GAAG;IAChC,wBAAwB;IACxB,oBAAoB;IACpB,uBAAuB;IACvB,sBAAsB;IACtB,qBAAqB;IACrB,yBAAyB;IACzB,qBAAqB;IACrB,sBAAsB;IACtB,yBAAyB;CAC1B,CAAC;AAEF,MAAM,gBAAgB,GAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAE3E;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa,CAC3B,MAAuB,EAAE;IAEzB,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IAC5C,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;IAClD,MAAM,cAAc,GAAG,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9E,MAAM,eAAe,GAAG,UAAU,CAAC,GAAG,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC;IAC5D,MAAM,aAAa,GACjB,eAAe,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAE/C,MAAM,gBAAgB,GAAG,GAAG,CAAC,gBAAgB,IAAI,yBAAyB,CAAC;IAE3E,MAAM,QAAQ,GAAgB,gBAAgB,CAAC,QAAQ,CACrD,GAAG,CAAC,QAAuB,CAC5B;QACC,CAAC,CAAE,GAAG,CAAC,QAAwB;QAC/B,CAAC,CAAC,MAAM,CAAC;IAEX,OAAO;QACL,OAAO,EAAE,GAAG,CAAC,OAAO,KAAK,KAAK;QAC9B,MAAM;QACN,SAAS;QACT,cAAc;QACd,aAAa;QACb,gBAAgB,EAAE,IAAI,GAAG,CAAC,gBAAgB,CAAC;QAC3C,QAAQ;KACT,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ResolvedWixConfig, WixLogger } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Shape of a `before_tool_call` event payload — only the fields we use.
|
|
4
|
+
* Mirrors `PluginHookBeforeToolCallEvent` from the SDK.
|
|
5
|
+
*/
|
|
6
|
+
export interface BeforeToolCallEvent {
|
|
7
|
+
toolName: string;
|
|
8
|
+
params: Record<string, unknown>;
|
|
9
|
+
runId?: string;
|
|
10
|
+
toolCallId?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Subset of the SDK's `PluginHookBeforeToolCallResult` that we produce.
|
|
14
|
+
*/
|
|
15
|
+
export interface BeforeToolCallResult {
|
|
16
|
+
requireApproval?: {
|
|
17
|
+
title: string;
|
|
18
|
+
description: string;
|
|
19
|
+
severity?: "info" | "warning" | "critical";
|
|
20
|
+
timeoutMs?: number;
|
|
21
|
+
timeoutBehavior?: "allow" | "deny";
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Build a `before_tool_call` handler bound to a resolved Wix config.
|
|
26
|
+
* Extracted as a factory so tests can exercise it without a full plugin
|
|
27
|
+
* registration.
|
|
28
|
+
*/
|
|
29
|
+
export declare function createApprovalHook(config: ResolvedWixConfig, logger: WixLogger): (event: BeforeToolCallEvent) => BeforeToolCallResult | undefined;
|