harvester_sdk 1.0.23 → 1.0.24
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/index.d.ts +2 -0
- package/dist/index.js +7 -1
- package/dist/sdk.d.ts +294 -0
- package/dist/sdk.js +418 -0
- package/index.ts +4 -0
- package/package.json +1 -1
- package/sdk.ts +558 -0
package/dist/index.d.ts
CHANGED
|
@@ -24,6 +24,8 @@
|
|
|
24
24
|
/// <reference types="mongoose/types/inferschematype" />
|
|
25
25
|
/// <reference types="mongoose/types/inferrawdoctype" />
|
|
26
26
|
export * from './types';
|
|
27
|
+
export * from './sdk';
|
|
28
|
+
export { HarvesterSDK, createHarvesterSDK, HarvesterSDKError } from './sdk';
|
|
27
29
|
import { Schema } from 'mongoose';
|
|
28
30
|
export declare const MongoDataSchema: Schema<any, import("mongoose").Model<any, any, any, any, any, any>, {}, {}, {}, {}, {
|
|
29
31
|
versionKey: false;
|
package/dist/index.js
CHANGED
|
@@ -14,9 +14,15 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.MongoApiKeySchema = exports.MongoGeoSelectionSchema = exports.MongoGeoSchema = exports.MongoSourceSchema = exports.MongoSourceGroupSchema = exports.MongoRegionSchema = exports.MongoDataSchema = void 0;
|
|
17
|
+
exports.MongoApiKeySchema = exports.MongoGeoSelectionSchema = exports.MongoGeoSchema = exports.MongoSourceSchema = exports.MongoSourceGroupSchema = exports.MongoRegionSchema = exports.MongoDataSchema = exports.HarvesterSDKError = exports.createHarvesterSDK = exports.HarvesterSDK = void 0;
|
|
18
18
|
// Export types for consumers
|
|
19
19
|
__exportStar(require("./types"), exports);
|
|
20
|
+
// Export SDK
|
|
21
|
+
__exportStar(require("./sdk"), exports);
|
|
22
|
+
var sdk_1 = require("./sdk");
|
|
23
|
+
Object.defineProperty(exports, "HarvesterSDK", { enumerable: true, get: function () { return sdk_1.HarvesterSDK; } });
|
|
24
|
+
Object.defineProperty(exports, "createHarvesterSDK", { enumerable: true, get: function () { return sdk_1.createHarvesterSDK; } });
|
|
25
|
+
Object.defineProperty(exports, "HarvesterSDKError", { enumerable: true, get: function () { return sdk_1.HarvesterSDKError; } });
|
|
20
26
|
const mongoose_1 = require("mongoose");
|
|
21
27
|
const types_1 = require("./types");
|
|
22
28
|
exports.MongoDataSchema = new mongoose_1.Schema({
|
package/dist/sdk.d.ts
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { AxiosRequestConfig } from 'axios';
|
|
2
|
+
import { RegionType, GeoType, DataType, platformsList } from './types';
|
|
3
|
+
export interface HarvesterSDKConfig {
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
timeout?: number;
|
|
7
|
+
headers?: Record<string, string>;
|
|
8
|
+
}
|
|
9
|
+
export interface TimeRange {
|
|
10
|
+
start: number;
|
|
11
|
+
end: number;
|
|
12
|
+
}
|
|
13
|
+
export interface RelativeTimeRange {
|
|
14
|
+
value: number;
|
|
15
|
+
unit: 'minutes' | 'hours' | 'days' | 'weeks' | 'months';
|
|
16
|
+
}
|
|
17
|
+
export type Platform = (typeof platformsList)[number];
|
|
18
|
+
export interface PaginationParams {
|
|
19
|
+
page?: number;
|
|
20
|
+
limit?: number;
|
|
21
|
+
sort_by?: string;
|
|
22
|
+
sort_order?: 'asc' | 'desc';
|
|
23
|
+
}
|
|
24
|
+
export interface GetRegionsParams extends PaginationParams {
|
|
25
|
+
status?: 'active' | 'inactive' | 'deleted';
|
|
26
|
+
search?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface GetGeosParams extends PaginationParams {
|
|
29
|
+
region_id?: string;
|
|
30
|
+
region?: string;
|
|
31
|
+
is_used?: boolean;
|
|
32
|
+
search?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface GetDataParams extends PaginationParams {
|
|
35
|
+
region_id?: string;
|
|
36
|
+
region_ids?: string[];
|
|
37
|
+
time_range?: TimeRange;
|
|
38
|
+
relative_time?: RelativeTimeRange;
|
|
39
|
+
platform?: Platform;
|
|
40
|
+
platforms?: Platform[];
|
|
41
|
+
source_id?: string;
|
|
42
|
+
source_ids?: string[];
|
|
43
|
+
source_group_id?: string;
|
|
44
|
+
data_geo?: string[];
|
|
45
|
+
source_dominant_geos?: string[];
|
|
46
|
+
data_original_type?: string;
|
|
47
|
+
data_language?: string;
|
|
48
|
+
data_sentiment?: 'positive' | 'negative' | 'neutral' | 'mixed';
|
|
49
|
+
search?: string;
|
|
50
|
+
processing_status?: 'raw' | 'processed' | 'analyzed' | 'error';
|
|
51
|
+
fields?: string[];
|
|
52
|
+
exclude_fields?: string[];
|
|
53
|
+
}
|
|
54
|
+
export interface PaginatedResponse<T> {
|
|
55
|
+
data: T[];
|
|
56
|
+
pagination: {
|
|
57
|
+
page: number;
|
|
58
|
+
limit: number;
|
|
59
|
+
total: number;
|
|
60
|
+
total_pages: number;
|
|
61
|
+
has_next: boolean;
|
|
62
|
+
has_prev: boolean;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export interface SDKResponse<T> {
|
|
66
|
+
success: boolean;
|
|
67
|
+
data: T;
|
|
68
|
+
error?: string;
|
|
69
|
+
message?: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Harvester SDK - Client for interacting with the Harvester API
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const harvester = new HarvesterSDK({
|
|
77
|
+
* baseUrl: 'https://api.harvester.io',
|
|
78
|
+
* apiKey: 'your-api-key'
|
|
79
|
+
* });
|
|
80
|
+
*
|
|
81
|
+
* // Get all regions
|
|
82
|
+
* const regions = await harvester.getRegions();
|
|
83
|
+
*
|
|
84
|
+
* // Get geos by region
|
|
85
|
+
* const geos = await harvester.getGeosByRegion('region-id');
|
|
86
|
+
*
|
|
87
|
+
* // Get data with filters
|
|
88
|
+
* const data = await harvester.getData({
|
|
89
|
+
* region_id: 'region-id',
|
|
90
|
+
* platform: 'telegram',
|
|
91
|
+
* time_range: { start: Date.now() - 86400000, end: Date.now() }
|
|
92
|
+
* });
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
export declare class HarvesterSDK {
|
|
96
|
+
private client;
|
|
97
|
+
private config;
|
|
98
|
+
constructor(config: HarvesterSDKConfig);
|
|
99
|
+
/**
|
|
100
|
+
* Set or update the API key
|
|
101
|
+
*/
|
|
102
|
+
setApiKey(apiKey: string): void;
|
|
103
|
+
/**
|
|
104
|
+
* Make a custom request to the API
|
|
105
|
+
*/
|
|
106
|
+
request<T>(config: AxiosRequestConfig): Promise<T>;
|
|
107
|
+
/**
|
|
108
|
+
* Get all regions
|
|
109
|
+
*
|
|
110
|
+
* @param params - Optional filter and pagination parameters
|
|
111
|
+
* @returns Paginated list of regions
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```typescript
|
|
115
|
+
* const regions = await harvester.getRegions({ status: 'active' });
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
getRegions(params?: GetRegionsParams): Promise<PaginatedResponse<RegionType>>;
|
|
119
|
+
/**
|
|
120
|
+
* Get a single region by ID
|
|
121
|
+
*
|
|
122
|
+
* @param regionId - The region ID
|
|
123
|
+
* @returns The region object
|
|
124
|
+
*/
|
|
125
|
+
getRegionById(regionId: string): Promise<RegionType>;
|
|
126
|
+
/**
|
|
127
|
+
* Get a region by slug
|
|
128
|
+
*
|
|
129
|
+
* @param slug - The region slug (e.g., 'new-york')
|
|
130
|
+
* @returns The region object
|
|
131
|
+
*/
|
|
132
|
+
getRegionBySlug(slug: string): Promise<RegionType>;
|
|
133
|
+
/**
|
|
134
|
+
* Get all geographies
|
|
135
|
+
*
|
|
136
|
+
* @param params - Optional filter and pagination parameters
|
|
137
|
+
* @returns Paginated list of geographies
|
|
138
|
+
*/
|
|
139
|
+
getGeos(params?: GetGeosParams): Promise<PaginatedResponse<GeoType>>;
|
|
140
|
+
/**
|
|
141
|
+
* Get geographies by region ID
|
|
142
|
+
*
|
|
143
|
+
* @param regionId - The region ID
|
|
144
|
+
* @param params - Optional pagination parameters
|
|
145
|
+
* @returns Paginated list of geographies in the region
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```typescript
|
|
149
|
+
* const geos = await harvester.getGeosByRegion('region-id', { limit: 50 });
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
getGeosByRegion(regionId: string, params?: PaginationParams): Promise<PaginatedResponse<GeoType>>;
|
|
153
|
+
/**
|
|
154
|
+
* Get a single geography by ID
|
|
155
|
+
*
|
|
156
|
+
* @param geoId - The geography ID
|
|
157
|
+
* @returns The geography object
|
|
158
|
+
*/
|
|
159
|
+
getGeoById(geoId: string): Promise<GeoType>;
|
|
160
|
+
/**
|
|
161
|
+
* Search geographies by text
|
|
162
|
+
*
|
|
163
|
+
* @param query - Search query
|
|
164
|
+
* @param params - Optional filter parameters
|
|
165
|
+
* @returns Paginated list of matching geographies
|
|
166
|
+
*/
|
|
167
|
+
searchGeos(query: string, params?: GetGeosParams): Promise<PaginatedResponse<GeoType>>;
|
|
168
|
+
/**
|
|
169
|
+
* Get data with filters
|
|
170
|
+
*
|
|
171
|
+
* @param params - Filter and pagination parameters
|
|
172
|
+
* @returns Paginated list of data items
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```typescript
|
|
176
|
+
* // Get telegram data from a specific region in the last 24 hours
|
|
177
|
+
* const data = await harvester.getData({
|
|
178
|
+
* region_id: 'region-id',
|
|
179
|
+
* platform: 'telegram',
|
|
180
|
+
* relative_time: { value: 24, unit: 'hours' }
|
|
181
|
+
* });
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
getData(params?: GetDataParams): Promise<PaginatedResponse<DataType>>;
|
|
185
|
+
/**
|
|
186
|
+
* Get data by region ID
|
|
187
|
+
*
|
|
188
|
+
* @param regionId - The region ID
|
|
189
|
+
* @param params - Optional filter parameters
|
|
190
|
+
* @returns Paginated list of data items from the region
|
|
191
|
+
*/
|
|
192
|
+
getDataByRegion(regionId: string, params?: Omit<GetDataParams, 'region_id'>): Promise<PaginatedResponse<DataType>>;
|
|
193
|
+
/**
|
|
194
|
+
* Get data by platform
|
|
195
|
+
*
|
|
196
|
+
* @param platform - The platform to filter by
|
|
197
|
+
* @param params - Optional filter parameters
|
|
198
|
+
* @returns Paginated list of data items from the platform
|
|
199
|
+
*/
|
|
200
|
+
getDataByPlatform(platform: Platform, params?: Omit<GetDataParams, 'platform'>): Promise<PaginatedResponse<DataType>>;
|
|
201
|
+
/**
|
|
202
|
+
* Get data within a time range
|
|
203
|
+
*
|
|
204
|
+
* @param timeRange - The time range (start and end timestamps)
|
|
205
|
+
* @param params - Optional filter parameters
|
|
206
|
+
* @returns Paginated list of data items within the time range
|
|
207
|
+
*/
|
|
208
|
+
getDataByTimeRange(timeRange: TimeRange, params?: Omit<GetDataParams, 'time_range'>): Promise<PaginatedResponse<DataType>>;
|
|
209
|
+
/**
|
|
210
|
+
* Get data from relative time (e.g., last 24 hours)
|
|
211
|
+
*
|
|
212
|
+
* @param relativeTime - Relative time specification
|
|
213
|
+
* @param params - Optional filter parameters
|
|
214
|
+
* @returns Paginated list of data items
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* ```typescript
|
|
218
|
+
* const data = await harvester.getDataFromRelativeTime(
|
|
219
|
+
* { value: 7, unit: 'days' },
|
|
220
|
+
* { platform: 'telegram' }
|
|
221
|
+
* );
|
|
222
|
+
* ```
|
|
223
|
+
*/
|
|
224
|
+
getDataFromRelativeTime(relativeTime: RelativeTimeRange, params?: Omit<GetDataParams, 'relative_time'>): Promise<PaginatedResponse<DataType>>;
|
|
225
|
+
/**
|
|
226
|
+
* Get a single data item by ID
|
|
227
|
+
*
|
|
228
|
+
* @param dataId - The data item ID
|
|
229
|
+
* @returns The data object
|
|
230
|
+
*/
|
|
231
|
+
getDataById(dataId: string): Promise<DataType>;
|
|
232
|
+
/**
|
|
233
|
+
* Search data by text content
|
|
234
|
+
*
|
|
235
|
+
* @param query - Search query
|
|
236
|
+
* @param params - Optional filter parameters
|
|
237
|
+
* @returns Paginated list of matching data items
|
|
238
|
+
*/
|
|
239
|
+
searchData(query: string, params?: GetDataParams): Promise<PaginatedResponse<DataType>>;
|
|
240
|
+
/**
|
|
241
|
+
* Get data count by filters (without fetching all data)
|
|
242
|
+
*
|
|
243
|
+
* @param params - Filter parameters
|
|
244
|
+
* @returns Count of matching data items
|
|
245
|
+
*/
|
|
246
|
+
getDataCount(params?: GetDataParams): Promise<number>;
|
|
247
|
+
/**
|
|
248
|
+
* Get data aggregated by a field
|
|
249
|
+
*
|
|
250
|
+
* @param field - Field to aggregate by (e.g., 'platform', 'source_region_id')
|
|
251
|
+
* @param params - Optional filter parameters
|
|
252
|
+
* @returns Aggregation results
|
|
253
|
+
*/
|
|
254
|
+
getDataAggregation(field: string, params?: GetDataParams): Promise<{
|
|
255
|
+
_id: string;
|
|
256
|
+
count: number;
|
|
257
|
+
}[]>;
|
|
258
|
+
/**
|
|
259
|
+
* Convert relative time to absolute time range
|
|
260
|
+
*/
|
|
261
|
+
relativeToAbsoluteTime(relative: RelativeTimeRange): TimeRange;
|
|
262
|
+
/**
|
|
263
|
+
* Build query parameters, removing undefined values
|
|
264
|
+
*/
|
|
265
|
+
private buildQueryParams;
|
|
266
|
+
/**
|
|
267
|
+
* Build data-specific query parameters
|
|
268
|
+
*/
|
|
269
|
+
private buildDataQueryParams;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Custom error class for Harvester SDK errors
|
|
273
|
+
*/
|
|
274
|
+
export declare class HarvesterSDKError extends Error {
|
|
275
|
+
status?: number;
|
|
276
|
+
data?: any;
|
|
277
|
+
constructor(message: string, status?: number, data?: any);
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Create a new Harvester SDK instance
|
|
281
|
+
*
|
|
282
|
+
* @param config - SDK configuration
|
|
283
|
+
* @returns HarvesterSDK instance
|
|
284
|
+
*
|
|
285
|
+
* @example
|
|
286
|
+
* ```typescript
|
|
287
|
+
* const harvester = createHarvesterSDK({
|
|
288
|
+
* baseUrl: 'https://api.harvester.io',
|
|
289
|
+
* apiKey: 'your-api-key'
|
|
290
|
+
* });
|
|
291
|
+
* ```
|
|
292
|
+
*/
|
|
293
|
+
export declare function createHarvesterSDK(config: HarvesterSDKConfig): HarvesterSDK;
|
|
294
|
+
export default HarvesterSDK;
|
package/dist/sdk.js
ADDED
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createHarvesterSDK = exports.HarvesterSDKError = exports.HarvesterSDK = void 0;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
/**
|
|
9
|
+
* Harvester SDK - Client for interacting with the Harvester API
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const harvester = new HarvesterSDK({
|
|
14
|
+
* baseUrl: 'https://api.harvester.io',
|
|
15
|
+
* apiKey: 'your-api-key'
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* // Get all regions
|
|
19
|
+
* const regions = await harvester.getRegions();
|
|
20
|
+
*
|
|
21
|
+
* // Get geos by region
|
|
22
|
+
* const geos = await harvester.getGeosByRegion('region-id');
|
|
23
|
+
*
|
|
24
|
+
* // Get data with filters
|
|
25
|
+
* const data = await harvester.getData({
|
|
26
|
+
* region_id: 'region-id',
|
|
27
|
+
* platform: 'telegram',
|
|
28
|
+
* time_range: { start: Date.now() - 86400000, end: Date.now() }
|
|
29
|
+
* });
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
class HarvesterSDK {
|
|
33
|
+
constructor(config) {
|
|
34
|
+
this.config = config;
|
|
35
|
+
this.client = axios_1.default.create({
|
|
36
|
+
baseURL: config.baseUrl,
|
|
37
|
+
timeout: config.timeout || 30000,
|
|
38
|
+
headers: {
|
|
39
|
+
'Content-Type': 'application/json',
|
|
40
|
+
...(config.apiKey && { Authorization: `Bearer ${config.apiKey}` }),
|
|
41
|
+
...config.headers,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
// Add response interceptor for error handling
|
|
45
|
+
this.client.interceptors.response.use((response) => response, (error) => {
|
|
46
|
+
var _a, _b, _c, _d;
|
|
47
|
+
const message = ((_b = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.message) || error.message;
|
|
48
|
+
throw new HarvesterSDKError(message, (_c = error.response) === null || _c === void 0 ? void 0 : _c.status, (_d = error.response) === null || _d === void 0 ? void 0 : _d.data);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Set or update the API key
|
|
53
|
+
*/
|
|
54
|
+
setApiKey(apiKey) {
|
|
55
|
+
this.config.apiKey = apiKey;
|
|
56
|
+
this.client.defaults.headers.common['Authorization'] = `Bearer ${apiKey}`;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Make a custom request to the API
|
|
60
|
+
*/
|
|
61
|
+
async request(config) {
|
|
62
|
+
const response = await this.client.request(config);
|
|
63
|
+
return response.data;
|
|
64
|
+
}
|
|
65
|
+
// ============================================
|
|
66
|
+
// REGIONS
|
|
67
|
+
// ============================================
|
|
68
|
+
/**
|
|
69
|
+
* Get all regions
|
|
70
|
+
*
|
|
71
|
+
* @param params - Optional filter and pagination parameters
|
|
72
|
+
* @returns Paginated list of regions
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const regions = await harvester.getRegions({ status: 'active' });
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
async getRegions(params) {
|
|
80
|
+
const response = await this.client.get('/regions', {
|
|
81
|
+
params: this.buildQueryParams(params),
|
|
82
|
+
});
|
|
83
|
+
return response.data;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get a single region by ID
|
|
87
|
+
*
|
|
88
|
+
* @param regionId - The region ID
|
|
89
|
+
* @returns The region object
|
|
90
|
+
*/
|
|
91
|
+
async getRegionById(regionId) {
|
|
92
|
+
const response = await this.client.get(`/regions/${regionId}`);
|
|
93
|
+
return response.data.data;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Get a region by slug
|
|
97
|
+
*
|
|
98
|
+
* @param slug - The region slug (e.g., 'new-york')
|
|
99
|
+
* @returns The region object
|
|
100
|
+
*/
|
|
101
|
+
async getRegionBySlug(slug) {
|
|
102
|
+
const response = await this.client.get(`/regions/slug/${slug}`);
|
|
103
|
+
return response.data.data;
|
|
104
|
+
}
|
|
105
|
+
// ============================================
|
|
106
|
+
// GEOGRAPHIES
|
|
107
|
+
// ============================================
|
|
108
|
+
/**
|
|
109
|
+
* Get all geographies
|
|
110
|
+
*
|
|
111
|
+
* @param params - Optional filter and pagination parameters
|
|
112
|
+
* @returns Paginated list of geographies
|
|
113
|
+
*/
|
|
114
|
+
async getGeos(params) {
|
|
115
|
+
const response = await this.client.get('/geos', {
|
|
116
|
+
params: this.buildQueryParams(params),
|
|
117
|
+
});
|
|
118
|
+
return response.data;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Get geographies by region ID
|
|
122
|
+
*
|
|
123
|
+
* @param regionId - The region ID
|
|
124
|
+
* @param params - Optional pagination parameters
|
|
125
|
+
* @returns Paginated list of geographies in the region
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```typescript
|
|
129
|
+
* const geos = await harvester.getGeosByRegion('region-id', { limit: 50 });
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
async getGeosByRegion(regionId, params) {
|
|
133
|
+
const response = await this.client.get(`/regions/${regionId}/geos`, {
|
|
134
|
+
params: this.buildQueryParams(params),
|
|
135
|
+
});
|
|
136
|
+
return response.data;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Get a single geography by ID
|
|
140
|
+
*
|
|
141
|
+
* @param geoId - The geography ID
|
|
142
|
+
* @returns The geography object
|
|
143
|
+
*/
|
|
144
|
+
async getGeoById(geoId) {
|
|
145
|
+
const response = await this.client.get(`/geos/${geoId}`);
|
|
146
|
+
return response.data.data;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Search geographies by text
|
|
150
|
+
*
|
|
151
|
+
* @param query - Search query
|
|
152
|
+
* @param params - Optional filter parameters
|
|
153
|
+
* @returns Paginated list of matching geographies
|
|
154
|
+
*/
|
|
155
|
+
async searchGeos(query, params) {
|
|
156
|
+
const response = await this.client.get('/geos/search', {
|
|
157
|
+
params: this.buildQueryParams({ ...params, search: query }),
|
|
158
|
+
});
|
|
159
|
+
return response.data;
|
|
160
|
+
}
|
|
161
|
+
// ============================================
|
|
162
|
+
// DATA
|
|
163
|
+
// ============================================
|
|
164
|
+
/**
|
|
165
|
+
* Get data with filters
|
|
166
|
+
*
|
|
167
|
+
* @param params - Filter and pagination parameters
|
|
168
|
+
* @returns Paginated list of data items
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```typescript
|
|
172
|
+
* // Get telegram data from a specific region in the last 24 hours
|
|
173
|
+
* const data = await harvester.getData({
|
|
174
|
+
* region_id: 'region-id',
|
|
175
|
+
* platform: 'telegram',
|
|
176
|
+
* relative_time: { value: 24, unit: 'hours' }
|
|
177
|
+
* });
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
180
|
+
async getData(params) {
|
|
181
|
+
const queryParams = this.buildDataQueryParams(params);
|
|
182
|
+
const response = await this.client.get('/data', {
|
|
183
|
+
params: queryParams,
|
|
184
|
+
});
|
|
185
|
+
return response.data;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Get data by region ID
|
|
189
|
+
*
|
|
190
|
+
* @param regionId - The region ID
|
|
191
|
+
* @param params - Optional filter parameters
|
|
192
|
+
* @returns Paginated list of data items from the region
|
|
193
|
+
*/
|
|
194
|
+
async getDataByRegion(regionId, params) {
|
|
195
|
+
return this.getData({ ...params, region_id: regionId });
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Get data by platform
|
|
199
|
+
*
|
|
200
|
+
* @param platform - The platform to filter by
|
|
201
|
+
* @param params - Optional filter parameters
|
|
202
|
+
* @returns Paginated list of data items from the platform
|
|
203
|
+
*/
|
|
204
|
+
async getDataByPlatform(platform, params) {
|
|
205
|
+
return this.getData({ ...params, platform });
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Get data within a time range
|
|
209
|
+
*
|
|
210
|
+
* @param timeRange - The time range (start and end timestamps)
|
|
211
|
+
* @param params - Optional filter parameters
|
|
212
|
+
* @returns Paginated list of data items within the time range
|
|
213
|
+
*/
|
|
214
|
+
async getDataByTimeRange(timeRange, params) {
|
|
215
|
+
return this.getData({ ...params, time_range: timeRange });
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Get data from relative time (e.g., last 24 hours)
|
|
219
|
+
*
|
|
220
|
+
* @param relativeTime - Relative time specification
|
|
221
|
+
* @param params - Optional filter parameters
|
|
222
|
+
* @returns Paginated list of data items
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* ```typescript
|
|
226
|
+
* const data = await harvester.getDataFromRelativeTime(
|
|
227
|
+
* { value: 7, unit: 'days' },
|
|
228
|
+
* { platform: 'telegram' }
|
|
229
|
+
* );
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
async getDataFromRelativeTime(relativeTime, params) {
|
|
233
|
+
return this.getData({ ...params, relative_time: relativeTime });
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Get a single data item by ID
|
|
237
|
+
*
|
|
238
|
+
* @param dataId - The data item ID
|
|
239
|
+
* @returns The data object
|
|
240
|
+
*/
|
|
241
|
+
async getDataById(dataId) {
|
|
242
|
+
const response = await this.client.get(`/data/${dataId}`);
|
|
243
|
+
return response.data.data;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Search data by text content
|
|
247
|
+
*
|
|
248
|
+
* @param query - Search query
|
|
249
|
+
* @param params - Optional filter parameters
|
|
250
|
+
* @returns Paginated list of matching data items
|
|
251
|
+
*/
|
|
252
|
+
async searchData(query, params) {
|
|
253
|
+
return this.getData({ ...params, search: query });
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Get data count by filters (without fetching all data)
|
|
257
|
+
*
|
|
258
|
+
* @param params - Filter parameters
|
|
259
|
+
* @returns Count of matching data items
|
|
260
|
+
*/
|
|
261
|
+
async getDataCount(params) {
|
|
262
|
+
const queryParams = this.buildDataQueryParams(params);
|
|
263
|
+
const response = await this.client.get('/data/count', {
|
|
264
|
+
params: queryParams,
|
|
265
|
+
});
|
|
266
|
+
return response.data.count;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Get data aggregated by a field
|
|
270
|
+
*
|
|
271
|
+
* @param field - Field to aggregate by (e.g., 'platform', 'source_region_id')
|
|
272
|
+
* @param params - Optional filter parameters
|
|
273
|
+
* @returns Aggregation results
|
|
274
|
+
*/
|
|
275
|
+
async getDataAggregation(field, params) {
|
|
276
|
+
const queryParams = this.buildDataQueryParams(params);
|
|
277
|
+
const response = await this.client.get(`/data/aggregate/${field}`, { params: queryParams });
|
|
278
|
+
return response.data.data;
|
|
279
|
+
}
|
|
280
|
+
// ============================================
|
|
281
|
+
// HELPER METHODS
|
|
282
|
+
// ============================================
|
|
283
|
+
/**
|
|
284
|
+
* Convert relative time to absolute time range
|
|
285
|
+
*/
|
|
286
|
+
relativeToAbsoluteTime(relative) {
|
|
287
|
+
const now = Date.now();
|
|
288
|
+
const multipliers = {
|
|
289
|
+
minutes: 60 * 1000,
|
|
290
|
+
hours: 60 * 60 * 1000,
|
|
291
|
+
days: 24 * 60 * 60 * 1000,
|
|
292
|
+
weeks: 7 * 24 * 60 * 60 * 1000,
|
|
293
|
+
months: 30 * 24 * 60 * 60 * 1000,
|
|
294
|
+
};
|
|
295
|
+
const ms = relative.value * multipliers[relative.unit];
|
|
296
|
+
return {
|
|
297
|
+
start: now - ms,
|
|
298
|
+
end: now,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Build query parameters, removing undefined values
|
|
303
|
+
*/
|
|
304
|
+
buildQueryParams(params) {
|
|
305
|
+
if (!params)
|
|
306
|
+
return {};
|
|
307
|
+
const cleaned = {};
|
|
308
|
+
for (const [key, value] of Object.entries(params)) {
|
|
309
|
+
if (value !== undefined && value !== null) {
|
|
310
|
+
if (Array.isArray(value)) {
|
|
311
|
+
cleaned[key] = value.join(',');
|
|
312
|
+
}
|
|
313
|
+
else if (typeof value === 'object') {
|
|
314
|
+
cleaned[key] = JSON.stringify(value);
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
cleaned[key] = value;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return cleaned;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Build data-specific query parameters
|
|
325
|
+
*/
|
|
326
|
+
buildDataQueryParams(params) {
|
|
327
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
328
|
+
if (!params)
|
|
329
|
+
return {};
|
|
330
|
+
const queryParams = {};
|
|
331
|
+
// Handle time range
|
|
332
|
+
if (params.time_range) {
|
|
333
|
+
queryParams.start_time = params.time_range.start;
|
|
334
|
+
queryParams.end_time = params.time_range.end;
|
|
335
|
+
}
|
|
336
|
+
else if (params.relative_time) {
|
|
337
|
+
const absoluteTime = this.relativeToAbsoluteTime(params.relative_time);
|
|
338
|
+
queryParams.start_time = absoluteTime.start;
|
|
339
|
+
queryParams.end_time = absoluteTime.end;
|
|
340
|
+
}
|
|
341
|
+
// Handle arrays
|
|
342
|
+
if ((_a = params.region_ids) === null || _a === void 0 ? void 0 : _a.length) {
|
|
343
|
+
queryParams.region_ids = params.region_ids.join(',');
|
|
344
|
+
}
|
|
345
|
+
if ((_b = params.platforms) === null || _b === void 0 ? void 0 : _b.length) {
|
|
346
|
+
queryParams.platforms = params.platforms.join(',');
|
|
347
|
+
}
|
|
348
|
+
if ((_c = params.source_ids) === null || _c === void 0 ? void 0 : _c.length) {
|
|
349
|
+
queryParams.source_ids = params.source_ids.join(',');
|
|
350
|
+
}
|
|
351
|
+
if ((_d = params.data_geo) === null || _d === void 0 ? void 0 : _d.length) {
|
|
352
|
+
queryParams.data_geo = params.data_geo.join(',');
|
|
353
|
+
}
|
|
354
|
+
if ((_e = params.source_dominant_geos) === null || _e === void 0 ? void 0 : _e.length) {
|
|
355
|
+
queryParams.source_dominant_geos = params.source_dominant_geos.join(',');
|
|
356
|
+
}
|
|
357
|
+
if ((_f = params.fields) === null || _f === void 0 ? void 0 : _f.length) {
|
|
358
|
+
queryParams.fields = params.fields.join(',');
|
|
359
|
+
}
|
|
360
|
+
if ((_g = params.exclude_fields) === null || _g === void 0 ? void 0 : _g.length) {
|
|
361
|
+
queryParams.exclude_fields = params.exclude_fields.join(',');
|
|
362
|
+
}
|
|
363
|
+
// Handle simple parameters
|
|
364
|
+
const simpleParams = [
|
|
365
|
+
'region_id',
|
|
366
|
+
'platform',
|
|
367
|
+
'source_id',
|
|
368
|
+
'source_group_id',
|
|
369
|
+
'data_original_type',
|
|
370
|
+
'data_language',
|
|
371
|
+
'data_sentiment',
|
|
372
|
+
'search',
|
|
373
|
+
'processing_status',
|
|
374
|
+
'page',
|
|
375
|
+
'limit',
|
|
376
|
+
'sort_by',
|
|
377
|
+
'sort_order',
|
|
378
|
+
];
|
|
379
|
+
for (const param of simpleParams) {
|
|
380
|
+
if (params[param] !== undefined) {
|
|
381
|
+
queryParams[param] = params[param];
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return queryParams;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
exports.HarvesterSDK = HarvesterSDK;
|
|
388
|
+
/**
|
|
389
|
+
* Custom error class for Harvester SDK errors
|
|
390
|
+
*/
|
|
391
|
+
class HarvesterSDKError extends Error {
|
|
392
|
+
constructor(message, status, data) {
|
|
393
|
+
super(message);
|
|
394
|
+
this.name = 'HarvesterSDKError';
|
|
395
|
+
this.status = status;
|
|
396
|
+
this.data = data;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
exports.HarvesterSDKError = HarvesterSDKError;
|
|
400
|
+
/**
|
|
401
|
+
* Create a new Harvester SDK instance
|
|
402
|
+
*
|
|
403
|
+
* @param config - SDK configuration
|
|
404
|
+
* @returns HarvesterSDK instance
|
|
405
|
+
*
|
|
406
|
+
* @example
|
|
407
|
+
* ```typescript
|
|
408
|
+
* const harvester = createHarvesterSDK({
|
|
409
|
+
* baseUrl: 'https://api.harvester.io',
|
|
410
|
+
* apiKey: 'your-api-key'
|
|
411
|
+
* });
|
|
412
|
+
* ```
|
|
413
|
+
*/
|
|
414
|
+
function createHarvesterSDK(config) {
|
|
415
|
+
return new HarvesterSDK(config);
|
|
416
|
+
}
|
|
417
|
+
exports.createHarvesterSDK = createHarvesterSDK;
|
|
418
|
+
exports.default = HarvesterSDK;
|
package/index.ts
CHANGED
package/package.json
CHANGED
package/sdk.ts
ADDED
|
@@ -0,0 +1,558 @@
|
|
|
1
|
+
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
|
|
2
|
+
import {
|
|
3
|
+
RegionType,
|
|
4
|
+
GeoType,
|
|
5
|
+
DataType,
|
|
6
|
+
platformsList,
|
|
7
|
+
} from './types';
|
|
8
|
+
|
|
9
|
+
// SDK Configuration
|
|
10
|
+
export interface HarvesterSDKConfig {
|
|
11
|
+
baseUrl: string;
|
|
12
|
+
apiKey?: string;
|
|
13
|
+
timeout?: number;
|
|
14
|
+
headers?: Record<string, string>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Query Parameters
|
|
18
|
+
export interface TimeRange {
|
|
19
|
+
start: number; // Unix timestamp in milliseconds
|
|
20
|
+
end: number; // Unix timestamp in milliseconds
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface RelativeTimeRange {
|
|
24
|
+
value: number;
|
|
25
|
+
unit: 'minutes' | 'hours' | 'days' | 'weeks' | 'months';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type Platform = (typeof platformsList)[number];
|
|
29
|
+
|
|
30
|
+
export interface PaginationParams {
|
|
31
|
+
page?: number;
|
|
32
|
+
limit?: number;
|
|
33
|
+
sort_by?: string;
|
|
34
|
+
sort_order?: 'asc' | 'desc';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface GetRegionsParams extends PaginationParams {
|
|
38
|
+
status?: 'active' | 'inactive' | 'deleted';
|
|
39
|
+
search?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface GetGeosParams extends PaginationParams {
|
|
43
|
+
region_id?: string;
|
|
44
|
+
region?: string; // region slug or name
|
|
45
|
+
is_used?: boolean;
|
|
46
|
+
search?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface GetDataParams extends PaginationParams {
|
|
50
|
+
// Region filters
|
|
51
|
+
region_id?: string;
|
|
52
|
+
region_ids?: string[];
|
|
53
|
+
|
|
54
|
+
// Time filters
|
|
55
|
+
time_range?: TimeRange;
|
|
56
|
+
relative_time?: RelativeTimeRange;
|
|
57
|
+
|
|
58
|
+
// Platform filters
|
|
59
|
+
platform?: Platform;
|
|
60
|
+
platforms?: Platform[];
|
|
61
|
+
|
|
62
|
+
// Source filters
|
|
63
|
+
source_id?: string;
|
|
64
|
+
source_ids?: string[];
|
|
65
|
+
source_group_id?: string;
|
|
66
|
+
|
|
67
|
+
// Geo filters
|
|
68
|
+
data_geo?: string[];
|
|
69
|
+
source_dominant_geos?: string[];
|
|
70
|
+
|
|
71
|
+
// Content filters
|
|
72
|
+
data_original_type?: string;
|
|
73
|
+
data_language?: string;
|
|
74
|
+
data_sentiment?: 'positive' | 'negative' | 'neutral' | 'mixed';
|
|
75
|
+
|
|
76
|
+
// Text search
|
|
77
|
+
search?: string;
|
|
78
|
+
|
|
79
|
+
// Processing status
|
|
80
|
+
processing_status?: 'raw' | 'processed' | 'analyzed' | 'error';
|
|
81
|
+
|
|
82
|
+
// Include/exclude fields
|
|
83
|
+
fields?: string[];
|
|
84
|
+
exclude_fields?: string[];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Response types
|
|
88
|
+
export interface PaginatedResponse<T> {
|
|
89
|
+
data: T[];
|
|
90
|
+
pagination: {
|
|
91
|
+
page: number;
|
|
92
|
+
limit: number;
|
|
93
|
+
total: number;
|
|
94
|
+
total_pages: number;
|
|
95
|
+
has_next: boolean;
|
|
96
|
+
has_prev: boolean;
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface SDKResponse<T> {
|
|
101
|
+
success: boolean;
|
|
102
|
+
data: T;
|
|
103
|
+
error?: string;
|
|
104
|
+
message?: string;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Harvester SDK - Client for interacting with the Harvester API
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```typescript
|
|
112
|
+
* const harvester = new HarvesterSDK({
|
|
113
|
+
* baseUrl: 'https://api.harvester.io',
|
|
114
|
+
* apiKey: 'your-api-key'
|
|
115
|
+
* });
|
|
116
|
+
*
|
|
117
|
+
* // Get all regions
|
|
118
|
+
* const regions = await harvester.getRegions();
|
|
119
|
+
*
|
|
120
|
+
* // Get geos by region
|
|
121
|
+
* const geos = await harvester.getGeosByRegion('region-id');
|
|
122
|
+
*
|
|
123
|
+
* // Get data with filters
|
|
124
|
+
* const data = await harvester.getData({
|
|
125
|
+
* region_id: 'region-id',
|
|
126
|
+
* platform: 'telegram',
|
|
127
|
+
* time_range: { start: Date.now() - 86400000, end: Date.now() }
|
|
128
|
+
* });
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
export class HarvesterSDK {
|
|
132
|
+
private client: AxiosInstance;
|
|
133
|
+
private config: HarvesterSDKConfig;
|
|
134
|
+
|
|
135
|
+
constructor(config: HarvesterSDKConfig) {
|
|
136
|
+
this.config = config;
|
|
137
|
+
this.client = axios.create({
|
|
138
|
+
baseURL: config.baseUrl,
|
|
139
|
+
timeout: config.timeout || 30000,
|
|
140
|
+
headers: {
|
|
141
|
+
'Content-Type': 'application/json',
|
|
142
|
+
...(config.apiKey && { Authorization: `Bearer ${config.apiKey}` }),
|
|
143
|
+
...config.headers,
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Add response interceptor for error handling
|
|
148
|
+
this.client.interceptors.response.use(
|
|
149
|
+
(response) => response,
|
|
150
|
+
(error) => {
|
|
151
|
+
const message = error.response?.data?.message || error.message;
|
|
152
|
+
throw new HarvesterSDKError(message, error.response?.status, error.response?.data);
|
|
153
|
+
}
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Set or update the API key
|
|
159
|
+
*/
|
|
160
|
+
setApiKey(apiKey: string): void {
|
|
161
|
+
this.config.apiKey = apiKey;
|
|
162
|
+
this.client.defaults.headers.common['Authorization'] = `Bearer ${apiKey}`;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Make a custom request to the API
|
|
167
|
+
*/
|
|
168
|
+
async request<T>(config: AxiosRequestConfig): Promise<T> {
|
|
169
|
+
const response = await this.client.request<T>(config);
|
|
170
|
+
return response.data;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ============================================
|
|
174
|
+
// REGIONS
|
|
175
|
+
// ============================================
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Get all regions
|
|
179
|
+
*
|
|
180
|
+
* @param params - Optional filter and pagination parameters
|
|
181
|
+
* @returns Paginated list of regions
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* ```typescript
|
|
185
|
+
* const regions = await harvester.getRegions({ status: 'active' });
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
async getRegions(params?: GetRegionsParams): Promise<PaginatedResponse<RegionType>> {
|
|
189
|
+
const response = await this.client.get<PaginatedResponse<RegionType>>('/regions', {
|
|
190
|
+
params: this.buildQueryParams(params),
|
|
191
|
+
});
|
|
192
|
+
return response.data;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Get a single region by ID
|
|
197
|
+
*
|
|
198
|
+
* @param regionId - The region ID
|
|
199
|
+
* @returns The region object
|
|
200
|
+
*/
|
|
201
|
+
async getRegionById(regionId: string): Promise<RegionType> {
|
|
202
|
+
const response = await this.client.get<SDKResponse<RegionType>>(`/regions/${regionId}`);
|
|
203
|
+
return response.data.data;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Get a region by slug
|
|
208
|
+
*
|
|
209
|
+
* @param slug - The region slug (e.g., 'new-york')
|
|
210
|
+
* @returns The region object
|
|
211
|
+
*/
|
|
212
|
+
async getRegionBySlug(slug: string): Promise<RegionType> {
|
|
213
|
+
const response = await this.client.get<SDKResponse<RegionType>>(`/regions/slug/${slug}`);
|
|
214
|
+
return response.data.data;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// ============================================
|
|
218
|
+
// GEOGRAPHIES
|
|
219
|
+
// ============================================
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Get all geographies
|
|
223
|
+
*
|
|
224
|
+
* @param params - Optional filter and pagination parameters
|
|
225
|
+
* @returns Paginated list of geographies
|
|
226
|
+
*/
|
|
227
|
+
async getGeos(params?: GetGeosParams): Promise<PaginatedResponse<GeoType>> {
|
|
228
|
+
const response = await this.client.get<PaginatedResponse<GeoType>>('/geos', {
|
|
229
|
+
params: this.buildQueryParams(params),
|
|
230
|
+
});
|
|
231
|
+
return response.data;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Get geographies by region ID
|
|
236
|
+
*
|
|
237
|
+
* @param regionId - The region ID
|
|
238
|
+
* @param params - Optional pagination parameters
|
|
239
|
+
* @returns Paginated list of geographies in the region
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* ```typescript
|
|
243
|
+
* const geos = await harvester.getGeosByRegion('region-id', { limit: 50 });
|
|
244
|
+
* ```
|
|
245
|
+
*/
|
|
246
|
+
async getGeosByRegion(regionId: string, params?: PaginationParams): Promise<PaginatedResponse<GeoType>> {
|
|
247
|
+
const response = await this.client.get<PaginatedResponse<GeoType>>(`/regions/${regionId}/geos`, {
|
|
248
|
+
params: this.buildQueryParams(params),
|
|
249
|
+
});
|
|
250
|
+
return response.data;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Get a single geography by ID
|
|
255
|
+
*
|
|
256
|
+
* @param geoId - The geography ID
|
|
257
|
+
* @returns The geography object
|
|
258
|
+
*/
|
|
259
|
+
async getGeoById(geoId: string): Promise<GeoType> {
|
|
260
|
+
const response = await this.client.get<SDKResponse<GeoType>>(`/geos/${geoId}`);
|
|
261
|
+
return response.data.data;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Search geographies by text
|
|
266
|
+
*
|
|
267
|
+
* @param query - Search query
|
|
268
|
+
* @param params - Optional filter parameters
|
|
269
|
+
* @returns Paginated list of matching geographies
|
|
270
|
+
*/
|
|
271
|
+
async searchGeos(query: string, params?: GetGeosParams): Promise<PaginatedResponse<GeoType>> {
|
|
272
|
+
const response = await this.client.get<PaginatedResponse<GeoType>>('/geos/search', {
|
|
273
|
+
params: this.buildQueryParams({ ...params, search: query }),
|
|
274
|
+
});
|
|
275
|
+
return response.data;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// ============================================
|
|
279
|
+
// DATA
|
|
280
|
+
// ============================================
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Get data with filters
|
|
284
|
+
*
|
|
285
|
+
* @param params - Filter and pagination parameters
|
|
286
|
+
* @returns Paginated list of data items
|
|
287
|
+
*
|
|
288
|
+
* @example
|
|
289
|
+
* ```typescript
|
|
290
|
+
* // Get telegram data from a specific region in the last 24 hours
|
|
291
|
+
* const data = await harvester.getData({
|
|
292
|
+
* region_id: 'region-id',
|
|
293
|
+
* platform: 'telegram',
|
|
294
|
+
* relative_time: { value: 24, unit: 'hours' }
|
|
295
|
+
* });
|
|
296
|
+
* ```
|
|
297
|
+
*/
|
|
298
|
+
async getData(params?: GetDataParams): Promise<PaginatedResponse<DataType>> {
|
|
299
|
+
const queryParams = this.buildDataQueryParams(params);
|
|
300
|
+
const response = await this.client.get<PaginatedResponse<DataType>>('/data', {
|
|
301
|
+
params: queryParams,
|
|
302
|
+
});
|
|
303
|
+
return response.data;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Get data by region ID
|
|
308
|
+
*
|
|
309
|
+
* @param regionId - The region ID
|
|
310
|
+
* @param params - Optional filter parameters
|
|
311
|
+
* @returns Paginated list of data items from the region
|
|
312
|
+
*/
|
|
313
|
+
async getDataByRegion(regionId: string, params?: Omit<GetDataParams, 'region_id'>): Promise<PaginatedResponse<DataType>> {
|
|
314
|
+
return this.getData({ ...params, region_id: regionId });
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Get data by platform
|
|
319
|
+
*
|
|
320
|
+
* @param platform - The platform to filter by
|
|
321
|
+
* @param params - Optional filter parameters
|
|
322
|
+
* @returns Paginated list of data items from the platform
|
|
323
|
+
*/
|
|
324
|
+
async getDataByPlatform(platform: Platform, params?: Omit<GetDataParams, 'platform'>): Promise<PaginatedResponse<DataType>> {
|
|
325
|
+
return this.getData({ ...params, platform });
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Get data within a time range
|
|
330
|
+
*
|
|
331
|
+
* @param timeRange - The time range (start and end timestamps)
|
|
332
|
+
* @param params - Optional filter parameters
|
|
333
|
+
* @returns Paginated list of data items within the time range
|
|
334
|
+
*/
|
|
335
|
+
async getDataByTimeRange(timeRange: TimeRange, params?: Omit<GetDataParams, 'time_range'>): Promise<PaginatedResponse<DataType>> {
|
|
336
|
+
return this.getData({ ...params, time_range: timeRange });
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Get data from relative time (e.g., last 24 hours)
|
|
341
|
+
*
|
|
342
|
+
* @param relativeTime - Relative time specification
|
|
343
|
+
* @param params - Optional filter parameters
|
|
344
|
+
* @returns Paginated list of data items
|
|
345
|
+
*
|
|
346
|
+
* @example
|
|
347
|
+
* ```typescript
|
|
348
|
+
* const data = await harvester.getDataFromRelativeTime(
|
|
349
|
+
* { value: 7, unit: 'days' },
|
|
350
|
+
* { platform: 'telegram' }
|
|
351
|
+
* );
|
|
352
|
+
* ```
|
|
353
|
+
*/
|
|
354
|
+
async getDataFromRelativeTime(relativeTime: RelativeTimeRange, params?: Omit<GetDataParams, 'relative_time'>): Promise<PaginatedResponse<DataType>> {
|
|
355
|
+
return this.getData({ ...params, relative_time: relativeTime });
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Get a single data item by ID
|
|
360
|
+
*
|
|
361
|
+
* @param dataId - The data item ID
|
|
362
|
+
* @returns The data object
|
|
363
|
+
*/
|
|
364
|
+
async getDataById(dataId: string): Promise<DataType> {
|
|
365
|
+
const response = await this.client.get<SDKResponse<DataType>>(`/data/${dataId}`);
|
|
366
|
+
return response.data.data;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Search data by text content
|
|
371
|
+
*
|
|
372
|
+
* @param query - Search query
|
|
373
|
+
* @param params - Optional filter parameters
|
|
374
|
+
* @returns Paginated list of matching data items
|
|
375
|
+
*/
|
|
376
|
+
async searchData(query: string, params?: GetDataParams): Promise<PaginatedResponse<DataType>> {
|
|
377
|
+
return this.getData({ ...params, search: query });
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Get data count by filters (without fetching all data)
|
|
382
|
+
*
|
|
383
|
+
* @param params - Filter parameters
|
|
384
|
+
* @returns Count of matching data items
|
|
385
|
+
*/
|
|
386
|
+
async getDataCount(params?: GetDataParams): Promise<number> {
|
|
387
|
+
const queryParams = this.buildDataQueryParams(params);
|
|
388
|
+
const response = await this.client.get<{ count: number }>('/data/count', {
|
|
389
|
+
params: queryParams,
|
|
390
|
+
});
|
|
391
|
+
return response.data.count;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Get data aggregated by a field
|
|
396
|
+
*
|
|
397
|
+
* @param field - Field to aggregate by (e.g., 'platform', 'source_region_id')
|
|
398
|
+
* @param params - Optional filter parameters
|
|
399
|
+
* @returns Aggregation results
|
|
400
|
+
*/
|
|
401
|
+
async getDataAggregation(
|
|
402
|
+
field: string,
|
|
403
|
+
params?: GetDataParams
|
|
404
|
+
): Promise<{ _id: string; count: number }[]> {
|
|
405
|
+
const queryParams = this.buildDataQueryParams(params);
|
|
406
|
+
const response = await this.client.get<{ data: { _id: string; count: number }[] }>(
|
|
407
|
+
`/data/aggregate/${field}`,
|
|
408
|
+
{ params: queryParams }
|
|
409
|
+
);
|
|
410
|
+
return response.data.data;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// ============================================
|
|
414
|
+
// HELPER METHODS
|
|
415
|
+
// ============================================
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Convert relative time to absolute time range
|
|
419
|
+
*/
|
|
420
|
+
relativeToAbsoluteTime(relative: RelativeTimeRange): TimeRange {
|
|
421
|
+
const now = Date.now();
|
|
422
|
+
const multipliers: Record<string, number> = {
|
|
423
|
+
minutes: 60 * 1000,
|
|
424
|
+
hours: 60 * 60 * 1000,
|
|
425
|
+
days: 24 * 60 * 60 * 1000,
|
|
426
|
+
weeks: 7 * 24 * 60 * 60 * 1000,
|
|
427
|
+
months: 30 * 24 * 60 * 60 * 1000,
|
|
428
|
+
};
|
|
429
|
+
const ms = relative.value * multipliers[relative.unit];
|
|
430
|
+
return {
|
|
431
|
+
start: now - ms,
|
|
432
|
+
end: now,
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Build query parameters, removing undefined values
|
|
438
|
+
*/
|
|
439
|
+
private buildQueryParams(params?: Record<string, any>): Record<string, any> {
|
|
440
|
+
if (!params) return {};
|
|
441
|
+
|
|
442
|
+
const cleaned: Record<string, any> = {};
|
|
443
|
+
for (const [key, value] of Object.entries(params)) {
|
|
444
|
+
if (value !== undefined && value !== null) {
|
|
445
|
+
if (Array.isArray(value)) {
|
|
446
|
+
cleaned[key] = value.join(',');
|
|
447
|
+
} else if (typeof value === 'object') {
|
|
448
|
+
cleaned[key] = JSON.stringify(value);
|
|
449
|
+
} else {
|
|
450
|
+
cleaned[key] = value;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
return cleaned;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Build data-specific query parameters
|
|
459
|
+
*/
|
|
460
|
+
private buildDataQueryParams(params?: GetDataParams): Record<string, any> {
|
|
461
|
+
if (!params) return {};
|
|
462
|
+
|
|
463
|
+
const queryParams: Record<string, any> = {};
|
|
464
|
+
|
|
465
|
+
// Handle time range
|
|
466
|
+
if (params.time_range) {
|
|
467
|
+
queryParams.start_time = params.time_range.start;
|
|
468
|
+
queryParams.end_time = params.time_range.end;
|
|
469
|
+
} else if (params.relative_time) {
|
|
470
|
+
const absoluteTime = this.relativeToAbsoluteTime(params.relative_time);
|
|
471
|
+
queryParams.start_time = absoluteTime.start;
|
|
472
|
+
queryParams.end_time = absoluteTime.end;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Handle arrays
|
|
476
|
+
if (params.region_ids?.length) {
|
|
477
|
+
queryParams.region_ids = params.region_ids.join(',');
|
|
478
|
+
}
|
|
479
|
+
if (params.platforms?.length) {
|
|
480
|
+
queryParams.platforms = params.platforms.join(',');
|
|
481
|
+
}
|
|
482
|
+
if (params.source_ids?.length) {
|
|
483
|
+
queryParams.source_ids = params.source_ids.join(',');
|
|
484
|
+
}
|
|
485
|
+
if (params.data_geo?.length) {
|
|
486
|
+
queryParams.data_geo = params.data_geo.join(',');
|
|
487
|
+
}
|
|
488
|
+
if (params.source_dominant_geos?.length) {
|
|
489
|
+
queryParams.source_dominant_geos = params.source_dominant_geos.join(',');
|
|
490
|
+
}
|
|
491
|
+
if (params.fields?.length) {
|
|
492
|
+
queryParams.fields = params.fields.join(',');
|
|
493
|
+
}
|
|
494
|
+
if (params.exclude_fields?.length) {
|
|
495
|
+
queryParams.exclude_fields = params.exclude_fields.join(',');
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Handle simple parameters
|
|
499
|
+
const simpleParams = [
|
|
500
|
+
'region_id',
|
|
501
|
+
'platform',
|
|
502
|
+
'source_id',
|
|
503
|
+
'source_group_id',
|
|
504
|
+
'data_original_type',
|
|
505
|
+
'data_language',
|
|
506
|
+
'data_sentiment',
|
|
507
|
+
'search',
|
|
508
|
+
'processing_status',
|
|
509
|
+
'page',
|
|
510
|
+
'limit',
|
|
511
|
+
'sort_by',
|
|
512
|
+
'sort_order',
|
|
513
|
+
];
|
|
514
|
+
|
|
515
|
+
for (const param of simpleParams) {
|
|
516
|
+
if (params[param as keyof GetDataParams] !== undefined) {
|
|
517
|
+
queryParams[param] = params[param as keyof GetDataParams];
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
return queryParams;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Custom error class for Harvester SDK errors
|
|
527
|
+
*/
|
|
528
|
+
export class HarvesterSDKError extends Error {
|
|
529
|
+
status?: number;
|
|
530
|
+
data?: any;
|
|
531
|
+
|
|
532
|
+
constructor(message: string, status?: number, data?: any) {
|
|
533
|
+
super(message);
|
|
534
|
+
this.name = 'HarvesterSDKError';
|
|
535
|
+
this.status = status;
|
|
536
|
+
this.data = data;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* Create a new Harvester SDK instance
|
|
542
|
+
*
|
|
543
|
+
* @param config - SDK configuration
|
|
544
|
+
* @returns HarvesterSDK instance
|
|
545
|
+
*
|
|
546
|
+
* @example
|
|
547
|
+
* ```typescript
|
|
548
|
+
* const harvester = createHarvesterSDK({
|
|
549
|
+
* baseUrl: 'https://api.harvester.io',
|
|
550
|
+
* apiKey: 'your-api-key'
|
|
551
|
+
* });
|
|
552
|
+
* ```
|
|
553
|
+
*/
|
|
554
|
+
export function createHarvesterSDK(config: HarvesterSDKConfig): HarvesterSDK {
|
|
555
|
+
return new HarvesterSDK(config);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
export default HarvesterSDK;
|