@sellable/mcp 0.1.219 → 0.1.221

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.
@@ -137,6 +137,51 @@ export const linkedinToolDefinitions = [
137
137
  },
138
138
  },
139
139
  ];
140
+ function normalizePostDate(post) {
141
+ if (post.activityDate)
142
+ return post.activityDate;
143
+ if (typeof post.postedAt === "string")
144
+ return post.postedAt;
145
+ if (post.postedAt?.date)
146
+ return post.postedAt.date;
147
+ if (typeof post.postedAt?.timestamp === "number") {
148
+ return new Date(post.postedAt.timestamp).toISOString();
149
+ }
150
+ return "";
151
+ }
152
+ function normalizePostUrl(post) {
153
+ return (post.activityUrl ||
154
+ post.linkedinUrl ||
155
+ post.shareLinkedinUrl ||
156
+ post.socialContent?.shareUrl ||
157
+ post.header?.linkedinUrl ||
158
+ "");
159
+ }
160
+ function serializeLinkedInPost(post) {
161
+ return {
162
+ text: post.text || post.content || "",
163
+ date: normalizePostDate(post),
164
+ reactions: post.reactionsCount ?? post.engagement?.likes ?? 0,
165
+ comments: post.commentsCount ?? post.engagement?.comments ?? 0,
166
+ url: normalizePostUrl(post),
167
+ isRepost: Boolean(post.isRepublishedPost || post.repostedBy || post.repostedAt),
168
+ };
169
+ }
170
+ function isUsableSerializedPost(post) {
171
+ return Boolean(post.text.trim() ||
172
+ post.date ||
173
+ post.url ||
174
+ post.reactions > 0 ||
175
+ post.comments > 0);
176
+ }
177
+ export function serializeLinkedInPosts(rawPosts, context) {
178
+ const raw = rawPosts || [];
179
+ const posts = raw.map(serializeLinkedInPost).filter(isUsableSerializedPost);
180
+ if (raw.length > 0 && posts.length === 0) {
181
+ throw new Error(`${context} returned ${raw.length} post placeholder row(s), but none contained usable text, date, URL, or engagement data.`);
182
+ }
183
+ return posts;
184
+ }
140
185
  export async function fetchLinkedInPosts(linkedinUrl, limit = 25) {
141
186
  const api = getApi();
142
187
  const normalizedLinkedinUrl = normalizeLinkedInProfileInput(linkedinUrl);
@@ -145,15 +190,7 @@ export async function fetchLinkedInPosts(linkedinUrl, limit = 25) {
145
190
  limit: String(limit),
146
191
  });
147
192
  const response = await api.get(`/api/v1/scrape/linkedin/user-posts?${params.toString()}`);
148
- // Serialize to compact format: just text and key metadata
149
- const posts = (response.posts || []).map((post) => ({
150
- text: post.text || "",
151
- date: post.activityDate || "",
152
- reactions: post.reactionsCount || 0,
153
- comments: post.commentsCount || 0,
154
- url: post.activityUrl || "",
155
- isRepost: post.isRepublishedPost || false,
156
- }));
193
+ const posts = serializeLinkedInPosts(response.posts, "LinkedIn user posts fetch");
157
194
  return {
158
195
  posts,
159
196
  count: posts.length,
@@ -198,14 +235,7 @@ export async function fetchCompanyPosts(companyUrl, limit = 25, sortBy = "recent
198
235
  sortBy,
199
236
  });
200
237
  const response = await api.get(`/api/v1/scrape/linkedin/company-posts?${params.toString()}`);
201
- const posts = (response.posts || []).map((post) => ({
202
- text: post.text || "",
203
- date: post.activityDate || "",
204
- reactions: post.reactionsCount || 0,
205
- comments: post.commentsCount || 0,
206
- url: post.activityUrl || "",
207
- isRepost: post.isRepublishedPost || false,
208
- }));
238
+ const posts = serializeLinkedInPosts(response.posts, "LinkedIn company posts fetch");
209
239
  return {
210
240
  posts,
211
241
  count: posts.length,