@jam-nodes/nodes 0.1.2 → 0.2.0
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/ai/analyze-posts.d.ts +175 -0
- package/dist/ai/analyze-posts.d.ts.map +1 -0
- package/dist/ai/analyze-posts.js +172 -0
- package/dist/ai/analyze-posts.js.map +1 -0
- package/dist/ai/draft-emails.d.ts +45 -0
- package/dist/ai/draft-emails.d.ts.map +1 -0
- package/dist/ai/draft-emails.js +134 -0
- package/dist/ai/draft-emails.js.map +1 -0
- package/dist/ai/index.d.ts +4 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +4 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/keyword-generator.d.ts +37 -0
- package/dist/ai/keyword-generator.d.ts.map +1 -0
- package/dist/ai/keyword-generator.js +124 -0
- package/dist/ai/keyword-generator.js.map +1 -0
- package/dist/index.d.ts +323 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -1
- package/dist/integrations/apollo/index.d.ts +2 -0
- package/dist/integrations/apollo/index.d.ts.map +1 -0
- package/dist/integrations/apollo/index.js +2 -0
- package/dist/integrations/apollo/index.js.map +1 -0
- package/dist/integrations/apollo/search-contacts.d.ts +158 -0
- package/dist/integrations/apollo/search-contacts.d.ts.map +1 -0
- package/dist/integrations/apollo/search-contacts.js +161 -0
- package/dist/integrations/apollo/search-contacts.js.map +1 -0
- package/dist/integrations/dataforseo/index.d.ts +3 -0
- package/dist/integrations/dataforseo/index.d.ts.map +1 -0
- package/dist/integrations/dataforseo/index.js +3 -0
- package/dist/integrations/dataforseo/index.js.map +1 -0
- package/dist/integrations/dataforseo/keyword-research.d.ts +96 -0
- package/dist/integrations/dataforseo/keyword-research.d.ts.map +1 -0
- package/dist/integrations/dataforseo/keyword-research.js +115 -0
- package/dist/integrations/dataforseo/keyword-research.js.map +1 -0
- package/dist/integrations/dataforseo/seo-audit.d.ts +257 -0
- package/dist/integrations/dataforseo/seo-audit.d.ts.map +1 -0
- package/dist/integrations/dataforseo/seo-audit.js +266 -0
- package/dist/integrations/dataforseo/seo-audit.js.map +1 -0
- package/dist/integrations/index.d.ts +5 -0
- package/dist/integrations/index.d.ts.map +1 -0
- package/dist/integrations/index.js +9 -0
- package/dist/integrations/index.js.map +1 -0
- package/dist/integrations/openai/index.d.ts +2 -0
- package/dist/integrations/openai/index.d.ts.map +1 -0
- package/dist/integrations/openai/index.js +2 -0
- package/dist/integrations/openai/index.js.map +1 -0
- package/dist/integrations/openai/sora-video.d.ts +89 -0
- package/dist/integrations/openai/sora-video.d.ts.map +1 -0
- package/dist/integrations/openai/sora-video.js +93 -0
- package/dist/integrations/openai/sora-video.js.map +1 -0
- package/dist/integrations/social/index.d.ts +4 -0
- package/dist/integrations/social/index.d.ts.map +1 -0
- package/dist/integrations/social/index.js +4 -0
- package/dist/integrations/social/index.js.map +1 -0
- package/dist/integrations/social/linkedin-monitor.d.ts +166 -0
- package/dist/integrations/social/linkedin-monitor.d.ts.map +1 -0
- package/dist/integrations/social/linkedin-monitor.js +167 -0
- package/dist/integrations/social/linkedin-monitor.js.map +1 -0
- package/dist/integrations/social/reddit-monitor.d.ts +177 -0
- package/dist/integrations/social/reddit-monitor.d.ts.map +1 -0
- package/dist/integrations/social/reddit-monitor.js +162 -0
- package/dist/integrations/social/reddit-monitor.js.map +1 -0
- package/dist/integrations/social/twitter-monitor.d.ts +186 -0
- package/dist/integrations/social/twitter-monitor.d.ts.map +1 -0
- package/dist/integrations/social/twitter-monitor.js +174 -0
- package/dist/integrations/social/twitter-monitor.js.map +1 -0
- package/dist/prompts/analyze-posts.d.ts +31 -0
- package/dist/prompts/analyze-posts.d.ts.map +1 -0
- package/dist/prompts/analyze-posts.js +87 -0
- package/dist/prompts/analyze-posts.js.map +1 -0
- package/dist/prompts/draft-emails.d.ts +19 -0
- package/dist/prompts/draft-emails.d.ts.map +1 -0
- package/dist/prompts/draft-emails.js +117 -0
- package/dist/prompts/draft-emails.js.map +1 -0
- package/dist/prompts/index.d.ts +4 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +7 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/keyword-generator.d.ts +17 -0
- package/dist/prompts/keyword-generator.d.ts.map +1 -0
- package/dist/prompts/keyword-generator.js +61 -0
- package/dist/prompts/keyword-generator.js.map +1 -0
- package/dist/schemas/ai.d.ts +1212 -0
- package/dist/schemas/ai.d.ts.map +1 -0
- package/dist/schemas/ai.js +119 -0
- package/dist/schemas/ai.js.map +1 -0
- package/dist/schemas/index.d.ts +2 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +9 -0
- package/dist/schemas/index.js.map +1 -0
- package/package.json +14 -6
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { defineNode } from '@jam-nodes/core';
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// Schemas
|
|
5
|
+
// =============================================================================
|
|
6
|
+
export const RedditMonitorInputSchema = z.object({
|
|
7
|
+
/** Keywords to search for */
|
|
8
|
+
keywords: z.array(z.string()),
|
|
9
|
+
/** Time filter for search results */
|
|
10
|
+
timeFilter: z.enum(['hour', 'day', 'week', 'month', 'year', 'all']).optional().default('day'),
|
|
11
|
+
/** Sort order for results */
|
|
12
|
+
sortBy: z.enum(['relevance', 'hot', 'top', 'new', 'comments']).optional().default('new'),
|
|
13
|
+
/** Maximum number of results to return */
|
|
14
|
+
maxResults: z.number().optional().default(50),
|
|
15
|
+
});
|
|
16
|
+
export const RedditMonitorOutputSchema = z.object({
|
|
17
|
+
posts: z.array(z.object({
|
|
18
|
+
id: z.string(),
|
|
19
|
+
platform: z.literal('reddit'),
|
|
20
|
+
url: z.string(),
|
|
21
|
+
text: z.string(),
|
|
22
|
+
title: z.string(),
|
|
23
|
+
authorName: z.string(),
|
|
24
|
+
authorHandle: z.string(),
|
|
25
|
+
authorUrl: z.string(),
|
|
26
|
+
subreddit: z.string(),
|
|
27
|
+
engagement: z.object({
|
|
28
|
+
likes: z.number(),
|
|
29
|
+
comments: z.number(),
|
|
30
|
+
shares: z.number(),
|
|
31
|
+
}),
|
|
32
|
+
upvoteRatio: z.number(),
|
|
33
|
+
postedAt: z.string(),
|
|
34
|
+
})),
|
|
35
|
+
totalFound: z.number(),
|
|
36
|
+
subredditsSearched: z.array(z.string()),
|
|
37
|
+
});
|
|
38
|
+
// =============================================================================
|
|
39
|
+
// Reddit API Helper
|
|
40
|
+
// =============================================================================
|
|
41
|
+
/**
|
|
42
|
+
* Search Reddit using the public search.json endpoint.
|
|
43
|
+
* No authentication required.
|
|
44
|
+
*/
|
|
45
|
+
async function searchReddit(query, options = {}) {
|
|
46
|
+
const { sort = 'new', time = 'day', limit = 50 } = options;
|
|
47
|
+
const params = new URLSearchParams({
|
|
48
|
+
q: query,
|
|
49
|
+
type: 'link',
|
|
50
|
+
sort,
|
|
51
|
+
t: time,
|
|
52
|
+
limit: String(Math.min(limit, 100)),
|
|
53
|
+
restrict_sr: 'off',
|
|
54
|
+
});
|
|
55
|
+
const url = `https://www.reddit.com/search.json?${params.toString()}`;
|
|
56
|
+
const response = await fetch(url, {
|
|
57
|
+
headers: {
|
|
58
|
+
'User-Agent': 'Mozilla/5.0 (compatible; JamNodes/1.0)',
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
if (!response.ok) {
|
|
62
|
+
throw new Error(`Reddit API error: ${response.status} ${response.statusText}`);
|
|
63
|
+
}
|
|
64
|
+
return response.json();
|
|
65
|
+
}
|
|
66
|
+
// =============================================================================
|
|
67
|
+
// Node Definition
|
|
68
|
+
// =============================================================================
|
|
69
|
+
/**
|
|
70
|
+
* Reddit Monitor Node
|
|
71
|
+
*
|
|
72
|
+
* Searches Reddit for posts matching keywords using the public search.json API.
|
|
73
|
+
* No authentication required - uses public Reddit API.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* const result = await redditMonitorNode.executor({
|
|
78
|
+
* keywords: ['typescript', 'nodejs'],
|
|
79
|
+
* timeFilter: 'week',
|
|
80
|
+
* maxResults: 25
|
|
81
|
+
* }, context);
|
|
82
|
+
* // Returns: { posts: [...], totalFound: 25, subredditsSearched: ['all'] }
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export const redditMonitorNode = defineNode({
|
|
86
|
+
type: 'reddit_monitor',
|
|
87
|
+
name: 'Reddit Monitor',
|
|
88
|
+
description: 'Search Reddit for posts matching keywords across all subreddits',
|
|
89
|
+
category: 'integration',
|
|
90
|
+
inputSchema: RedditMonitorInputSchema,
|
|
91
|
+
outputSchema: RedditMonitorOutputSchema,
|
|
92
|
+
estimatedDuration: 20,
|
|
93
|
+
capabilities: {
|
|
94
|
+
supportsRerun: true,
|
|
95
|
+
},
|
|
96
|
+
executor: async (input, context) => {
|
|
97
|
+
try {
|
|
98
|
+
const allPosts = [];
|
|
99
|
+
// Build search query with proper quoting for multi-word keywords
|
|
100
|
+
const query = input.keywords
|
|
101
|
+
.map((k) => (k.includes(' ') ? `"${k}"` : k))
|
|
102
|
+
.join(' OR ');
|
|
103
|
+
const maxResults = Math.min(input.maxResults || 50, 100);
|
|
104
|
+
// Search Reddit
|
|
105
|
+
const response = await searchReddit(query, {
|
|
106
|
+
sort: input.sortBy || 'new',
|
|
107
|
+
time: input.timeFilter || 'day',
|
|
108
|
+
limit: maxResults,
|
|
109
|
+
});
|
|
110
|
+
// Transform to unified format
|
|
111
|
+
for (const post of response.data.children) {
|
|
112
|
+
const submission = post.data;
|
|
113
|
+
allPosts.push({
|
|
114
|
+
id: submission.id,
|
|
115
|
+
platform: 'reddit',
|
|
116
|
+
url: `https://reddit.com${submission.permalink}`,
|
|
117
|
+
text: submission.selftext || '',
|
|
118
|
+
title: submission.title,
|
|
119
|
+
authorName: submission.author || '[deleted]',
|
|
120
|
+
authorHandle: submission.author || '[deleted]',
|
|
121
|
+
authorUrl: submission.author && submission.author !== '[deleted]'
|
|
122
|
+
? `https://reddit.com/u/${submission.author}`
|
|
123
|
+
: '',
|
|
124
|
+
subreddit: submission.subreddit,
|
|
125
|
+
engagement: {
|
|
126
|
+
likes: submission.score,
|
|
127
|
+
comments: submission.num_comments,
|
|
128
|
+
shares: submission.num_crossposts || 0,
|
|
129
|
+
},
|
|
130
|
+
upvoteRatio: submission.upvote_ratio,
|
|
131
|
+
postedAt: new Date(submission.created_utc * 1000).toISOString(),
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
// Sort by recency
|
|
135
|
+
allPosts.sort((a, b) => new Date(b.postedAt).getTime() - new Date(a.postedAt).getTime());
|
|
136
|
+
// Optional: send notification if service available
|
|
137
|
+
if (context.services?.notifications && allPosts.length > 0) {
|
|
138
|
+
await context.services.notifications.send({
|
|
139
|
+
userId: context.userId,
|
|
140
|
+
title: 'Reddit Monitor Complete',
|
|
141
|
+
message: `Found ${allPosts.length} Reddit posts`,
|
|
142
|
+
data: { posts: allPosts.slice(0, 5) },
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
success: true,
|
|
147
|
+
output: {
|
|
148
|
+
posts: allPosts,
|
|
149
|
+
totalFound: allPosts.length,
|
|
150
|
+
subredditsSearched: ['all'],
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
return {
|
|
156
|
+
success: false,
|
|
157
|
+
error: error instanceof Error ? error.message : 'Failed to monitor Reddit',
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
//# sourceMappingURL=reddit-monitor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reddit-monitor.js","sourceRoot":"","sources":["../../../src/integrations/social/reddit-monitor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Twitter/X post in unified social format
|
|
4
|
+
*/
|
|
5
|
+
export interface TwitterPost {
|
|
6
|
+
id: string;
|
|
7
|
+
platform: 'twitter';
|
|
8
|
+
url: string;
|
|
9
|
+
text: string;
|
|
10
|
+
authorName: string;
|
|
11
|
+
authorHandle: string;
|
|
12
|
+
authorUrl: string;
|
|
13
|
+
authorFollowers: number;
|
|
14
|
+
engagement: {
|
|
15
|
+
likes: number;
|
|
16
|
+
comments: number;
|
|
17
|
+
shares: number;
|
|
18
|
+
views: number;
|
|
19
|
+
};
|
|
20
|
+
postedAt: string;
|
|
21
|
+
}
|
|
22
|
+
export declare const TwitterMonitorInputSchema: z.ZodObject<{
|
|
23
|
+
/** Keywords to search for */
|
|
24
|
+
keywords: z.ZodArray<z.ZodString, "many">;
|
|
25
|
+
/** Exclude retweets from results */
|
|
26
|
+
excludeRetweets: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
27
|
+
/** Minimum likes filter */
|
|
28
|
+
minLikes: z.ZodOptional<z.ZodNumber>;
|
|
29
|
+
/** Maximum number of results */
|
|
30
|
+
maxResults: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
31
|
+
/** Language filter (e.g., 'en') */
|
|
32
|
+
lang: z.ZodOptional<z.ZodString>;
|
|
33
|
+
/** Search tweets from last N days */
|
|
34
|
+
sinceDays: z.ZodOptional<z.ZodNumber>;
|
|
35
|
+
}, "strip", z.ZodTypeAny, {
|
|
36
|
+
keywords: string[];
|
|
37
|
+
maxResults: number;
|
|
38
|
+
excludeRetweets: boolean;
|
|
39
|
+
minLikes?: number | undefined;
|
|
40
|
+
lang?: string | undefined;
|
|
41
|
+
sinceDays?: number | undefined;
|
|
42
|
+
}, {
|
|
43
|
+
keywords: string[];
|
|
44
|
+
maxResults?: number | undefined;
|
|
45
|
+
excludeRetweets?: boolean | undefined;
|
|
46
|
+
minLikes?: number | undefined;
|
|
47
|
+
lang?: string | undefined;
|
|
48
|
+
sinceDays?: number | undefined;
|
|
49
|
+
}>;
|
|
50
|
+
export type TwitterMonitorInput = z.infer<typeof TwitterMonitorInputSchema>;
|
|
51
|
+
export declare const TwitterMonitorOutputSchema: z.ZodObject<{
|
|
52
|
+
posts: z.ZodArray<z.ZodObject<{
|
|
53
|
+
id: z.ZodString;
|
|
54
|
+
platform: z.ZodLiteral<"twitter">;
|
|
55
|
+
url: z.ZodString;
|
|
56
|
+
text: z.ZodString;
|
|
57
|
+
authorName: z.ZodString;
|
|
58
|
+
authorHandle: z.ZodString;
|
|
59
|
+
authorUrl: z.ZodString;
|
|
60
|
+
authorFollowers: z.ZodNumber;
|
|
61
|
+
engagement: z.ZodObject<{
|
|
62
|
+
likes: z.ZodNumber;
|
|
63
|
+
comments: z.ZodNumber;
|
|
64
|
+
shares: z.ZodNumber;
|
|
65
|
+
views: z.ZodNumber;
|
|
66
|
+
}, "strip", z.ZodTypeAny, {
|
|
67
|
+
comments: number;
|
|
68
|
+
likes: number;
|
|
69
|
+
shares: number;
|
|
70
|
+
views: number;
|
|
71
|
+
}, {
|
|
72
|
+
comments: number;
|
|
73
|
+
likes: number;
|
|
74
|
+
shares: number;
|
|
75
|
+
views: number;
|
|
76
|
+
}>;
|
|
77
|
+
postedAt: z.ZodString;
|
|
78
|
+
}, "strip", z.ZodTypeAny, {
|
|
79
|
+
url: string;
|
|
80
|
+
id: string;
|
|
81
|
+
platform: "twitter";
|
|
82
|
+
text: string;
|
|
83
|
+
authorName: string;
|
|
84
|
+
authorHandle: string;
|
|
85
|
+
authorUrl: string;
|
|
86
|
+
engagement: {
|
|
87
|
+
comments: number;
|
|
88
|
+
likes: number;
|
|
89
|
+
shares: number;
|
|
90
|
+
views: number;
|
|
91
|
+
};
|
|
92
|
+
postedAt: string;
|
|
93
|
+
authorFollowers: number;
|
|
94
|
+
}, {
|
|
95
|
+
url: string;
|
|
96
|
+
id: string;
|
|
97
|
+
platform: "twitter";
|
|
98
|
+
text: string;
|
|
99
|
+
authorName: string;
|
|
100
|
+
authorHandle: string;
|
|
101
|
+
authorUrl: string;
|
|
102
|
+
engagement: {
|
|
103
|
+
comments: number;
|
|
104
|
+
likes: number;
|
|
105
|
+
shares: number;
|
|
106
|
+
views: number;
|
|
107
|
+
};
|
|
108
|
+
postedAt: string;
|
|
109
|
+
authorFollowers: number;
|
|
110
|
+
}>, "many">;
|
|
111
|
+
totalFound: z.ZodNumber;
|
|
112
|
+
hasMore: z.ZodBoolean;
|
|
113
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
114
|
+
}, "strip", z.ZodTypeAny, {
|
|
115
|
+
posts: {
|
|
116
|
+
url: string;
|
|
117
|
+
id: string;
|
|
118
|
+
platform: "twitter";
|
|
119
|
+
text: string;
|
|
120
|
+
authorName: string;
|
|
121
|
+
authorHandle: string;
|
|
122
|
+
authorUrl: string;
|
|
123
|
+
engagement: {
|
|
124
|
+
comments: number;
|
|
125
|
+
likes: number;
|
|
126
|
+
shares: number;
|
|
127
|
+
views: number;
|
|
128
|
+
};
|
|
129
|
+
postedAt: string;
|
|
130
|
+
authorFollowers: number;
|
|
131
|
+
}[];
|
|
132
|
+
totalFound: number;
|
|
133
|
+
hasMore: boolean;
|
|
134
|
+
cursor?: string | undefined;
|
|
135
|
+
}, {
|
|
136
|
+
posts: {
|
|
137
|
+
url: string;
|
|
138
|
+
id: string;
|
|
139
|
+
platform: "twitter";
|
|
140
|
+
text: string;
|
|
141
|
+
authorName: string;
|
|
142
|
+
authorHandle: string;
|
|
143
|
+
authorUrl: string;
|
|
144
|
+
engagement: {
|
|
145
|
+
comments: number;
|
|
146
|
+
likes: number;
|
|
147
|
+
shares: number;
|
|
148
|
+
views: number;
|
|
149
|
+
};
|
|
150
|
+
postedAt: string;
|
|
151
|
+
authorFollowers: number;
|
|
152
|
+
}[];
|
|
153
|
+
totalFound: number;
|
|
154
|
+
hasMore: boolean;
|
|
155
|
+
cursor?: string | undefined;
|
|
156
|
+
}>;
|
|
157
|
+
export type TwitterMonitorOutput = z.infer<typeof TwitterMonitorOutputSchema>;
|
|
158
|
+
/**
|
|
159
|
+
* Twitter Monitor Node
|
|
160
|
+
*
|
|
161
|
+
* Searches Twitter/X for posts matching keywords.
|
|
162
|
+
* Requires `context.services.twitter` to be provided by the host application.
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```typescript
|
|
166
|
+
* const result = await twitterMonitorNode.executor({
|
|
167
|
+
* keywords: ['typescript', 'nodejs'],
|
|
168
|
+
* excludeRetweets: true,
|
|
169
|
+
* maxResults: 25,
|
|
170
|
+
* sinceDays: 7
|
|
171
|
+
* }, context);
|
|
172
|
+
* ```
|
|
173
|
+
*/
|
|
174
|
+
export declare const twitterMonitorNode: import("@jam-nodes/core").NodeDefinition<{
|
|
175
|
+
keywords: string[];
|
|
176
|
+
maxResults?: number | undefined;
|
|
177
|
+
excludeRetweets?: boolean | undefined;
|
|
178
|
+
minLikes?: number | undefined;
|
|
179
|
+
lang?: string | undefined;
|
|
180
|
+
sinceDays?: number | undefined;
|
|
181
|
+
}, {
|
|
182
|
+
posts: TwitterPost[];
|
|
183
|
+
totalFound: number;
|
|
184
|
+
hasMore: boolean;
|
|
185
|
+
}>;
|
|
186
|
+
//# sourceMappingURL=twitter-monitor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"twitter-monitor.d.ts","sourceRoot":"","sources":["../../../src/integrations/social/twitter-monitor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,SAAS,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE;QACV,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,QAAQ,EAAE,MAAM,CAAC;CAClB;AAMD,eAAO,MAAM,yBAAyB;IACpC,6BAA6B;;IAE7B,oCAAoC;;IAEpC,2BAA2B;;IAE3B,gCAAgC;;IAEhC,mCAAmC;;IAEnC,qCAAqC;;;;;;;;;;;;;;;;EAErC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqBrC,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAgD9E;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;EA6F7B,CAAC"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { defineNode } from '@jam-nodes/core';
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// Schemas
|
|
5
|
+
// =============================================================================
|
|
6
|
+
export const TwitterMonitorInputSchema = z.object({
|
|
7
|
+
/** Keywords to search for */
|
|
8
|
+
keywords: z.array(z.string()),
|
|
9
|
+
/** Exclude retweets from results */
|
|
10
|
+
excludeRetweets: z.boolean().optional().default(true),
|
|
11
|
+
/** Minimum likes filter */
|
|
12
|
+
minLikes: z.number().optional(),
|
|
13
|
+
/** Maximum number of results */
|
|
14
|
+
maxResults: z.number().optional().default(50),
|
|
15
|
+
/** Language filter (e.g., 'en') */
|
|
16
|
+
lang: z.string().optional(),
|
|
17
|
+
/** Search tweets from last N days */
|
|
18
|
+
sinceDays: z.number().optional(),
|
|
19
|
+
});
|
|
20
|
+
export const TwitterMonitorOutputSchema = z.object({
|
|
21
|
+
posts: z.array(z.object({
|
|
22
|
+
id: z.string(),
|
|
23
|
+
platform: z.literal('twitter'),
|
|
24
|
+
url: z.string(),
|
|
25
|
+
text: z.string(),
|
|
26
|
+
authorName: z.string(),
|
|
27
|
+
authorHandle: z.string(),
|
|
28
|
+
authorUrl: z.string(),
|
|
29
|
+
authorFollowers: z.number(),
|
|
30
|
+
engagement: z.object({
|
|
31
|
+
likes: z.number(),
|
|
32
|
+
comments: z.number(),
|
|
33
|
+
shares: z.number(),
|
|
34
|
+
views: z.number(),
|
|
35
|
+
}),
|
|
36
|
+
postedAt: z.string(),
|
|
37
|
+
})),
|
|
38
|
+
totalFound: z.number(),
|
|
39
|
+
hasMore: z.boolean(),
|
|
40
|
+
cursor: z.string().optional(),
|
|
41
|
+
});
|
|
42
|
+
// =============================================================================
|
|
43
|
+
// Query Builder
|
|
44
|
+
// =============================================================================
|
|
45
|
+
/**
|
|
46
|
+
* Build Twitter search query with proper syntax
|
|
47
|
+
*/
|
|
48
|
+
function buildTwitterSearchQuery(keywords, options = {}) {
|
|
49
|
+
// Join keywords with OR
|
|
50
|
+
const keywordQuery = keywords
|
|
51
|
+
.map((k) => (k.includes(' ') ? `"${k}"` : k))
|
|
52
|
+
.join(' OR ');
|
|
53
|
+
let query = `(${keywordQuery})`;
|
|
54
|
+
if (options.excludeRetweets) {
|
|
55
|
+
query += ' -is:retweet';
|
|
56
|
+
}
|
|
57
|
+
if (options.minLikes) {
|
|
58
|
+
query += ` min_faves:${options.minLikes}`;
|
|
59
|
+
}
|
|
60
|
+
if (options.since) {
|
|
61
|
+
query += ` since:${options.since}`;
|
|
62
|
+
}
|
|
63
|
+
if (options.lang) {
|
|
64
|
+
query += ` lang:${options.lang}`;
|
|
65
|
+
}
|
|
66
|
+
return query;
|
|
67
|
+
}
|
|
68
|
+
// =============================================================================
|
|
69
|
+
// Node Definition
|
|
70
|
+
// =============================================================================
|
|
71
|
+
/**
|
|
72
|
+
* Twitter Monitor Node
|
|
73
|
+
*
|
|
74
|
+
* Searches Twitter/X for posts matching keywords.
|
|
75
|
+
* Requires `context.services.twitter` to be provided by the host application.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* const result = await twitterMonitorNode.executor({
|
|
80
|
+
* keywords: ['typescript', 'nodejs'],
|
|
81
|
+
* excludeRetweets: true,
|
|
82
|
+
* maxResults: 25,
|
|
83
|
+
* sinceDays: 7
|
|
84
|
+
* }, context);
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export const twitterMonitorNode = defineNode({
|
|
88
|
+
type: 'twitter_monitor',
|
|
89
|
+
name: 'Twitter Monitor',
|
|
90
|
+
description: 'Search Twitter/X for posts matching keywords',
|
|
91
|
+
category: 'integration',
|
|
92
|
+
inputSchema: TwitterMonitorInputSchema,
|
|
93
|
+
outputSchema: TwitterMonitorOutputSchema,
|
|
94
|
+
estimatedDuration: 15,
|
|
95
|
+
capabilities: {
|
|
96
|
+
supportsRerun: true,
|
|
97
|
+
},
|
|
98
|
+
executor: async (input, context) => {
|
|
99
|
+
try {
|
|
100
|
+
if (!input.keywords || input.keywords.length === 0) {
|
|
101
|
+
return {
|
|
102
|
+
success: false,
|
|
103
|
+
error: 'No keywords provided for Twitter search',
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
// Require Twitter service
|
|
107
|
+
if (!context.services?.twitter) {
|
|
108
|
+
return {
|
|
109
|
+
success: false,
|
|
110
|
+
error: 'Twitter service not configured. Please provide context.services.twitter.',
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
// Build the search query
|
|
114
|
+
const sinceDate = input.sinceDays
|
|
115
|
+
? new Date(Date.now() - input.sinceDays * 24 * 60 * 60 * 1000)
|
|
116
|
+
.toISOString()
|
|
117
|
+
.split('T')[0]
|
|
118
|
+
: undefined;
|
|
119
|
+
const query = buildTwitterSearchQuery(input.keywords, {
|
|
120
|
+
excludeRetweets: input.excludeRetweets ?? true,
|
|
121
|
+
minLikes: input.minLikes,
|
|
122
|
+
since: sinceDate,
|
|
123
|
+
lang: input.lang,
|
|
124
|
+
});
|
|
125
|
+
// Search tweets
|
|
126
|
+
const tweets = await context.services.twitter.searchTweets(query, {
|
|
127
|
+
maxResults: input.maxResults || 50,
|
|
128
|
+
sinceDays: input.sinceDays,
|
|
129
|
+
});
|
|
130
|
+
// Transform to unified format
|
|
131
|
+
const posts = tweets.map((tweet) => ({
|
|
132
|
+
id: tweet.id,
|
|
133
|
+
platform: 'twitter',
|
|
134
|
+
url: tweet.url,
|
|
135
|
+
text: tweet.text,
|
|
136
|
+
authorName: tweet.authorName,
|
|
137
|
+
authorHandle: tweet.authorHandle,
|
|
138
|
+
authorUrl: `https://twitter.com/${tweet.authorHandle}`,
|
|
139
|
+
authorFollowers: tweet.authorFollowers,
|
|
140
|
+
engagement: {
|
|
141
|
+
likes: tweet.likes,
|
|
142
|
+
comments: tweet.replies,
|
|
143
|
+
shares: tweet.retweets,
|
|
144
|
+
views: tweet.views || 0,
|
|
145
|
+
},
|
|
146
|
+
postedAt: tweet.createdAt,
|
|
147
|
+
}));
|
|
148
|
+
// Optional: send notification if service available
|
|
149
|
+
if (context.services?.notifications && posts.length > 0) {
|
|
150
|
+
await context.services.notifications.send({
|
|
151
|
+
userId: context.userId,
|
|
152
|
+
title: 'Twitter Monitor Complete',
|
|
153
|
+
message: `Found ${posts.length} tweets`,
|
|
154
|
+
data: { posts: posts.slice(0, 5) },
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
success: true,
|
|
159
|
+
output: {
|
|
160
|
+
posts,
|
|
161
|
+
totalFound: posts.length,
|
|
162
|
+
hasMore: false, // Simplified - pagination handled by service
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
return {
|
|
168
|
+
success: false,
|
|
169
|
+
error: error instanceof Error ? error.message : 'Failed to monitor Twitter',
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
//# sourceMappingURL=twitter-monitor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"twitter-monitor.js","sourceRoot":"","sources":["../../../src/integrations/social/twitter-monitor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { SocialPost } from '../schemas/ai';
|
|
2
|
+
/**
|
|
3
|
+
* Prompt for analyzing social media posts for relevance, sentiment, and urgency.
|
|
4
|
+
*
|
|
5
|
+
* Template variables:
|
|
6
|
+
* - {{TOPIC}}: The monitoring topic
|
|
7
|
+
* - {{INTENT}}: What the user is looking for
|
|
8
|
+
* - {{POSTS_JSON}}: JSON array of posts to analyze
|
|
9
|
+
*/
|
|
10
|
+
export declare const ANALYSIS_PROMPT = "You are analyzing social media posts to find ones relevant to a user's monitoring topic.\n\n<user_topic>\n{{TOPIC}}\n</user_topic>\n\n<user_intent>\n{{INTENT}}\n</user_intent>\n\nAnalyze each post and determine:\n1. **Relevance Score (0-100)**: How relevant is this post to what the user is looking for?\n2. **Sentiment**: Is the post positive, negative, or neutral about the topic?\n3. **Is Complaint**: Is this post a complaint or expressing frustration?\n4. **Urgency Level**:\n - HIGH: Urgent issue, direct complaint, someone actively looking for alternatives\n - MEDIUM: General discussion, mild frustration, asking questions\n - LOW: Casual mention, positive review, tangentially related\n5. **Summary**: 2-3 sentence summary of what this post is about\n6. **Matched Keywords**: Which keywords/concepts from the topic match this post\n\n<posts>\n{{POSTS_JSON}}\n</posts>\n\nRespond with a JSON array of analyzed posts:\n[\n {\n \"id\": \"post_id\",\n \"relevanceScore\": 85,\n \"sentiment\": \"negative\",\n \"isComplaint\": true,\n \"urgencyLevel\": \"high\",\n \"aiSummary\": \"User is frustrated with...\",\n \"matchedKeywords\": [\"keyword1\", \"keyword2\"]\n }\n]\n\nOnly include posts with relevance score >= 30. Filter out irrelevant posts entirely.";
|
|
11
|
+
/**
|
|
12
|
+
* Build the complete analysis prompt for a batch of posts.
|
|
13
|
+
*/
|
|
14
|
+
export declare function buildAnalysisPrompt(topic: string, userIntent: string, posts: SocialPost[]): string;
|
|
15
|
+
/**
|
|
16
|
+
* Normalize sentiment values from Claude response.
|
|
17
|
+
*/
|
|
18
|
+
export declare function normalizeSentiment(s: string): 'positive' | 'negative' | 'neutral';
|
|
19
|
+
/**
|
|
20
|
+
* Normalize urgency level values from Claude response.
|
|
21
|
+
*/
|
|
22
|
+
export declare function normalizeUrgency(u: string): 'low' | 'medium' | 'high';
|
|
23
|
+
/**
|
|
24
|
+
* Minimum relevance score to include in results.
|
|
25
|
+
*/
|
|
26
|
+
export declare const MIN_RELEVANCE_SCORE = 30;
|
|
27
|
+
/**
|
|
28
|
+
* Batch size for processing posts through Claude.
|
|
29
|
+
*/
|
|
30
|
+
export declare const ANALYSIS_BATCH_SIZE = 20;
|
|
31
|
+
//# sourceMappingURL=analyze-posts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze-posts.d.ts","sourceRoot":"","sources":["../../src/prompts/analyze-posts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,gxCAsCyD,CAAC;AAEtF;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,UAAU,EAAE,GAClB,MAAM,CAKR;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,CAKjF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAKrE;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC;;GAEG;AACH,eAAO,MAAM,mBAAmB,KAAK,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt for analyzing social media posts for relevance, sentiment, and urgency.
|
|
3
|
+
*
|
|
4
|
+
* Template variables:
|
|
5
|
+
* - {{TOPIC}}: The monitoring topic
|
|
6
|
+
* - {{INTENT}}: What the user is looking for
|
|
7
|
+
* - {{POSTS_JSON}}: JSON array of posts to analyze
|
|
8
|
+
*/
|
|
9
|
+
export const ANALYSIS_PROMPT = `You are analyzing social media posts to find ones relevant to a user's monitoring topic.
|
|
10
|
+
|
|
11
|
+
<user_topic>
|
|
12
|
+
{{TOPIC}}
|
|
13
|
+
</user_topic>
|
|
14
|
+
|
|
15
|
+
<user_intent>
|
|
16
|
+
{{INTENT}}
|
|
17
|
+
</user_intent>
|
|
18
|
+
|
|
19
|
+
Analyze each post and determine:
|
|
20
|
+
1. **Relevance Score (0-100)**: How relevant is this post to what the user is looking for?
|
|
21
|
+
2. **Sentiment**: Is the post positive, negative, or neutral about the topic?
|
|
22
|
+
3. **Is Complaint**: Is this post a complaint or expressing frustration?
|
|
23
|
+
4. **Urgency Level**:
|
|
24
|
+
- HIGH: Urgent issue, direct complaint, someone actively looking for alternatives
|
|
25
|
+
- MEDIUM: General discussion, mild frustration, asking questions
|
|
26
|
+
- LOW: Casual mention, positive review, tangentially related
|
|
27
|
+
5. **Summary**: 2-3 sentence summary of what this post is about
|
|
28
|
+
6. **Matched Keywords**: Which keywords/concepts from the topic match this post
|
|
29
|
+
|
|
30
|
+
<posts>
|
|
31
|
+
{{POSTS_JSON}}
|
|
32
|
+
</posts>
|
|
33
|
+
|
|
34
|
+
Respond with a JSON array of analyzed posts:
|
|
35
|
+
[
|
|
36
|
+
{
|
|
37
|
+
"id": "post_id",
|
|
38
|
+
"relevanceScore": 85,
|
|
39
|
+
"sentiment": "negative",
|
|
40
|
+
"isComplaint": true,
|
|
41
|
+
"urgencyLevel": "high",
|
|
42
|
+
"aiSummary": "User is frustrated with...",
|
|
43
|
+
"matchedKeywords": ["keyword1", "keyword2"]
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
Only include posts with relevance score >= 30. Filter out irrelevant posts entirely.`;
|
|
48
|
+
/**
|
|
49
|
+
* Build the complete analysis prompt for a batch of posts.
|
|
50
|
+
*/
|
|
51
|
+
export function buildAnalysisPrompt(topic, userIntent, posts) {
|
|
52
|
+
return ANALYSIS_PROMPT
|
|
53
|
+
.replace('{{TOPIC}}', topic)
|
|
54
|
+
.replace('{{INTENT}}', userIntent)
|
|
55
|
+
.replace('{{POSTS_JSON}}', JSON.stringify(posts, null, 2));
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Normalize sentiment values from Claude response.
|
|
59
|
+
*/
|
|
60
|
+
export function normalizeSentiment(s) {
|
|
61
|
+
const lower = String(s).toLowerCase().trim();
|
|
62
|
+
if (lower === 'positive')
|
|
63
|
+
return 'positive';
|
|
64
|
+
if (lower === 'negative')
|
|
65
|
+
return 'negative';
|
|
66
|
+
return 'neutral';
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Normalize urgency level values from Claude response.
|
|
70
|
+
*/
|
|
71
|
+
export function normalizeUrgency(u) {
|
|
72
|
+
const lower = String(u).toLowerCase().trim();
|
|
73
|
+
if (lower === 'high')
|
|
74
|
+
return 'high';
|
|
75
|
+
if (lower === 'medium')
|
|
76
|
+
return 'medium';
|
|
77
|
+
return 'low';
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Minimum relevance score to include in results.
|
|
81
|
+
*/
|
|
82
|
+
export const MIN_RELEVANCE_SCORE = 30;
|
|
83
|
+
/**
|
|
84
|
+
* Batch size for processing posts through Claude.
|
|
85
|
+
*/
|
|
86
|
+
export const ANALYSIS_BATCH_SIZE = 20;
|
|
87
|
+
//# sourceMappingURL=analyze-posts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze-posts.js","sourceRoot":"","sources":["../../src/prompts/analyze-posts.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qFAsCsD,CAAC;AAEtF;;GAEG;AACH,MAAM,UAAU,mBAAmB,CACjC,KAAa,EACb,UAAkB,EAClB,KAAmB;IAEnB,OAAO,eAAe;SACnB,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC;SAC3B,OAAO,CAAC,YAAY,EAAE,UAAU,CAAC;SACjC,OAAO,CAAC,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,CAAS;IAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IAC7C,IAAI,KAAK,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IAC5C,IAAI,KAAK,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IAC5C,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,CAAS;IACxC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IAC7C,IAAI,KAAK,KAAK,MAAM;QAAE,OAAO,MAAM,CAAC;IACpC,IAAI,KAAK,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IACxC,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAEtC;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC"}
|