proofio-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,319 @@
1
+ # Proofio SDK
2
+
3
+ Official JavaScript/TypeScript SDK for the Proofio API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install proofio-sdk
9
+ # or
10
+ yarn add proofio-sdk
11
+ # or
12
+ pnpm add proofio-sdk
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ```typescript
18
+ import { Proofio } from 'proofio-sdk';
19
+
20
+ const proofio = new Proofio({ apiKey: 'your-api-key' });
21
+
22
+ // List reviews
23
+ const reviews = await proofio.reviews.list();
24
+
25
+ // Get insights summary
26
+ const summary = await proofio.insights.summary();
27
+
28
+ // Get trends
29
+ const trends = await proofio.insights.trends();
30
+
31
+ // Get widget data
32
+ const widget = await proofio.widget.get();
33
+ ```
34
+
35
+ ## Authentication
36
+
37
+ The SDK uses API key authentication. Get your API key from the Proofio dashboard.
38
+
39
+ ```typescript
40
+ const proofio = new Proofio({
41
+ apiKey: 'your-api-key-here',
42
+ });
43
+ ```
44
+
45
+ ## Usage Examples
46
+
47
+ ### Reviews
48
+
49
+ #### List Reviews
50
+
51
+ ```typescript
52
+ // Get all reviews (default: 10)
53
+ const reviews = await proofio.reviews.list();
54
+
55
+ // With filters and pagination
56
+ const filteredReviews = await proofio.reviews.list({
57
+ limit: 50,
58
+ offset: 0,
59
+ minRating: 4,
60
+ sentiment: 'positive',
61
+ language: 'de',
62
+ sourceId: 'source-id-here',
63
+ since: '2024-01-01T00:00:00Z',
64
+ });
65
+ ```
66
+
67
+ #### Get Single Review
68
+
69
+ ```typescript
70
+ const review = await proofio.reviews.get('review-id-here');
71
+ if (review) {
72
+ console.log(review.text);
73
+ console.log(review.rating);
74
+ }
75
+ ```
76
+
77
+ ### Insights
78
+
79
+ #### Get Summary
80
+
81
+ ```typescript
82
+ const summary = await proofio.insights.summary();
83
+
84
+ console.log(`Total Reviews: ${summary.totalReviews}`);
85
+ console.log(`Average Rating: ${summary.averageRating}`);
86
+ console.log(`Rating Distribution:`, summary.ratingDistribution);
87
+ console.log(`Sentiment:`, summary.sentimentDistribution);
88
+
89
+ // AI Summary (if available for paid plans)
90
+ if (summary.aiSummary) {
91
+ console.log(`AI Summary: ${summary.aiSummary.summary}`);
92
+ }
93
+ ```
94
+
95
+ #### Get Trends
96
+
97
+ ```typescript
98
+ const trends = await proofio.insights.trends();
99
+
100
+ console.log(`Trend over time:`, trends.trendOverTime);
101
+ console.log(`Top topics:`, trends.topTopics);
102
+ console.log(`Key takeaways:`, trends.keyTakeaways);
103
+ console.log(`Recent changes:`, trends.recentChanges);
104
+ ```
105
+
106
+ ### Widget
107
+
108
+ #### Get Widget Data
109
+
110
+ ```typescript
111
+ const widget = await proofio.widget.get();
112
+
113
+ console.log(`Stats:`, widget.stats);
114
+ console.log(`Settings:`, widget.settings);
115
+ ```
116
+
117
+ #### Get Widget Configuration
118
+
119
+ ```typescript
120
+ const config = await proofio.widget.config();
121
+
122
+ console.log(`Language: ${config.language}`);
123
+ console.log(`Theme: ${config.theme}`);
124
+ console.log(`Show AI Badge: ${config.showAiBadge}`);
125
+ ```
126
+
127
+ ### Competitors
128
+
129
+ #### Compare with Competitor
130
+
131
+ ```typescript
132
+ const comparison = await proofio.competitors.compare('competitor-id', {
133
+ force: false, // Set to true to force refresh
134
+ });
135
+
136
+ console.log(`Summary: ${comparison.summary}`);
137
+ console.log(`Strengths:`, comparison.strengths);
138
+ console.log(`Weaknesses:`, comparison.weaknesses);
139
+ console.log(`Recommendations:`, comparison.recommendations);
140
+ ```
141
+
142
+ ## Error Handling
143
+
144
+ The SDK throws `ProofioError` for all API errors. Always wrap API calls in try-catch blocks.
145
+
146
+ ```typescript
147
+ import { Proofio, ProofioError } from 'proofio';
148
+
149
+ try {
150
+ const reviews = await proofio.reviews.list();
151
+ } catch (error) {
152
+ if (error instanceof ProofioError) {
153
+ console.error(`API Error: ${error.message}`);
154
+ console.error(`Status: ${error.status}`);
155
+ console.error(`Code: ${error.code}`);
156
+
157
+ // Check if retryable
158
+ if (error.isRetryable()) {
159
+ // Implement retry logic
160
+ }
161
+
162
+ // Rate limit handling
163
+ if (error.status === 429) {
164
+ console.error(`Rate limit exceeded. Retry after: ${error.retryAfter} seconds`);
165
+ }
166
+ } else {
167
+ console.error('Unexpected error:', error);
168
+ }
169
+ }
170
+ ```
171
+
172
+ ### Error Types
173
+
174
+ - `INVALID_API_KEY`: API key is missing or invalid
175
+ - `RATE_LIMIT_EXCEEDED`: Rate limit exceeded (status 429)
176
+ - `API_ERROR`: General API error
177
+ - `NETWORK_ERROR`: Network/connection error
178
+ - `TIMEOUT`: Request timeout
179
+
180
+ ## Pagination
181
+
182
+ The SDK supports pagination for list endpoints:
183
+
184
+ ```typescript
185
+ let offset = 0;
186
+ const limit = 50;
187
+ let allReviews: Review[] = [];
188
+
189
+ while (true) {
190
+ const reviews = await proofio.reviews.list({ limit, offset });
191
+
192
+ if (reviews.length === 0) {
193
+ break;
194
+ }
195
+
196
+ allReviews = allReviews.concat(reviews);
197
+ offset += limit;
198
+
199
+ // Prevent infinite loops
200
+ if (reviews.length < limit) {
201
+ break;
202
+ }
203
+ }
204
+ ```
205
+
206
+ ## Configuration Options
207
+
208
+ ```typescript
209
+ const proofio = new Proofio({
210
+ apiKey: 'your-api-key',
211
+ baseURL: 'https://proofio.app', // Optional, default: https://proofio.app
212
+ timeout: 30000, // Optional, default: 30000ms (30 seconds)
213
+ maxRetries: 3, // Optional, default: 3
214
+ retryDelay: 1000, // Optional, default: 1000ms (1 second)
215
+ });
216
+ ```
217
+
218
+ ## TypeScript Support
219
+
220
+ The SDK is written in TypeScript and provides full type definitions:
221
+
222
+ ```typescript
223
+ import { Proofio, Review, InsightSummary } from 'proofio';
224
+
225
+ const proofio = new Proofio({ apiKey: 'your-api-key' });
226
+
227
+ // All types are inferred
228
+ const reviews: Review[] = await proofio.reviews.list();
229
+ const summary: InsightSummary = await proofio.insights.summary();
230
+ ```
231
+
232
+ ## API Reference
233
+
234
+ ### Proofio Class
235
+
236
+ Main SDK client class.
237
+
238
+ #### Constructor
239
+
240
+ ```typescript
241
+ new Proofio(config: ProofioConfig)
242
+ ```
243
+
244
+ #### Methods
245
+
246
+ - `reviews`: ReviewsResource - Access to review endpoints
247
+ - `insights`: InsightsResource - Access to insights endpoints
248
+ - `competitors`: CompetitorsResource - Access to competitor endpoints
249
+ - `widget`: WidgetResource - Access to widget endpoints
250
+
251
+ ### ReviewsResource
252
+
253
+ #### `list(options?: ReviewFilterOptions): Promise<Review[]>`
254
+
255
+ List reviews with optional filters.
256
+
257
+ #### `get(id: string): Promise<Review | null>`
258
+
259
+ Get a single review by ID.
260
+
261
+ ### InsightsResource
262
+
263
+ #### `summary(): Promise<InsightSummary>`
264
+
265
+ Get aggregated insights summary.
266
+
267
+ #### `trends(): Promise<InsightTrends>`
268
+
269
+ Get trend analysis data.
270
+
271
+ ### CompetitorsResource
272
+
273
+ #### `compare(competitorId: string, options?: { force?: boolean }): Promise<CompetitorComparison>`
274
+
275
+ Compare your product with a competitor.
276
+
277
+ ### WidgetResource
278
+
279
+ #### `get(): Promise<WidgetData>`
280
+
281
+ Get widget data including stats and settings.
282
+
283
+ #### `config(): Promise<WidgetSettings>`
284
+
285
+ Get widget configuration only.
286
+
287
+ ## Rate Limits
288
+
289
+ The SDK automatically handles rate limits and includes retry logic. Rate limit information is available in error responses:
290
+
291
+ ```typescript
292
+ try {
293
+ await proofio.reviews.list();
294
+ } catch (error) {
295
+ if (error instanceof ProofioError && error.status === 429) {
296
+ console.log(`Remaining: ${error.rateLimitRemaining}`);
297
+ console.log(`Reset at: ${new Date(error.rateLimitReset! * 1000)}`);
298
+ console.log(`Retry after: ${error.retryAfter} seconds`);
299
+ }
300
+ }
301
+ ```
302
+
303
+ ## Browser Support
304
+
305
+ The SDK uses the Fetch API, which is available in:
306
+ - Modern browsers (Chrome, Firefox, Safari, Edge)
307
+ - Node.js 18+ (with native fetch support)
308
+ - For older Node.js versions, use a fetch polyfill like `node-fetch`
309
+
310
+ ## License
311
+
312
+ MIT
313
+
314
+ ## Support
315
+
316
+ For issues and questions:
317
+ - GitHub Issues: https://github.com/proofio/proofio-sdk/issues
318
+ - Documentation: https://proofio.app/docs
319
+ - Email: support@proofio.app
@@ -0,0 +1,284 @@
1
+ "use strict";
2
+ /**
3
+ * Core API Client für Proofio SDK
4
+ *
5
+ * Handles:
6
+ * - API Key Authentication
7
+ * - Base URL Management
8
+ * - Request/Response Handling
9
+ * - Error Normalization
10
+ * - Rate Limit Handling
11
+ * - Retry Logic
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.ApiClient = void 0;
15
+ const errors_1 = require("../utils/errors");
16
+ class ApiClient {
17
+ constructor(config) {
18
+ if (!config.apiKey || typeof config.apiKey !== 'string' || config.apiKey.trim().length === 0) {
19
+ throw new errors_1.ProofioError({
20
+ message: 'API key is required',
21
+ status: 0,
22
+ code: 'INVALID_API_KEY',
23
+ });
24
+ }
25
+ // Validate API key format (basic validation)
26
+ if (config.apiKey.length < 10) {
27
+ throw new errors_1.ProofioError({
28
+ message: 'API key format is invalid',
29
+ status: 0,
30
+ code: 'INVALID_API_KEY',
31
+ });
32
+ }
33
+ this.apiKey = config.apiKey.trim();
34
+ this.baseURL = config.baseURL || 'https://proofio.app';
35
+ this.timeout = config.timeout || 30000; // 30 seconds
36
+ this.maxRetries = config.maxRetries ?? 3;
37
+ this.retryDelay = config.retryDelay ?? 1000; // 1 second
38
+ }
39
+ /**
40
+ * Sanitize API key for logging (never log full key)
41
+ */
42
+ sanitizeApiKey() {
43
+ if (this.apiKey.length <= 8) {
44
+ return '***';
45
+ }
46
+ return `${this.apiKey.substring(0, 4)}...${this.apiKey.substring(this.apiKey.length - 4)}`;
47
+ }
48
+ /**
49
+ * Build headers for requests
50
+ */
51
+ buildHeaders(customHeaders) {
52
+ const headers = new Headers({
53
+ 'Content-Type': 'application/json',
54
+ 'x-api-key': this.apiKey,
55
+ 'User-Agent': 'proofio-sdk/1.0.0',
56
+ ...customHeaders,
57
+ });
58
+ // Make headers immutable by creating new Headers object
59
+ return new Headers(headers);
60
+ }
61
+ /**
62
+ * Build full URL
63
+ */
64
+ buildURL(path, queryParams) {
65
+ const url = new URL(path, this.baseURL);
66
+ if (queryParams) {
67
+ Object.entries(queryParams).forEach(([key, value]) => {
68
+ if (value !== undefined && value !== null) {
69
+ url.searchParams.append(key, String(value));
70
+ }
71
+ });
72
+ }
73
+ return url.toString();
74
+ }
75
+ /**
76
+ * Handle rate limit errors
77
+ */
78
+ async handleRateLimit(response) {
79
+ const retryAfter = response.headers.get('Retry-After');
80
+ const rateLimitRemaining = response.headers.get('X-RateLimit-Remaining');
81
+ const rateLimitReset = response.headers.get('X-RateLimit-Reset');
82
+ const errorData = {
83
+ message: 'Rate limit exceeded',
84
+ status: 429,
85
+ code: 'RATE_LIMIT_EXCEEDED',
86
+ };
87
+ if (retryAfter) {
88
+ errorData.retryAfter = parseInt(retryAfter, 10);
89
+ }
90
+ if (rateLimitRemaining !== null) {
91
+ errorData.rateLimitRemaining = parseInt(rateLimitRemaining, 10);
92
+ }
93
+ if (rateLimitReset) {
94
+ errorData.rateLimitReset = parseInt(rateLimitReset, 10);
95
+ }
96
+ throw new errors_1.ProofioError(errorData);
97
+ }
98
+ /**
99
+ * Parse error response
100
+ */
101
+ async parseErrorResponse(response) {
102
+ let errorData = {
103
+ message: `API request failed with status ${response.status}`,
104
+ status: response.status,
105
+ code: 'API_ERROR',
106
+ };
107
+ try {
108
+ const contentType = response.headers.get('content-type');
109
+ if (contentType && contentType.includes('application/json')) {
110
+ const data = await response.json();
111
+ errorData = {
112
+ ...errorData,
113
+ message: data.error || data.message || errorData.message,
114
+ code: data.code || errorData.code,
115
+ requestId: data.requestId,
116
+ };
117
+ }
118
+ }
119
+ catch {
120
+ // If JSON parsing fails, use default error
121
+ }
122
+ return new errors_1.ProofioError(errorData);
123
+ }
124
+ /**
125
+ * Sleep helper for retries
126
+ */
127
+ sleep(ms) {
128
+ return new Promise((resolve) => setTimeout(resolve, ms));
129
+ }
130
+ /**
131
+ * Check if error is retryable
132
+ */
133
+ isRetryableError(status, error) {
134
+ // Retry on network errors, timeouts, and 5xx errors
135
+ if (!status)
136
+ return true; // Network error
137
+ if (status >= 500)
138
+ return true; // Server errors
139
+ if (status === 429)
140
+ return true; // Rate limit (with backoff)
141
+ if (status === 408)
142
+ return true; // Request timeout
143
+ return false;
144
+ }
145
+ /**
146
+ * Execute request with retry logic
147
+ */
148
+ async executeWithRetry(requestFn, retryCount = 0) {
149
+ try {
150
+ const response = await requestFn();
151
+ // If rate limited, throw immediately (don't retry immediately)
152
+ if (response.status === 429) {
153
+ await this.handleRateLimit(response);
154
+ }
155
+ // If error is retryable and we haven't exceeded max retries
156
+ if (!response.ok && this.isRetryableError(response.status) && retryCount < this.maxRetries) {
157
+ // Exponential backoff with jitter
158
+ const delay = this.retryDelay * Math.pow(2, retryCount) + Math.random() * 1000;
159
+ await this.sleep(delay);
160
+ return this.executeWithRetry(requestFn, retryCount + 1);
161
+ }
162
+ return response;
163
+ }
164
+ catch (error) {
165
+ // Network errors are retryable
166
+ if (retryCount < this.maxRetries && this.isRetryableError(0, error)) {
167
+ const delay = this.retryDelay * Math.pow(2, retryCount) + Math.random() * 1000;
168
+ await this.sleep(delay);
169
+ return this.executeWithRetry(requestFn, retryCount + 1);
170
+ }
171
+ throw error;
172
+ }
173
+ }
174
+ /**
175
+ * Make GET request
176
+ */
177
+ async get(path, options) {
178
+ const url = this.buildURL(path, options?.queryParams);
179
+ const headers = this.buildHeaders(options?.headers);
180
+ const controller = new AbortController();
181
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
182
+ try {
183
+ const response = await this.executeWithRetry(async () => {
184
+ return fetch(url, {
185
+ method: 'GET',
186
+ headers,
187
+ signal: controller.signal,
188
+ });
189
+ });
190
+ clearTimeout(timeoutId);
191
+ if (!response.ok) {
192
+ if (response.status === 429) {
193
+ await this.handleRateLimit(response);
194
+ }
195
+ throw await this.parseErrorResponse(response);
196
+ }
197
+ const data = await response.json();
198
+ // Convert Headers to plain object
199
+ const headers = {};
200
+ response.headers.forEach((value, key) => {
201
+ headers[key] = value;
202
+ });
203
+ return {
204
+ data,
205
+ status: response.status,
206
+ headers,
207
+ };
208
+ }
209
+ catch (error) {
210
+ clearTimeout(timeoutId);
211
+ if (error instanceof errors_1.ProofioError) {
212
+ throw error;
213
+ }
214
+ if (error instanceof Error && error.name === 'AbortError') {
215
+ throw new errors_1.ProofioError({
216
+ message: 'Request timeout',
217
+ status: 408,
218
+ code: 'TIMEOUT',
219
+ });
220
+ }
221
+ throw new errors_1.ProofioError({
222
+ message: error instanceof Error ? error.message : 'Unknown error occurred',
223
+ status: 0,
224
+ code: 'NETWORK_ERROR',
225
+ });
226
+ }
227
+ }
228
+ /**
229
+ * Make POST request
230
+ */
231
+ async post(path, body, options) {
232
+ const url = this.buildURL(path, options?.queryParams);
233
+ const headers = this.buildHeaders(options?.headers);
234
+ const controller = new AbortController();
235
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
236
+ try {
237
+ const response = await this.executeWithRetry(async () => {
238
+ return fetch(url, {
239
+ method: 'POST',
240
+ headers,
241
+ body: body ? JSON.stringify(body) : undefined,
242
+ signal: controller.signal,
243
+ });
244
+ });
245
+ clearTimeout(timeoutId);
246
+ if (!response.ok) {
247
+ if (response.status === 429) {
248
+ await this.handleRateLimit(response);
249
+ }
250
+ throw await this.parseErrorResponse(response);
251
+ }
252
+ const data = await response.json();
253
+ // Convert Headers to plain object
254
+ const headers = {};
255
+ response.headers.forEach((value, key) => {
256
+ headers[key] = value;
257
+ });
258
+ return {
259
+ data,
260
+ status: response.status,
261
+ headers,
262
+ };
263
+ }
264
+ catch (error) {
265
+ clearTimeout(timeoutId);
266
+ if (error instanceof errors_1.ProofioError) {
267
+ throw error;
268
+ }
269
+ if (error instanceof Error && error.name === 'AbortError') {
270
+ throw new errors_1.ProofioError({
271
+ message: 'Request timeout',
272
+ status: 408,
273
+ code: 'TIMEOUT',
274
+ });
275
+ }
276
+ throw new errors_1.ProofioError({
277
+ message: error instanceof Error ? error.message : 'Unknown error occurred',
278
+ status: 0,
279
+ code: 'NETWORK_ERROR',
280
+ });
281
+ }
282
+ }
283
+ }
284
+ exports.ApiClient = ApiClient;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ /**
3
+ * Proofio SDK
4
+ *
5
+ * Official JavaScript/TypeScript SDK for Proofio API
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { Proofio } from 'proofio-sdk';
10
+ *
11
+ * const proofio = new Proofio({ apiKey: 'your-api-key' });
12
+ *
13
+ * const reviews = await proofio.reviews.list();
14
+ * const summary = await proofio.insights.summary();
15
+ * ```
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.Proofio = exports.ApiClient = exports.ProofioError = void 0;
19
+ const api_client_1 = require("./client/api-client");
20
+ const reviews_1 = require("./resources/reviews");
21
+ const insights_1 = require("./resources/insights");
22
+ const competitors_1 = require("./resources/competitors");
23
+ const widget_1 = require("./resources/widget");
24
+ var errors_1 = require("./utils/errors");
25
+ Object.defineProperty(exports, "ProofioError", { enumerable: true, get: function () { return errors_1.ProofioError; } });
26
+ var api_client_2 = require("./client/api-client");
27
+ Object.defineProperty(exports, "ApiClient", { enumerable: true, get: function () { return api_client_2.ApiClient; } });
28
+ /**
29
+ * Main Proofio SDK Client
30
+ *
31
+ * Provides access to all Proofio API resources:
32
+ * - reviews: List and get reviews
33
+ * - insights: Get summaries and trends
34
+ * - competitors: Compare with competitors
35
+ * - widget: Get widget data and configuration
36
+ */
37
+ class Proofio {
38
+ /**
39
+ * Create a new Proofio SDK instance
40
+ *
41
+ * @param config - SDK configuration
42
+ * @param config.apiKey - Your Proofio API key (required)
43
+ * @param config.baseURL - Base URL for API (default: https://proofio.app)
44
+ * @param config.timeout - Request timeout in milliseconds (default: 30000)
45
+ * @param config.maxRetries - Maximum number of retries (default: 3)
46
+ * @param config.retryDelay - Delay between retries in milliseconds (default: 1000)
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * const proofio = new Proofio({
51
+ * apiKey: 'your-api-key-here',
52
+ * baseURL: 'https://proofio.app', // optional
53
+ * timeout: 30000, // optional
54
+ * });
55
+ * ```
56
+ */
57
+ constructor(config) {
58
+ this.client = new api_client_1.ApiClient(config);
59
+ // Initialize resources
60
+ this.reviews = new reviews_1.ReviewsResource(this.client);
61
+ this.insights = new insights_1.InsightsResource(this.client);
62
+ this.competitors = new competitors_1.CompetitorsResource(this.client);
63
+ this.widget = new widget_1.WidgetResource(this.client);
64
+ }
65
+ /**
66
+ * Get the underlying API client (for advanced usage)
67
+ */
68
+ getClient() {
69
+ return this.client;
70
+ }
71
+ }
72
+ exports.Proofio = Proofio;
73
+ // Default export
74
+ exports.default = Proofio;