@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
|
@@ -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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"}
|
package/dist/types.d.ts
ADDED
|
@@ -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 @@
|
|
|
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
|
+
}
|