noverload-mcp 0.9.1 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/client.d.ts +588 -30
  2. package/dist/client.d.ts.map +1 -1
  3. package/dist/client.js +408 -115
  4. package/dist/client.js.map +1 -1
  5. package/dist/index.js +2 -2
  6. package/dist/resources/index.d.ts +6 -1
  7. package/dist/resources/index.d.ts.map +1 -1
  8. package/dist/tools/implementations/explore-topic.d.ts.map +1 -1
  9. package/dist/tools/implementations/explore-topic.js +41 -22
  10. package/dist/tools/implementations/explore-topic.js.map +1 -1
  11. package/dist/tools/implementations/extract-frameworks.d.ts.map +1 -1
  12. package/dist/tools/implementations/extract-frameworks.js +91 -29
  13. package/dist/tools/implementations/extract-frameworks.js.map +1 -1
  14. package/dist/tools/implementations/get-content.d.ts.map +1 -1
  15. package/dist/tools/implementations/get-content.js +3 -1
  16. package/dist/tools/implementations/get-content.js.map +1 -1
  17. package/dist/tools/implementations/list-content.d.ts.map +1 -1
  18. package/dist/tools/implementations/list-content.js +3 -1
  19. package/dist/tools/implementations/list-content.js.map +1 -1
  20. package/dist/tools/implementations/list-tags.d.ts +3 -0
  21. package/dist/tools/implementations/list-tags.d.ts.map +1 -0
  22. package/dist/tools/implementations/list-tags.js +115 -0
  23. package/dist/tools/implementations/list-tags.js.map +1 -0
  24. package/dist/tools/implementations/manage-tags.d.ts +5 -0
  25. package/dist/tools/implementations/manage-tags.d.ts.map +1 -0
  26. package/dist/tools/implementations/manage-tags.js +157 -0
  27. package/dist/tools/implementations/manage-tags.js.map +1 -0
  28. package/dist/tools/implementations/save-content.d.ts.map +1 -1
  29. package/dist/tools/implementations/save-content.js +43 -4
  30. package/dist/tools/implementations/save-content.js.map +1 -1
  31. package/dist/tools/implementations/swipe-file.d.ts +4 -0
  32. package/dist/tools/implementations/swipe-file.d.ts.map +1 -0
  33. package/dist/tools/implementations/swipe-file.js +82 -0
  34. package/dist/tools/implementations/swipe-file.js.map +1 -0
  35. package/dist/tools/index.d.ts +4 -1
  36. package/dist/tools/index.d.ts.map +1 -1
  37. package/dist/tools/index.js +15 -3
  38. package/dist/tools/index.js.map +1 -1
  39. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/client.js CHANGED
@@ -1,34 +1,65 @@
1
1
  import { z } from "zod";
2
- // Schema definitions matching your Noverload database
3
- // Made more flexible to handle API variations
2
+ // Content types enum for reuse
3
+ export const ContentTypeEnum = z.enum(["youtube", "x_twitter", "reddit", "article", "pdf"]);
4
+ export const ContentStatusEnum = z.enum(["pending", "processing", "completed", "failed"]);
5
+ // Summary can be either a string or a structured object
6
+ // The API returns different formats depending on processing stage
7
+ export const SummaryObjectSchema = z.object({
8
+ one_sentence: z.string().optional(),
9
+ text: z.string().optional(),
10
+ key_points: z.array(z.string()).optional(),
11
+ actionable_takeaways: z.array(z.string()).optional(),
12
+ }).passthrough(); // Allow additional fields from API
13
+ export const SummarySchema = z.union([
14
+ z.string(),
15
+ SummaryObjectSchema,
16
+ ]).nullable().optional();
17
+ // Processing metadata schema (flexible for API variations)
18
+ export const ProcessingMetadataSchema = z.object({
19
+ processedAt: z.string().optional(),
20
+ duration: z.number().optional(),
21
+ model: z.string().optional(),
22
+ version: z.string().optional(),
23
+ }).passthrough().nullable().optional();
24
+ // Schema definitions matching Noverload database
25
+ // Required fields will throw if missing - no silent defaults for critical data
4
26
  export const ContentSchema = z.object({
5
- id: z.string(),
6
- userId: z.string().optional().default(""), // Made optional with default
7
- url: z.string(),
27
+ // Required fields - will throw if missing
28
+ id: z.string().min(1, "Content ID is required"),
29
+ url: z.string().min(1, "Content URL is required"),
30
+ // Optional metadata - may not be present in API response
31
+ userId: z.string().optional(),
8
32
  title: z.string().nullable().optional(),
9
33
  description: z.string().nullable().optional(),
10
- contentType: z.enum(["youtube", "x_twitter", "reddit", "article", "pdf"]).optional().default("article"),
11
- status: z.enum(["pending", "processing", "completed", "failed"]).optional().default("completed"),
12
- summary: z.any().nullable().optional(), // Can be string or object
13
- keyInsights: z.array(z.string()).nullable().optional().default(null),
14
- rawText: z.string().nullable().optional(), // Full content text
15
- tokenCount: z.number().nullable().optional(), // Estimated token count for raw_text
34
+ // Fields with API-behavior defaults (API typically provides these)
35
+ contentType: ContentTypeEnum.optional().default("article"),
36
+ status: ContentStatusEnum.optional().default("pending"),
37
+ // Properly typed summary field
38
+ summary: SummarySchema,
39
+ keyInsights: z.array(z.string()).nullable().optional(),
40
+ // Content data
41
+ rawText: z.string().nullable().optional(),
42
+ tokenCount: z.number().nullable().optional(),
16
43
  ogImage: z.string().nullable().optional(),
17
- processingMetadata: z.any().nullable().optional(),
18
- tags: z.array(z.string()).optional().default([]), // Associated tags with default
19
- createdAt: z.string().optional().default(() => new Date().toISOString()),
20
- updatedAt: z.string().optional().default(() => new Date().toISOString()),
44
+ processingMetadata: ProcessingMetadataSchema,
45
+ // Tags default to empty array (API convention)
46
+ tags: z.array(z.string()).optional().default([]),
47
+ // Timestamps - optional, no fabrication if missing
48
+ createdAt: z.string().optional(),
49
+ updatedAt: z.string().optional(),
21
50
  });
22
51
  export const ActionSchema = z.object({
23
- id: z.string(),
24
- contentId: z.string().optional().default(""),
25
- goalId: z.string().nullable().optional().default(null),
26
- title: z.string(),
27
- description: z.string().nullable().optional().default(null),
28
- priority: z.enum(["high", "medium", "low"]).nullable().optional().default("medium"),
52
+ // Required fields
53
+ id: z.string().min(1, "Action ID is required"),
54
+ title: z.string().min(1, "Action title is required"),
55
+ // Optional fields - no data fabrication
56
+ contentId: z.string().optional(),
57
+ goalId: z.string().nullable().optional(),
58
+ description: z.string().nullable().optional(),
59
+ priority: z.enum(["high", "medium", "low"]).nullable().optional(),
29
60
  completed: z.boolean().optional().default(false),
30
- completedAt: z.string().nullable().optional().default(null),
31
- createdAt: z.string().optional().default(() => new Date().toISOString()),
61
+ completedAt: z.string().nullable().optional(),
62
+ createdAt: z.string().optional(),
32
63
  });
33
64
  export const GoalSchema = z.object({
34
65
  id: z.string(),
@@ -39,6 +70,90 @@ export const GoalSchema = z.object({
39
70
  isActive: z.boolean(),
40
71
  createdAt: z.string(),
41
72
  });
73
+ export const TagSchema = z.object({
74
+ id: z.string(),
75
+ name: z.string(),
76
+ slug: z.string(),
77
+ isSystem: z.boolean(),
78
+ description: z.string().nullable().optional(),
79
+ category: z.string().nullable().optional(),
80
+ usageCount: z.number().optional().default(0),
81
+ });
82
+ export const TagsResponseSchema = z.object({
83
+ success: z.boolean(),
84
+ tags: z.array(TagSchema),
85
+ grouped: z.object({
86
+ system: z.array(TagSchema),
87
+ custom: z.array(TagSchema),
88
+ }).optional(),
89
+ total: z.number(),
90
+ });
91
+ export const CreateTagResponseSchema = z.object({
92
+ success: z.boolean(),
93
+ tag: z.object({
94
+ id: z.string(),
95
+ name: z.string(),
96
+ slug: z.string(),
97
+ isSystem: z.boolean(),
98
+ isNew: z.boolean().optional(),
99
+ }),
100
+ message: z.string().optional(),
101
+ });
102
+ export const AddTagsResponseSchema = z.object({
103
+ success: z.boolean(),
104
+ contentId: z.string(),
105
+ addedTags: z.array(z.object({
106
+ id: z.string(),
107
+ name: z.string(),
108
+ slug: z.string(),
109
+ created: z.boolean(),
110
+ })),
111
+ errors: z.array(z.string()).optional(),
112
+ message: z.string().optional(),
113
+ });
114
+ export const RemoveTagsResponseSchema = z.object({
115
+ success: z.boolean(),
116
+ contentId: z.string(),
117
+ removedTags: z.array(z.string()),
118
+ errors: z.array(z.string()).optional(),
119
+ message: z.string().optional(),
120
+ });
121
+ // Swipe file response schemas
122
+ export const MarkSwipeFileResponseSchema = z.object({
123
+ success: z.boolean(),
124
+ contentId: z.string(),
125
+ contentTitle: z.string().optional(),
126
+ isSwipeFile: z.boolean(),
127
+ analysisTriggered: z.boolean().optional(),
128
+ analysisError: z.string().optional(),
129
+ tagsAdded: z.array(z.object({
130
+ name: z.string(),
131
+ confidence: z.number(),
132
+ reason: z.string(),
133
+ })).optional(),
134
+ totalTags: z.number().optional(),
135
+ message: z.string().optional(),
136
+ });
137
+ export const UnmarkSwipeFileResponseSchema = z.object({
138
+ success: z.boolean(),
139
+ contentId: z.string(),
140
+ contentTitle: z.string().optional(),
141
+ isSwipeFile: z.boolean(),
142
+ message: z.string().optional(),
143
+ });
144
+ export const SwipeFileStatusResponseSchema = z.object({
145
+ success: z.boolean(),
146
+ contentId: z.string(),
147
+ contentTitle: z.string().optional(),
148
+ isSwipeFile: z.boolean(),
149
+ swipeFileTags: z.array(z.object({
150
+ id: z.string(),
151
+ name: z.string(),
152
+ slug: z.string(),
153
+ confidenceScore: z.number().nullable(),
154
+ })).optional(),
155
+ totalSwipeFileTags: z.number().optional(),
156
+ });
42
157
  export class NoverloadClient {
43
158
  config;
44
159
  headers;
@@ -79,6 +194,43 @@ export class NoverloadClient {
79
194
  },
80
195
  });
81
196
  }
197
+ /**
198
+ * Transform raw API content to schema format
199
+ * Handles both camelCase and snake_case field names from API
200
+ * Required fields (id, url) are passed through - Zod validates them
201
+ */
202
+ transformRawContent(item) {
203
+ // Get required fields - let Zod validate they exist
204
+ const id = item.id ?? item._id;
205
+ const url = item.url;
206
+ if (!id || !url) {
207
+ throw new Error(`Invalid content from API: missing ${!id ? 'id' : 'url'}`);
208
+ }
209
+ return {
210
+ // Required fields
211
+ id,
212
+ url,
213
+ // Optional metadata - use undefined if missing, not empty string
214
+ userId: item.userId ?? item.user_id ?? undefined,
215
+ title: item.title ?? null,
216
+ description: item.description ?? null,
217
+ // Fields with defaults handled by schema
218
+ contentType: item.contentType ?? item.content_type ?? undefined,
219
+ status: item.status ?? undefined,
220
+ // Content fields
221
+ summary: item.summary ?? null,
222
+ keyInsights: item.keyInsights ?? item.key_insights ?? null,
223
+ rawText: item.rawText ?? item.raw_text ?? null,
224
+ tokenCount: item.tokenCount ?? item.token_count ?? null,
225
+ ogImage: item.ogImage ?? item.og_image ?? null,
226
+ processingMetadata: item.processingMetadata ?? item.processing_metadata ?? null,
227
+ // Tags
228
+ tags: item.tags ?? undefined,
229
+ // Timestamps - pass through as-is, no fabrication
230
+ createdAt: item.createdAt ?? item.created_at ?? undefined,
231
+ updatedAt: item.updatedAt ?? item.updated_at ?? undefined,
232
+ };
233
+ }
82
234
  // Content methods
83
235
  async listContent(filters) {
84
236
  const params = new URLSearchParams();
@@ -110,26 +262,12 @@ export class NoverloadClient {
110
262
  }
111
263
  const data = await response.json();
112
264
  // v2 returns { success, contents, pagination }
113
- const rawContents = data.contents || data;
114
- // Transform and validate each item with defaults for missing fields
115
- const transformedContents = Array.isArray(rawContents) ? rawContents.map((item) => ({
116
- id: item.id || item._id || "",
117
- userId: item.userId || item.user_id || "",
118
- url: item.url || "",
119
- title: item.title || null,
120
- description: item.description || null,
121
- contentType: item.contentType || item.content_type || "article",
122
- status: item.status || "completed",
123
- summary: item.summary || null,
124
- keyInsights: item.keyInsights || item.key_insights || null,
125
- rawText: item.rawText || item.raw_text || null,
126
- tokenCount: item.tokenCount || item.token_count || null,
127
- ogImage: item.ogImage || item.og_image || null,
128
- processingMetadata: item.processingMetadata || item.processing_metadata || null,
129
- tags: item.tags || [],
130
- createdAt: item.createdAt || item.created_at || new Date().toISOString(),
131
- updatedAt: item.updatedAt || item.updated_at || new Date().toISOString(),
132
- })) : [];
265
+ const rawContents = (data.contents ?? data);
266
+ if (!Array.isArray(rawContents)) {
267
+ throw new Error("Invalid API response: expected array of contents");
268
+ }
269
+ // Transform and validate each item
270
+ const transformedContents = rawContents.map((item) => this.transformRawContent(item));
133
271
  return z.array(ContentSchema).parse(transformedContents);
134
272
  }
135
273
  async getContent(id) {
@@ -149,33 +287,18 @@ export class NoverloadClient {
149
287
  }
150
288
  }
151
289
  catch {
152
- // If JSON parsing fails, use status text
153
290
  errorMessage = `${errorMessage} (HTTP ${response.status})`;
154
291
  }
155
292
  throw new Error(errorMessage);
156
293
  }
157
294
  const data = await response.json();
158
295
  // v2 returns { success, content }
159
- const rawContent = data.content || data;
160
- // Transform with defaults for missing fields
161
- const transformedContent = {
162
- id: rawContent.id || rawContent._id || "",
163
- userId: rawContent.userId || rawContent.user_id || "",
164
- url: rawContent.url || "",
165
- title: rawContent.title || null,
166
- description: rawContent.description || null,
167
- contentType: rawContent.contentType || rawContent.content_type || "article",
168
- status: rawContent.status || "completed",
169
- summary: rawContent.summary || null,
170
- keyInsights: rawContent.keyInsights || rawContent.key_insights || null,
171
- rawText: rawContent.rawText || rawContent.raw_text || null,
172
- tokenCount: rawContent.tokenCount || rawContent.token_count || null,
173
- ogImage: rawContent.ogImage || rawContent.og_image || null,
174
- processingMetadata: rawContent.processingMetadata || rawContent.processing_metadata || null,
175
- tags: rawContent.tags || [],
176
- createdAt: rawContent.createdAt || rawContent.created_at || new Date().toISOString(),
177
- updatedAt: rawContent.updatedAt || rawContent.updated_at || new Date().toISOString(),
178
- };
296
+ const rawContent = (data.content ?? data);
297
+ if (!rawContent || typeof rawContent !== 'object') {
298
+ throw new Error(`Invalid API response for content ID: ${id}`);
299
+ }
300
+ // Transform and validate
301
+ const transformedContent = this.transformRawContent(rawContent);
179
302
  return ContentSchema.parse(transformedContent);
180
303
  }
181
304
  async saveContent(url) {
@@ -209,6 +332,28 @@ export class NoverloadClient {
209
332
  const data = await response.json();
210
333
  return ContentSchema.parse(data);
211
334
  }
335
+ /**
336
+ * Transform raw API action to schema format
337
+ * Handles both camelCase and snake_case field names from API
338
+ */
339
+ transformRawAction(item) {
340
+ const id = item.id;
341
+ const title = item.title;
342
+ if (!id || !title) {
343
+ throw new Error(`Invalid action from API: missing ${!id ? 'id' : 'title'}`);
344
+ }
345
+ return {
346
+ id,
347
+ title,
348
+ contentId: item.contentId ?? item.content_id ?? undefined,
349
+ goalId: item.goalId ?? item.goal_id ?? null,
350
+ description: item.description ?? null,
351
+ priority: item.priority ?? undefined,
352
+ completed: item.completed ?? item.is_completed ?? false,
353
+ completedAt: item.completedAt ?? item.completed_at ?? null,
354
+ createdAt: item.createdAt ?? item.created_at ?? undefined,
355
+ };
356
+ }
212
357
  // Action methods
213
358
  async listActions(filters) {
214
359
  const params = new URLSearchParams();
@@ -224,19 +369,12 @@ export class NoverloadClient {
224
369
  throw new Error("Failed to fetch actions");
225
370
  const data = await response.json();
226
371
  // v2 returns { success, actions, pagination, statistics }
227
- const rawActions = data.actions || data;
228
- // Transform snake_case to camelCase and handle missing fields
229
- const transformedActions = Array.isArray(rawActions) ? rawActions.map((item) => ({
230
- id: item.id || "",
231
- contentId: item.contentId || item.content_id || "",
232
- goalId: item.goalId || item.goal_id || null,
233
- title: item.title || "Untitled Action",
234
- description: item.description || null,
235
- priority: item.priority || "medium",
236
- completed: item.completed ?? item.is_completed ?? false,
237
- completedAt: item.completedAt || item.completed_at || null,
238
- createdAt: item.createdAt || item.created_at || new Date().toISOString(),
239
- })) : [];
372
+ const rawActions = (data.actions ?? data);
373
+ if (!Array.isArray(rawActions)) {
374
+ throw new Error("Invalid API response: expected array of actions");
375
+ }
376
+ // Transform and validate each item
377
+ const transformedActions = rawActions.map((item) => this.transformRawAction(item));
240
378
  return z.array(ActionSchema).parse(transformedActions);
241
379
  }
242
380
  async completeAction(id) {
@@ -319,25 +457,15 @@ export class NoverloadClient {
319
457
  // v2 returns { success, query, results, pagination, metadata }
320
458
  const results = data?.results || [];
321
459
  if (Array.isArray(results) && results.length > 0) {
322
- return results.map((item) => ({
323
- id: item.id || item._id || "",
324
- userId: item.userId || item.user_id || "",
325
- url: item.url || "",
326
- title: item.title || "Untitled",
327
- description: item.description || (typeof item.summary === 'string' ? item.summary.slice(0, 500) : ""),
328
- contentType: item.contentType || item.content_type || "article",
329
- status: item.status || item.metadata?.processingStatus || "completed",
330
- summary: item.summary || null,
331
- keyInsights: item.keyInsights || item.key_insights || [],
332
- rawText: item.rawText || item.raw_text || item.fullContent || null,
333
- tokenCount: item.tokenCount || item.token_count || null,
334
- ogImage: item.ogImage || item.og_image || null,
335
- processingMetadata: item.processingMetadata || item.processing_metadata || null,
336
- tags: item.tags || [],
337
- createdAt: item.createdAt || item.created_at || item.metadata?.createdAt || new Date().toISOString(),
338
- updatedAt: item.updatedAt || item.updated_at || item.metadata?.updatedAt || new Date().toISOString(),
339
- relevanceScore: item.relevanceScore || item.score || 0,
340
- }));
460
+ return results.map((item) => {
461
+ // Transform content fields using helper, but preserve search-specific fields
462
+ const baseContent = this.transformRawContent(item);
463
+ return {
464
+ ...baseContent,
465
+ // Search-specific fields
466
+ relevanceScore: (item.relevanceScore ?? item.score ?? 0),
467
+ };
468
+ });
341
469
  }
342
470
  // If no results, try a fallback search with looser parameters
343
471
  if (results.length === 0 && !options?.includeFullContent) {
@@ -371,25 +499,8 @@ export class NoverloadClient {
371
499
  return [];
372
500
  }
373
501
  const data = await response.json();
374
- const results = Array.isArray(data) ? data : (data.results || []);
375
- return results.map((item) => ({
376
- id: item.id || item._id || "",
377
- userId: item.userId || item.user_id || "",
378
- url: item.url || "",
379
- title: item.title || "Untitled",
380
- description: item.description || "",
381
- contentType: item.contentType || item.content_type || "article",
382
- status: item.status || "completed",
383
- summary: item.summary || null,
384
- keyInsights: item.keyInsights || item.key_insights || [],
385
- rawText: item.rawText || item.raw_text || null,
386
- tokenCount: item.tokenCount || item.token_count || null,
387
- ogImage: item.ogImage || item.og_image || null,
388
- processingMetadata: item.processingMetadata || item.processing_metadata || null,
389
- tags: item.tags || [],
390
- createdAt: item.createdAt || item.created_at || new Date().toISOString(),
391
- updatedAt: item.updatedAt || item.updated_at || new Date().toISOString(),
392
- }));
502
+ const results = Array.isArray(data) ? data : (data.results ?? []);
503
+ return results.map((item) => this.transformRawContent(item));
393
504
  }
394
505
  catch (error) {
395
506
  console.error("v1 search error:", error);
@@ -664,5 +775,187 @@ export class NoverloadClient {
664
775
  return [];
665
776
  }
666
777
  }
778
+ // Tag methods
779
+ async listTags() {
780
+ const response = await this.request("/api/mcp/tags");
781
+ if (!response.ok) {
782
+ let errorMessage = "Failed to fetch tags";
783
+ try {
784
+ const errorData = await response.json();
785
+ if (errorData.message)
786
+ errorMessage = errorData.message;
787
+ else if (errorData.error)
788
+ errorMessage = errorData.error;
789
+ }
790
+ catch {
791
+ errorMessage = `${errorMessage} (HTTP ${response.status})`;
792
+ }
793
+ throw new Error(errorMessage);
794
+ }
795
+ const data = await response.json();
796
+ return TagsResponseSchema.parse(data);
797
+ }
798
+ async createTag(name) {
799
+ if (this.config.readOnly) {
800
+ throw new Error("Cannot create tag in read-only mode");
801
+ }
802
+ const response = await this.request("/api/mcp/tags", {
803
+ method: "POST",
804
+ body: JSON.stringify({ name }),
805
+ });
806
+ if (!response.ok) {
807
+ let errorMessage = `Failed to create tag: ${name}`;
808
+ try {
809
+ const errorData = await response.json();
810
+ if (errorData.message)
811
+ errorMessage = errorData.message;
812
+ else if (errorData.error)
813
+ errorMessage = errorData.error;
814
+ }
815
+ catch {
816
+ errorMessage = `${errorMessage} (HTTP ${response.status})`;
817
+ }
818
+ throw new Error(errorMessage);
819
+ }
820
+ const data = await response.json();
821
+ return CreateTagResponseSchema.parse(data);
822
+ }
823
+ async addTagsToContent(contentId, tags) {
824
+ if (this.config.readOnly) {
825
+ throw new Error("Cannot add tags in read-only mode");
826
+ }
827
+ const response = await this.request(`/api/mcp/content/${contentId}/tags`, {
828
+ method: "POST",
829
+ body: JSON.stringify({ tags }),
830
+ });
831
+ if (!response.ok) {
832
+ let errorMessage = "Failed to add tags to content";
833
+ try {
834
+ const errorData = await response.json();
835
+ if (errorData.message)
836
+ errorMessage = errorData.message;
837
+ else if (errorData.error)
838
+ errorMessage = errorData.error;
839
+ }
840
+ catch {
841
+ errorMessage = `${errorMessage} (HTTP ${response.status})`;
842
+ }
843
+ throw new Error(errorMessage);
844
+ }
845
+ const data = await response.json();
846
+ return AddTagsResponseSchema.parse(data);
847
+ }
848
+ async removeTagsFromContent(contentId, tags) {
849
+ if (this.config.readOnly) {
850
+ throw new Error("Cannot remove tags in read-only mode");
851
+ }
852
+ const response = await this.request(`/api/mcp/content/${contentId}/tags`, {
853
+ method: "DELETE",
854
+ body: JSON.stringify({ tags }),
855
+ });
856
+ if (!response.ok) {
857
+ let errorMessage = "Failed to remove tags from content";
858
+ try {
859
+ const errorData = await response.json();
860
+ if (errorData.message)
861
+ errorMessage = errorData.message;
862
+ else if (errorData.error)
863
+ errorMessage = errorData.error;
864
+ }
865
+ catch {
866
+ errorMessage = `${errorMessage} (HTTP ${response.status})`;
867
+ }
868
+ throw new Error(errorMessage);
869
+ }
870
+ const data = await response.json();
871
+ return RemoveTagsResponseSchema.parse(data);
872
+ }
873
+ async getContentTags(contentId) {
874
+ const response = await this.request(`/api/mcp/content/${contentId}/tags`);
875
+ if (!response.ok) {
876
+ let errorMessage = "Failed to get content tags";
877
+ try {
878
+ const errorData = await response.json();
879
+ if (errorData.message)
880
+ errorMessage = errorData.message;
881
+ else if (errorData.error)
882
+ errorMessage = errorData.error;
883
+ }
884
+ catch {
885
+ errorMessage = `${errorMessage} (HTTP ${response.status})`;
886
+ }
887
+ throw new Error(errorMessage);
888
+ }
889
+ const data = await response.json();
890
+ return z.array(TagSchema).parse(data.tags || []);
891
+ }
892
+ // Swipe file methods
893
+ async markAsSwipeFile(contentId) {
894
+ if (this.config.readOnly) {
895
+ throw new Error("Cannot mark as swipe file in read-only mode");
896
+ }
897
+ const response = await this.request(`/api/mcp/content/${contentId}/swipe-file`, {
898
+ method: "POST",
899
+ });
900
+ if (!response.ok) {
901
+ let errorMessage = "Failed to mark as swipe file";
902
+ try {
903
+ const errorData = await response.json();
904
+ if (errorData.message)
905
+ errorMessage = errorData.message;
906
+ else if (errorData.error)
907
+ errorMessage = errorData.error;
908
+ }
909
+ catch {
910
+ errorMessage = `${errorMessage} (HTTP ${response.status})`;
911
+ }
912
+ throw new Error(errorMessage);
913
+ }
914
+ const data = await response.json();
915
+ return MarkSwipeFileResponseSchema.parse(data);
916
+ }
917
+ async unmarkAsSwipeFile(contentId) {
918
+ if (this.config.readOnly) {
919
+ throw new Error("Cannot unmark swipe file in read-only mode");
920
+ }
921
+ const response = await this.request(`/api/mcp/content/${contentId}/swipe-file`, {
922
+ method: "DELETE",
923
+ });
924
+ if (!response.ok) {
925
+ let errorMessage = "Failed to unmark swipe file";
926
+ try {
927
+ const errorData = await response.json();
928
+ if (errorData.message)
929
+ errorMessage = errorData.message;
930
+ else if (errorData.error)
931
+ errorMessage = errorData.error;
932
+ }
933
+ catch {
934
+ errorMessage = `${errorMessage} (HTTP ${response.status})`;
935
+ }
936
+ throw new Error(errorMessage);
937
+ }
938
+ const data = await response.json();
939
+ return UnmarkSwipeFileResponseSchema.parse(data);
940
+ }
941
+ async getSwipeFileStatus(contentId) {
942
+ const response = await this.request(`/api/mcp/content/${contentId}/swipe-file`);
943
+ if (!response.ok) {
944
+ let errorMessage = "Failed to get swipe file status";
945
+ try {
946
+ const errorData = await response.json();
947
+ if (errorData.message)
948
+ errorMessage = errorData.message;
949
+ else if (errorData.error)
950
+ errorMessage = errorData.error;
951
+ }
952
+ catch {
953
+ errorMessage = `${errorMessage} (HTTP ${response.status})`;
954
+ }
955
+ throw new Error(errorMessage);
956
+ }
957
+ const data = await response.json();
958
+ return SwipeFileStatusResponseSchema.parse(data);
959
+ }
667
960
  }
668
961
  //# sourceMappingURL=client.js.map