harvester_sdk 1.0.23 → 1.0.25

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 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
@@ -1,6 +1,10 @@
1
1
  // Export types for consumers
2
2
  export * from './types';
3
3
 
4
+ // Export SDK
5
+ export * from './sdk';
6
+ export { HarvesterSDK, createHarvesterSDK, HarvesterSDKError } from './sdk';
7
+
4
8
  import { Schema } from 'mongoose';
5
9
  import {
6
10
  generalStatusList,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "harvester_sdk",
3
- "version": "1.0.23",
3
+ "version": "1.0.25",
4
4
  "description": "SDK for interacting with the Harvester API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
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;