@redonvn/redai-openapi-generic 0.1.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/README.md +38 -0
- package/dist/index.cjs +616 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +265 -0
- package/dist/index.d.ts +265 -0
- package/dist/index.js +590 -0
- package/dist/index.js.map +1 -0
- package/openclaw.plugin.json +84 -0
- package/package.json +52 -0
- package/tool-catalog.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# @redonvn/redai-openapi-generic
|
|
2
|
+
|
|
3
|
+
OpenClaw plugin generated from `openapi/redai/generic.json`.
|
|
4
|
+
|
|
5
|
+
## Build
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm run build --workspace @redonvn/redai-openapi-generic
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Install in OpenClaw
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
openclaw plugins install @redonvn/redai-openapi-generic
|
|
15
|
+
openclaw plugins enable redai-openapi-generic
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Runtime config
|
|
19
|
+
|
|
20
|
+
Add runtime config in `~/.openclaw/openclaw.json`:
|
|
21
|
+
|
|
22
|
+
```json5
|
|
23
|
+
{
|
|
24
|
+
"plugins": {
|
|
25
|
+
"entries": {
|
|
26
|
+
"redai-openapi-generic": {
|
|
27
|
+
"enabled": true,
|
|
28
|
+
"config": {
|
|
29
|
+
"baseUrl": "https://v2.redai.vn/api",
|
|
30
|
+
"bearerToken": "YOUR_TOKEN",
|
|
31
|
+
"workspaceId": "YOUR_WORKSPACE_ID",
|
|
32
|
+
"baseId": "YOUR_BASE_ID"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,616 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
catalog: () => tool_catalog_default,
|
|
24
|
+
default: () => register,
|
|
25
|
+
spec: () => generic_default
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(index_exports);
|
|
28
|
+
var import_promises = require("fs/promises");
|
|
29
|
+
var import_node_path = require("path");
|
|
30
|
+
|
|
31
|
+
// ../redai-agent-sdk/dist/index.js
|
|
32
|
+
var DEFAULT_BASE_URL = "https://api.redai.vn/api/v1";
|
|
33
|
+
var encodeQueryValue = (value) => {
|
|
34
|
+
if (value === void 0) {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
if (Array.isArray(value)) {
|
|
38
|
+
return value.map((item) => String(item));
|
|
39
|
+
}
|
|
40
|
+
return [String(value)];
|
|
41
|
+
};
|
|
42
|
+
var headersToObject = (headers) => {
|
|
43
|
+
const result = {};
|
|
44
|
+
headers.forEach((value, key) => {
|
|
45
|
+
result[key] = value;
|
|
46
|
+
});
|
|
47
|
+
return result;
|
|
48
|
+
};
|
|
49
|
+
var applyPathParams = (pathTemplate, pathParams) => pathTemplate.replace(/\{([^}]+)\}/g, (_, key) => {
|
|
50
|
+
const raw = pathParams?.[key];
|
|
51
|
+
if (raw === void 0 || raw === null) {
|
|
52
|
+
throw new RedaiAgentError(`Missing required path parameter: ${key}`);
|
|
53
|
+
}
|
|
54
|
+
return encodeURIComponent(String(raw));
|
|
55
|
+
});
|
|
56
|
+
var buildUrl = (baseUrl, path, query) => {
|
|
57
|
+
const url = new URL(baseUrl);
|
|
58
|
+
const normalizedBasePath = url.pathname.replace(/\/+$/, "");
|
|
59
|
+
const normalizedRequestPath = path.startsWith("/") ? path : `/${path}`;
|
|
60
|
+
url.pathname = `${normalizedBasePath}${normalizedRequestPath}`.replace(/\/{2,}/g, "/");
|
|
61
|
+
if (query) {
|
|
62
|
+
for (const [key, value] of Object.entries(query)) {
|
|
63
|
+
for (const item of encodeQueryValue(value)) {
|
|
64
|
+
url.searchParams.append(key, item);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return url;
|
|
69
|
+
};
|
|
70
|
+
var parseResponse = async (response) => {
|
|
71
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
72
|
+
if (contentType.includes("application/json")) {
|
|
73
|
+
return response.json();
|
|
74
|
+
}
|
|
75
|
+
return response.text();
|
|
76
|
+
};
|
|
77
|
+
var RedaiAgentError = class extends Error {
|
|
78
|
+
constructor(message, options) {
|
|
79
|
+
super(message);
|
|
80
|
+
this.name = "RedaiAgentError";
|
|
81
|
+
this.status = options?.status;
|
|
82
|
+
this.body = options?.body;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
var RedaiAgentClient = class {
|
|
86
|
+
constructor(options = {}) {
|
|
87
|
+
this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
88
|
+
this.bearerToken = options.bearerToken;
|
|
89
|
+
this.apiKey = options.apiKey;
|
|
90
|
+
this.apiKeyHeader = options.apiKeyHeader ?? "x-api-key";
|
|
91
|
+
this.defaultHeaders = options.defaultHeaders;
|
|
92
|
+
this.timeoutMs = options.timeoutMs;
|
|
93
|
+
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
94
|
+
this.tenantContext = {
|
|
95
|
+
workspaceId: options.workspaceId,
|
|
96
|
+
baseId: options.baseId
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
createTenantHeaders(overrides) {
|
|
100
|
+
const workspaceId = overrides?.workspaceId ?? this.tenantContext.workspaceId;
|
|
101
|
+
const baseId = overrides?.baseId ?? this.tenantContext.baseId;
|
|
102
|
+
return {
|
|
103
|
+
"x-workspace-id": workspaceId,
|
|
104
|
+
"x-base-id": baseId
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
async executeTool(tool, input = {}) {
|
|
108
|
+
return this.request({
|
|
109
|
+
method: tool.method,
|
|
110
|
+
path: tool.path,
|
|
111
|
+
pathParams: input.path,
|
|
112
|
+
query: input.query,
|
|
113
|
+
headers: input.headers,
|
|
114
|
+
body: input.body
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
async request(request) {
|
|
118
|
+
const url = buildUrl(this.baseUrl, applyPathParams(request.path, request.pathParams), request.query);
|
|
119
|
+
const controller = new AbortController();
|
|
120
|
+
const timeout = this.timeoutMs ? setTimeout(() => controller.abort(), this.timeoutMs) : void 0;
|
|
121
|
+
const headers = this.buildHeaders(request.method, request.headers, request.body !== void 0);
|
|
122
|
+
try {
|
|
123
|
+
const response = await this.fetchImpl(url, {
|
|
124
|
+
method: request.method,
|
|
125
|
+
headers,
|
|
126
|
+
body: request.body === void 0 ? void 0 : JSON.stringify(request.body),
|
|
127
|
+
signal: controller.signal
|
|
128
|
+
});
|
|
129
|
+
const data = await parseResponse(response);
|
|
130
|
+
const result = {
|
|
131
|
+
ok: response.ok,
|
|
132
|
+
status: response.status,
|
|
133
|
+
statusText: response.statusText,
|
|
134
|
+
headers: headersToObject(response.headers),
|
|
135
|
+
data
|
|
136
|
+
};
|
|
137
|
+
if (!response.ok) {
|
|
138
|
+
throw new RedaiAgentError(`Request failed with status ${response.status}`, {
|
|
139
|
+
status: response.status,
|
|
140
|
+
body: data
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
return result;
|
|
144
|
+
} catch (error) {
|
|
145
|
+
if (error instanceof RedaiAgentError) {
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
throw new RedaiAgentError("Request failed", { body: error });
|
|
149
|
+
} finally {
|
|
150
|
+
if (timeout) {
|
|
151
|
+
clearTimeout(timeout);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
buildHeaders(method, requestHeaders, hasBody) {
|
|
156
|
+
const headers = new Headers();
|
|
157
|
+
for (const [key, value] of Object.entries(this.defaultHeaders ?? {})) {
|
|
158
|
+
headers.set(key, value);
|
|
159
|
+
}
|
|
160
|
+
for (const [key, value] of Object.entries(this.createTenantHeaders())) {
|
|
161
|
+
if (value !== void 0 && value !== null && value !== "") {
|
|
162
|
+
headers.set(key, value);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (this.bearerToken) {
|
|
166
|
+
headers.set("authorization", `Bearer ${this.bearerToken}`);
|
|
167
|
+
} else if (this.apiKey) {
|
|
168
|
+
headers.set(this.apiKeyHeader ?? "x-api-key", this.apiKey);
|
|
169
|
+
}
|
|
170
|
+
for (const [key, value] of Object.entries(requestHeaders ?? {})) {
|
|
171
|
+
if (value !== void 0 && value !== null && value !== "") {
|
|
172
|
+
headers.set(key, value);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (!headers.has("accept")) {
|
|
176
|
+
headers.set("accept", "application/json");
|
|
177
|
+
}
|
|
178
|
+
if (hasBody && method !== "GET" && !headers.has("content-type")) {
|
|
179
|
+
headers.set("content-type", "application/json");
|
|
180
|
+
}
|
|
181
|
+
return headers;
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// tool-catalog.json
|
|
186
|
+
var tool_catalog_default = {
|
|
187
|
+
pluginId: "redai-openapi-generic",
|
|
188
|
+
pluginName: "RedAI User API Export - Generic",
|
|
189
|
+
version: "0.1.0",
|
|
190
|
+
description: "OpenAPI export cho nh\xF3m API user \u0111\xE3 ch\u1ECDn: Generic.",
|
|
191
|
+
serverUrl: "https://v2.redai.vn/api",
|
|
192
|
+
optional: true,
|
|
193
|
+
tools: [
|
|
194
|
+
{
|
|
195
|
+
name: "redai_openapi_generic_genericpageusercontroller_getpublishedgenericpagebypath_v1",
|
|
196
|
+
description: "L\u1EA5y th\xF4ng tin trang \u0111\xE3 xu\u1EA5t b\u1EA3n theo \u0111\u01B0\u1EDDng d\u1EABn",
|
|
197
|
+
method: "GET",
|
|
198
|
+
path: "/v1/user/generic-pages/by-path/{path}",
|
|
199
|
+
operationId: "genericpageusercontroller_getpublishedgenericpagebypath_v1",
|
|
200
|
+
parameters: {
|
|
201
|
+
type: "object",
|
|
202
|
+
properties: {
|
|
203
|
+
path: {
|
|
204
|
+
type: "object",
|
|
205
|
+
properties: {
|
|
206
|
+
path: {
|
|
207
|
+
type: "string",
|
|
208
|
+
description: "\u0110\u01B0\u1EDDng d\u1EABn c\u1EE7a trang"
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
required: [
|
|
212
|
+
"path"
|
|
213
|
+
],
|
|
214
|
+
additionalProperties: false
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
required: [
|
|
218
|
+
"path"
|
|
219
|
+
],
|
|
220
|
+
additionalProperties: false,
|
|
221
|
+
description: "L\u1EA5y th\xF4ng tin trang \u0111\xE3 xu\u1EA5t b\u1EA3n theo \u0111\u01B0\u1EDDng d\u1EABn tool arguments"
|
|
222
|
+
},
|
|
223
|
+
tags: [
|
|
224
|
+
"User Generic Page"
|
|
225
|
+
]
|
|
226
|
+
}
|
|
227
|
+
]
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// generic.json
|
|
231
|
+
var generic_default = {
|
|
232
|
+
openapi: "3.0.0",
|
|
233
|
+
paths: {
|
|
234
|
+
"/v1/user/generic-pages/by-path/{path}": {
|
|
235
|
+
get: {
|
|
236
|
+
operationId: "GenericPageUserController_getPublishedGenericPageByPath_v1",
|
|
237
|
+
parameters: [
|
|
238
|
+
{
|
|
239
|
+
name: "path",
|
|
240
|
+
required: true,
|
|
241
|
+
in: "path",
|
|
242
|
+
description: "\u0110\u01B0\u1EDDng d\u1EABn c\u1EE7a trang",
|
|
243
|
+
schema: {
|
|
244
|
+
type: "string"
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
],
|
|
248
|
+
responses: {
|
|
249
|
+
"200": {
|
|
250
|
+
description: "Th\xF4ng tin trang",
|
|
251
|
+
content: {
|
|
252
|
+
"application/json": {
|
|
253
|
+
schema: {
|
|
254
|
+
allOf: [
|
|
255
|
+
{
|
|
256
|
+
$ref: "#/components/schemas/ApiResponseDto"
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
properties: {
|
|
260
|
+
result: {
|
|
261
|
+
$ref: "#/components/schemas/UserGenericPageResponseDto"
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
]
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
summary: "L\u1EA5y th\xF4ng tin trang \u0111\xE3 xu\u1EA5t b\u1EA3n theo \u0111\u01B0\u1EDDng d\u1EABn",
|
|
272
|
+
tags: [
|
|
273
|
+
"User Generic Page"
|
|
274
|
+
]
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
info: {
|
|
279
|
+
title: "RedAI User API Export - Generic",
|
|
280
|
+
description: "OpenAPI export cho nh\xF3m API user \u0111\xE3 ch\u1ECDn: Generic.",
|
|
281
|
+
version: "1.0",
|
|
282
|
+
contact: {
|
|
283
|
+
name: "RedAI Support",
|
|
284
|
+
url: "https://redai.com/support",
|
|
285
|
+
email: "support@redai.com"
|
|
286
|
+
},
|
|
287
|
+
license: {
|
|
288
|
+
name: "MIT",
|
|
289
|
+
url: "https://opensource.org/licenses/MIT"
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
tags: [],
|
|
293
|
+
servers: [
|
|
294
|
+
{
|
|
295
|
+
url: "http://localhost:3000",
|
|
296
|
+
description: "Local Server"
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
url: "http://localhost:3003",
|
|
300
|
+
description: "Development Server"
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
url: "http://14.225.29.196:3003",
|
|
304
|
+
description: "Test Server"
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
url: "https://api-staging.redai.vn",
|
|
308
|
+
description: "Staging Server"
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
url: "https://v2.redai.vn/api",
|
|
312
|
+
description: "Production Server"
|
|
313
|
+
}
|
|
314
|
+
],
|
|
315
|
+
components: {
|
|
316
|
+
schemas: {
|
|
317
|
+
ApiResponseDto: {
|
|
318
|
+
type: "object",
|
|
319
|
+
properties: {
|
|
320
|
+
code: {
|
|
321
|
+
type: "number",
|
|
322
|
+
description: "M\xE3 tr\u1EA1ng th\xE1i (0: Th\xE0nh c\xF4ng, kh\xE1c 0: M\xE3 l\u1ED7i c\u1EE5 th\u1EC3)",
|
|
323
|
+
example: 0
|
|
324
|
+
},
|
|
325
|
+
message: {
|
|
326
|
+
type: "string",
|
|
327
|
+
description: "Th\xF4ng \u0111i\u1EC7p m\xF4 t\u1EA3 k\u1EBFt qu\u1EA3",
|
|
328
|
+
example: "Success"
|
|
329
|
+
}
|
|
330
|
+
},
|
|
331
|
+
required: [
|
|
332
|
+
"code",
|
|
333
|
+
"message"
|
|
334
|
+
]
|
|
335
|
+
},
|
|
336
|
+
UserGenericPageResponseDto: {
|
|
337
|
+
type: "object",
|
|
338
|
+
properties: {
|
|
339
|
+
id: {
|
|
340
|
+
type: "string",
|
|
341
|
+
description: "ID c\u1EE7a trang",
|
|
342
|
+
example: "f47ac10b-58cc-4372-a567-0e02b2c3d479"
|
|
343
|
+
},
|
|
344
|
+
name: {
|
|
345
|
+
type: "string",
|
|
346
|
+
description: "T\xEAn c\u1EE7a trang",
|
|
347
|
+
example: "Trang li\xEAn h\u1EC7"
|
|
348
|
+
},
|
|
349
|
+
description: {
|
|
350
|
+
type: "string",
|
|
351
|
+
description: "M\xF4 t\u1EA3 v\u1EC1 trang",
|
|
352
|
+
example: "Form li\xEAn h\u1EC7 cho kh\xE1ch h\xE0ng",
|
|
353
|
+
nullable: true
|
|
354
|
+
},
|
|
355
|
+
path: {
|
|
356
|
+
type: "string",
|
|
357
|
+
description: "\u0110\u01B0\u1EDDng d\u1EABn URL c\u1EE7a trang",
|
|
358
|
+
example: "lien-he"
|
|
359
|
+
},
|
|
360
|
+
config: {
|
|
361
|
+
type: "object",
|
|
362
|
+
description: "C\u1EA5u h\xECnh trang d\u1EA1ng JSON",
|
|
363
|
+
example: {
|
|
364
|
+
formId: "contact-form",
|
|
365
|
+
title: "Li\xEAn h\u1EC7 v\u1EDBi ch\xFAng t\xF4i",
|
|
366
|
+
subtitle: "H\xE3y \u0111\u1EC3 l\u1EA1i th\xF4ng tin, ch\xFAng t\xF4i s\u1EBD li\xEAn h\u1EC7 l\u1EA1i v\u1EDBi b\u1EA1n",
|
|
367
|
+
groups: []
|
|
368
|
+
}
|
|
369
|
+
},
|
|
370
|
+
publishedAt: {
|
|
371
|
+
type: "number",
|
|
372
|
+
description: "Th\u1EDDi \u0111i\u1EC3m xu\u1EA5t b\u1EA3n trang (Unix timestamp)",
|
|
373
|
+
example: 16733634e5
|
|
374
|
+
}
|
|
375
|
+
},
|
|
376
|
+
required: [
|
|
377
|
+
"id",
|
|
378
|
+
"name",
|
|
379
|
+
"description",
|
|
380
|
+
"path",
|
|
381
|
+
"config",
|
|
382
|
+
"publishedAt"
|
|
383
|
+
]
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
},
|
|
387
|
+
externalDocs: {
|
|
388
|
+
description: "Additional Documentation",
|
|
389
|
+
url: "https://redai.com/docs"
|
|
390
|
+
},
|
|
391
|
+
generatedAt: "2026-03-16T08:19:30.792Z",
|
|
392
|
+
"x-redai-export-modules": [
|
|
393
|
+
"generic"
|
|
394
|
+
],
|
|
395
|
+
"x-redai-export-scope": "user"
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
// index.ts
|
|
399
|
+
var DEFAULT_AUTH_STORE_PATH = "C:\\Users\\Acer\\.openclaw\\workspace-nhan-vien-redai\\auth\\redai-auth.json";
|
|
400
|
+
var typedCatalog = tool_catalog_default;
|
|
401
|
+
var formatToolResult = (payload) => ({
|
|
402
|
+
content: [
|
|
403
|
+
{
|
|
404
|
+
type: "text",
|
|
405
|
+
text: typeof payload === "string" ? payload : JSON.stringify(payload, null, 2)
|
|
406
|
+
}
|
|
407
|
+
]
|
|
408
|
+
});
|
|
409
|
+
var resolvePluginConfig = (api) => api.config?.plugins?.entries?.[typedCatalog.pluginId]?.config ?? {};
|
|
410
|
+
var cloneJson = (value) => JSON.parse(JSON.stringify(value));
|
|
411
|
+
var removeHeadersFromSchema = (schema) => {
|
|
412
|
+
const cloned = cloneJson(schema ?? { type: "object", properties: {} });
|
|
413
|
+
const objectSchema = cloned;
|
|
414
|
+
if (!objectSchema.properties) {
|
|
415
|
+
objectSchema.properties = {};
|
|
416
|
+
}
|
|
417
|
+
delete objectSchema.properties.headers;
|
|
418
|
+
if (Array.isArray(objectSchema.required)) {
|
|
419
|
+
objectSchema.required = objectSchema.required.filter((item) => item !== "headers");
|
|
420
|
+
}
|
|
421
|
+
objectSchema.additionalProperties = false;
|
|
422
|
+
return objectSchema;
|
|
423
|
+
};
|
|
424
|
+
var buildAuthWrappedParameters = (tool) => {
|
|
425
|
+
const baseSchema = removeHeadersFromSchema(tool.parameters);
|
|
426
|
+
return {
|
|
427
|
+
...baseSchema,
|
|
428
|
+
description: `${tool.description} Uses the logged-in RedAI auth for the current Telegram DM user.`,
|
|
429
|
+
properties: {
|
|
430
|
+
telegramUserId: {
|
|
431
|
+
type: "string",
|
|
432
|
+
description: "Telegram sender ID from DM metadata. The agent must derive this automatically from the current message."
|
|
433
|
+
},
|
|
434
|
+
...baseSchema.properties ?? {}
|
|
435
|
+
},
|
|
436
|
+
required: [
|
|
437
|
+
"telegramUserId",
|
|
438
|
+
...(baseSchema.required ?? []).filter((item) => item !== "telegramUserId")
|
|
439
|
+
]
|
|
440
|
+
};
|
|
441
|
+
};
|
|
442
|
+
var buildAuthToolName = (toolName) => toolName.startsWith("redai_openapi_generic_") ? toolName.replace(/^redai_openapi_generic_/, "redai_openapi_generic_auth_") : "redai_openapi_generic_auth_${toolName}";
|
|
443
|
+
var getAuthStorePath = (runtimeConfig) => runtimeConfig.authStorePath?.trim() || DEFAULT_AUTH_STORE_PATH;
|
|
444
|
+
var ensureStoreDirectory = async (storePath) => {
|
|
445
|
+
await (0, import_promises.mkdir)((0, import_node_path.dirname)(storePath), { recursive: true });
|
|
446
|
+
};
|
|
447
|
+
var loadAuthStore = async (runtimeConfig) => {
|
|
448
|
+
const storePath = getAuthStorePath(runtimeConfig);
|
|
449
|
+
try {
|
|
450
|
+
const raw = await (0, import_promises.readFile)(storePath, "utf8");
|
|
451
|
+
const parsed = JSON.parse(raw);
|
|
452
|
+
return { version: 1, users: parsed?.users ?? {} };
|
|
453
|
+
} catch (error) {
|
|
454
|
+
const maybeNodeError = error;
|
|
455
|
+
if (maybeNodeError?.code === "ENOENT") {
|
|
456
|
+
await ensureStoreDirectory(storePath);
|
|
457
|
+
await (0, import_promises.writeFile)(storePath, JSON.stringify({ version: 1, users: {} }, null, 2), "utf8");
|
|
458
|
+
return { version: 1, users: {} };
|
|
459
|
+
}
|
|
460
|
+
throw error;
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
var getAuthStoreEntry = async (runtimeConfig, telegramUserId) => {
|
|
464
|
+
const store = await loadAuthStore(runtimeConfig);
|
|
465
|
+
return store.users[telegramUserId] ?? null;
|
|
466
|
+
};
|
|
467
|
+
var withRedaiAuth = (runtimeConfig, auth) => {
|
|
468
|
+
const defaultHeaders = {
|
|
469
|
+
...runtimeConfig.defaultHeaders ?? {},
|
|
470
|
+
"x-workspace-id": auth.workspaceId
|
|
471
|
+
};
|
|
472
|
+
if (auth.baseId) {
|
|
473
|
+
defaultHeaders["x-base-id"] = auth.baseId;
|
|
474
|
+
} else {
|
|
475
|
+
delete defaultHeaders["x-base-id"];
|
|
476
|
+
}
|
|
477
|
+
return {
|
|
478
|
+
...runtimeConfig,
|
|
479
|
+
bearerToken: auth.bearerToken,
|
|
480
|
+
apiKey: void 0,
|
|
481
|
+
apiKeyHeader: void 0,
|
|
482
|
+
defaultHeaders,
|
|
483
|
+
workspaceId: auth.workspaceId,
|
|
484
|
+
baseId: auth.baseId ?? void 0
|
|
485
|
+
};
|
|
486
|
+
};
|
|
487
|
+
var resolveUserRuntimeConfig = async (api, telegramUserId) => {
|
|
488
|
+
const runtimeConfig = resolvePluginConfig(api);
|
|
489
|
+
const authEntry = await getAuthStoreEntry(runtimeConfig, telegramUserId);
|
|
490
|
+
if (!authEntry || authEntry.status !== "active") {
|
|
491
|
+
return null;
|
|
492
|
+
}
|
|
493
|
+
return {
|
|
494
|
+
runtimeConfig,
|
|
495
|
+
scopedConfig: withRedaiAuth(runtimeConfig, authEntry)
|
|
496
|
+
};
|
|
497
|
+
};
|
|
498
|
+
var authRequiredResult = (telegramUserId) => formatToolResult({
|
|
499
|
+
ok: false,
|
|
500
|
+
status: 401,
|
|
501
|
+
statusText: "AUTH_REQUIRED",
|
|
502
|
+
data: {
|
|
503
|
+
message: "Ban chua dang nhap RedAI auth hop le. Hay dung /login <bearerToken> <workspaceId> [baseId] trong DM truoc khi thao tac nghiep vu.",
|
|
504
|
+
telegramUserId
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
var hasHeadersSection = (tool) => {
|
|
508
|
+
const parameters = tool.parameters;
|
|
509
|
+
return Boolean(parameters?.properties?.headers);
|
|
510
|
+
};
|
|
511
|
+
var mergeTenantHeaders = (tool, inputHeaders, runtimeConfig) => {
|
|
512
|
+
const entries = Object.entries(inputHeaders ?? {}).filter(([, value]) => value !== void 0 && value !== null && value !== "").map(([key, value]) => [key, String(value)]);
|
|
513
|
+
if (hasHeadersSection(tool)) {
|
|
514
|
+
if (runtimeConfig.workspaceId && !entries.some(([key]) => key.toLowerCase() === "x-workspace-id")) {
|
|
515
|
+
entries.push(["x-workspace-id", runtimeConfig.workspaceId]);
|
|
516
|
+
}
|
|
517
|
+
if (runtimeConfig.baseId && !entries.some(([key]) => key.toLowerCase() === "x-base-id")) {
|
|
518
|
+
entries.push(["x-base-id", runtimeConfig.baseId]);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
return entries.length > 0 ? Object.fromEntries(entries) : void 0;
|
|
522
|
+
};
|
|
523
|
+
var executeCatalogTool = async (runtimeConfig, tool, rawParams) => {
|
|
524
|
+
const client = new RedaiAgentClient({
|
|
525
|
+
...runtimeConfig,
|
|
526
|
+
baseUrl: runtimeConfig.baseUrl ?? typedCatalog.serverUrl
|
|
527
|
+
});
|
|
528
|
+
const params = rawParams ?? {};
|
|
529
|
+
return client.executeTool(tool, {
|
|
530
|
+
path: params.path,
|
|
531
|
+
query: params.query,
|
|
532
|
+
body: params.body,
|
|
533
|
+
headers: mergeTenantHeaders(tool, params.headers, runtimeConfig)
|
|
534
|
+
});
|
|
535
|
+
};
|
|
536
|
+
var registerAuthProxyTool = (api, tool) => {
|
|
537
|
+
api.registerTool(
|
|
538
|
+
{
|
|
539
|
+
name: buildAuthToolName(tool.name),
|
|
540
|
+
description: `${tool.description} Uses the logged-in RedAI auth for the current Telegram DM user.`,
|
|
541
|
+
parameters: buildAuthWrappedParameters(tool),
|
|
542
|
+
execute: async (_id, rawParams) => {
|
|
543
|
+
const params = rawParams ?? {};
|
|
544
|
+
const telegramUserId = String(params.telegramUserId ?? "");
|
|
545
|
+
const resolved = await resolveUserRuntimeConfig(api, telegramUserId);
|
|
546
|
+
if (!resolved) {
|
|
547
|
+
return authRequiredResult(telegramUserId);
|
|
548
|
+
}
|
|
549
|
+
const forwardedParams = { ...params };
|
|
550
|
+
delete forwardedParams.telegramUserId;
|
|
551
|
+
try {
|
|
552
|
+
const response = await executeCatalogTool(resolved.scopedConfig, tool, forwardedParams);
|
|
553
|
+
return formatToolResult(response.data);
|
|
554
|
+
} catch (error) {
|
|
555
|
+
if (error instanceof RedaiAgentError) {
|
|
556
|
+
return formatToolResult({
|
|
557
|
+
ok: false,
|
|
558
|
+
status: error.status ?? 500,
|
|
559
|
+
statusText: error.message,
|
|
560
|
+
data: error.body
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
return formatToolResult({
|
|
564
|
+
ok: false,
|
|
565
|
+
status: 500,
|
|
566
|
+
statusText: "PLUGIN_EXECUTION_FAILED",
|
|
567
|
+
data: String(error)
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
},
|
|
572
|
+
{ optional: typedCatalog.optional ?? true }
|
|
573
|
+
);
|
|
574
|
+
};
|
|
575
|
+
function register(api) {
|
|
576
|
+
for (const tool of typedCatalog.tools) {
|
|
577
|
+
api.registerTool(
|
|
578
|
+
{
|
|
579
|
+
name: tool.name,
|
|
580
|
+
description: tool.description,
|
|
581
|
+
parameters: tool.parameters,
|
|
582
|
+
execute: async (_id, rawParams) => {
|
|
583
|
+
try {
|
|
584
|
+
const response = await executeCatalogTool(resolvePluginConfig(api), tool, rawParams);
|
|
585
|
+
return formatToolResult(response.data);
|
|
586
|
+
} catch (error) {
|
|
587
|
+
if (error instanceof RedaiAgentError) {
|
|
588
|
+
return formatToolResult({
|
|
589
|
+
ok: false,
|
|
590
|
+
status: error.status ?? 500,
|
|
591
|
+
statusText: error.message,
|
|
592
|
+
data: error.body
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
return formatToolResult({
|
|
596
|
+
ok: false,
|
|
597
|
+
status: 500,
|
|
598
|
+
statusText: "PLUGIN_EXECUTION_FAILED",
|
|
599
|
+
data: String(error)
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
},
|
|
604
|
+
{ optional: typedCatalog.optional ?? true }
|
|
605
|
+
);
|
|
606
|
+
}
|
|
607
|
+
for (const tool of typedCatalog.tools) {
|
|
608
|
+
registerAuthProxyTool(api, tool);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
612
|
+
0 && (module.exports = {
|
|
613
|
+
catalog,
|
|
614
|
+
spec
|
|
615
|
+
});
|
|
616
|
+
//# sourceMappingURL=index.cjs.map
|