@jam-nodes/nodes 0.2.3 → 0.2.5
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 +4 -2
- package/dist/ai/analyze-posts.d.ts.map +1 -1
- package/dist/ai/analyze-posts.js +48 -44
- package/dist/ai/analyze-posts.js.map +1 -1
- package/dist/ai/draft-emails.d.ts +4 -2
- package/dist/ai/draft-emails.d.ts.map +1 -1
- package/dist/ai/draft-emails.js +57 -42
- package/dist/ai/draft-emails.js.map +1 -1
- package/dist/ai/keyword-generator.d.ts +1 -1
- package/dist/ai/keyword-generator.d.ts.map +1 -1
- package/dist/ai/keyword-generator.js +45 -20
- package/dist/ai/keyword-generator.js.map +1 -1
- package/dist/examples/bread.d.ts +24 -0
- package/dist/examples/bread.d.ts.map +1 -0
- package/dist/examples/bread.js +33 -0
- package/dist/examples/bread.js.map +1 -0
- package/dist/examples/index.d.ts +3 -0
- package/dist/examples/index.d.ts.map +1 -1
- package/dist/examples/index.js +2 -0
- package/dist/examples/index.js.map +1 -1
- package/dist/index.d.ts +38 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -5
- package/dist/index.js.map +1 -1
- package/dist/integrations/apollo/search-contacts.d.ts +8 -8
- package/dist/integrations/apollo/search-contacts.d.ts.map +1 -1
- package/dist/integrations/apollo/search-contacts.js +110 -26
- package/dist/integrations/apollo/search-contacts.js.map +1 -1
- package/dist/integrations/dataforseo/keyword-research.d.ts +1 -1
- package/dist/integrations/dataforseo/keyword-research.d.ts.map +1 -1
- package/dist/integrations/dataforseo/keyword-research.js +59 -9
- package/dist/integrations/dataforseo/keyword-research.js.map +1 -1
- package/dist/integrations/dataforseo/seo-audit.d.ts +1 -1
- package/dist/integrations/dataforseo/seo-audit.d.ts.map +1 -1
- package/dist/integrations/dataforseo/seo-audit.js +52 -23
- package/dist/integrations/dataforseo/seo-audit.js.map +1 -1
- package/dist/integrations/openai/sora-video.d.ts +1 -1
- package/dist/integrations/openai/sora-video.d.ts.map +1 -1
- package/dist/integrations/openai/sora-video.js +82 -7
- package/dist/integrations/openai/sora-video.js.map +1 -1
- package/dist/integrations/social/linkedin-monitor.d.ts +1 -1
- package/dist/integrations/social/linkedin-monitor.d.ts.map +1 -1
- package/dist/integrations/social/linkedin-monitor.js +69 -35
- package/dist/integrations/social/linkedin-monitor.js.map +1 -1
- package/dist/integrations/social/reddit-monitor.d.ts.map +1 -1
- package/dist/integrations/social/reddit-monitor.js +5 -12
- package/dist/integrations/social/reddit-monitor.js.map +1 -1
- package/dist/integrations/social/twitter-monitor.d.ts +20 -3
- package/dist/integrations/social/twitter-monitor.d.ts.map +1 -1
- package/dist/integrations/social/twitter-monitor.js +44 -28
- package/dist/integrations/social/twitter-monitor.js.map +1 -1
- package/dist/transform/index.d.ts +3 -0
- package/dist/transform/index.d.ts.map +1 -1
- package/dist/transform/index.js +2 -0
- package/dist/transform/index.js.map +1 -1
- package/dist/transform/sort.d.ts +37 -0
- package/dist/transform/sort.d.ts.map +1 -0
- package/dist/transform/sort.js +68 -0
- package/dist/transform/sort.js.map +1 -0
- package/dist/utils/http.d.ts +60 -0
- package/dist/utils/http.d.ts.map +1 -0
- package/dist/utils/http.js +126 -0
- package/dist/utils/http.js.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +1 -1
|
@@ -1 +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;
|
|
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;AAqDxB;;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;AA+E9E;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoF7B,CAAC"}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { defineNode } from '@jam-nodes/core';
|
|
3
|
+
import { fetchWithRetry } from '../../utils/http.js';
|
|
4
|
+
// =============================================================================
|
|
5
|
+
// Constants
|
|
6
|
+
// =============================================================================
|
|
7
|
+
const TWITTERAPI_BASE_URL = 'https://api.twitterapi.io';
|
|
3
8
|
// =============================================================================
|
|
4
9
|
// Schemas
|
|
5
10
|
// =============================================================================
|
|
@@ -65,14 +70,33 @@ function buildTwitterSearchQuery(keywords, options = {}) {
|
|
|
65
70
|
}
|
|
66
71
|
return query;
|
|
67
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Search Twitter using TwitterAPI.io
|
|
75
|
+
*/
|
|
76
|
+
async function searchTwitter(apiKey, query, queryType = 'Latest') {
|
|
77
|
+
const url = new URL(`${TWITTERAPI_BASE_URL}/twitter/tweet/advanced_search`);
|
|
78
|
+
url.searchParams.set('query', query);
|
|
79
|
+
url.searchParams.set('queryType', queryType);
|
|
80
|
+
const response = await fetchWithRetry(url.toString(), {
|
|
81
|
+
method: 'GET',
|
|
82
|
+
headers: {
|
|
83
|
+
'X-API-Key': apiKey,
|
|
84
|
+
},
|
|
85
|
+
}, { maxRetries: 3, backoffMs: 1000, timeoutMs: 30000 });
|
|
86
|
+
if (!response.ok) {
|
|
87
|
+
const errorText = await response.text();
|
|
88
|
+
throw new Error(`Twitter API error: ${response.status} - ${errorText}`);
|
|
89
|
+
}
|
|
90
|
+
return response.json();
|
|
91
|
+
}
|
|
68
92
|
// =============================================================================
|
|
69
93
|
// Node Definition
|
|
70
94
|
// =============================================================================
|
|
71
95
|
/**
|
|
72
96
|
* Twitter Monitor Node
|
|
73
97
|
*
|
|
74
|
-
* Searches Twitter/X for posts matching keywords.
|
|
75
|
-
* Requires `context.
|
|
98
|
+
* Searches Twitter/X for posts matching keywords using TwitterAPI.io.
|
|
99
|
+
* Requires `context.credentials.twitter.twitterApiIoKey` to be provided.
|
|
76
100
|
*
|
|
77
101
|
* @example
|
|
78
102
|
* ```typescript
|
|
@@ -103,11 +127,12 @@ export const twitterMonitorNode = defineNode({
|
|
|
103
127
|
error: 'No keywords provided for Twitter search',
|
|
104
128
|
};
|
|
105
129
|
}
|
|
106
|
-
//
|
|
107
|
-
|
|
130
|
+
// Check for API key (prefer TwitterAPI.io key)
|
|
131
|
+
const apiKey = context.credentials?.twitter?.twitterApiIoKey;
|
|
132
|
+
if (!apiKey) {
|
|
108
133
|
return {
|
|
109
134
|
success: false,
|
|
110
|
-
error: 'Twitter
|
|
135
|
+
error: 'Twitter API key not configured. Please provide context.credentials.twitter.twitterApiIoKey.',
|
|
111
136
|
};
|
|
112
137
|
}
|
|
113
138
|
// Build the search query
|
|
@@ -123,43 +148,34 @@ export const twitterMonitorNode = defineNode({
|
|
|
123
148
|
lang: input.lang,
|
|
124
149
|
});
|
|
125
150
|
// Search tweets
|
|
126
|
-
const
|
|
127
|
-
maxResults: input.maxResults || 50,
|
|
128
|
-
sinceDays: input.sinceDays,
|
|
129
|
-
});
|
|
151
|
+
const response = await searchTwitter(apiKey, query, 'Latest');
|
|
130
152
|
// Transform to unified format
|
|
131
|
-
const posts = tweets
|
|
153
|
+
const posts = (response.tweets || [])
|
|
154
|
+
.slice(0, input.maxResults || 50)
|
|
155
|
+
.map((tweet) => ({
|
|
132
156
|
id: tweet.id,
|
|
133
157
|
platform: 'twitter',
|
|
134
158
|
url: tweet.url,
|
|
135
159
|
text: tweet.text,
|
|
136
|
-
authorName: tweet.
|
|
137
|
-
authorHandle: tweet.
|
|
138
|
-
authorUrl: `https://twitter.com/${tweet.
|
|
139
|
-
authorFollowers: tweet.
|
|
160
|
+
authorName: tweet.author.name,
|
|
161
|
+
authorHandle: tweet.author.userName,
|
|
162
|
+
authorUrl: `https://twitter.com/${tweet.author.userName}`,
|
|
163
|
+
authorFollowers: tweet.author.followers,
|
|
140
164
|
engagement: {
|
|
141
|
-
likes: tweet.
|
|
142
|
-
comments: tweet.
|
|
143
|
-
shares: tweet.
|
|
144
|
-
views: tweet.
|
|
165
|
+
likes: tweet.likeCount,
|
|
166
|
+
comments: tweet.replyCount,
|
|
167
|
+
shares: tweet.retweetCount,
|
|
168
|
+
views: tweet.viewCount || 0,
|
|
145
169
|
},
|
|
146
170
|
postedAt: tweet.createdAt,
|
|
147
171
|
}));
|
|
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
172
|
return {
|
|
158
173
|
success: true,
|
|
159
174
|
output: {
|
|
160
175
|
posts,
|
|
161
176
|
totalFound: posts.length,
|
|
162
|
-
hasMore:
|
|
177
|
+
hasMore: response.has_next_page,
|
|
178
|
+
cursor: response.next_cursor || undefined,
|
|
163
179
|
},
|
|
164
180
|
};
|
|
165
181
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"twitter-monitor.js","sourceRoot":"","sources":["../../../src/integrations/social/twitter-monitor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"twitter-monitor.js","sourceRoot":"","sources":["../../../src/integrations/social/twitter-monitor.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,4 +4,7 @@ export { MapInputSchema, MapOutputSchema } from './map.js';
|
|
|
4
4
|
export { filterNode } from './filter.js';
|
|
5
5
|
export type { FilterInput, FilterOutput, FilterOperator } from './filter.js';
|
|
6
6
|
export { FilterInputSchema, FilterOutputSchema, FilterOperatorSchema } from './filter.js';
|
|
7
|
+
export { sortNode } from './sort.js';
|
|
8
|
+
export type { SortInput, SortOutput, SortDirection } from './sort.js';
|
|
9
|
+
export { SortInputSchema, SortOutputSchema, SortDirectionSchema } from './sort.js';
|
|
7
10
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transform/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transform/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAE1F,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/transform/index.js
CHANGED
|
@@ -2,4 +2,6 @@ export { mapNode } from './map.js';
|
|
|
2
2
|
export { MapInputSchema, MapOutputSchema } from './map.js';
|
|
3
3
|
export { filterNode } from './filter.js';
|
|
4
4
|
export { FilterInputSchema, FilterOutputSchema, FilterOperatorSchema } from './filter.js';
|
|
5
|
+
export { sortNode } from './sort.js';
|
|
6
|
+
export { SortInputSchema, SortOutputSchema, SortDirectionSchema } from './sort.js';
|
|
5
7
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transform/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transform/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAE1F,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const SortDirectionSchema: z.ZodEnum<["asc", "desc"]>;
|
|
3
|
+
export type SortDirection = z.infer<typeof SortDirectionSchema>;
|
|
4
|
+
export declare const SortInputSchema: z.ZodObject<{
|
|
5
|
+
items: z.ZodArray<z.ZodUnknown, "many">;
|
|
6
|
+
path: z.ZodString;
|
|
7
|
+
direction: z.ZodDefault<z.ZodEnum<["asc", "desc"]>>;
|
|
8
|
+
}, "strip", z.ZodTypeAny, {
|
|
9
|
+
path: string;
|
|
10
|
+
items: unknown[];
|
|
11
|
+
direction: "asc" | "desc";
|
|
12
|
+
}, {
|
|
13
|
+
path: string;
|
|
14
|
+
items: unknown[];
|
|
15
|
+
direction?: "asc" | "desc" | undefined;
|
|
16
|
+
}>;
|
|
17
|
+
export type SortInput = z.infer<typeof SortInputSchema>;
|
|
18
|
+
export declare const SortOutputSchema: z.ZodObject<{
|
|
19
|
+
results: z.ZodArray<z.ZodUnknown, "many">;
|
|
20
|
+
count: z.ZodNumber;
|
|
21
|
+
}, "strip", z.ZodTypeAny, {
|
|
22
|
+
results: unknown[];
|
|
23
|
+
count: number;
|
|
24
|
+
}, {
|
|
25
|
+
results: unknown[];
|
|
26
|
+
count: number;
|
|
27
|
+
}>;
|
|
28
|
+
export type SortOutput = z.infer<typeof SortOutputSchema>;
|
|
29
|
+
export declare const sortNode: import("@jam-nodes/core").NodeDefinition<{
|
|
30
|
+
path: string;
|
|
31
|
+
items: unknown[];
|
|
32
|
+
direction?: "asc" | "desc" | undefined;
|
|
33
|
+
}, {
|
|
34
|
+
results: unknown[];
|
|
35
|
+
count: number;
|
|
36
|
+
}>;
|
|
37
|
+
//# sourceMappingURL=sort.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sort.d.ts","sourceRoot":"","sources":["../../src/transform/sort.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,mBAAmB,4BAA0B,CAAC;AAC3D,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,eAAe;;;;;;;;;;;;EAI1B,CAAC;AAEH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,eAAO,MAAM,gBAAgB;;;;;;;;;EAG3B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAsB1D,eAAO,MAAM,QAAQ;;;;;;;EA4BnB,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { defineNode } from '@jam-nodes/core';
|
|
3
|
+
export const SortDirectionSchema = z.enum(['asc', 'desc']);
|
|
4
|
+
export const SortInputSchema = z.object({
|
|
5
|
+
items: z.array(z.unknown()),
|
|
6
|
+
path: z.string(),
|
|
7
|
+
direction: SortDirectionSchema.default('asc'),
|
|
8
|
+
});
|
|
9
|
+
export const SortOutputSchema = z.object({
|
|
10
|
+
results: z.array(z.unknown()),
|
|
11
|
+
count: z.number(),
|
|
12
|
+
});
|
|
13
|
+
function resolvePath(obj, path) {
|
|
14
|
+
if (!path)
|
|
15
|
+
return obj;
|
|
16
|
+
const parts = path.split('.');
|
|
17
|
+
let current = obj;
|
|
18
|
+
for (const part of parts) {
|
|
19
|
+
if (current === null || current === undefined)
|
|
20
|
+
return undefined;
|
|
21
|
+
current = current[part];
|
|
22
|
+
}
|
|
23
|
+
return current;
|
|
24
|
+
}
|
|
25
|
+
function compare(a, b) {
|
|
26
|
+
if (a === b)
|
|
27
|
+
return 0;
|
|
28
|
+
if (a == null)
|
|
29
|
+
return 1;
|
|
30
|
+
if (b == null)
|
|
31
|
+
return -1;
|
|
32
|
+
if (typeof a === 'number' && typeof b === 'number')
|
|
33
|
+
return a - b;
|
|
34
|
+
if (typeof a === 'string' && typeof b === 'string')
|
|
35
|
+
return a.localeCompare(b);
|
|
36
|
+
return String(a).localeCompare(String(b));
|
|
37
|
+
}
|
|
38
|
+
export const sortNode = defineNode({
|
|
39
|
+
type: 'sort',
|
|
40
|
+
name: 'Sort',
|
|
41
|
+
description: 'Sort array by a property path',
|
|
42
|
+
category: 'transform',
|
|
43
|
+
inputSchema: SortInputSchema,
|
|
44
|
+
outputSchema: SortOutputSchema,
|
|
45
|
+
estimatedDuration: 0,
|
|
46
|
+
capabilities: { supportsRerun: true },
|
|
47
|
+
executor: async (input) => {
|
|
48
|
+
try {
|
|
49
|
+
const { direction } = input;
|
|
50
|
+
const results = [...input.items].sort((a, b) => {
|
|
51
|
+
const va = resolvePath(a, input.path);
|
|
52
|
+
const vb = resolvePath(b, input.path);
|
|
53
|
+
return direction === 'asc' ? compare(va, vb) : -compare(va, vb);
|
|
54
|
+
});
|
|
55
|
+
return {
|
|
56
|
+
success: true,
|
|
57
|
+
output: { results, count: results.length },
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
return {
|
|
62
|
+
success: false,
|
|
63
|
+
error: error instanceof Error ? error.message : 'Sort failed',
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
//# sourceMappingURL=sort.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sort.js","sourceRoot":"","sources":["../../src/transform/sort.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP utilities for making API calls with retry logic, timeouts, and rate limiting.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Sleep for a specified duration
|
|
6
|
+
*/
|
|
7
|
+
export declare function sleep(ms: number): Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Configuration for fetch with retry
|
|
10
|
+
*/
|
|
11
|
+
export interface FetchWithRetryOptions {
|
|
12
|
+
/** Maximum number of retry attempts (default: 3) */
|
|
13
|
+
maxRetries?: number;
|
|
14
|
+
/** Base delay in milliseconds for exponential backoff (default: 1000) */
|
|
15
|
+
backoffMs?: number;
|
|
16
|
+
/** Request timeout in milliseconds (default: 30000) */
|
|
17
|
+
timeoutMs?: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Error thrown when all retry attempts are exhausted
|
|
21
|
+
*/
|
|
22
|
+
export declare class FetchRetryError extends Error {
|
|
23
|
+
readonly status?: number | undefined;
|
|
24
|
+
readonly body?: string | undefined;
|
|
25
|
+
constructor(message: string, status?: number | undefined, body?: string | undefined);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Fetch with automatic retry, timeout, and rate limit handling.
|
|
29
|
+
*
|
|
30
|
+
* Features:
|
|
31
|
+
* - Exponential backoff on rate limits (429) and server errors (5xx)
|
|
32
|
+
* - Configurable timeout
|
|
33
|
+
* - Respects Retry-After header
|
|
34
|
+
* - Does not retry on auth errors (401, 403) or client errors (4xx)
|
|
35
|
+
*
|
|
36
|
+
* @param url - URL to fetch
|
|
37
|
+
* @param options - Fetch options (same as native fetch)
|
|
38
|
+
* @param config - Retry and timeout configuration
|
|
39
|
+
* @returns Promise resolving to Response
|
|
40
|
+
* @throws FetchRetryError if all retries exhausted or non-retryable error
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* const response = await fetchWithRetry(
|
|
45
|
+
* 'https://api.example.com/data',
|
|
46
|
+
* {
|
|
47
|
+
* method: 'POST',
|
|
48
|
+
* headers: { 'Authorization': 'Bearer token' },
|
|
49
|
+
* body: JSON.stringify({ key: 'value' })
|
|
50
|
+
* },
|
|
51
|
+
* { maxRetries: 3, timeoutMs: 30000 }
|
|
52
|
+
* );
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare function fetchWithRetry(url: string, options?: RequestInit, config?: FetchWithRetryOptions): Promise<Response>;
|
|
56
|
+
/**
|
|
57
|
+
* Parse JSON response with error handling
|
|
58
|
+
*/
|
|
59
|
+
export declare function parseJsonResponse<T>(response: Response): Promise<T>;
|
|
60
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/utils/http.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,KAAK;aAGtB,MAAM,CAAC,EAAE,MAAM;aACf,IAAI,CAAC,EAAE,MAAM;gBAF7B,OAAO,EAAE,MAAM,EACC,MAAM,CAAC,EAAE,MAAM,YAAA,EACf,IAAI,CAAC,EAAE,MAAM,YAAA;CAKhC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,WAAgB,EACzB,MAAM,GAAE,qBAA0B,GACjC,OAAO,CAAC,QAAQ,CAAC,CAoFnB;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,CAWzE"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP utilities for making API calls with retry logic, timeouts, and rate limiting.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Sleep for a specified duration
|
|
6
|
+
*/
|
|
7
|
+
export function sleep(ms) {
|
|
8
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Error thrown when all retry attempts are exhausted
|
|
12
|
+
*/
|
|
13
|
+
export class FetchRetryError extends Error {
|
|
14
|
+
status;
|
|
15
|
+
body;
|
|
16
|
+
constructor(message, status, body) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.status = status;
|
|
19
|
+
this.body = body;
|
|
20
|
+
this.name = 'FetchRetryError';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Fetch with automatic retry, timeout, and rate limit handling.
|
|
25
|
+
*
|
|
26
|
+
* Features:
|
|
27
|
+
* - Exponential backoff on rate limits (429) and server errors (5xx)
|
|
28
|
+
* - Configurable timeout
|
|
29
|
+
* - Respects Retry-After header
|
|
30
|
+
* - Does not retry on auth errors (401, 403) or client errors (4xx)
|
|
31
|
+
*
|
|
32
|
+
* @param url - URL to fetch
|
|
33
|
+
* @param options - Fetch options (same as native fetch)
|
|
34
|
+
* @param config - Retry and timeout configuration
|
|
35
|
+
* @returns Promise resolving to Response
|
|
36
|
+
* @throws FetchRetryError if all retries exhausted or non-retryable error
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* const response = await fetchWithRetry(
|
|
41
|
+
* 'https://api.example.com/data',
|
|
42
|
+
* {
|
|
43
|
+
* method: 'POST',
|
|
44
|
+
* headers: { 'Authorization': 'Bearer token' },
|
|
45
|
+
* body: JSON.stringify({ key: 'value' })
|
|
46
|
+
* },
|
|
47
|
+
* { maxRetries: 3, timeoutMs: 30000 }
|
|
48
|
+
* );
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export async function fetchWithRetry(url, options = {}, config = {}) {
|
|
52
|
+
const { maxRetries = 3, backoffMs = 1000, timeoutMs = 30000 } = config;
|
|
53
|
+
let lastError = null;
|
|
54
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
55
|
+
const controller = new AbortController();
|
|
56
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
57
|
+
try {
|
|
58
|
+
const response = await fetch(url, {
|
|
59
|
+
...options,
|
|
60
|
+
signal: controller.signal,
|
|
61
|
+
});
|
|
62
|
+
clearTimeout(timeout);
|
|
63
|
+
// Don't retry on auth errors
|
|
64
|
+
if (response.status === 401 || response.status === 403) {
|
|
65
|
+
const errorText = await response.text();
|
|
66
|
+
throw new FetchRetryError(`Authentication error: ${response.status} ${response.statusText}`, response.status, errorText);
|
|
67
|
+
}
|
|
68
|
+
// Handle rate limiting
|
|
69
|
+
if (response.status === 429) {
|
|
70
|
+
const retryAfter = response.headers.get('retry-after');
|
|
71
|
+
const delayMs = retryAfter
|
|
72
|
+
? parseInt(retryAfter, 10) * 1000
|
|
73
|
+
: backoffMs * Math.pow(2, attempt);
|
|
74
|
+
if (attempt < maxRetries - 1) {
|
|
75
|
+
await sleep(delayMs);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Retry on server errors
|
|
80
|
+
if (response.status >= 500 && response.status < 600) {
|
|
81
|
+
if (attempt < maxRetries - 1) {
|
|
82
|
+
await sleep(backoffMs * Math.pow(2, attempt));
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const errorText = await response.text();
|
|
86
|
+
throw new FetchRetryError(`Server error: ${response.status} ${response.statusText}`, response.status, errorText);
|
|
87
|
+
}
|
|
88
|
+
// Return response for success or client errors (let caller handle)
|
|
89
|
+
return response;
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
clearTimeout(timeout);
|
|
93
|
+
// Don't retry abort errors (timeout) on last attempt
|
|
94
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
95
|
+
lastError = new FetchRetryError('Request timed out');
|
|
96
|
+
if (attempt < maxRetries - 1) {
|
|
97
|
+
await sleep(backoffMs * Math.pow(2, attempt));
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
throw lastError;
|
|
101
|
+
}
|
|
102
|
+
// Re-throw FetchRetryError (auth errors, etc.)
|
|
103
|
+
if (error instanceof FetchRetryError) {
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
// Network errors - retry
|
|
107
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
108
|
+
if (attempt < maxRetries - 1) {
|
|
109
|
+
await sleep(backoffMs * Math.pow(2, attempt));
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
throw lastError || new FetchRetryError('Max retries exceeded');
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Parse JSON response with error handling
|
|
118
|
+
*/
|
|
119
|
+
export async function parseJsonResponse(response) {
|
|
120
|
+
if (!response.ok) {
|
|
121
|
+
const errorText = await response.text();
|
|
122
|
+
throw new FetchRetryError(`HTTP error: ${response.status} ${response.statusText}`, response.status, errorText);
|
|
123
|
+
}
|
|
124
|
+
return response.json();
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/utils/http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,KAAK,EACL,eAAe,EACf,KAAK,qBAAqB,GAC3B,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,KAAK,EACL,eAAe,GAEhB,MAAM,WAAW,CAAC"}
|