@elvatis_com/openclaw-ispconfig 0.1.2
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/LICENSE +21 -0
- package/README.md +138 -0
- package/dist/client.d.ts +16 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +162 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +14 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +132 -0
- package/dist/errors.js.map +1 -0
- package/dist/guards.d.ts +4 -0
- package/dist/guards.d.ts.map +1 -0
- package/dist/guards.js +32 -0
- package/dist/guards.js.map +1 -0
- package/dist/index.d.ts +71 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/tools.d.ts +3 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +409 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +130 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/validate.d.ts +21 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +89 -0
- package/dist/validate.js.map +1 -0
- package/openclaw.plugin.json +81 -0
- package/package.json +44 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Elvatis - Emre Kohler
|
|
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,138 @@
|
|
|
1
|
+
# @elvatis_com/openclaw-ispconfig
|
|
2
|
+
|
|
3
|
+
OpenClaw plugin to manage ISPConfig via the Remote JSON API.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Session-based API client with auto-reconnect
|
|
8
|
+
- 31 tools for read, write, and one-command provisioning
|
|
9
|
+
- Safety guards via `readOnly` and `allowedOperations`
|
|
10
|
+
- Live integration tests against a real ISPConfig host (read-only)
|
|
11
|
+
|
|
12
|
+
## ISPConfig API format
|
|
13
|
+
|
|
14
|
+
This plugin uses the JSON endpoint format:
|
|
15
|
+
|
|
16
|
+
- URL: `https://server:8080/remote/json.php?method_name`
|
|
17
|
+
- Method is passed as query string, not in JSON body
|
|
18
|
+
- Body format:
|
|
19
|
+
- login: `{ "username": "...", "password": "..." }`
|
|
20
|
+
- normal calls: `{ "session_id": "...", ...params }`
|
|
21
|
+
- logout: `{ "session_id": "..." }`
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
### ClawHub
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
clawhub install openclaw-ispconfig
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### npm
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install @elvatis_com/openclaw-ispconfig
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## ISPConfig setup
|
|
38
|
+
|
|
39
|
+
1. In ISPConfig, create a Remote User.
|
|
40
|
+
2. Grant required API permissions.
|
|
41
|
+
3. Copy endpoint URL and credentials.
|
|
42
|
+
4. Configure plugin in OpenClaw.
|
|
43
|
+
|
|
44
|
+
## Configuration
|
|
45
|
+
|
|
46
|
+
`openclaw.plugin.json` config keys:
|
|
47
|
+
|
|
48
|
+
- `apiUrl` (required): ISPConfig JSON API URL
|
|
49
|
+
- `username` (required): remote user
|
|
50
|
+
- `password` (required, secret): remote password
|
|
51
|
+
- `serverId` (default `1`): default server id
|
|
52
|
+
- `defaultServerIp` (optional): fallback IP for provisioning DNS A record
|
|
53
|
+
- `readOnly` (default `false`): block write tools
|
|
54
|
+
- `allowedOperations` (default `[]`): whitelist of tool names
|
|
55
|
+
- `verifySsl` (default `true`): TLS certificate verification
|
|
56
|
+
|
|
57
|
+
## Tools
|
|
58
|
+
|
|
59
|
+
### Read tools
|
|
60
|
+
|
|
61
|
+
- `isp_methods_list` params: none
|
|
62
|
+
- `isp_system_info` params: none
|
|
63
|
+
- `isp_client_list` params: optional filter fields
|
|
64
|
+
- `isp_client_get` params: `client_id`
|
|
65
|
+
- `isp_sites_list` params: optional filters accepted by `sites_web_domain_get`
|
|
66
|
+
- `isp_site_get` params: `primary_id` (or `site_id`, `domain_id`)
|
|
67
|
+
- `isp_domains_list` params: none
|
|
68
|
+
- `isp_dns_zone_list` params: user-related filter params
|
|
69
|
+
- `isp_dns_record_list` params: `zone_id`
|
|
70
|
+
- `isp_mail_domain_list` params: optional filters
|
|
71
|
+
- `isp_mail_user_list` params: optional filters
|
|
72
|
+
- `isp_db_list` params: user-related filters
|
|
73
|
+
- `isp_ssl_status` params: none
|
|
74
|
+
- `isp_quota_check` params: `client_id`
|
|
75
|
+
- `isp_backup_list` params: none (returns skipped if API method unavailable)
|
|
76
|
+
- `isp_cron_list` params: optional filters
|
|
77
|
+
|
|
78
|
+
### Write tools
|
|
79
|
+
|
|
80
|
+
- `isp_client_add` params: ISPConfig `client_add` payload
|
|
81
|
+
- `isp_site_add` params: ISPConfig `sites_web_domain_add` payload
|
|
82
|
+
- `isp_domain_add` params: alias for `isp_site_add`
|
|
83
|
+
- `isp_dns_zone_add` params: ISPConfig `dns_zone_add` payload
|
|
84
|
+
- `isp_dns_record_add` params: include `type` (`A`, `AAAA`, `MX`, `TXT`, `CNAME`) and matching payload
|
|
85
|
+
- `isp_dns_record_delete` params: include `type` and matching delete payload
|
|
86
|
+
- `isp_mail_domain_add` params: ISPConfig `mail_domain_add` payload
|
|
87
|
+
- `isp_mail_user_add` params: ISPConfig `mail_user_add` payload
|
|
88
|
+
- `isp_mail_user_delete` params: ISPConfig `mail_user_delete` payload
|
|
89
|
+
- `isp_db_add` params: ISPConfig `sites_database_add` payload
|
|
90
|
+
- `isp_db_user_add` params: ISPConfig `sites_database_user_add` payload
|
|
91
|
+
- `isp_shell_user_add` params: ISPConfig `sites_shell_user_add` payload
|
|
92
|
+
- `isp_ftp_user_add` params: ISPConfig `sites_ftp_user_add` payload
|
|
93
|
+
- `isp_cron_add` params: ISPConfig `sites_cron_add` payload
|
|
94
|
+
|
|
95
|
+
### Provisioning tool
|
|
96
|
+
|
|
97
|
+
- `isp_provision_site`
|
|
98
|
+
- Required params:
|
|
99
|
+
- `domain`
|
|
100
|
+
- `clientName`
|
|
101
|
+
- `clientEmail`
|
|
102
|
+
- Optional params:
|
|
103
|
+
- `serverIp`
|
|
104
|
+
- `createMail` (default `true`)
|
|
105
|
+
- `createDb` (default `true`)
|
|
106
|
+
- `serverId` (default from config)
|
|
107
|
+
|
|
108
|
+
Workflow:
|
|
109
|
+
|
|
110
|
+
1. Create client
|
|
111
|
+
2. Create site with SSL and Let's Encrypt enabled
|
|
112
|
+
3. Create DNS zone
|
|
113
|
+
4. Add DNS records (`A`, `CNAME`, SPF TXT, DMARC TXT)
|
|
114
|
+
5. Optionally create mail domain and `info@` + `admin@` mailboxes
|
|
115
|
+
6. Optionally create DB user and database
|
|
116
|
+
7. Ensure SSL flags are enabled on the site
|
|
117
|
+
|
|
118
|
+
## Safety
|
|
119
|
+
|
|
120
|
+
- `readOnly=true` blocks all write and provisioning tools
|
|
121
|
+
- `allowedOperations=[...]` allows only named tools
|
|
122
|
+
|
|
123
|
+
## Development
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
npm run build
|
|
127
|
+
npm test
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
For live tests, provide environment variables:
|
|
131
|
+
|
|
132
|
+
- `ISPCONFIG_API_URL`
|
|
133
|
+
- `ISPCONFIG_USER`
|
|
134
|
+
- `ISPCONFIG_PASS`
|
|
135
|
+
|
|
136
|
+
## License
|
|
137
|
+
|
|
138
|
+
MIT
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ISPConfigPluginConfig, JsonMap } from "./types";
|
|
2
|
+
export declare class ISPConfigClient {
|
|
3
|
+
private readonly config;
|
|
4
|
+
private readonly url;
|
|
5
|
+
private readonly timeoutMs;
|
|
6
|
+
private readonly verifySsl;
|
|
7
|
+
private sessionId;
|
|
8
|
+
private isLoggingIn;
|
|
9
|
+
constructor(config: ISPConfigPluginConfig);
|
|
10
|
+
login(): Promise<string>;
|
|
11
|
+
logout(): Promise<unknown>;
|
|
12
|
+
call<T>(method: string, params?: JsonMap): Promise<T>;
|
|
13
|
+
private shouldRetrySession;
|
|
14
|
+
private rawCall;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAIA,OAAO,EAAwB,qBAAqB,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAE/E,qBAAa,eAAe;IAOP,OAAO,CAAC,QAAQ,CAAC,MAAM;IAN1C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAM;IAC1B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAU;IACpC,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,WAAW,CAAS;gBAEQ,MAAM,EAAE,qBAAqB;IAMpD,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IA2BxB,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IAY1B,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,OAAY,GAAG,OAAO,CAAC,CAAC,CAAC;IAetE,OAAO,CAAC,kBAAkB;YAWZ,OAAO;CA0FtB"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ISPConfigClient = void 0;
|
|
7
|
+
const node_http_1 = __importDefault(require("node:http"));
|
|
8
|
+
const node_https_1 = __importDefault(require("node:https"));
|
|
9
|
+
const node_url_1 = require("node:url");
|
|
10
|
+
const errors_1 = require("./errors");
|
|
11
|
+
class ISPConfigClient {
|
|
12
|
+
config;
|
|
13
|
+
url;
|
|
14
|
+
timeoutMs;
|
|
15
|
+
verifySsl;
|
|
16
|
+
sessionId = null;
|
|
17
|
+
isLoggingIn = false;
|
|
18
|
+
constructor(config) {
|
|
19
|
+
this.config = config;
|
|
20
|
+
this.url = new node_url_1.URL(config.apiUrl);
|
|
21
|
+
this.timeoutMs = config.timeoutMs ?? 20_000;
|
|
22
|
+
this.verifySsl = config.verifySsl ?? true;
|
|
23
|
+
}
|
|
24
|
+
async login() {
|
|
25
|
+
if (this.sessionId) {
|
|
26
|
+
return this.sessionId;
|
|
27
|
+
}
|
|
28
|
+
if (this.isLoggingIn) {
|
|
29
|
+
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
30
|
+
return this.login();
|
|
31
|
+
}
|
|
32
|
+
this.isLoggingIn = true;
|
|
33
|
+
try {
|
|
34
|
+
const res = await this.rawCall("login", {
|
|
35
|
+
username: this.config.username,
|
|
36
|
+
password: this.config.password,
|
|
37
|
+
}, true);
|
|
38
|
+
if (!res || typeof res !== "string") {
|
|
39
|
+
throw new errors_1.ISPConfigError("auth_error", "ISPConfig login failed: no session_id returned");
|
|
40
|
+
}
|
|
41
|
+
this.sessionId = res;
|
|
42
|
+
return this.sessionId;
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
this.isLoggingIn = false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async logout() {
|
|
49
|
+
if (!this.sessionId) {
|
|
50
|
+
return { ok: true, message: "No active session" };
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
return await this.rawCall("logout", { session_id: this.sessionId }, true);
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
this.sessionId = null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async call(method, params = {}) {
|
|
60
|
+
const sessionId = await this.login();
|
|
61
|
+
try {
|
|
62
|
+
return await this.rawCall(method, { session_id: sessionId, ...params }, true);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
if (!this.shouldRetrySession(error)) {
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
this.sessionId = null;
|
|
69
|
+
const refreshed = await this.login();
|
|
70
|
+
return this.rawCall(method, { session_id: refreshed, ...params }, true);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
shouldRetrySession(error) {
|
|
74
|
+
if (error instanceof errors_1.ISPConfigError) {
|
|
75
|
+
return error.code === "auth_error" && error.retryable;
|
|
76
|
+
}
|
|
77
|
+
if (!(error instanceof Error)) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
const msg = error.message.toLowerCase();
|
|
81
|
+
return msg.includes("session") || msg.includes("invalid") || msg.includes("expired") || msg.includes("auth");
|
|
82
|
+
}
|
|
83
|
+
async rawCall(method, body, unwrapEnvelope) {
|
|
84
|
+
const methodUrl = new node_url_1.URL(this.url.toString());
|
|
85
|
+
methodUrl.search = method;
|
|
86
|
+
const payload = JSON.stringify(body);
|
|
87
|
+
const protocol = methodUrl.protocol === "https:" ? node_https_1.default : node_http_1.default;
|
|
88
|
+
const requestOptions = {
|
|
89
|
+
method: "POST",
|
|
90
|
+
hostname: methodUrl.hostname,
|
|
91
|
+
port: methodUrl.port,
|
|
92
|
+
path: `${methodUrl.pathname}${methodUrl.search}`,
|
|
93
|
+
headers: {
|
|
94
|
+
"content-type": "application/json",
|
|
95
|
+
"content-length": Buffer.byteLength(payload),
|
|
96
|
+
},
|
|
97
|
+
timeout: this.timeoutMs,
|
|
98
|
+
rejectUnauthorized: this.verifySsl,
|
|
99
|
+
};
|
|
100
|
+
const raw = await new Promise((resolve, reject) => {
|
|
101
|
+
const req = protocol.request(requestOptions, (res) => {
|
|
102
|
+
const chunks = [];
|
|
103
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
104
|
+
res.on("end", () => {
|
|
105
|
+
const txt = Buffer.concat(chunks).toString("utf8");
|
|
106
|
+
const status = res.statusCode ?? 500;
|
|
107
|
+
if (status >= 400) {
|
|
108
|
+
const code = status === 401 ? "auth_error"
|
|
109
|
+
: status === 403 ? "permission_denied"
|
|
110
|
+
: "api_error";
|
|
111
|
+
reject(new errors_1.ISPConfigError(code, `ISPConfig HTTP ${status}: ${txt}`, {
|
|
112
|
+
statusCode: status,
|
|
113
|
+
retryable: status >= 500 || status === 401,
|
|
114
|
+
}));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
resolve(txt);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
req.on("timeout", () => {
|
|
121
|
+
req.destroy(new errors_1.ISPConfigError("network_error", `ISPConfig request timeout after ${this.timeoutMs}ms`, { retryable: true }));
|
|
122
|
+
});
|
|
123
|
+
req.on("error", (err) => {
|
|
124
|
+
if (err instanceof errors_1.ISPConfigError) {
|
|
125
|
+
reject(err);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
reject(new errors_1.ISPConfigError("network_error", err.message, {
|
|
129
|
+
retryable: true,
|
|
130
|
+
cause: err,
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
req.write(payload);
|
|
135
|
+
req.end();
|
|
136
|
+
});
|
|
137
|
+
let parsed;
|
|
138
|
+
try {
|
|
139
|
+
parsed = JSON.parse(raw);
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
throw new errors_1.ISPConfigError("parse_error", `ISPConfig returned non-JSON response: ${raw}`);
|
|
143
|
+
}
|
|
144
|
+
if (!unwrapEnvelope) {
|
|
145
|
+
return parsed;
|
|
146
|
+
}
|
|
147
|
+
const envelope = parsed;
|
|
148
|
+
if (envelope.code && envelope.code !== "ok") {
|
|
149
|
+
const msg = `ISPConfig API ${envelope.code}: ${envelope.message ?? "Unknown error"}`;
|
|
150
|
+
const errorCode = (0, errors_1.classifyApiMessage)(msg);
|
|
151
|
+
throw new errors_1.ISPConfigError(errorCode, msg, {
|
|
152
|
+
retryable: errorCode === "auth_error",
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
if (Object.prototype.hasOwnProperty.call(envelope, "response")) {
|
|
156
|
+
return envelope.response;
|
|
157
|
+
}
|
|
158
|
+
return parsed;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
exports.ISPConfigClient = ISPConfigClient;
|
|
162
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":";;;;;;AAAA,0DAA6B;AAC7B,4DAA+B;AAC/B,uCAA+B;AAC/B,qCAA8D;AAG9D,MAAa,eAAe;IAOU;IANnB,GAAG,CAAM;IACT,SAAS,CAAS;IAClB,SAAS,CAAU;IAC5B,SAAS,GAAkB,IAAI,CAAC;IAChC,WAAW,GAAG,KAAK,CAAC;IAE5B,YAAoC,MAA6B;QAA7B,WAAM,GAAN,MAAM,CAAuB;QAC/D,IAAI,CAAC,GAAG,GAAG,IAAI,cAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAClC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC;QAC5C,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,IAAI,CAAC;IAC5C,CAAC;IAEM,KAAK,CAAC,KAAK;QAChB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,OAAO,IAAI,CAAC,SAAS,CAAC;QACxB,CAAC;QACD,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;YACzD,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC;QACtB,CAAC;QAED,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAS,OAAO,EAAE;gBAC9C,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;gBAC9B,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;aAC/B,EAAE,IAAI,CAAC,CAAC;YAET,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;gBACpC,MAAM,IAAI,uBAAc,CAAC,YAAY,EAAE,gDAAgD,CAAC,CAAC;YAC3F,CAAC;YAED,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC;YACrB,OAAO,IAAI,CAAC,SAAS,CAAC;QACxB,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QAC3B,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,MAAM;QACjB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC;QACpD,CAAC;QAED,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,OAAO,CAAU,QAAQ,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,SAAS,EAAE,EAAE,IAAI,CAAC,CAAC;QACrF,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACxB,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,IAAI,CAAI,MAAc,EAAE,SAAkB,EAAE;QACvD,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACrC,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,OAAO,CAAI,MAAM,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC;QACnF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;gBACpC,MAAM,KAAK,CAAC;YACd,CAAC;YAED,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;YACtB,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;YACrC,OAAO,IAAI,CAAC,OAAO,CAAI,MAAM,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC;QAC7E,CAAC;IACH,CAAC;IAEO,kBAAkB,CAAC,KAAc;QACvC,IAAI,KAAK,YAAY,uBAAc,EAAE,CAAC;YACpC,OAAO,KAAK,CAAC,IAAI,KAAK,YAAY,IAAI,KAAK,CAAC,SAAS,CAAC;QACxD,CAAC;QACD,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,EAAE,CAAC;YAC9B,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QACxC,OAAO,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/G,CAAC;IAEO,KAAK,CAAC,OAAO,CAAI,MAAc,EAAE,IAAa,EAAE,cAAuB;QAC7E,MAAM,SAAS,GAAG,IAAI,cAAG,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC/C,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC;QAE1B,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,oBAAK,CAAC,CAAC,CAAC,mBAAI,CAAC;QAEhE,MAAM,cAAc,GAAyB;YAC3C,MAAM,EAAE,MAAM;YACd,QAAQ,EAAE,SAAS,CAAC,QAAQ;YAC5B,IAAI,EAAE,SAAS,CAAC,IAAI;YACpB,IAAI,EAAE,GAAG,SAAS,CAAC,QAAQ,GAAG,SAAS,CAAC,MAAM,EAAE;YAChD,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC;aAC7C;YACD,OAAO,EAAE,IAAI,CAAC,SAAS;YACvB,kBAAkB,EAAE,IAAI,CAAC,SAAS;SACnC,CAAC;QAEF,MAAM,GAAG,GAAG,MAAM,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACxD,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,GAAG,EAAE,EAAE;gBACnD,MAAM,MAAM,GAAa,EAAE,CAAC;gBAC5B,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;gBACtD,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;oBACjB,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;oBACnD,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC;oBACrC,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;wBAClB,MAAM,IAAI,GAAG,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,YAAY;4BACxC,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,mBAAmB;gCACtC,CAAC,CAAC,WAAW,CAAC;wBAChB,MAAM,CAAC,IAAI,uBAAc,CAAC,IAAI,EAAE,kBAAkB,MAAM,KAAK,GAAG,EAAE,EAAE;4BAClE,UAAU,EAAE,MAAM;4BAClB,SAAS,EAAE,MAAM,IAAI,GAAG,IAAI,MAAM,KAAK,GAAG;yBAC3C,CAAC,CAAC,CAAC;wBACJ,OAAO;oBACT,CAAC;oBACD,OAAO,CAAC,GAAG,CAAC,CAAC;gBACf,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;gBACrB,GAAG,CAAC,OAAO,CAAC,IAAI,uBAAc,CAAC,eAAe,EAC5C,mCAAmC,IAAI,CAAC,SAAS,IAAI,EACrD,EAAE,SAAS,EAAE,IAAI,EAAE,CACpB,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACtB,IAAI,GAAG,YAAY,uBAAc,EAAE,CAAC;oBAClC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACd,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,IAAI,uBAAc,CAAC,eAAe,EAAE,GAAG,CAAC,OAAO,EAAE;wBACtD,SAAS,EAAE,IAAI;wBACf,KAAK,EAAE,GAAG;qBACX,CAAC,CAAC,CAAC;gBACN,CAAC;YACH,CAAC,CAAC,CAAC;YACH,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACnB,GAAG,CAAC,GAAG,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;QAEH,IAAI,MAAe,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,uBAAc,CAAC,aAAa,EACpC,yCAAyC,GAAG,EAAE,CAAC,CAAC;QACpD,CAAC;QAED,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,OAAO,MAAW,CAAC;QACrB,CAAC;QAED,MAAM,QAAQ,GAAG,MAAiC,CAAC;QAEnD,IAAI,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YAC5C,MAAM,GAAG,GAAG,iBAAiB,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC,OAAO,IAAI,eAAe,EAAE,CAAC;YACrF,MAAM,SAAS,GAAG,IAAA,2BAAkB,EAAC,GAAG,CAAC,CAAC;YAC1C,MAAM,IAAI,uBAAc,CAAC,SAAS,EAAE,GAAG,EAAE;gBACvC,SAAS,EAAE,SAAS,KAAK,YAAY;aACtC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,CAAC;YAC/D,OAAO,QAAQ,CAAC,QAAa,CAAC;QAChC,CAAC;QAED,OAAO,MAAW,CAAC;IACrB,CAAC;CACF;AAxKD,0CAwKC"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type ISPConfigErrorCode = "validation_error" | "permission_denied" | "invalid_method" | "auth_error" | "api_error" | "network_error" | "parse_error";
|
|
2
|
+
export declare class ISPConfigError extends Error {
|
|
3
|
+
readonly code: ISPConfigErrorCode;
|
|
4
|
+
readonly retryable: boolean;
|
|
5
|
+
readonly statusCode?: number;
|
|
6
|
+
constructor(code: ISPConfigErrorCode, message: string, options?: {
|
|
7
|
+
retryable?: boolean;
|
|
8
|
+
statusCode?: number;
|
|
9
|
+
cause?: unknown;
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
export declare function classifyApiMessage(message: string): ISPConfigErrorCode;
|
|
13
|
+
export declare function normalizeError(err: unknown): ISPConfigError;
|
|
14
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,kBAAkB,GAC1B,kBAAkB,GAClB,mBAAmB,GACnB,gBAAgB,GAChB,YAAY,GACZ,WAAW,GACX,eAAe,GACf,aAAa,CAAC;AAElB,qBAAa,cAAe,SAAQ,KAAK;IACvC,SAAgB,IAAI,EAAE,kBAAkB,CAAC;IACzC,SAAgB,SAAS,EAAE,OAAO,CAAC;IACnC,SAAgB,UAAU,CAAC,EAAE,MAAM,CAAC;gBAGlC,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAQ1E;AAuCD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,kBAAkB,CAKtE;AAMD,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,CAiF3D"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// Structured error types for ISPConfig plugin
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ISPConfigError = void 0;
|
|
7
|
+
exports.classifyApiMessage = classifyApiMessage;
|
|
8
|
+
exports.normalizeError = normalizeError;
|
|
9
|
+
class ISPConfigError extends Error {
|
|
10
|
+
code;
|
|
11
|
+
retryable;
|
|
12
|
+
statusCode;
|
|
13
|
+
constructor(code, message, options) {
|
|
14
|
+
super(message, { cause: options?.cause });
|
|
15
|
+
this.name = "ISPConfigError";
|
|
16
|
+
this.code = code;
|
|
17
|
+
this.retryable = options?.retryable ?? false;
|
|
18
|
+
this.statusCode = options?.statusCode;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.ISPConfigError = ISPConfigError;
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Classify raw ISPConfig API error messages into error codes
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
const INVALID_METHOD_PATTERNS = [
|
|
26
|
+
"invalid function",
|
|
27
|
+
"unknown method",
|
|
28
|
+
"method not found",
|
|
29
|
+
"function not found",
|
|
30
|
+
"not a valid method",
|
|
31
|
+
];
|
|
32
|
+
const PERMISSION_PATTERNS = [
|
|
33
|
+
"permission denied",
|
|
34
|
+
"access denied",
|
|
35
|
+
"not allowed",
|
|
36
|
+
"forbidden",
|
|
37
|
+
"no permission",
|
|
38
|
+
"not permitted",
|
|
39
|
+
"authorization required",
|
|
40
|
+
];
|
|
41
|
+
const AUTH_PATTERNS = [
|
|
42
|
+
"session",
|
|
43
|
+
"login failed",
|
|
44
|
+
"authentication",
|
|
45
|
+
"auth failed",
|
|
46
|
+
"invalid credentials",
|
|
47
|
+
"expired",
|
|
48
|
+
"no session",
|
|
49
|
+
];
|
|
50
|
+
function matchesAny(msg, patterns) {
|
|
51
|
+
const lower = msg.toLowerCase();
|
|
52
|
+
return patterns.some((p) => lower.includes(p));
|
|
53
|
+
}
|
|
54
|
+
function classifyApiMessage(message) {
|
|
55
|
+
if (matchesAny(message, INVALID_METHOD_PATTERNS))
|
|
56
|
+
return "invalid_method";
|
|
57
|
+
if (matchesAny(message, PERMISSION_PATTERNS))
|
|
58
|
+
return "permission_denied";
|
|
59
|
+
if (matchesAny(message, AUTH_PATTERNS))
|
|
60
|
+
return "auth_error";
|
|
61
|
+
return "api_error";
|
|
62
|
+
}
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
// Normalize any thrown value into an ISPConfigError
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
function normalizeError(err) {
|
|
67
|
+
if (err instanceof ISPConfigError)
|
|
68
|
+
return err;
|
|
69
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
70
|
+
const cause = err instanceof Error ? err : undefined;
|
|
71
|
+
// Network / timeout
|
|
72
|
+
if (message.includes("timeout") ||
|
|
73
|
+
message.includes("ECONNREFUSED") ||
|
|
74
|
+
message.includes("ECONNRESET") ||
|
|
75
|
+
message.includes("ENOTFOUND") ||
|
|
76
|
+
message.includes("socket hang up")) {
|
|
77
|
+
return new ISPConfigError("network_error", message, {
|
|
78
|
+
retryable: true,
|
|
79
|
+
cause,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
// HTTP status errors from rawCall
|
|
83
|
+
const httpMatch = message.match(/^ISPConfig HTTP (\d+)/);
|
|
84
|
+
if (httpMatch) {
|
|
85
|
+
const status = Number(httpMatch[1]);
|
|
86
|
+
if (status === 401 || status === 403) {
|
|
87
|
+
return new ISPConfigError(status === 401 ? "auth_error" : "permission_denied", message, { statusCode: status, retryable: status === 401, cause });
|
|
88
|
+
}
|
|
89
|
+
return new ISPConfigError("api_error", message, {
|
|
90
|
+
statusCode: status,
|
|
91
|
+
retryable: status >= 500,
|
|
92
|
+
cause,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
// Non-JSON
|
|
96
|
+
if (message.includes("non-JSON response")) {
|
|
97
|
+
return new ISPConfigError("parse_error", message, { cause });
|
|
98
|
+
}
|
|
99
|
+
// ISPConfig API envelope errors
|
|
100
|
+
if (message.startsWith("ISPConfig API ")) {
|
|
101
|
+
const code = classifyApiMessage(message);
|
|
102
|
+
return new ISPConfigError(code, message, {
|
|
103
|
+
retryable: code === "auth_error",
|
|
104
|
+
cause,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
// Login failure
|
|
108
|
+
if (message.includes("login failed")) {
|
|
109
|
+
return new ISPConfigError("auth_error", message, { cause });
|
|
110
|
+
}
|
|
111
|
+
// Validation errors (from validateParams or tool-level checks)
|
|
112
|
+
if (message.includes("Validation failed") ||
|
|
113
|
+
message.includes("Missing required") ||
|
|
114
|
+
message.includes("must not be empty") ||
|
|
115
|
+
message.includes("must be a valid number") ||
|
|
116
|
+
message.includes("must be one of")) {
|
|
117
|
+
return new ISPConfigError("validation_error", message, {
|
|
118
|
+
statusCode: 400,
|
|
119
|
+
cause,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
// Guard/policy errors
|
|
123
|
+
if (message.includes("readOnly=true") || message.includes("blocked by allowedOperations")) {
|
|
124
|
+
return new ISPConfigError("permission_denied", message, {
|
|
125
|
+
statusCode: 403,
|
|
126
|
+
cause,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
// Fallback
|
|
130
|
+
return new ISPConfigError("api_error", message, { cause });
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
|
package/dist/guards.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../src/guards.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAEhD,eAAO,MAAM,WAAW,aAgBtB,CAAC;AAEH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAevF"}
|
package/dist/guards.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WRITE_TOOLS = void 0;
|
|
4
|
+
exports.assertToolAllowed = assertToolAllowed;
|
|
5
|
+
const errors_1 = require("./errors");
|
|
6
|
+
exports.WRITE_TOOLS = new Set([
|
|
7
|
+
"isp_client_add",
|
|
8
|
+
"isp_site_add",
|
|
9
|
+
"isp_domain_add",
|
|
10
|
+
"isp_dns_zone_add",
|
|
11
|
+
"isp_dns_record_add",
|
|
12
|
+
"isp_dns_record_delete",
|
|
13
|
+
"isp_mail_domain_add",
|
|
14
|
+
"isp_mail_user_add",
|
|
15
|
+
"isp_mail_user_delete",
|
|
16
|
+
"isp_db_add",
|
|
17
|
+
"isp_db_user_add",
|
|
18
|
+
"isp_shell_user_add",
|
|
19
|
+
"isp_ftp_user_add",
|
|
20
|
+
"isp_cron_add",
|
|
21
|
+
"isp_provision_site",
|
|
22
|
+
]);
|
|
23
|
+
function assertToolAllowed(config, toolName) {
|
|
24
|
+
const allowed = config.allowedOperations ?? [];
|
|
25
|
+
if (allowed.length > 0 && !allowed.includes(toolName)) {
|
|
26
|
+
throw new errors_1.ISPConfigError("permission_denied", `Tool ${toolName} is blocked by allowedOperations policy`, { statusCode: 403 });
|
|
27
|
+
}
|
|
28
|
+
if ((config.readOnly ?? false) && exports.WRITE_TOOLS.has(toolName)) {
|
|
29
|
+
throw new errors_1.ISPConfigError("permission_denied", `Tool ${toolName} is blocked because readOnly=true`, { statusCode: 403 });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=guards.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guards.js","sourceRoot":"","sources":["../src/guards.ts"],"names":[],"mappings":";;;AAqBA,8CAeC;AApCD,qCAA0C;AAG7B,QAAA,WAAW,GAAG,IAAI,GAAG,CAAS;IACzC,gBAAgB;IAChB,cAAc;IACd,gBAAgB;IAChB,kBAAkB;IAClB,oBAAoB;IACpB,uBAAuB;IACvB,qBAAqB;IACrB,mBAAmB;IACnB,sBAAsB;IACtB,YAAY;IACZ,iBAAiB;IACjB,oBAAoB;IACpB,kBAAkB;IAClB,cAAc;IACd,oBAAoB;CACrB,CAAC,CAAC;AAEH,SAAgB,iBAAiB,CAAC,MAA6B,EAAE,QAAgB;IAC/E,MAAM,OAAO,GAAG,MAAM,CAAC,iBAAiB,IAAI,EAAE,CAAC;IAC/C,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,uBAAc,CAAC,mBAAmB,EAC1C,QAAQ,QAAQ,yCAAyC,EACzD,EAAE,UAAU,EAAE,GAAG,EAAE,CACpB,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,KAAK,CAAC,IAAI,mBAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,uBAAc,CAAC,mBAAmB,EAC1C,QAAQ,QAAQ,mCAAmC,EACnD,EAAE,UAAU,EAAE,GAAG,EAAE,CACpB,CAAC;IACJ,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export { ISPConfigError, ISPConfigErrorCode, normalizeError } from "./errors";
|
|
2
|
+
import { ISPConfigPluginConfig, JsonMap } from "./types";
|
|
3
|
+
export interface OpenClawRuntimeLike {
|
|
4
|
+
registerTool: (name: string, definition: {
|
|
5
|
+
description: string;
|
|
6
|
+
run: (params: JsonMap) => Promise<unknown>;
|
|
7
|
+
}) => void;
|
|
8
|
+
}
|
|
9
|
+
export interface BoundTool {
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
run: (params: JsonMap) => Promise<unknown>;
|
|
13
|
+
}
|
|
14
|
+
export declare function buildToolset(config: Partial<ISPConfigPluginConfig>): BoundTool[];
|
|
15
|
+
export declare function registerAllTools(runtime: OpenClawRuntimeLike, config: Partial<ISPConfigPluginConfig>): void;
|
|
16
|
+
declare const plugin: {
|
|
17
|
+
manifest: {
|
|
18
|
+
name: string;
|
|
19
|
+
version: string;
|
|
20
|
+
description: string;
|
|
21
|
+
config: {
|
|
22
|
+
apiUrl: {
|
|
23
|
+
type: string;
|
|
24
|
+
description: string;
|
|
25
|
+
required: boolean;
|
|
26
|
+
};
|
|
27
|
+
username: {
|
|
28
|
+
type: string;
|
|
29
|
+
description: string;
|
|
30
|
+
required: boolean;
|
|
31
|
+
};
|
|
32
|
+
password: {
|
|
33
|
+
type: string;
|
|
34
|
+
description: string;
|
|
35
|
+
required: boolean;
|
|
36
|
+
secret: boolean;
|
|
37
|
+
};
|
|
38
|
+
serverId: {
|
|
39
|
+
type: string;
|
|
40
|
+
description: string;
|
|
41
|
+
default: number;
|
|
42
|
+
};
|
|
43
|
+
defaultServerIp: {
|
|
44
|
+
type: string;
|
|
45
|
+
description: string;
|
|
46
|
+
};
|
|
47
|
+
readOnly: {
|
|
48
|
+
type: string;
|
|
49
|
+
description: string;
|
|
50
|
+
default: boolean;
|
|
51
|
+
};
|
|
52
|
+
allowedOperations: {
|
|
53
|
+
type: string;
|
|
54
|
+
description: string;
|
|
55
|
+
items: {
|
|
56
|
+
type: string;
|
|
57
|
+
};
|
|
58
|
+
default: never[];
|
|
59
|
+
};
|
|
60
|
+
verifySsl: {
|
|
61
|
+
type: string;
|
|
62
|
+
description: string;
|
|
63
|
+
default: boolean;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
tools: string[];
|
|
67
|
+
};
|
|
68
|
+
register: typeof registerAllTools;
|
|
69
|
+
};
|
|
70
|
+
export default plugin;
|
|
71
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE9E,OAAO,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzD,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;KAAE,KAAK,IAAI,CAAC;CACvH;AAoBD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC5C;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,qBAAqB,CAAC,GAAG,SAAS,EAAE,CAQhF;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,mBAAmB,EAAE,MAAM,EAAE,OAAO,CAAC,qBAAqB,CAAC,GAAG,IAAI,CAQ3G;AAED,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAGX,CAAC;AAEF,eAAe,MAAM,CAAC"}
|