@redonvn/redai-openapi-wp-content-post 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/dist/index.cjs ADDED
@@ -0,0 +1,2036 @@
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: () => wp_content_post_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-wp-content-post",
188
+ pluginName: "RedAI User API Export - WP Content Post",
189
+ version: "0.1.0",
190
+ description: "OpenAPI export cho nh\xF3m API user \u0111\xE3 ch\u1ECDn: WP Content Post.",
191
+ serverUrl: "https://v2.redai.vn/api",
192
+ optional: true,
193
+ tools: [
194
+ {
195
+ name: "redai_openapi_wp_content_post_wpcontentpostusercontroller_bulkdelete_v1",
196
+ description: "X\xF3a nhi\u1EC1u b\xE0i vi\u1EBFt. X\xF3a nhi\u1EC1u b\xE0i vi\u1EBFt c\xF9ng l\xFAc (soft delete ho\u1EB7c hard delete)",
197
+ method: "DELETE",
198
+ path: "/v1/user/posts",
199
+ operationId: "wpcontentpostusercontroller_bulkdelete_v1",
200
+ parameters: {
201
+ type: "object",
202
+ properties: {
203
+ headers: {
204
+ type: "object",
205
+ properties: {
206
+ "x-workspace-id": {
207
+ type: "string",
208
+ description: "Workspace ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID)"
209
+ },
210
+ "x-base-id": {
211
+ type: "string",
212
+ description: "Base ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID, optional)"
213
+ }
214
+ },
215
+ required: [
216
+ "x-workspace-id"
217
+ ],
218
+ additionalProperties: false
219
+ },
220
+ body: {
221
+ type: "object",
222
+ properties: {
223
+ ids: {
224
+ type: "array",
225
+ description: "Array of post IDs to delete",
226
+ items: {
227
+ type: "string"
228
+ }
229
+ },
230
+ permanent: {
231
+ type: "boolean",
232
+ description: "Permanent delete (hard delete) or soft delete (status=trash)",
233
+ default: false
234
+ }
235
+ },
236
+ required: [
237
+ "ids"
238
+ ]
239
+ }
240
+ },
241
+ required: [
242
+ "headers",
243
+ "body"
244
+ ],
245
+ additionalProperties: false,
246
+ description: "X\xF3a nhi\u1EC1u b\xE0i vi\u1EBFt tool arguments"
247
+ },
248
+ tags: [
249
+ "User - WP Content Post"
250
+ ]
251
+ },
252
+ {
253
+ name: "redai_openapi_wp_content_post_wpcontentpostusercontroller_create_v1",
254
+ description: "T\u1EA1o b\xE0i vi\u1EBFt m\u1EDBi. User ho\u1EB7c Employee t\u1EA1o b\xE0i vi\u1EBFt m\u1EDBi (draft ho\u1EB7c publish)",
255
+ method: "POST",
256
+ path: "/v1/user/posts",
257
+ operationId: "wpcontentpostusercontroller_create_v1",
258
+ parameters: {
259
+ type: "object",
260
+ properties: {
261
+ headers: {
262
+ type: "object",
263
+ properties: {
264
+ "x-workspace-id": {
265
+ type: "string",
266
+ description: "Workspace ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID)"
267
+ },
268
+ "x-base-id": {
269
+ type: "string",
270
+ description: "Base ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID, optional)"
271
+ }
272
+ },
273
+ required: [
274
+ "x-workspace-id"
275
+ ],
276
+ additionalProperties: false
277
+ },
278
+ body: {
279
+ type: "object",
280
+ properties: {
281
+ title: {
282
+ type: "string",
283
+ description: "Ti\xEAu \u0111\u1EC1 b\xE0i vi\u1EBFt"
284
+ },
285
+ slug: {
286
+ type: "string",
287
+ description: "Slug (friendly URL) - auto-generate n\u1EBFu kh\xF4ng nh\u1EADp"
288
+ },
289
+ excerpt: {
290
+ type: "string",
291
+ description: "M\xF4 t\u1EA3 ng\u1EAFn"
292
+ },
293
+ content: {
294
+ description: "N\u1ED9i dung b\xE0i vi\u1EBFt (Gutenberg blocks)",
295
+ allOf: [
296
+ {
297
+ type: "object",
298
+ properties: {
299
+ blocks: {
300
+ type: "array",
301
+ description: "Array of Gutenberg blocks",
302
+ items: {
303
+ type: "array",
304
+ items: {
305
+ type: "a"
306
+ }
307
+ }
308
+ },
309
+ meta: {
310
+ type: "object",
311
+ description: "Additional metadata"
312
+ },
313
+ settings: {
314
+ type: "object",
315
+ description: "Content settings"
316
+ }
317
+ },
318
+ required: [
319
+ "blocks"
320
+ ]
321
+ }
322
+ ]
323
+ },
324
+ featuredImageId: {
325
+ type: "string",
326
+ description: "ID \u1EA3nh \u0111\u1EA1i di\u1EC7n (UUID)"
327
+ },
328
+ status: {
329
+ type: "string",
330
+ description: "Tr\u1EA1ng th\xE1i b\xE0i vi\u1EBFt",
331
+ default: "draft",
332
+ enum: [
333
+ "draft",
334
+ "pending",
335
+ "private",
336
+ "publish",
337
+ "future",
338
+ "trash",
339
+ "archived"
340
+ ]
341
+ },
342
+ type: {
343
+ type: "string",
344
+ description: "Lo\u1EA1i b\xE0i vi\u1EBFt",
345
+ default: "post"
346
+ },
347
+ metaTitle: {
348
+ type: "string",
349
+ description: "SEO: Meta title (max 70 chars)"
350
+ },
351
+ metaDescription: {
352
+ type: "string",
353
+ description: "SEO: Meta description (max 160 chars)"
354
+ },
355
+ metaKeywords: {
356
+ type: "array",
357
+ description: "SEO: Meta keywords",
358
+ items: {
359
+ type: "string"
360
+ }
361
+ },
362
+ commentStatus: {
363
+ type: "string",
364
+ description: "Tr\u1EA1ng th\xE1i comment",
365
+ default: "open"
366
+ },
367
+ sticky: {
368
+ type: "boolean",
369
+ description: "\u0110\xE1nh d\u1EA5u sticky post",
370
+ default: false
371
+ },
372
+ password: {
373
+ type: "string",
374
+ description: "M\u1EADt kh\u1EA9u b\u1EA3o v\u1EC7 b\xE0i vi\u1EBFt (plaintext)"
375
+ },
376
+ menuOrder: {
377
+ type: "number",
378
+ description: "Th\u1EE9 t\u1EF1 hi\u1EC3n th\u1ECB",
379
+ default: 0
380
+ }
381
+ },
382
+ required: [
383
+ "title",
384
+ "content"
385
+ ]
386
+ }
387
+ },
388
+ required: [
389
+ "headers",
390
+ "body"
391
+ ],
392
+ additionalProperties: false,
393
+ description: "T\u1EA1o b\xE0i vi\u1EBFt m\u1EDBi tool arguments"
394
+ },
395
+ tags: [
396
+ "User - WP Content Post"
397
+ ]
398
+ },
399
+ {
400
+ name: "redai_openapi_wp_content_post_wpcontentpostusercontroller_findall_v1",
401
+ description: "L\u1EA5y danh s\xE1ch b\xE0i vi\u1EBFt. L\u1EA5y danh s\xE1ch b\xE0i vi\u1EBFt c\u1EE7a user/employee v\u1EDBi filters v\xE0 pagination",
402
+ method: "GET",
403
+ path: "/v1/user/posts",
404
+ operationId: "wpcontentpostusercontroller_findall_v1",
405
+ parameters: {
406
+ type: "object",
407
+ properties: {
408
+ query: {
409
+ type: "object",
410
+ properties: {
411
+ status: {
412
+ type: "string",
413
+ enum: [
414
+ "draft",
415
+ "pending",
416
+ "private",
417
+ "publish",
418
+ "future",
419
+ "trash",
420
+ "archived"
421
+ ],
422
+ description: "Filter by status"
423
+ },
424
+ type: {
425
+ type: "string",
426
+ description: "Filter by type"
427
+ },
428
+ search: {
429
+ type: "string",
430
+ description: "Search in title, excerpt, content"
431
+ },
432
+ sticky: {
433
+ type: "boolean",
434
+ default: false,
435
+ description: "Filter sticky posts only"
436
+ },
437
+ sortBy: {
438
+ type: "string",
439
+ default: "createdAt",
440
+ description: "Sort field"
441
+ },
442
+ sortOrder: {
443
+ type: "string",
444
+ default: "DESC",
445
+ enum: [
446
+ "ASC",
447
+ "DESC"
448
+ ],
449
+ description: "Sort order"
450
+ },
451
+ page: {
452
+ type: "number",
453
+ default: 1,
454
+ description: "Page number"
455
+ },
456
+ limit: {
457
+ type: "number",
458
+ default: 10,
459
+ description: "Items per page"
460
+ }
461
+ },
462
+ additionalProperties: false
463
+ },
464
+ headers: {
465
+ type: "object",
466
+ properties: {
467
+ "x-workspace-id": {
468
+ type: "string",
469
+ description: "Workspace ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID)"
470
+ },
471
+ "x-base-id": {
472
+ type: "string",
473
+ description: "Base ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID, optional)"
474
+ }
475
+ },
476
+ required: [
477
+ "x-workspace-id"
478
+ ],
479
+ additionalProperties: false
480
+ }
481
+ },
482
+ required: [
483
+ "headers"
484
+ ],
485
+ additionalProperties: false,
486
+ description: "L\u1EA5y danh s\xE1ch b\xE0i vi\u1EBFt tool arguments"
487
+ },
488
+ tags: [
489
+ "User - WP Content Post"
490
+ ]
491
+ },
492
+ {
493
+ name: "redai_openapi_wp_content_post_wpcontentpostusercontroller_findone_v1",
494
+ description: "L\u1EA5y chi ti\u1EBFt b\xE0i vi\u1EBFt. L\u1EA5y th\xF4ng tin chi ti\u1EBFt c\u1EE7a m\u1ED9t b\xE0i vi\u1EBFt (ch\u1EC9 b\xE0i vi\u1EBFt c\u1EE7a ch\xEDnh user/employee)",
495
+ method: "GET",
496
+ path: "/v1/user/posts/{id}",
497
+ operationId: "wpcontentpostusercontroller_findone_v1",
498
+ parameters: {
499
+ type: "object",
500
+ properties: {
501
+ path: {
502
+ type: "object",
503
+ properties: {
504
+ id: {
505
+ type: "string",
506
+ description: "Post ID (UUID)"
507
+ }
508
+ },
509
+ required: [
510
+ "id"
511
+ ],
512
+ additionalProperties: false
513
+ },
514
+ headers: {
515
+ type: "object",
516
+ properties: {
517
+ "x-workspace-id": {
518
+ type: "string",
519
+ description: "Workspace ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID)"
520
+ },
521
+ "x-base-id": {
522
+ type: "string",
523
+ description: "Base ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID, optional)"
524
+ }
525
+ },
526
+ required: [
527
+ "x-workspace-id"
528
+ ],
529
+ additionalProperties: false
530
+ }
531
+ },
532
+ required: [
533
+ "path",
534
+ "headers"
535
+ ],
536
+ additionalProperties: false,
537
+ description: "L\u1EA5y chi ti\u1EBFt b\xE0i vi\u1EBFt tool arguments"
538
+ },
539
+ tags: [
540
+ "User - WP Content Post"
541
+ ]
542
+ },
543
+ {
544
+ name: "redai_openapi_wp_content_post_wpcontentpostusercontroller_submitforreview_v1",
545
+ description: "G\u1EEDi b\xE0i vi\u1EBFt \u0111i duy\u1EC7t. Chuy\u1EC3n tr\u1EA1ng th\xE1i b\xE0i vi\u1EBFt sang pending \u0111\u1EC3 ch\u1EDD admin duy\u1EC7t",
546
+ method: "POST",
547
+ path: "/v1/user/posts/{id}/submit-for-review",
548
+ operationId: "wpcontentpostusercontroller_submitforreview_v1",
549
+ parameters: {
550
+ type: "object",
551
+ properties: {
552
+ path: {
553
+ type: "object",
554
+ properties: {
555
+ id: {
556
+ type: "string",
557
+ description: "Post ID (UUID)"
558
+ }
559
+ },
560
+ required: [
561
+ "id"
562
+ ],
563
+ additionalProperties: false
564
+ },
565
+ headers: {
566
+ type: "object",
567
+ properties: {
568
+ "x-workspace-id": {
569
+ type: "string",
570
+ description: "Workspace ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID)"
571
+ },
572
+ "x-base-id": {
573
+ type: "string",
574
+ description: "Base ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID, optional)"
575
+ }
576
+ },
577
+ required: [
578
+ "x-workspace-id"
579
+ ],
580
+ additionalProperties: false
581
+ }
582
+ },
583
+ required: [
584
+ "path",
585
+ "headers"
586
+ ],
587
+ additionalProperties: false,
588
+ description: "G\u1EEDi b\xE0i vi\u1EBFt \u0111i duy\u1EC7t tool arguments"
589
+ },
590
+ tags: [
591
+ "User - WP Content Post"
592
+ ]
593
+ },
594
+ {
595
+ name: "redai_openapi_wp_content_post_wpcontentpostusercontroller_togglesticky_v1",
596
+ description: "Toggle sticky status. \u0110\u1EA3o tr\u1EA1ng th\xE1i sticky c\u1EE7a b\xE0i vi\u1EBFt (true \u2192 false ho\u1EB7c false \u2192 true)",
597
+ method: "PATCH",
598
+ path: "/v1/user/posts/{id}/toggle-sticky",
599
+ operationId: "wpcontentpostusercontroller_togglesticky_v1",
600
+ parameters: {
601
+ type: "object",
602
+ properties: {
603
+ path: {
604
+ type: "object",
605
+ properties: {
606
+ id: {
607
+ type: "string",
608
+ description: "Post ID (UUID)"
609
+ }
610
+ },
611
+ required: [
612
+ "id"
613
+ ],
614
+ additionalProperties: false
615
+ },
616
+ headers: {
617
+ type: "object",
618
+ properties: {
619
+ "x-workspace-id": {
620
+ type: "string",
621
+ description: "Workspace ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID)"
622
+ },
623
+ "x-base-id": {
624
+ type: "string",
625
+ description: "Base ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID, optional)"
626
+ }
627
+ },
628
+ required: [
629
+ "x-workspace-id"
630
+ ],
631
+ additionalProperties: false
632
+ }
633
+ },
634
+ required: [
635
+ "path",
636
+ "headers"
637
+ ],
638
+ additionalProperties: false,
639
+ description: "Toggle sticky status tool arguments"
640
+ },
641
+ tags: [
642
+ "User - WP Content Post"
643
+ ]
644
+ },
645
+ {
646
+ name: "redai_openapi_wp_content_post_wpcontentpostusercontroller_update_v1",
647
+ description: "C\u1EADp nh\u1EADt b\xE0i vi\u1EBFt. C\u1EADp nh\u1EADt th\xF4ng tin b\xE0i vi\u1EBFt (ch\u1EC9 b\xE0i vi\u1EBFt c\u1EE7a ch\xEDnh user/employee)",
648
+ method: "PUT",
649
+ path: "/v1/user/posts/{id}",
650
+ operationId: "wpcontentpostusercontroller_update_v1",
651
+ parameters: {
652
+ type: "object",
653
+ properties: {
654
+ path: {
655
+ type: "object",
656
+ properties: {
657
+ id: {
658
+ type: "string",
659
+ description: "Post ID (UUID)"
660
+ }
661
+ },
662
+ required: [
663
+ "id"
664
+ ],
665
+ additionalProperties: false
666
+ },
667
+ headers: {
668
+ type: "object",
669
+ properties: {
670
+ "x-workspace-id": {
671
+ type: "string",
672
+ description: "Workspace ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID)"
673
+ },
674
+ "x-base-id": {
675
+ type: "string",
676
+ description: "Base ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID, optional)"
677
+ }
678
+ },
679
+ required: [
680
+ "x-workspace-id"
681
+ ],
682
+ additionalProperties: false
683
+ },
684
+ body: {
685
+ type: "object",
686
+ properties: {
687
+ title: {
688
+ type: "string",
689
+ description: "Ti\xEAu \u0111\u1EC1 b\xE0i vi\u1EBFt"
690
+ },
691
+ slug: {
692
+ type: "string",
693
+ description: "Slug (friendly URL) - auto-generate n\u1EBFu kh\xF4ng nh\u1EADp"
694
+ },
695
+ excerpt: {
696
+ type: "string",
697
+ description: "M\xF4 t\u1EA3 ng\u1EAFn"
698
+ },
699
+ content: {
700
+ description: "N\u1ED9i dung b\xE0i vi\u1EBFt (Gutenberg blocks)",
701
+ allOf: [
702
+ {
703
+ type: "object",
704
+ properties: {
705
+ blocks: {
706
+ type: "array",
707
+ description: "Array of Gutenberg blocks",
708
+ items: {
709
+ type: "array",
710
+ items: {
711
+ type: "a"
712
+ }
713
+ }
714
+ },
715
+ meta: {
716
+ type: "object",
717
+ description: "Additional metadata"
718
+ },
719
+ settings: {
720
+ type: "object",
721
+ description: "Content settings"
722
+ }
723
+ },
724
+ required: [
725
+ "blocks"
726
+ ]
727
+ }
728
+ ]
729
+ },
730
+ featuredImageId: {
731
+ type: "string",
732
+ description: "ID \u1EA3nh \u0111\u1EA1i di\u1EC7n (UUID)"
733
+ },
734
+ status: {
735
+ type: "string",
736
+ description: "Tr\u1EA1ng th\xE1i b\xE0i vi\u1EBFt",
737
+ default: "draft",
738
+ enum: [
739
+ "draft",
740
+ "pending",
741
+ "private",
742
+ "publish",
743
+ "future",
744
+ "trash",
745
+ "archived"
746
+ ]
747
+ },
748
+ type: {
749
+ type: "string",
750
+ description: "Lo\u1EA1i b\xE0i vi\u1EBFt",
751
+ default: "post"
752
+ },
753
+ metaTitle: {
754
+ type: "string",
755
+ description: "SEO: Meta title (max 70 chars)"
756
+ },
757
+ metaDescription: {
758
+ type: "string",
759
+ description: "SEO: Meta description (max 160 chars)"
760
+ },
761
+ metaKeywords: {
762
+ type: "array",
763
+ description: "SEO: Meta keywords",
764
+ items: {
765
+ type: "string"
766
+ }
767
+ },
768
+ commentStatus: {
769
+ type: "string",
770
+ description: "Tr\u1EA1ng th\xE1i comment",
771
+ default: "open"
772
+ },
773
+ sticky: {
774
+ type: "boolean",
775
+ description: "\u0110\xE1nh d\u1EA5u sticky post",
776
+ default: false
777
+ },
778
+ password: {
779
+ type: "string",
780
+ description: "M\u1EADt kh\u1EA9u b\u1EA3o v\u1EC7 b\xE0i vi\u1EBFt (plaintext)"
781
+ },
782
+ menuOrder: {
783
+ type: "number",
784
+ description: "Th\u1EE9 t\u1EF1 hi\u1EC3n th\u1ECB",
785
+ default: 0
786
+ }
787
+ }
788
+ }
789
+ },
790
+ required: [
791
+ "path",
792
+ "headers",
793
+ "body"
794
+ ],
795
+ additionalProperties: false,
796
+ description: "C\u1EADp nh\u1EADt b\xE0i vi\u1EBFt tool arguments"
797
+ },
798
+ tags: [
799
+ "User - WP Content Post"
800
+ ]
801
+ }
802
+ ]
803
+ };
804
+
805
+ // wp-content-post.json
806
+ var wp_content_post_default = {
807
+ openapi: "3.0.0",
808
+ paths: {
809
+ "/v1/user/posts": {
810
+ post: {
811
+ description: "User ho\u1EB7c Employee t\u1EA1o b\xE0i vi\u1EBFt m\u1EDBi (draft ho\u1EB7c publish)",
812
+ operationId: "WpContentPostUserController_create_v1",
813
+ parameters: [
814
+ {
815
+ name: "x-workspace-id",
816
+ in: "header",
817
+ description: "Workspace ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID)",
818
+ required: true,
819
+ schema: {
820
+ type: "string",
821
+ format: "uuid"
822
+ }
823
+ },
824
+ {
825
+ name: "x-base-id",
826
+ in: "header",
827
+ description: "Base ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID, optional)",
828
+ required: false,
829
+ schema: {
830
+ type: "string",
831
+ format: "uuid"
832
+ }
833
+ }
834
+ ],
835
+ requestBody: {
836
+ required: true,
837
+ content: {
838
+ "application/json": {
839
+ schema: {
840
+ $ref: "#/components/schemas/CreatePostDto"
841
+ }
842
+ }
843
+ }
844
+ },
845
+ responses: {
846
+ "201": {
847
+ description: "B\xE0i vi\u1EBFt \u0111\xE3 \u0111\u01B0\u1EE3c t\u1EA1o th\xE0nh c\xF4ng",
848
+ content: {
849
+ "application/json": {
850
+ schema: {
851
+ $ref: "#/components/schemas/PostResponseDto"
852
+ }
853
+ }
854
+ }
855
+ },
856
+ "400": {
857
+ description: "D\u1EEF li\u1EC7u \u0111\u1EA7u v\xE0o kh\xF4ng h\u1EE3p l\u1EC7"
858
+ }
859
+ },
860
+ security: [
861
+ {
862
+ "JWT-auth": []
863
+ }
864
+ ],
865
+ summary: "T\u1EA1o b\xE0i vi\u1EBFt m\u1EDBi",
866
+ tags: [
867
+ "User - WP Content Post"
868
+ ]
869
+ },
870
+ get: {
871
+ description: "L\u1EA5y danh s\xE1ch b\xE0i vi\u1EBFt c\u1EE7a user/employee v\u1EDBi filters v\xE0 pagination",
872
+ operationId: "WpContentPostUserController_findAll_v1",
873
+ parameters: [
874
+ {
875
+ name: "x-workspace-id",
876
+ in: "header",
877
+ description: "Workspace ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID)",
878
+ required: true,
879
+ schema: {
880
+ type: "string",
881
+ format: "uuid"
882
+ }
883
+ },
884
+ {
885
+ name: "x-base-id",
886
+ in: "header",
887
+ description: "Base ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID, optional)",
888
+ required: false,
889
+ schema: {
890
+ type: "string",
891
+ format: "uuid"
892
+ }
893
+ },
894
+ {
895
+ name: "status",
896
+ required: false,
897
+ in: "query",
898
+ description: "Filter by status",
899
+ schema: {
900
+ type: "string",
901
+ enum: [
902
+ "draft",
903
+ "pending",
904
+ "private",
905
+ "publish",
906
+ "future",
907
+ "trash",
908
+ "archived"
909
+ ]
910
+ }
911
+ },
912
+ {
913
+ name: "type",
914
+ required: false,
915
+ in: "query",
916
+ description: "Filter by type",
917
+ schema: {
918
+ example: "post",
919
+ type: "string"
920
+ }
921
+ },
922
+ {
923
+ name: "search",
924
+ required: false,
925
+ in: "query",
926
+ description: "Search in title, excerpt, content",
927
+ schema: {
928
+ example: "hello",
929
+ type: "string"
930
+ }
931
+ },
932
+ {
933
+ name: "sticky",
934
+ required: false,
935
+ in: "query",
936
+ description: "Filter sticky posts only",
937
+ schema: {
938
+ default: false,
939
+ type: "boolean"
940
+ }
941
+ },
942
+ {
943
+ name: "sortBy",
944
+ required: false,
945
+ in: "query",
946
+ description: "Sort field",
947
+ schema: {
948
+ default: "createdAt",
949
+ example: "createdAt",
950
+ type: "string"
951
+ }
952
+ },
953
+ {
954
+ name: "sortOrder",
955
+ required: false,
956
+ in: "query",
957
+ description: "Sort order",
958
+ schema: {
959
+ default: "DESC",
960
+ type: "string",
961
+ enum: [
962
+ "ASC",
963
+ "DESC"
964
+ ]
965
+ }
966
+ },
967
+ {
968
+ name: "page",
969
+ required: false,
970
+ in: "query",
971
+ description: "Page number",
972
+ schema: {
973
+ minimum: 1,
974
+ default: 1,
975
+ type: "number"
976
+ }
977
+ },
978
+ {
979
+ name: "limit",
980
+ required: false,
981
+ in: "query",
982
+ description: "Items per page",
983
+ schema: {
984
+ minimum: 1,
985
+ maximum: 100,
986
+ default: 10,
987
+ type: "number"
988
+ }
989
+ }
990
+ ],
991
+ responses: {
992
+ "200": {
993
+ description: "Danh s\xE1ch b\xE0i vi\u1EBFt",
994
+ content: {
995
+ "application/json": {
996
+ schema: {
997
+ type: "object",
998
+ properties: {
999
+ data: {
1000
+ type: "array",
1001
+ items: {
1002
+ $ref: "#/components/schemas/PostResponseDto"
1003
+ }
1004
+ },
1005
+ total: {
1006
+ type: "number",
1007
+ example: 100
1008
+ },
1009
+ page: {
1010
+ type: "number",
1011
+ example: 1
1012
+ },
1013
+ limit: {
1014
+ type: "number",
1015
+ example: 10
1016
+ }
1017
+ }
1018
+ }
1019
+ }
1020
+ }
1021
+ }
1022
+ },
1023
+ security: [
1024
+ {
1025
+ "JWT-auth": []
1026
+ }
1027
+ ],
1028
+ summary: "L\u1EA5y danh s\xE1ch b\xE0i vi\u1EBFt",
1029
+ tags: [
1030
+ "User - WP Content Post"
1031
+ ]
1032
+ },
1033
+ delete: {
1034
+ description: "X\xF3a nhi\u1EC1u b\xE0i vi\u1EBFt c\xF9ng l\xFAc (soft delete ho\u1EB7c hard delete)",
1035
+ operationId: "WpContentPostUserController_bulkDelete_v1",
1036
+ parameters: [
1037
+ {
1038
+ name: "x-workspace-id",
1039
+ in: "header",
1040
+ description: "Workspace ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID)",
1041
+ required: true,
1042
+ schema: {
1043
+ type: "string",
1044
+ format: "uuid"
1045
+ }
1046
+ },
1047
+ {
1048
+ name: "x-base-id",
1049
+ in: "header",
1050
+ description: "Base ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID, optional)",
1051
+ required: false,
1052
+ schema: {
1053
+ type: "string",
1054
+ format: "uuid"
1055
+ }
1056
+ }
1057
+ ],
1058
+ requestBody: {
1059
+ required: true,
1060
+ content: {
1061
+ "application/json": {
1062
+ schema: {
1063
+ $ref: "#/components/schemas/BulkDeletePostDto"
1064
+ }
1065
+ }
1066
+ }
1067
+ },
1068
+ responses: {
1069
+ "200": {
1070
+ description: "K\u1EBFt qu\u1EA3 bulk delete",
1071
+ content: {
1072
+ "application/json": {
1073
+ schema: {
1074
+ type: "object",
1075
+ properties: {
1076
+ deleted: {
1077
+ type: "number",
1078
+ example: 5
1079
+ },
1080
+ failed: {
1081
+ type: "array",
1082
+ items: {
1083
+ type: "string"
1084
+ },
1085
+ example: [
1086
+ "uuid-1",
1087
+ "uuid-2"
1088
+ ]
1089
+ }
1090
+ }
1091
+ }
1092
+ }
1093
+ }
1094
+ }
1095
+ },
1096
+ security: [
1097
+ {
1098
+ "JWT-auth": []
1099
+ }
1100
+ ],
1101
+ summary: "X\xF3a nhi\u1EC1u b\xE0i vi\u1EBFt",
1102
+ tags: [
1103
+ "User - WP Content Post"
1104
+ ]
1105
+ }
1106
+ },
1107
+ "/v1/user/posts/{id}": {
1108
+ get: {
1109
+ description: "L\u1EA5y th\xF4ng tin chi ti\u1EBFt c\u1EE7a m\u1ED9t b\xE0i vi\u1EBFt (ch\u1EC9 b\xE0i vi\u1EBFt c\u1EE7a ch\xEDnh user/employee)",
1110
+ operationId: "WpContentPostUserController_findOne_v1",
1111
+ parameters: [
1112
+ {
1113
+ name: "x-workspace-id",
1114
+ in: "header",
1115
+ description: "Workspace ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID)",
1116
+ required: true,
1117
+ schema: {
1118
+ type: "string",
1119
+ format: "uuid"
1120
+ }
1121
+ },
1122
+ {
1123
+ name: "x-base-id",
1124
+ in: "header",
1125
+ description: "Base ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID, optional)",
1126
+ required: false,
1127
+ schema: {
1128
+ type: "string",
1129
+ format: "uuid"
1130
+ }
1131
+ },
1132
+ {
1133
+ name: "id",
1134
+ required: true,
1135
+ in: "path",
1136
+ description: "Post ID (UUID)",
1137
+ schema: {
1138
+ example: "123e4567-e89b-12d3-a456-426614174000",
1139
+ type: "string"
1140
+ }
1141
+ }
1142
+ ],
1143
+ responses: {
1144
+ "200": {
1145
+ description: "Chi ti\u1EBFt b\xE0i vi\u1EBFt",
1146
+ content: {
1147
+ "application/json": {
1148
+ schema: {
1149
+ $ref: "#/components/schemas/PostResponseDto"
1150
+ }
1151
+ }
1152
+ }
1153
+ },
1154
+ "403": {
1155
+ description: "Kh\xF4ng c\xF3 quy\u1EC1n truy c\u1EADp b\xE0i vi\u1EBFt n\xE0y"
1156
+ },
1157
+ "404": {
1158
+ description: "Kh\xF4ng t\xECm th\u1EA5y b\xE0i vi\u1EBFt"
1159
+ }
1160
+ },
1161
+ security: [
1162
+ {
1163
+ "JWT-auth": []
1164
+ }
1165
+ ],
1166
+ summary: "L\u1EA5y chi ti\u1EBFt b\xE0i vi\u1EBFt",
1167
+ tags: [
1168
+ "User - WP Content Post"
1169
+ ]
1170
+ },
1171
+ put: {
1172
+ description: "C\u1EADp nh\u1EADt th\xF4ng tin b\xE0i vi\u1EBFt (ch\u1EC9 b\xE0i vi\u1EBFt c\u1EE7a ch\xEDnh user/employee)",
1173
+ operationId: "WpContentPostUserController_update_v1",
1174
+ parameters: [
1175
+ {
1176
+ name: "x-workspace-id",
1177
+ in: "header",
1178
+ description: "Workspace ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID)",
1179
+ required: true,
1180
+ schema: {
1181
+ type: "string",
1182
+ format: "uuid"
1183
+ }
1184
+ },
1185
+ {
1186
+ name: "x-base-id",
1187
+ in: "header",
1188
+ description: "Base ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID, optional)",
1189
+ required: false,
1190
+ schema: {
1191
+ type: "string",
1192
+ format: "uuid"
1193
+ }
1194
+ },
1195
+ {
1196
+ name: "id",
1197
+ required: true,
1198
+ in: "path",
1199
+ description: "Post ID (UUID)",
1200
+ schema: {
1201
+ example: "123e4567-e89b-12d3-a456-426614174000",
1202
+ type: "string"
1203
+ }
1204
+ }
1205
+ ],
1206
+ requestBody: {
1207
+ required: true,
1208
+ content: {
1209
+ "application/json": {
1210
+ schema: {
1211
+ $ref: "#/components/schemas/UpdatePostDto"
1212
+ }
1213
+ }
1214
+ }
1215
+ },
1216
+ responses: {
1217
+ "200": {
1218
+ description: "B\xE0i vi\u1EBFt \u0111\xE3 \u0111\u01B0\u1EE3c c\u1EADp nh\u1EADt",
1219
+ content: {
1220
+ "application/json": {
1221
+ schema: {
1222
+ $ref: "#/components/schemas/PostResponseDto"
1223
+ }
1224
+ }
1225
+ }
1226
+ },
1227
+ "403": {
1228
+ description: "Kh\xF4ng c\xF3 quy\u1EC1n c\u1EADp nh\u1EADt b\xE0i vi\u1EBFt n\xE0y"
1229
+ },
1230
+ "404": {
1231
+ description: "Kh\xF4ng t\xECm th\u1EA5y b\xE0i vi\u1EBFt"
1232
+ }
1233
+ },
1234
+ security: [
1235
+ {
1236
+ "JWT-auth": []
1237
+ }
1238
+ ],
1239
+ summary: "C\u1EADp nh\u1EADt b\xE0i vi\u1EBFt",
1240
+ tags: [
1241
+ "User - WP Content Post"
1242
+ ]
1243
+ }
1244
+ },
1245
+ "/v1/user/posts/{id}/submit-for-review": {
1246
+ post: {
1247
+ description: "Chuy\u1EC3n tr\u1EA1ng th\xE1i b\xE0i vi\u1EBFt sang pending \u0111\u1EC3 ch\u1EDD admin duy\u1EC7t",
1248
+ operationId: "WpContentPostUserController_submitForReview_v1",
1249
+ parameters: [
1250
+ {
1251
+ name: "x-workspace-id",
1252
+ in: "header",
1253
+ description: "Workspace ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID)",
1254
+ required: true,
1255
+ schema: {
1256
+ type: "string",
1257
+ format: "uuid"
1258
+ }
1259
+ },
1260
+ {
1261
+ name: "x-base-id",
1262
+ in: "header",
1263
+ description: "Base ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID, optional)",
1264
+ required: false,
1265
+ schema: {
1266
+ type: "string",
1267
+ format: "uuid"
1268
+ }
1269
+ },
1270
+ {
1271
+ name: "id",
1272
+ required: true,
1273
+ in: "path",
1274
+ description: "Post ID (UUID)",
1275
+ schema: {
1276
+ example: "123e4567-e89b-12d3-a456-426614174000",
1277
+ type: "string"
1278
+ }
1279
+ }
1280
+ ],
1281
+ responses: {
1282
+ "200": {
1283
+ description: "B\xE0i vi\u1EBFt \u0111\xE3 \u0111\u01B0\u1EE3c g\u1EEDi \u0111i duy\u1EC7t",
1284
+ content: {
1285
+ "application/json": {
1286
+ schema: {
1287
+ $ref: "#/components/schemas/PostResponseDto"
1288
+ }
1289
+ }
1290
+ }
1291
+ },
1292
+ "400": {
1293
+ description: "B\xE0i vi\u1EBFt ch\u01B0a \u0111\u1EE7 th\xF4ng tin b\u1EAFt bu\u1ED9c"
1294
+ },
1295
+ "403": {
1296
+ description: "Kh\xF4ng c\xF3 quy\u1EC1n g\u1EEDi duy\u1EC7t b\xE0i vi\u1EBFt n\xE0y"
1297
+ },
1298
+ "404": {
1299
+ description: "Kh\xF4ng t\xECm th\u1EA5y b\xE0i vi\u1EBFt"
1300
+ }
1301
+ },
1302
+ security: [
1303
+ {
1304
+ "JWT-auth": []
1305
+ }
1306
+ ],
1307
+ summary: "G\u1EEDi b\xE0i vi\u1EBFt \u0111i duy\u1EC7t",
1308
+ tags: [
1309
+ "User - WP Content Post"
1310
+ ]
1311
+ }
1312
+ },
1313
+ "/v1/user/posts/{id}/toggle-sticky": {
1314
+ patch: {
1315
+ description: "\u0110\u1EA3o tr\u1EA1ng th\xE1i sticky c\u1EE7a b\xE0i vi\u1EBFt (true \u2192 false ho\u1EB7c false \u2192 true)",
1316
+ operationId: "WpContentPostUserController_toggleSticky_v1",
1317
+ parameters: [
1318
+ {
1319
+ name: "x-workspace-id",
1320
+ in: "header",
1321
+ description: "Workspace ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID)",
1322
+ required: true,
1323
+ schema: {
1324
+ type: "string",
1325
+ format: "uuid"
1326
+ }
1327
+ },
1328
+ {
1329
+ name: "x-base-id",
1330
+ in: "header",
1331
+ description: "Base ID c\u1EE7a tenant hi\u1EC7n t\u1EA1i (UUID, optional)",
1332
+ required: false,
1333
+ schema: {
1334
+ type: "string",
1335
+ format: "uuid"
1336
+ }
1337
+ },
1338
+ {
1339
+ name: "id",
1340
+ required: true,
1341
+ in: "path",
1342
+ description: "Post ID (UUID)",
1343
+ schema: {
1344
+ example: "123e4567-e89b-12d3-a456-426614174000",
1345
+ type: "string"
1346
+ }
1347
+ }
1348
+ ],
1349
+ responses: {
1350
+ "200": {
1351
+ description: "Sticky status \u0111\xE3 \u0111\u01B0\u1EE3c c\u1EADp nh\u1EADt",
1352
+ content: {
1353
+ "application/json": {
1354
+ schema: {
1355
+ $ref: "#/components/schemas/PostResponseDto"
1356
+ }
1357
+ }
1358
+ }
1359
+ },
1360
+ "403": {
1361
+ description: "Kh\xF4ng c\xF3 quy\u1EC1n ch\u1EC9nh s\u1EEDa b\xE0i vi\u1EBFt n\xE0y"
1362
+ },
1363
+ "404": {
1364
+ description: "Kh\xF4ng t\xECm th\u1EA5y b\xE0i vi\u1EBFt"
1365
+ }
1366
+ },
1367
+ security: [
1368
+ {
1369
+ "JWT-auth": []
1370
+ }
1371
+ ],
1372
+ summary: "Toggle sticky status",
1373
+ tags: [
1374
+ "User - WP Content Post"
1375
+ ]
1376
+ }
1377
+ }
1378
+ },
1379
+ info: {
1380
+ title: "RedAI User API Export - WP Content Post",
1381
+ description: "OpenAPI export cho nh\xF3m API user \u0111\xE3 ch\u1ECDn: WP Content Post.",
1382
+ version: "1.0",
1383
+ contact: {
1384
+ name: "RedAI Support",
1385
+ url: "https://redai.com/support",
1386
+ email: "support@redai.com"
1387
+ },
1388
+ license: {
1389
+ name: "MIT",
1390
+ url: "https://opensource.org/licenses/MIT"
1391
+ }
1392
+ },
1393
+ tags: [
1394
+ {
1395
+ name: "User - WP Content Post",
1396
+ description: "User - WP Content Post endpoints"
1397
+ }
1398
+ ],
1399
+ servers: [
1400
+ {
1401
+ url: "http://localhost:3000",
1402
+ description: "Local Server"
1403
+ },
1404
+ {
1405
+ url: "http://localhost:3003",
1406
+ description: "Development Server"
1407
+ },
1408
+ {
1409
+ url: "http://14.225.29.196:3003",
1410
+ description: "Test Server"
1411
+ },
1412
+ {
1413
+ url: "https://api-staging.redai.vn",
1414
+ description: "Staging Server"
1415
+ },
1416
+ {
1417
+ url: "https://v2.redai.vn/api",
1418
+ description: "Production Server"
1419
+ }
1420
+ ],
1421
+ components: {
1422
+ schemas: {
1423
+ CreatePostDto: {
1424
+ type: "object",
1425
+ properties: {
1426
+ title: {
1427
+ type: "string",
1428
+ description: "Ti\xEAu \u0111\u1EC1 b\xE0i vi\u1EBFt",
1429
+ example: "Hello World"
1430
+ },
1431
+ slug: {
1432
+ type: "string",
1433
+ description: "Slug (friendly URL) - auto-generate n\u1EBFu kh\xF4ng nh\u1EADp",
1434
+ example: "hello-world"
1435
+ },
1436
+ excerpt: {
1437
+ type: "string",
1438
+ description: "M\xF4 t\u1EA3 ng\u1EAFn",
1439
+ example: "This is a short excerpt..."
1440
+ },
1441
+ content: {
1442
+ description: "N\u1ED9i dung b\xE0i vi\u1EBFt (Gutenberg blocks)",
1443
+ allOf: [
1444
+ {
1445
+ $ref: "#/components/schemas/WpContentDto"
1446
+ }
1447
+ ]
1448
+ },
1449
+ featuredImageId: {
1450
+ type: "string",
1451
+ description: "ID \u1EA3nh \u0111\u1EA1i di\u1EC7n (UUID)",
1452
+ example: "123e4567-e89b-12d3-a456-426614174000"
1453
+ },
1454
+ status: {
1455
+ type: "string",
1456
+ description: "Tr\u1EA1ng th\xE1i b\xE0i vi\u1EBFt",
1457
+ enum: [
1458
+ "draft",
1459
+ "pending",
1460
+ "private",
1461
+ "publish",
1462
+ "future",
1463
+ "trash",
1464
+ "archived"
1465
+ ],
1466
+ default: "draft"
1467
+ },
1468
+ type: {
1469
+ type: "string",
1470
+ description: "Lo\u1EA1i b\xE0i vi\u1EBFt",
1471
+ example: "post",
1472
+ default: "post"
1473
+ },
1474
+ metaTitle: {
1475
+ type: "string",
1476
+ description: "SEO: Meta title (max 70 chars)",
1477
+ example: "Hello World - My Blog",
1478
+ maxLength: 70
1479
+ },
1480
+ metaDescription: {
1481
+ type: "string",
1482
+ description: "SEO: Meta description (max 160 chars)",
1483
+ maxLength: 160
1484
+ },
1485
+ metaKeywords: {
1486
+ description: "SEO: Meta keywords",
1487
+ example: [
1488
+ "wordpress",
1489
+ "cms",
1490
+ "blog"
1491
+ ],
1492
+ type: "array",
1493
+ items: {
1494
+ type: "string"
1495
+ }
1496
+ },
1497
+ commentStatus: {
1498
+ type: "string",
1499
+ description: "Tr\u1EA1ng th\xE1i comment",
1500
+ example: "open",
1501
+ default: "open"
1502
+ },
1503
+ sticky: {
1504
+ type: "boolean",
1505
+ description: "\u0110\xE1nh d\u1EA5u sticky post",
1506
+ default: false
1507
+ },
1508
+ password: {
1509
+ type: "string",
1510
+ description: "M\u1EADt kh\u1EA9u b\u1EA3o v\u1EC7 b\xE0i vi\u1EBFt (plaintext)",
1511
+ maxLength: 255
1512
+ },
1513
+ menuOrder: {
1514
+ type: "number",
1515
+ description: "Th\u1EE9 t\u1EF1 hi\u1EC3n th\u1ECB",
1516
+ example: 0,
1517
+ default: 0
1518
+ }
1519
+ },
1520
+ required: [
1521
+ "title",
1522
+ "content"
1523
+ ]
1524
+ },
1525
+ PostResponseDto: {
1526
+ type: "object",
1527
+ properties: {
1528
+ id: {
1529
+ type: "string",
1530
+ description: "Post ID (UUID)",
1531
+ example: "123e4567-e89b-12d3-a456-426614174000"
1532
+ },
1533
+ title: {
1534
+ type: "string",
1535
+ description: "Ti\xEAu \u0111\u1EC1 b\xE0i vi\u1EBFt",
1536
+ example: "Hello World"
1537
+ },
1538
+ slug: {
1539
+ type: "string",
1540
+ description: "Slug (friendly URL)",
1541
+ example: "hello-world"
1542
+ },
1543
+ excerpt: {
1544
+ type: "string",
1545
+ description: "M\xF4 t\u1EA3 ng\u1EAFn"
1546
+ },
1547
+ content: {
1548
+ type: "object",
1549
+ description: "N\u1ED9i dung b\xE0i vi\u1EBFt (rendered HTML + blocks)"
1550
+ },
1551
+ featuredImageId: {
1552
+ type: "string",
1553
+ description: "ID \u1EA3nh \u0111\u1EA1i di\u1EC7n"
1554
+ },
1555
+ status: {
1556
+ type: "string",
1557
+ description: "Tr\u1EA1ng th\xE1i b\xE0i vi\u1EBFt",
1558
+ enum: [
1559
+ "draft",
1560
+ "pending",
1561
+ "private",
1562
+ "publish",
1563
+ "future",
1564
+ "trash",
1565
+ "archived"
1566
+ ]
1567
+ },
1568
+ type: {
1569
+ type: "string",
1570
+ description: "Lo\u1EA1i b\xE0i vi\u1EBFt",
1571
+ example: "post"
1572
+ },
1573
+ authorId: {
1574
+ type: "number",
1575
+ description: "ID ng\u01B0\u1EDDi d\xF9ng (author)"
1576
+ },
1577
+ employeeId: {
1578
+ type: "number",
1579
+ description: "ID nh\xE2n vi\xEAn"
1580
+ },
1581
+ createdAt: {
1582
+ type: "number",
1583
+ description: "Th\u1EDDi gian t\u1EA1o (unix timestamp ms)"
1584
+ },
1585
+ updatedAt: {
1586
+ type: "number",
1587
+ description: "Th\u1EDDi gian c\u1EADp nh\u1EADt (unix timestamp ms)"
1588
+ },
1589
+ publishedAt: {
1590
+ type: "number",
1591
+ description: "Th\u1EDDi gian xu\u1EA5t b\u1EA3n (unix timestamp ms)"
1592
+ },
1593
+ metaTitle: {
1594
+ type: "string",
1595
+ description: "SEO: Meta title"
1596
+ },
1597
+ metaDescription: {
1598
+ type: "string",
1599
+ description: "SEO: Meta description"
1600
+ },
1601
+ metaKeywords: {
1602
+ description: "SEO: Meta keywords",
1603
+ type: "array",
1604
+ items: {
1605
+ type: "string"
1606
+ }
1607
+ },
1608
+ commentStatus: {
1609
+ type: "string",
1610
+ description: "Tr\u1EA1ng th\xE1i comment",
1611
+ example: "open"
1612
+ },
1613
+ pingStatus: {
1614
+ type: "string",
1615
+ description: "Tr\u1EA1ng th\xE1i ping",
1616
+ example: "open"
1617
+ },
1618
+ sticky: {
1619
+ type: "boolean",
1620
+ description: "\u0110\xE1nh d\u1EA5u sticky post"
1621
+ },
1622
+ isPasswordProtected: {
1623
+ type: "boolean",
1624
+ description: "Password protected (c\xF3 m\u1EADt kh\u1EA9u hay kh\xF4ng)",
1625
+ example: false
1626
+ },
1627
+ menuOrder: {
1628
+ type: "number",
1629
+ description: "Th\u1EE9 t\u1EF1 hi\u1EC3n th\u1ECB"
1630
+ }
1631
+ },
1632
+ required: [
1633
+ "id",
1634
+ "title",
1635
+ "slug",
1636
+ "content",
1637
+ "status",
1638
+ "type",
1639
+ "createdAt",
1640
+ "updatedAt",
1641
+ "commentStatus",
1642
+ "pingStatus",
1643
+ "sticky",
1644
+ "menuOrder"
1645
+ ]
1646
+ },
1647
+ BulkDeletePostDto: {
1648
+ type: "object",
1649
+ properties: {
1650
+ ids: {
1651
+ description: "Array of post IDs to delete",
1652
+ example: [
1653
+ "uuid-1",
1654
+ "uuid-2"
1655
+ ],
1656
+ type: "array",
1657
+ items: {
1658
+ type: "string"
1659
+ }
1660
+ },
1661
+ permanent: {
1662
+ type: "boolean",
1663
+ description: "Permanent delete (hard delete) or soft delete (status=trash)",
1664
+ default: false
1665
+ }
1666
+ },
1667
+ required: [
1668
+ "ids"
1669
+ ]
1670
+ },
1671
+ UpdatePostDto: {
1672
+ type: "object",
1673
+ properties: {
1674
+ title: {
1675
+ type: "string",
1676
+ description: "Ti\xEAu \u0111\u1EC1 b\xE0i vi\u1EBFt",
1677
+ example: "Hello World"
1678
+ },
1679
+ slug: {
1680
+ type: "string",
1681
+ description: "Slug (friendly URL) - auto-generate n\u1EBFu kh\xF4ng nh\u1EADp",
1682
+ example: "hello-world"
1683
+ },
1684
+ excerpt: {
1685
+ type: "string",
1686
+ description: "M\xF4 t\u1EA3 ng\u1EAFn",
1687
+ example: "This is a short excerpt..."
1688
+ },
1689
+ content: {
1690
+ description: "N\u1ED9i dung b\xE0i vi\u1EBFt (Gutenberg blocks)",
1691
+ allOf: [
1692
+ {
1693
+ $ref: "#/components/schemas/WpContentDto"
1694
+ }
1695
+ ]
1696
+ },
1697
+ featuredImageId: {
1698
+ type: "string",
1699
+ description: "ID \u1EA3nh \u0111\u1EA1i di\u1EC7n (UUID)",
1700
+ example: "123e4567-e89b-12d3-a456-426614174000"
1701
+ },
1702
+ status: {
1703
+ type: "string",
1704
+ description: "Tr\u1EA1ng th\xE1i b\xE0i vi\u1EBFt",
1705
+ enum: [
1706
+ "draft",
1707
+ "pending",
1708
+ "private",
1709
+ "publish",
1710
+ "future",
1711
+ "trash",
1712
+ "archived"
1713
+ ],
1714
+ default: "draft"
1715
+ },
1716
+ type: {
1717
+ type: "string",
1718
+ description: "Lo\u1EA1i b\xE0i vi\u1EBFt",
1719
+ example: "post",
1720
+ default: "post"
1721
+ },
1722
+ metaTitle: {
1723
+ type: "string",
1724
+ description: "SEO: Meta title (max 70 chars)",
1725
+ example: "Hello World - My Blog",
1726
+ maxLength: 70
1727
+ },
1728
+ metaDescription: {
1729
+ type: "string",
1730
+ description: "SEO: Meta description (max 160 chars)",
1731
+ maxLength: 160
1732
+ },
1733
+ metaKeywords: {
1734
+ description: "SEO: Meta keywords",
1735
+ example: [
1736
+ "wordpress",
1737
+ "cms",
1738
+ "blog"
1739
+ ],
1740
+ type: "array",
1741
+ items: {
1742
+ type: "string"
1743
+ }
1744
+ },
1745
+ commentStatus: {
1746
+ type: "string",
1747
+ description: "Tr\u1EA1ng th\xE1i comment",
1748
+ example: "open",
1749
+ default: "open"
1750
+ },
1751
+ sticky: {
1752
+ type: "boolean",
1753
+ description: "\u0110\xE1nh d\u1EA5u sticky post",
1754
+ default: false
1755
+ },
1756
+ password: {
1757
+ type: "string",
1758
+ description: "M\u1EADt kh\u1EA9u b\u1EA3o v\u1EC7 b\xE0i vi\u1EBFt (plaintext)",
1759
+ maxLength: 255
1760
+ },
1761
+ menuOrder: {
1762
+ type: "number",
1763
+ description: "Th\u1EE9 t\u1EF1 hi\u1EC3n th\u1ECB",
1764
+ example: 0,
1765
+ default: 0
1766
+ }
1767
+ }
1768
+ },
1769
+ WpContentDto: {
1770
+ type: "object",
1771
+ properties: {
1772
+ blocks: {
1773
+ description: "Array of Gutenberg blocks",
1774
+ items: {
1775
+ type: "array",
1776
+ items: {
1777
+ type: "a"
1778
+ }
1779
+ },
1780
+ type: "array"
1781
+ },
1782
+ meta: {
1783
+ type: "object",
1784
+ description: "Additional metadata"
1785
+ },
1786
+ settings: {
1787
+ type: "object",
1788
+ description: "Content settings"
1789
+ }
1790
+ },
1791
+ required: [
1792
+ "blocks"
1793
+ ]
1794
+ }
1795
+ },
1796
+ securitySchemes: {
1797
+ "JWT-auth": {
1798
+ scheme: "bearer",
1799
+ bearerFormat: "JWT",
1800
+ type: "http",
1801
+ name: "JWT",
1802
+ description: "Enter JWT token",
1803
+ in: "header"
1804
+ }
1805
+ }
1806
+ },
1807
+ externalDocs: {
1808
+ description: "Additional Documentation",
1809
+ url: "https://redai.com/docs"
1810
+ },
1811
+ generatedAt: "2026-03-16T08:19:38.217Z",
1812
+ "x-redai-export-modules": [
1813
+ "wp-content-post"
1814
+ ],
1815
+ "x-redai-export-scope": "user"
1816
+ };
1817
+
1818
+ // index.ts
1819
+ var DEFAULT_AUTH_STORE_PATH = "C:\\Users\\Acer\\.openclaw\\workspace-nhan-vien-redai\\auth\\redai-auth.json";
1820
+ var typedCatalog = tool_catalog_default;
1821
+ var formatToolResult = (payload) => ({
1822
+ content: [
1823
+ {
1824
+ type: "text",
1825
+ text: typeof payload === "string" ? payload : JSON.stringify(payload, null, 2)
1826
+ }
1827
+ ]
1828
+ });
1829
+ var resolvePluginConfig = (api) => api.config?.plugins?.entries?.[typedCatalog.pluginId]?.config ?? {};
1830
+ var cloneJson = (value) => JSON.parse(JSON.stringify(value));
1831
+ var removeHeadersFromSchema = (schema) => {
1832
+ const cloned = cloneJson(schema ?? { type: "object", properties: {} });
1833
+ const objectSchema = cloned;
1834
+ if (!objectSchema.properties) {
1835
+ objectSchema.properties = {};
1836
+ }
1837
+ delete objectSchema.properties.headers;
1838
+ if (Array.isArray(objectSchema.required)) {
1839
+ objectSchema.required = objectSchema.required.filter((item) => item !== "headers");
1840
+ }
1841
+ objectSchema.additionalProperties = false;
1842
+ return objectSchema;
1843
+ };
1844
+ var buildAuthWrappedParameters = (tool) => {
1845
+ const baseSchema = removeHeadersFromSchema(tool.parameters);
1846
+ return {
1847
+ ...baseSchema,
1848
+ description: `${tool.description} Uses the logged-in RedAI auth for the current Telegram DM user.`,
1849
+ properties: {
1850
+ telegramUserId: {
1851
+ type: "string",
1852
+ description: "Telegram sender ID from DM metadata. The agent must derive this automatically from the current message."
1853
+ },
1854
+ ...baseSchema.properties ?? {}
1855
+ },
1856
+ required: [
1857
+ "telegramUserId",
1858
+ ...(baseSchema.required ?? []).filter((item) => item !== "telegramUserId")
1859
+ ]
1860
+ };
1861
+ };
1862
+ var buildAuthToolName = (toolName) => toolName.startsWith("redai_openapi_wp_content_post_") ? toolName.replace(/^redai_openapi_wp_content_post_/, "redai_openapi_wp_content_post_auth_") : "redai_openapi_wp_content_post_auth_${toolName}";
1863
+ var getAuthStorePath = (runtimeConfig) => runtimeConfig.authStorePath?.trim() || DEFAULT_AUTH_STORE_PATH;
1864
+ var ensureStoreDirectory = async (storePath) => {
1865
+ await (0, import_promises.mkdir)((0, import_node_path.dirname)(storePath), { recursive: true });
1866
+ };
1867
+ var loadAuthStore = async (runtimeConfig) => {
1868
+ const storePath = getAuthStorePath(runtimeConfig);
1869
+ try {
1870
+ const raw = await (0, import_promises.readFile)(storePath, "utf8");
1871
+ const parsed = JSON.parse(raw);
1872
+ return { version: 1, users: parsed?.users ?? {} };
1873
+ } catch (error) {
1874
+ const maybeNodeError = error;
1875
+ if (maybeNodeError?.code === "ENOENT") {
1876
+ await ensureStoreDirectory(storePath);
1877
+ await (0, import_promises.writeFile)(storePath, JSON.stringify({ version: 1, users: {} }, null, 2), "utf8");
1878
+ return { version: 1, users: {} };
1879
+ }
1880
+ throw error;
1881
+ }
1882
+ };
1883
+ var getAuthStoreEntry = async (runtimeConfig, telegramUserId) => {
1884
+ const store = await loadAuthStore(runtimeConfig);
1885
+ return store.users[telegramUserId] ?? null;
1886
+ };
1887
+ var withRedaiAuth = (runtimeConfig, auth) => {
1888
+ const defaultHeaders = {
1889
+ ...runtimeConfig.defaultHeaders ?? {},
1890
+ "x-workspace-id": auth.workspaceId
1891
+ };
1892
+ if (auth.baseId) {
1893
+ defaultHeaders["x-base-id"] = auth.baseId;
1894
+ } else {
1895
+ delete defaultHeaders["x-base-id"];
1896
+ }
1897
+ return {
1898
+ ...runtimeConfig,
1899
+ bearerToken: auth.bearerToken,
1900
+ apiKey: void 0,
1901
+ apiKeyHeader: void 0,
1902
+ defaultHeaders,
1903
+ workspaceId: auth.workspaceId,
1904
+ baseId: auth.baseId ?? void 0
1905
+ };
1906
+ };
1907
+ var resolveUserRuntimeConfig = async (api, telegramUserId) => {
1908
+ const runtimeConfig = resolvePluginConfig(api);
1909
+ const authEntry = await getAuthStoreEntry(runtimeConfig, telegramUserId);
1910
+ if (!authEntry || authEntry.status !== "active") {
1911
+ return null;
1912
+ }
1913
+ return {
1914
+ runtimeConfig,
1915
+ scopedConfig: withRedaiAuth(runtimeConfig, authEntry)
1916
+ };
1917
+ };
1918
+ var authRequiredResult = (telegramUserId) => formatToolResult({
1919
+ ok: false,
1920
+ status: 401,
1921
+ statusText: "AUTH_REQUIRED",
1922
+ data: {
1923
+ message: "Ban chua dang nhap RedAI auth hop le. Hay dung /login <bearerToken> <workspaceId> [baseId] trong DM truoc khi thao tac nghiep vu.",
1924
+ telegramUserId
1925
+ }
1926
+ });
1927
+ var hasHeadersSection = (tool) => {
1928
+ const parameters = tool.parameters;
1929
+ return Boolean(parameters?.properties?.headers);
1930
+ };
1931
+ var mergeTenantHeaders = (tool, inputHeaders, runtimeConfig) => {
1932
+ const entries = Object.entries(inputHeaders ?? {}).filter(([, value]) => value !== void 0 && value !== null && value !== "").map(([key, value]) => [key, String(value)]);
1933
+ if (hasHeadersSection(tool)) {
1934
+ if (runtimeConfig.workspaceId && !entries.some(([key]) => key.toLowerCase() === "x-workspace-id")) {
1935
+ entries.push(["x-workspace-id", runtimeConfig.workspaceId]);
1936
+ }
1937
+ if (runtimeConfig.baseId && !entries.some(([key]) => key.toLowerCase() === "x-base-id")) {
1938
+ entries.push(["x-base-id", runtimeConfig.baseId]);
1939
+ }
1940
+ }
1941
+ return entries.length > 0 ? Object.fromEntries(entries) : void 0;
1942
+ };
1943
+ var executeCatalogTool = async (runtimeConfig, tool, rawParams) => {
1944
+ const client = new RedaiAgentClient({
1945
+ ...runtimeConfig,
1946
+ baseUrl: runtimeConfig.baseUrl ?? typedCatalog.serverUrl
1947
+ });
1948
+ const params = rawParams ?? {};
1949
+ return client.executeTool(tool, {
1950
+ path: params.path,
1951
+ query: params.query,
1952
+ body: params.body,
1953
+ headers: mergeTenantHeaders(tool, params.headers, runtimeConfig)
1954
+ });
1955
+ };
1956
+ var registerAuthProxyTool = (api, tool) => {
1957
+ api.registerTool(
1958
+ {
1959
+ name: buildAuthToolName(tool.name),
1960
+ description: `${tool.description} Uses the logged-in RedAI auth for the current Telegram DM user.`,
1961
+ parameters: buildAuthWrappedParameters(tool),
1962
+ execute: async (_id, rawParams) => {
1963
+ const params = rawParams ?? {};
1964
+ const telegramUserId = String(params.telegramUserId ?? "");
1965
+ const resolved = await resolveUserRuntimeConfig(api, telegramUserId);
1966
+ if (!resolved) {
1967
+ return authRequiredResult(telegramUserId);
1968
+ }
1969
+ const forwardedParams = { ...params };
1970
+ delete forwardedParams.telegramUserId;
1971
+ try {
1972
+ const response = await executeCatalogTool(resolved.scopedConfig, tool, forwardedParams);
1973
+ return formatToolResult(response.data);
1974
+ } catch (error) {
1975
+ if (error instanceof RedaiAgentError) {
1976
+ return formatToolResult({
1977
+ ok: false,
1978
+ status: error.status ?? 500,
1979
+ statusText: error.message,
1980
+ data: error.body
1981
+ });
1982
+ }
1983
+ return formatToolResult({
1984
+ ok: false,
1985
+ status: 500,
1986
+ statusText: "PLUGIN_EXECUTION_FAILED",
1987
+ data: String(error)
1988
+ });
1989
+ }
1990
+ }
1991
+ },
1992
+ { optional: typedCatalog.optional ?? true }
1993
+ );
1994
+ };
1995
+ function register(api) {
1996
+ for (const tool of typedCatalog.tools) {
1997
+ api.registerTool(
1998
+ {
1999
+ name: tool.name,
2000
+ description: tool.description,
2001
+ parameters: tool.parameters,
2002
+ execute: async (_id, rawParams) => {
2003
+ try {
2004
+ const response = await executeCatalogTool(resolvePluginConfig(api), tool, rawParams);
2005
+ return formatToolResult(response.data);
2006
+ } catch (error) {
2007
+ if (error instanceof RedaiAgentError) {
2008
+ return formatToolResult({
2009
+ ok: false,
2010
+ status: error.status ?? 500,
2011
+ statusText: error.message,
2012
+ data: error.body
2013
+ });
2014
+ }
2015
+ return formatToolResult({
2016
+ ok: false,
2017
+ status: 500,
2018
+ statusText: "PLUGIN_EXECUTION_FAILED",
2019
+ data: String(error)
2020
+ });
2021
+ }
2022
+ }
2023
+ },
2024
+ { optional: typedCatalog.optional ?? true }
2025
+ );
2026
+ }
2027
+ for (const tool of typedCatalog.tools) {
2028
+ registerAuthProxyTool(api, tool);
2029
+ }
2030
+ }
2031
+ // Annotate the CommonJS export names for ESM import in node:
2032
+ 0 && (module.exports = {
2033
+ catalog,
2034
+ spec
2035
+ });
2036
+ //# sourceMappingURL=index.cjs.map