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.
- package/dist/client.d.ts +588 -30
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +408 -115
- package/dist/client.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/resources/index.d.ts +6 -1
- package/dist/resources/index.d.ts.map +1 -1
- package/dist/tools/implementations/explore-topic.d.ts.map +1 -1
- package/dist/tools/implementations/explore-topic.js +41 -22
- package/dist/tools/implementations/explore-topic.js.map +1 -1
- package/dist/tools/implementations/extract-frameworks.d.ts.map +1 -1
- package/dist/tools/implementations/extract-frameworks.js +91 -29
- package/dist/tools/implementations/extract-frameworks.js.map +1 -1
- package/dist/tools/implementations/get-content.d.ts.map +1 -1
- package/dist/tools/implementations/get-content.js +3 -1
- package/dist/tools/implementations/get-content.js.map +1 -1
- package/dist/tools/implementations/list-content.d.ts.map +1 -1
- package/dist/tools/implementations/list-content.js +3 -1
- package/dist/tools/implementations/list-content.js.map +1 -1
- package/dist/tools/implementations/list-tags.d.ts +3 -0
- package/dist/tools/implementations/list-tags.d.ts.map +1 -0
- package/dist/tools/implementations/list-tags.js +115 -0
- package/dist/tools/implementations/list-tags.js.map +1 -0
- package/dist/tools/implementations/manage-tags.d.ts +5 -0
- package/dist/tools/implementations/manage-tags.d.ts.map +1 -0
- package/dist/tools/implementations/manage-tags.js +157 -0
- package/dist/tools/implementations/manage-tags.js.map +1 -0
- package/dist/tools/implementations/save-content.d.ts.map +1 -1
- package/dist/tools/implementations/save-content.js +43 -4
- package/dist/tools/implementations/save-content.js.map +1 -1
- package/dist/tools/implementations/swipe-file.d.ts +4 -0
- package/dist/tools/implementations/swipe-file.d.ts.map +1 -0
- package/dist/tools/implementations/swipe-file.js +82 -0
- package/dist/tools/implementations/swipe-file.js.map +1 -0
- package/dist/tools/index.d.ts +4 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +15 -3
- package/dist/tools/index.js.map +1 -1
- package/package.json +1 -1
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;CACnB;
|
|
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
|
-
//
|
|
3
|
-
|
|
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
|
-
|
|
6
|
-
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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()
|
|
31
|
-
createdAt: z.string().optional()
|
|
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
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
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
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
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
|