@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.
Files changed (59) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/LICENSE +21 -0
  3. package/README.md +483 -0
  4. package/dist/config.d.ts +19 -0
  5. package/dist/config.js +60 -0
  6. package/dist/config.js.map +1 -0
  7. package/dist/hooks/approval.d.ts +29 -0
  8. package/dist/hooks/approval.js +65 -0
  9. package/dist/hooks/approval.js.map +1 -0
  10. package/dist/index.d.ts +18 -0
  11. package/dist/index.js +97 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/tools/_factory.d.ts +40 -0
  14. package/dist/tools/_factory.js +69 -0
  15. package/dist/tools/_factory.js.map +1 -0
  16. package/dist/tools/blog.d.ts +140 -0
  17. package/dist/tools/blog.js +191 -0
  18. package/dist/tools/blog.js.map +1 -0
  19. package/dist/tools/bookings.d.ts +116 -0
  20. package/dist/tools/bookings.js +97 -0
  21. package/dist/tools/bookings.js.map +1 -0
  22. package/dist/tools/contacts.d.ts +216 -0
  23. package/dist/tools/contacts.js +128 -0
  24. package/dist/tools/contacts.js.map +1 -0
  25. package/dist/tools/data.d.ts +114 -0
  26. package/dist/tools/data.js +129 -0
  27. package/dist/tools/data.js.map +1 -0
  28. package/dist/tools/design.d.ts +32 -0
  29. package/dist/tools/design.js +165 -0
  30. package/dist/tools/design.js.map +1 -0
  31. package/dist/tools/events.d.ts +66 -0
  32. package/dist/tools/events.js +70 -0
  33. package/dist/tools/events.js.map +1 -0
  34. package/dist/tools/faq.d.ts +98 -0
  35. package/dist/tools/faq.js +90 -0
  36. package/dist/tools/faq.js.map +1 -0
  37. package/dist/tools/forms.d.ts +46 -0
  38. package/dist/tools/forms.js +63 -0
  39. package/dist/tools/forms.js.map +1 -0
  40. package/dist/tools/media.d.ts +50 -0
  41. package/dist/tools/media.js +75 -0
  42. package/dist/tools/media.js.map +1 -0
  43. package/dist/tools/multilingual.d.ts +38 -0
  44. package/dist/tools/multilingual.js +48 -0
  45. package/dist/tools/multilingual.js.map +1 -0
  46. package/dist/tools/reviews.d.ts +62 -0
  47. package/dist/tools/reviews.js +72 -0
  48. package/dist/tools/reviews.js.map +1 -0
  49. package/dist/tools/site.d.ts +36 -0
  50. package/dist/tools/site.js +94 -0
  51. package/dist/tools/site.js.map +1 -0
  52. package/dist/types.d.ts +58 -0
  53. package/dist/types.js +7 -0
  54. package/dist/types.js.map +1 -0
  55. package/dist/wix-client.d.ts +66 -0
  56. package/dist/wix-client.js +194 -0
  57. package/dist/wix-client.js.map +1 -0
  58. package/openclaw.plugin.json +95 -0
  59. package/package.json +72 -0
@@ -0,0 +1,72 @@
1
+ // Wix Reviews (`/reviews/v1/...`) tools.
2
+ //
3
+ // Requires the Wix Reviews app to be installed on the target site.
4
+ // Without it, calls return HTTP 428 `APP_NOT_INSTALLED`. Endpoint paths
5
+ // pattern-validated against the public docs; untested live (app not
6
+ // installed on the smoke-test site).
7
+ import { Type } from "@sinclair/typebox";
8
+ import { defineWixTool } from "./_factory.js";
9
+ const SiteIdParam = Type.Optional(Type.String());
10
+ export function buildReviewsTools(client) {
11
+ return [
12
+ defineWixTool({
13
+ name: "wix_reviews_list",
14
+ description: "List reviews. Filter by moderation status if needed.",
15
+ parameters: Type.Object({
16
+ siteId: SiteIdParam,
17
+ moderationStatus: Type.Optional(Type.Union([
18
+ Type.Literal("PENDING"),
19
+ Type.Literal("APPROVED"),
20
+ Type.Literal("REJECTED"),
21
+ ])),
22
+ paging: Type.Optional(Type.Object({
23
+ limit: Type.Optional(Type.Number({ minimum: 1, maximum: 100 })),
24
+ offset: Type.Optional(Type.Number({ minimum: 0 })),
25
+ })),
26
+ }),
27
+ run: (params) => client.request("POST", "/reviews/v1/reviews/query", {
28
+ siteId: params.siteId,
29
+ body: {
30
+ query: {
31
+ filter: params.moderationStatus
32
+ ? { moderationStatus: params.moderationStatus }
33
+ : undefined,
34
+ paging: params.paging,
35
+ },
36
+ },
37
+ }),
38
+ }, client),
39
+ defineWixTool({
40
+ name: "wix_reviews_get",
41
+ description: "Fetch a single review by id.",
42
+ parameters: Type.Object({
43
+ siteId: SiteIdParam,
44
+ reviewId: Type.String(),
45
+ }),
46
+ run: (params) => client.request("GET", `/reviews/v1/reviews/${encodeURIComponent(params.reviewId)}`, { siteId: params.siteId }),
47
+ }, client),
48
+ defineWixTool({
49
+ name: "wix_reviews_moderate",
50
+ description: "Approve or reject a pending review. APPROVAL GATED.",
51
+ parameters: Type.Object({
52
+ siteId: SiteIdParam,
53
+ reviewId: Type.String(),
54
+ decision: Type.Union([
55
+ Type.Literal("APPROVED"),
56
+ Type.Literal("REJECTED"),
57
+ ]),
58
+ reason: Type.Optional(Type.String({
59
+ description: "Optional reason for rejection — surfaced to the reviewer.",
60
+ })),
61
+ }),
62
+ run: (params) => {
63
+ const verb = params.decision === "APPROVED" ? "approve" : "reject";
64
+ return client.request("POST", `/reviews/v1/reviews/${encodeURIComponent(params.reviewId)}/${verb}`, {
65
+ siteId: params.siteId,
66
+ body: params.reason ? { reason: params.reason } : {},
67
+ });
68
+ },
69
+ }, client),
70
+ ];
71
+ }
72
+ //# sourceMappingURL=reviews.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviews.js","sourceRoot":"","sources":["../../src/tools/reviews.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import type { WixClient } from "../wix-client.js";
2
+ export declare function buildSiteTools(client: WixClient): ({
3
+ name: string;
4
+ description: string;
5
+ label: string;
6
+ parameters: import("@sinclair/typebox").TObject<{
7
+ paging: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
8
+ limit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
9
+ offset: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
10
+ }>>;
11
+ }>;
12
+ execute: (toolCallId: string, params: {
13
+ paging?: {
14
+ limit?: number | undefined;
15
+ offset?: number | undefined;
16
+ } | undefined;
17
+ }, signal?: AbortSignal) => Promise<import("@mariozechner/pi-agent-core").AgentToolResult<{
18
+ status: "ok" | "failed";
19
+ data?: unknown;
20
+ error?: string;
21
+ }>>;
22
+ } | {
23
+ name: string;
24
+ description: string;
25
+ label: string;
26
+ parameters: import("@sinclair/typebox").TObject<{
27
+ siteId: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
28
+ }>;
29
+ execute: (toolCallId: string, params: {
30
+ siteId?: string | undefined;
31
+ }, signal?: AbortSignal) => Promise<import("@mariozechner/pi-agent-core").AgentToolResult<{
32
+ status: "ok" | "failed";
33
+ data?: unknown;
34
+ error?: string;
35
+ }>>;
36
+ })[];
@@ -0,0 +1,94 @@
1
+ // Wix Sites + Site Properties tools (read-only).
2
+ //
3
+ // `wix_sites_list` and `wix_site_url_get` are account-scoped — they hit
4
+ // the Site List API and Published Site URLs API and require the
5
+ // `wix-account-id` header (siteScoped: false).
6
+ // `wix_business_info_get` reads from the Site Properties API and is
7
+ // site-scoped.
8
+ //
9
+ // Verified against:
10
+ // - https://dev.wix.com/docs/rest/account-level/sites/sites/query-sites
11
+ // - https://dev.wix.com/docs/api-reference/business-management/site-urls/published-site-urls/list-published-site-urls
12
+ // - https://dev.wix.com/docs/rest/business-management/site-properties/properties/get-site-properties
13
+ import { Type } from "@sinclair/typebox";
14
+ import { defineWixTool } from "./_factory.js";
15
+ export function buildSiteTools(client) {
16
+ return [
17
+ defineWixTool({
18
+ name: "wix_sites_list",
19
+ description: "Query Wix sites under the configured account. Account-scoped — no site id required. Returns up to 1,000 sites.",
20
+ parameters: Type.Object({
21
+ paging: Type.Optional(Type.Object({
22
+ limit: Type.Optional(Type.Number({ minimum: 1, maximum: 1000 })),
23
+ offset: Type.Optional(Type.Number({ minimum: 0 })),
24
+ })),
25
+ }),
26
+ run: (params) => client.request("POST", "/site-list/v2/sites/query", {
27
+ siteScoped: false,
28
+ body: {
29
+ query: {
30
+ paging: params.paging
31
+ ? {
32
+ limit: params.paging.limit,
33
+ offset: params.paging.offset,
34
+ }
35
+ : undefined,
36
+ },
37
+ },
38
+ }),
39
+ }, client),
40
+ defineWixTool({
41
+ name: "wix_site_url_get",
42
+ description: "Get the published URL, editor URL, publish status and domain status for a site. " +
43
+ "Backed by the Site List API — needs the `Get Sites List` permission only.",
44
+ parameters: Type.Object({
45
+ siteId: Type.Optional(Type.String({
46
+ description: "Site UUID. Optional — falls back to defaultSiteId.",
47
+ })),
48
+ }),
49
+ run: async (params) => {
50
+ // This call is account-scoped, so we cannot rely on the
51
+ // `wix-site-id` header to inject the default. Read it directly
52
+ // from the client instead.
53
+ const targetId = params.siteId ?? client.defaultSiteId;
54
+ if (!targetId) {
55
+ throw new Error("wix_site_url_get requires a siteId. Set defaultSiteId in " +
56
+ "the plugin config or pass siteId explicitly.");
57
+ }
58
+ const resp = await client.request("POST", "/site-list/v2/sites/query", {
59
+ siteScoped: false,
60
+ body: {
61
+ query: {
62
+ filter: { metaSiteId: targetId },
63
+ paging: { limit: 1 },
64
+ },
65
+ },
66
+ });
67
+ const site = resp?.sites?.[0];
68
+ if (!site) {
69
+ return { error: `Site ${targetId} not found in this account.` };
70
+ }
71
+ return {
72
+ siteId: site.id,
73
+ displayName: site.displayName,
74
+ viewUrl: site.viewUrl,
75
+ editUrl: site.editUrl,
76
+ published: site.published,
77
+ domainConnected: site.domainConnected,
78
+ premium: site.premium,
79
+ };
80
+ },
81
+ }, client),
82
+ defineWixTool({
83
+ name: "wix_business_info_get",
84
+ description: "Read site properties (business profile, contact info, address, schedule, locale, time zone) for the configured site.",
85
+ parameters: Type.Object({
86
+ siteId: Type.Optional(Type.String()),
87
+ }),
88
+ run: (params) => client.request("GET", "/site-properties/v4/properties", {
89
+ siteId: params.siteId,
90
+ }),
91
+ }, client),
92
+ ];
93
+ }
94
+ //# sourceMappingURL=site.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"site.js","sourceRoot":"","sources":["../../src/tools/site.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Runtime configuration as it appears in
3
+ * `plugins.entries.wix-openclaw.config`. All fields are optional — defaults
4
+ * are applied in {@link resolveConfig}.
5
+ */
6
+ export interface WixPluginConfig {
7
+ enabled?: boolean;
8
+ apiKey?: string;
9
+ accountId?: string;
10
+ allowedSiteIds?: string[];
11
+ defaultSiteId?: string;
12
+ approvalRequired?: string[];
13
+ logLevel?: WixLogLevel;
14
+ }
15
+ export type WixLogLevel = "debug" | "info" | "warn" | "error";
16
+ /**
17
+ * Fully resolved plugin configuration after defaults and env substitution.
18
+ */
19
+ export interface ResolvedWixConfig {
20
+ enabled: boolean;
21
+ apiKey: string;
22
+ accountId: string;
23
+ allowedSiteIds: string[];
24
+ defaultSiteId: string;
25
+ approvalRequired: Set<string>;
26
+ logLevel: WixLogLevel;
27
+ }
28
+ /**
29
+ * Options for a single Wix REST request through {@link WixClient.request}.
30
+ *
31
+ * - `siteScoped` (default `true`) injects the `wix-site-id` header. Set to
32
+ * `false` for account-level endpoints (e.g. `/sites/v1/sites`).
33
+ * - `siteId` overrides the default site for this call. Must be present in
34
+ * `allowedSiteIds`, otherwise the request is rejected before any network
35
+ * round trip.
36
+ * - `query` is appended as URL search params after dropping `undefined`
37
+ * values.
38
+ * - `body` is JSON-encoded automatically.
39
+ * - `signal` is forwarded to `fetch` for cancellation.
40
+ */
41
+ export interface WixRequestOptions {
42
+ siteScoped?: boolean;
43
+ siteId?: string;
44
+ query?: Record<string, string | number | boolean | undefined>;
45
+ body?: unknown;
46
+ signal?: AbortSignal;
47
+ }
48
+ /**
49
+ * Plugin logger surface — structurally compatible with `PluginLogger` from
50
+ * the SDK. `debug` is optional because the SDK's contract makes it
51
+ * optional too; helpers should guard with `logger.debug?.(...)`.
52
+ */
53
+ export interface WixLogger {
54
+ debug?: (msg: string) => void;
55
+ info: (msg: string) => void;
56
+ warn: (msg: string) => void;
57
+ error: (msg: string) => void;
58
+ }
package/dist/types.js ADDED
@@ -0,0 +1,7 @@
1
+ // Type definitions for the wix-openclaw plugin.
2
+ //
3
+ // Kept separate from the entry point so that tools, hooks, and the HTTP
4
+ // client can import them without pulling in the full plugin registration
5
+ // code.
6
+ export {};
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,EAAE;AACF,wEAAwE;AACxE,yEAAyE;AACzE,QAAQ"}
@@ -0,0 +1,66 @@
1
+ import type { ResolvedWixConfig, WixLogger, WixRequestOptions } from "./types.js";
2
+ /**
3
+ * Thrown when the agent passes a `siteId` that is not in
4
+ * `config.allowedSiteIds`. The error never reaches the network — the check
5
+ * is performed before `fetch` is called.
6
+ */
7
+ export declare class WixSiteNotAllowedError extends Error {
8
+ constructor(siteId: string, allowed: string[]);
9
+ }
10
+ /**
11
+ * Thrown for non-retryable HTTP errors (4xx other than 429). The message
12
+ * includes the response status and the first 300 chars of the body for
13
+ * easier debugging.
14
+ */
15
+ export declare class WixApiError extends Error {
16
+ readonly status: number;
17
+ readonly bodyPreview: string;
18
+ constructor(status: number, bodyPreview: string, path: string);
19
+ }
20
+ /**
21
+ * Authenticated, site-aware Wix REST client.
22
+ *
23
+ * One instance per plugin registration — it captures the resolved config
24
+ * (api key, account id, whitelist) so callers can stay declarative.
25
+ */
26
+ export declare class WixClient {
27
+ private readonly config;
28
+ private readonly logger;
29
+ private readonly baseUrl;
30
+ private readonly fetchImpl;
31
+ constructor(config: ResolvedWixConfig, logger: WixLogger, options?: {
32
+ baseUrl?: string;
33
+ fetchImpl?: typeof fetch;
34
+ });
35
+ /**
36
+ * Public read-only access to the configured default site id. Tools that
37
+ * make account-scoped calls but still need to target a single site (e.g.
38
+ * `wix_site_url_get` filtering the sites query by id) can read it here.
39
+ */
40
+ get defaultSiteId(): string;
41
+ /**
42
+ * Resolve the effective site id for a request and validate it against the
43
+ * whitelist. Throws {@link WixSiteNotAllowedError} on mismatch. Returns
44
+ * `null` for non-site-scoped requests.
45
+ */
46
+ resolveSiteId(opts: WixRequestOptions): string | null;
47
+ /**
48
+ * Build the headers for a single request.
49
+ *
50
+ * Wix docs: "you must also include one of the following headers,
51
+ * depending on the type of call: `wix-account-id` ... or `wix-site-id`".
52
+ * We pick exactly one — `wix-site-id` for site-scoped calls,
53
+ * `wix-account-id` for account-scoped calls. Sending both is technically
54
+ * tolerated by Wix but contradicts the docs and risks future tightening.
55
+ */
56
+ private buildHeaders;
57
+ /**
58
+ * Perform an authenticated request against the Wix REST API. Retries up
59
+ * to {@link MAX_RETRIES} times on 429/5xx with exponential backoff.
60
+ *
61
+ * Returns the parsed JSON response, or `null` for empty 2xx bodies (e.g.
62
+ * 204 No Content). Throws {@link WixApiError} on non-retryable failures
63
+ * and {@link WixSiteNotAllowedError} on whitelist violations.
64
+ */
65
+ request<TResponse = unknown>(method: "GET" | "POST" | "PATCH" | "PUT" | "DELETE", path: string, opts?: WixRequestOptions): Promise<TResponse | null>;
66
+ }
@@ -0,0 +1,194 @@
1
+ // Wix REST API HTTP client.
2
+ //
3
+ // Centralises authentication, site whitelist enforcement, retry on 429, and
4
+ // JSON serialisation so individual tools stay thin. Uses Node's native
5
+ // `fetch` (Node 22+) — no axios, no node-fetch.
6
+ //
7
+ // Header conventions (verified against Wix REST docs):
8
+ // - `Authorization: <apiKey>` (raw key, NOT prefixed with "Bearer ")
9
+ // - `wix-account-id: <accountId>`
10
+ // - `wix-site-id: <siteId>` (only for site-scoped endpoints)
11
+ const DEFAULT_BASE_URL = "https://www.wixapis.com";
12
+ const RETRY_STATUSES = new Set([429, 502, 503, 504]);
13
+ const MAX_RETRIES = 2;
14
+ const INITIAL_BACKOFF_MS = 500;
15
+ /**
16
+ * Thrown when the agent passes a `siteId` that is not in
17
+ * `config.allowedSiteIds`. The error never reaches the network — the check
18
+ * is performed before `fetch` is called.
19
+ */
20
+ export class WixSiteNotAllowedError extends Error {
21
+ constructor(siteId, allowed) {
22
+ super(`Wix site "${siteId}" is not in the allowed list ` +
23
+ `(${allowed.length === 0 ? "<empty>" : allowed.join(", ")}). ` +
24
+ `Add it to plugins.entries.wix-openclaw.config.allowedSiteIds to enable.`);
25
+ this.name = "WixSiteNotAllowedError";
26
+ }
27
+ }
28
+ /**
29
+ * Thrown for non-retryable HTTP errors (4xx other than 429). The message
30
+ * includes the response status and the first 300 chars of the body for
31
+ * easier debugging.
32
+ */
33
+ export class WixApiError extends Error {
34
+ status;
35
+ bodyPreview;
36
+ constructor(status, bodyPreview, path) {
37
+ super(`Wix API ${status} on ${path}: ${bodyPreview.slice(0, 300)}`);
38
+ this.name = "WixApiError";
39
+ this.status = status;
40
+ this.bodyPreview = bodyPreview;
41
+ }
42
+ }
43
+ /**
44
+ * Sleep for `ms` milliseconds. Extracted for testability.
45
+ */
46
+ function sleep(ms) {
47
+ return new Promise((resolve) => setTimeout(resolve, ms));
48
+ }
49
+ /**
50
+ * Convert a record of query values to a URL-encoded search string. Drops
51
+ * `undefined` values and serialises booleans/numbers via `String()`.
52
+ */
53
+ function buildQueryString(query) {
54
+ if (!query)
55
+ return "";
56
+ const entries = Object.entries(query).filter(([, v]) => v !== undefined && v !== null);
57
+ if (entries.length === 0)
58
+ return "";
59
+ const params = new URLSearchParams();
60
+ for (const [k, v] of entries) {
61
+ params.set(k, String(v));
62
+ }
63
+ return `?${params.toString()}`;
64
+ }
65
+ /**
66
+ * Authenticated, site-aware Wix REST client.
67
+ *
68
+ * One instance per plugin registration — it captures the resolved config
69
+ * (api key, account id, whitelist) so callers can stay declarative.
70
+ */
71
+ export class WixClient {
72
+ config;
73
+ logger;
74
+ baseUrl;
75
+ fetchImpl;
76
+ constructor(config, logger, options = {}) {
77
+ this.config = config;
78
+ this.logger = logger;
79
+ this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
80
+ this.fetchImpl = options.fetchImpl ?? fetch;
81
+ }
82
+ /**
83
+ * Public read-only access to the configured default site id. Tools that
84
+ * make account-scoped calls but still need to target a single site (e.g.
85
+ * `wix_site_url_get` filtering the sites query by id) can read it here.
86
+ */
87
+ get defaultSiteId() {
88
+ return this.config.defaultSiteId;
89
+ }
90
+ /**
91
+ * Resolve the effective site id for a request and validate it against the
92
+ * whitelist. Throws {@link WixSiteNotAllowedError} on mismatch. Returns
93
+ * `null` for non-site-scoped requests.
94
+ */
95
+ resolveSiteId(opts) {
96
+ if (opts.siteScoped === false)
97
+ return null;
98
+ const candidate = opts.siteId ?? this.config.defaultSiteId;
99
+ if (!candidate) {
100
+ throw new Error("Wix request requires a site id but none is configured. " +
101
+ "Set `defaultSiteId` in the plugin config or pass `siteId` " +
102
+ "explicitly in the tool call.");
103
+ }
104
+ if (!this.config.allowedSiteIds.includes(candidate)) {
105
+ throw new WixSiteNotAllowedError(candidate, this.config.allowedSiteIds);
106
+ }
107
+ return candidate;
108
+ }
109
+ /**
110
+ * Build the headers for a single request.
111
+ *
112
+ * Wix docs: "you must also include one of the following headers,
113
+ * depending on the type of call: `wix-account-id` ... or `wix-site-id`".
114
+ * We pick exactly one — `wix-site-id` for site-scoped calls,
115
+ * `wix-account-id` for account-scoped calls. Sending both is technically
116
+ * tolerated by Wix but contradicts the docs and risks future tightening.
117
+ */
118
+ buildHeaders(siteId) {
119
+ const headers = {
120
+ "Content-Type": "application/json",
121
+ Accept: "application/json",
122
+ Authorization: this.config.apiKey,
123
+ };
124
+ if (siteId) {
125
+ headers["wix-site-id"] = siteId;
126
+ }
127
+ else if (this.config.accountId) {
128
+ headers["wix-account-id"] = this.config.accountId;
129
+ }
130
+ return headers;
131
+ }
132
+ /**
133
+ * Perform an authenticated request against the Wix REST API. Retries up
134
+ * to {@link MAX_RETRIES} times on 429/5xx with exponential backoff.
135
+ *
136
+ * Returns the parsed JSON response, or `null` for empty 2xx bodies (e.g.
137
+ * 204 No Content). Throws {@link WixApiError} on non-retryable failures
138
+ * and {@link WixSiteNotAllowedError} on whitelist violations.
139
+ */
140
+ async request(method, path, opts = {}) {
141
+ const siteId = this.resolveSiteId(opts);
142
+ const url = this.baseUrl + path + buildQueryString(opts.query);
143
+ const headers = this.buildHeaders(siteId);
144
+ const body = opts.body !== undefined ? JSON.stringify(opts.body) : undefined;
145
+ if (this.config.logLevel === "debug") {
146
+ this.logger.debug?.(`wix: ${method} ${path}${siteId ? ` site=${siteId.slice(0, 8)}` : ""}` +
147
+ (body ? ` body=${body.slice(0, 200)}` : ""));
148
+ }
149
+ let attempt = 0;
150
+ let lastErrorBody = "";
151
+ let lastStatus = 0;
152
+ while (attempt <= MAX_RETRIES) {
153
+ const resp = await this.fetchImpl(url, {
154
+ method,
155
+ headers,
156
+ body,
157
+ signal: opts.signal,
158
+ });
159
+ if (resp.ok) {
160
+ // 204 No Content or any empty body — return null so callers can
161
+ // distinguish "succeeded with no payload" from "succeeded with
162
+ // empty object".
163
+ const text = await resp.text();
164
+ if (!text)
165
+ return null;
166
+ try {
167
+ return JSON.parse(text);
168
+ }
169
+ catch {
170
+ // Wix sometimes returns text/plain for trivial endpoints — return
171
+ // it raw rather than crashing.
172
+ return text;
173
+ }
174
+ }
175
+ lastStatus = resp.status;
176
+ lastErrorBody = await resp.text();
177
+ if (!RETRY_STATUSES.has(resp.status) || attempt === MAX_RETRIES) {
178
+ throw new WixApiError(resp.status, lastErrorBody, path);
179
+ }
180
+ // Honour `Retry-After` if present, else exponential backoff.
181
+ const retryAfter = resp.headers.get("retry-after");
182
+ const backoff = retryAfter
183
+ ? parseInt(retryAfter, 10) * 1000
184
+ : INITIAL_BACKOFF_MS * Math.pow(2, attempt);
185
+ this.logger.warn(`wix: ${method} ${path} → ${resp.status}, retrying in ${backoff}ms (attempt ${attempt + 1}/${MAX_RETRIES})`);
186
+ await sleep(backoff);
187
+ attempt++;
188
+ }
189
+ // Defensive: should be unreachable since the loop either returns or
190
+ // throws on the last attempt.
191
+ throw new WixApiError(lastStatus, lastErrorBody, path);
192
+ }
193
+ }
194
+ //# sourceMappingURL=wix-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wix-client.js","sourceRoot":"","sources":["../src/wix-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,95 @@
1
+ {
2
+ "id": "wix-openclaw",
3
+ "name": "Wix",
4
+ "description": "Wix REST API plugin for OpenClaw — manage blog, CMS data, forms, bookings, contacts, events, FAQ on a single Wix site with site_id whitelist and approval gating on destructive ops",
5
+ "version": "0.1.0",
6
+ "configSchema": {
7
+ "type": "object",
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "enabled": {
11
+ "type": "boolean",
12
+ "default": true,
13
+ "description": "Master switch — disables all Wix tools when false"
14
+ },
15
+ "apiKey": {
16
+ "type": "string",
17
+ "description": "Wix API key sent raw as the `Authorization` header (NOT prefixed with 'Bearer '). Supports ${ENV_VAR} substitution."
18
+ },
19
+ "accountId": {
20
+ "type": "string",
21
+ "description": "Wix account UUID sent as the `wix-account-id` header. Supports ${ENV_VAR} substitution."
22
+ },
23
+ "allowedSiteIds": {
24
+ "type": "array",
25
+ "items": { "type": "string" },
26
+ "default": [],
27
+ "description": "Whitelist of Wix site UUIDs the plugin is allowed to operate on. Any tool call referencing a site outside this list is rejected before any HTTP request is made."
28
+ },
29
+ "defaultSiteId": {
30
+ "type": "string",
31
+ "description": "Default Wix site UUID injected as the `wix-site-id` header when a tool does not explicitly provide one. Must be present in `allowedSiteIds`. Supports ${ENV_VAR} substitution."
32
+ },
33
+ "approvalRequired": {
34
+ "type": "array",
35
+ "items": { "type": "string" },
36
+ "default": [
37
+ "wix_blog_publish_draft",
38
+ "wix_blog_unpublish",
39
+ "wix_blog_delete_draft",
40
+ "wix_data_remove_item",
41
+ "wix_contacts_delete",
42
+ "wix_bookings_reschedule",
43
+ "wix_bookings_cancel",
44
+ "wix_reviews_moderate",
45
+ "wix_faq_delete_question"
46
+ ],
47
+ "description": "Tool names that trigger an approval prompt via the `before_tool_call` hook before being executed. Defaults to every destructive operation."
48
+ },
49
+ "logLevel": {
50
+ "type": "string",
51
+ "enum": ["debug", "info", "warn", "error"],
52
+ "default": "info",
53
+ "description": "Plugin log verbosity. `debug` includes request bodies (be mindful of PII)."
54
+ }
55
+ },
56
+ "required": []
57
+ },
58
+ "uiHints": {
59
+ "enabled": {
60
+ "label": "Enable Wix tools",
61
+ "help": "Master switch — turn off to fully disable all wix_* tools without uninstalling"
62
+ },
63
+ "apiKey": {
64
+ "label": "Wix API Key",
65
+ "placeholder": "${WIX_API_KEY}",
66
+ "sensitive": true,
67
+ "help": "Wix REST API key. Sent raw in the `Authorization` header (no `Bearer ` prefix)."
68
+ },
69
+ "accountId": {
70
+ "label": "Wix Account ID",
71
+ "placeholder": "${WIX_ACCOUNT_ID}",
72
+ "sensitive": true,
73
+ "help": "Wix account UUID, sent as `wix-account-id` on every request"
74
+ },
75
+ "allowedSiteIds": {
76
+ "label": "Allowed Site IDs",
77
+ "help": "Whitelist of Wix site UUIDs. The plugin refuses to call any site outside this list."
78
+ },
79
+ "defaultSiteId": {
80
+ "label": "Default Site ID",
81
+ "placeholder": "${WIX_SITE_ID_ATARAXIS}",
82
+ "help": "Site UUID used when a tool does not specify one. Must appear in allowedSiteIds."
83
+ },
84
+ "approvalRequired": {
85
+ "label": "Tools requiring approval",
86
+ "advanced": true,
87
+ "help": "Tool names that trigger a `before_tool_call` approval prompt. Defaults cover every destructive operation."
88
+ },
89
+ "logLevel": {
90
+ "label": "Log level",
91
+ "advanced": true,
92
+ "help": "info (default), debug includes request bodies"
93
+ }
94
+ }
95
+ }