proofio-sdk 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/client.js +83 -0
- package/dist/cjs/error.js +30 -0
- package/dist/cjs/index.js +13 -64
- package/dist/cjs/resources/aggregations.js +13 -0
- package/dist/cjs/resources/clusters.js +14 -0
- package/dist/cjs/resources/insights.js +7 -88
- package/dist/cjs/resources/reviews.js +10 -60
- package/dist/cjs/resources/widget.js +5 -50
- package/dist/cjs/types.js +3 -0
- package/dist/client.d.ts +12 -0
- package/dist/error.d.ts +17 -0
- package/dist/esm/client.js +79 -0
- package/dist/esm/error.js +26 -0
- package/dist/esm/index.js +13 -63
- package/dist/esm/resources/aggregations.js +9 -0
- package/dist/esm/resources/clusters.js +10 -0
- package/dist/esm/resources/insights.js +7 -88
- package/dist/esm/resources/reviews.js +8 -58
- package/dist/esm/resources/widget.js +3 -48
- package/dist/esm/types.js +2 -0
- package/dist/index.d.ts +11 -61
- package/dist/resources/aggregations.d.ts +8 -0
- package/dist/resources/clusters.d.ts +8 -0
- package/dist/resources/insights.d.ts +9 -42
- package/dist/resources/reviews.d.ts +6 -27
- package/dist/resources/widget.d.ts +6 -42
- package/dist/types.d.ts +147 -0
- package/package.json +12 -11
- package/README.md +0 -319
- package/dist/cjs/client/api-client.js +0 -284
- package/dist/cjs/resources/competitors.js +0 -45
- package/dist/cjs/types/index.js +0 -7
- package/dist/cjs/utils/errors.js +0 -50
- package/dist/client/api-client.d.ts +0 -68
- package/dist/client/api-client.d.ts.map +0 -1
- package/dist/esm/client/api-client.js +0 -280
- package/dist/esm/resources/competitors.js +0 -41
- package/dist/esm/types/index.js +0 -6
- package/dist/esm/utils/errors.js +0 -46
- package/dist/index.d.ts.map +0 -1
- package/dist/resources/competitors.d.ts +0 -33
- package/dist/resources/competitors.d.ts.map +0 -1
- package/dist/resources/insights.d.ts.map +0 -1
- package/dist/resources/reviews.d.ts.map +0 -1
- package/dist/resources/widget.d.ts.map +0 -1
- package/dist/types/index.d.ts +0 -217
- package/dist/types/index.d.ts.map +0 -1
- package/dist/utils/errors.d.ts +0 -32
- package/dist/utils/errors.d.ts.map +0 -1
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HttpClient = void 0;
|
|
4
|
+
const error_1 = require("./error");
|
|
5
|
+
const DEFAULT_BASE_URL = 'https://api.proofio.app';
|
|
6
|
+
const DEFAULT_TIMEOUT = 30000;
|
|
7
|
+
const DEFAULT_MAX_RETRIES = 3;
|
|
8
|
+
const DEFAULT_RETRY_DELAY = 1000;
|
|
9
|
+
class HttpClient {
|
|
10
|
+
constructor(config) {
|
|
11
|
+
if (!config.apiKey) {
|
|
12
|
+
throw new Error('proofio-sdk: apiKey is required');
|
|
13
|
+
}
|
|
14
|
+
this.apiKey = config.apiKey;
|
|
15
|
+
this.baseURL = (config.baseURL ?? DEFAULT_BASE_URL).replace(/\/+$/, '');
|
|
16
|
+
this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
|
|
17
|
+
this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
18
|
+
this.retryDelay = config.retryDelay ?? DEFAULT_RETRY_DELAY;
|
|
19
|
+
}
|
|
20
|
+
async get(path, params) {
|
|
21
|
+
const url = this.buildURL(path, params);
|
|
22
|
+
return this.request(url);
|
|
23
|
+
}
|
|
24
|
+
buildURL(path, params) {
|
|
25
|
+
const url = new URL(`${this.baseURL}${path}`);
|
|
26
|
+
if (params) {
|
|
27
|
+
for (const [key, value] of Object.entries(params)) {
|
|
28
|
+
if (value !== undefined && value !== null) {
|
|
29
|
+
url.searchParams.set(key, String(value));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return url.toString();
|
|
34
|
+
}
|
|
35
|
+
async request(url, attempt = 0) {
|
|
36
|
+
const controller = new AbortController();
|
|
37
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
38
|
+
try {
|
|
39
|
+
const response = await fetch(url, {
|
|
40
|
+
method: 'GET',
|
|
41
|
+
headers: {
|
|
42
|
+
'x-api-key': this.apiKey,
|
|
43
|
+
'Content-Type': 'application/json',
|
|
44
|
+
},
|
|
45
|
+
signal: controller.signal,
|
|
46
|
+
});
|
|
47
|
+
if (!response.ok) {
|
|
48
|
+
const body = await response.json().catch(() => ({ error: response.statusText }));
|
|
49
|
+
const error = new error_1.ProofioError(body.message ?? body.error ?? `HTTP ${response.status}`, response.status, body.error ?? 'unknown_error', response.headers);
|
|
50
|
+
// Retry on 5xx or 429 (with backoff)
|
|
51
|
+
if (error.isRetryable() && attempt < this.maxRetries) {
|
|
52
|
+
const delay = error.status === 429 && error.retryAfter
|
|
53
|
+
? error.retryAfter * 1000
|
|
54
|
+
: this.retryDelay * Math.pow(2, attempt);
|
|
55
|
+
await sleep(delay);
|
|
56
|
+
return this.request(url, attempt + 1);
|
|
57
|
+
}
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
return (await response.json());
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
if (err instanceof error_1.ProofioError)
|
|
64
|
+
throw err;
|
|
65
|
+
// Network / timeout errors are retryable
|
|
66
|
+
if (attempt < this.maxRetries) {
|
|
67
|
+
await sleep(this.retryDelay * Math.pow(2, attempt));
|
|
68
|
+
return this.request(url, attempt + 1);
|
|
69
|
+
}
|
|
70
|
+
if (err instanceof DOMException && err.name === 'AbortError') {
|
|
71
|
+
throw new error_1.ProofioError(`Request timed out after ${this.timeout}ms`, 0, 'timeout');
|
|
72
|
+
}
|
|
73
|
+
throw new error_1.ProofioError(err instanceof Error ? err.message : 'Network error', 0, 'network_error');
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
clearTimeout(timeoutId);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
exports.HttpClient = HttpClient;
|
|
81
|
+
function sleep(ms) {
|
|
82
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
83
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProofioError = void 0;
|
|
4
|
+
class ProofioError extends Error {
|
|
5
|
+
constructor(message, status, code, headers) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = 'ProofioError';
|
|
8
|
+
this.status = status;
|
|
9
|
+
this.code = code;
|
|
10
|
+
const retryAfterHeader = headers?.get('retry-after');
|
|
11
|
+
this.retryAfter = retryAfterHeader ? parseInt(retryAfterHeader, 10) : null;
|
|
12
|
+
this.rateLimit = {
|
|
13
|
+
limit: parseHeaderInt(headers, 'x-ratelimit-limit'),
|
|
14
|
+
remaining: parseHeaderInt(headers, 'x-ratelimit-remaining'),
|
|
15
|
+
reset: parseHeaderInt(headers, 'x-ratelimit-reset'),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/** Whether this error is retryable (5xx or 429) */
|
|
19
|
+
isRetryable() {
|
|
20
|
+
return this.status === 429 || this.status >= 500;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.ProofioError = ProofioError;
|
|
24
|
+
function parseHeaderInt(headers, name) {
|
|
25
|
+
const value = headers?.get(name);
|
|
26
|
+
if (!value)
|
|
27
|
+
return null;
|
|
28
|
+
const parsed = parseInt(value, 10);
|
|
29
|
+
return isNaN(parsed) ? null : parsed;
|
|
30
|
+
}
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,74 +1,23 @@
|
|
|
1
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
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.
|
|
19
|
-
const
|
|
3
|
+
exports.ProofioError = exports.Proofio = void 0;
|
|
4
|
+
const client_1 = require("./client");
|
|
20
5
|
const reviews_1 = require("./resources/reviews");
|
|
6
|
+
const aggregations_1 = require("./resources/aggregations");
|
|
7
|
+
const clusters_1 = require("./resources/clusters");
|
|
21
8
|
const insights_1 = require("./resources/insights");
|
|
22
|
-
const competitors_1 = require("./resources/competitors");
|
|
23
9
|
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
10
|
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
11
|
constructor(config) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
this.
|
|
61
|
-
this.
|
|
62
|
-
this.
|
|
63
|
-
this.widget = new widget_1.
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Get the underlying API client (for advanced usage)
|
|
67
|
-
*/
|
|
68
|
-
getClient() {
|
|
69
|
-
return this.client;
|
|
12
|
+
const client = new client_1.HttpClient(config);
|
|
13
|
+
this.reviews = new reviews_1.Reviews(client);
|
|
14
|
+
this.aggregations = new aggregations_1.AggregationsResource(client);
|
|
15
|
+
this.clusters = new clusters_1.Clusters(client);
|
|
16
|
+
this.insights = new insights_1.InsightsResource(client);
|
|
17
|
+
this.widget = new widget_1.Widget(client);
|
|
70
18
|
}
|
|
71
19
|
}
|
|
72
20
|
exports.Proofio = Proofio;
|
|
73
|
-
//
|
|
74
|
-
|
|
21
|
+
// Re-export everything
|
|
22
|
+
var error_1 = require("./error");
|
|
23
|
+
Object.defineProperty(exports, "ProofioError", { enumerable: true, get: function () { return error_1.ProofioError; } });
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AggregationsResource = void 0;
|
|
4
|
+
class AggregationsResource {
|
|
5
|
+
constructor(client) {
|
|
6
|
+
this.client = client;
|
|
7
|
+
}
|
|
8
|
+
/** Get aggregated review statistics */
|
|
9
|
+
async get() {
|
|
10
|
+
return this.client.get('/api/v1/public/aggregations');
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
exports.AggregationsResource = AggregationsResource;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Clusters = void 0;
|
|
4
|
+
class Clusters {
|
|
5
|
+
constructor(client) {
|
|
6
|
+
this.client = client;
|
|
7
|
+
}
|
|
8
|
+
/** Get review clusters with keyword groupings */
|
|
9
|
+
async list() {
|
|
10
|
+
const response = await this.client.get('/api/v1/public/clusters');
|
|
11
|
+
return response.clusters;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
exports.Clusters = Clusters;
|
|
@@ -1,101 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Insights Resource
|
|
4
|
-
*
|
|
5
|
-
* Handles insights, summaries, and trend analysis
|
|
6
|
-
*/
|
|
7
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
3
|
exports.InsightsResource = void 0;
|
|
9
4
|
class InsightsResource {
|
|
10
5
|
constructor(client) {
|
|
11
6
|
this.client = client;
|
|
12
7
|
}
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
* Returns aggregated statistics including:
|
|
17
|
-
* - Total reviews
|
|
18
|
-
* - Average rating
|
|
19
|
-
* - Rating distribution
|
|
20
|
-
* - Sentiment distribution
|
|
21
|
-
* - Source breakdown
|
|
22
|
-
* - AI summary (if available for paid plans)
|
|
23
|
-
*
|
|
24
|
-
* @returns Promise with insight summary
|
|
25
|
-
*/
|
|
26
|
-
async summary() {
|
|
27
|
-
const response = await this.client.get('/api/v1/public/aggregations');
|
|
28
|
-
return response.data;
|
|
8
|
+
/** Get AI-powered review intelligence (trust score, risk, emotions, topics) */
|
|
9
|
+
async get() {
|
|
10
|
+
return this.client.get('/api/v1/public/insights');
|
|
29
11
|
}
|
|
30
12
|
/**
|
|
31
|
-
* Get
|
|
32
|
-
*
|
|
33
|
-
* Returns detailed trend data including:
|
|
34
|
-
* - Trend over time (last 30 days)
|
|
35
|
-
* - Review volume (7, 30, 90 days)
|
|
36
|
-
* - Top topics
|
|
37
|
-
* - Key takeaways
|
|
38
|
-
* - Recent changes
|
|
39
|
-
*
|
|
40
|
-
* Note: The public API provides limited trend data. For full trend analysis
|
|
41
|
-
* including trendOverTime, topTopics, and recentChanges, you need access
|
|
42
|
-
* to the dashboard API (requires authentication).
|
|
43
|
-
*
|
|
44
|
-
* This method returns available data from the public aggregations endpoint
|
|
45
|
-
* and sets default/empty values for fields not available in the public API.
|
|
46
|
-
*
|
|
47
|
-
* @returns Promise with trend data
|
|
13
|
+
* Get aggregated summary (totalReviews, averageRating, etc.)
|
|
14
|
+
* Alias for aggregations endpoint - provided for convenience.
|
|
48
15
|
*/
|
|
49
|
-
async
|
|
50
|
-
|
|
51
|
-
const response = await this.client.get('/api/v1/public/aggregations');
|
|
52
|
-
const data = response.data;
|
|
53
|
-
// Calculate positive percentage
|
|
54
|
-
const positivePercentage = data.totalReviews > 0
|
|
55
|
-
? (data.sentimentDistribution.positive / data.totalReviews) * 100
|
|
56
|
-
: 0;
|
|
57
|
-
// Transform to InsightTrends format
|
|
58
|
-
// Note: The public API doesn't provide all trend fields,
|
|
59
|
-
// so we provide what's available and set defaults for missing fields
|
|
60
|
-
return {
|
|
61
|
-
totalReviews: data.totalReviews,
|
|
62
|
-
averageRating: data.averageRating,
|
|
63
|
-
ratingDistribution: data.ratingDistribution,
|
|
64
|
-
sentimentDistribution: data.sentimentDistribution,
|
|
65
|
-
thisWeekCount: 0, // Not available in public API
|
|
66
|
-
thisWeekChange: 0, // Not available in public API
|
|
67
|
-
positivePercentage: Math.round(positivePercentage * 10) / 10,
|
|
68
|
-
reviewVolume: {
|
|
69
|
-
last7Days: 0, // Not available in public API
|
|
70
|
-
last30Days: 0, // Not available in public API
|
|
71
|
-
last90Days: 0, // Not available in public API
|
|
72
|
-
total: data.totalReviews,
|
|
73
|
-
},
|
|
74
|
-
sourceBreakdown: data.sources.reduce((acc, source) => {
|
|
75
|
-
acc[source.id] = {
|
|
76
|
-
count: source.total,
|
|
77
|
-
avgRating: source.averageRating,
|
|
78
|
-
sentiment: {
|
|
79
|
-
positive: 0, // Not available in public API
|
|
80
|
-
neutral: 0,
|
|
81
|
-
negative: 0,
|
|
82
|
-
},
|
|
83
|
-
};
|
|
84
|
-
return acc;
|
|
85
|
-
}, {}),
|
|
86
|
-
sourcesMap: data.sources.reduce((acc, source) => {
|
|
87
|
-
acc[source.id] = {
|
|
88
|
-
name: source.name || source.type || 'Unknown',
|
|
89
|
-
type: source.type || 'UNKNOWN',
|
|
90
|
-
};
|
|
91
|
-
return acc;
|
|
92
|
-
}, {}),
|
|
93
|
-
trendOverTime: [], // Not available in public API - requires dashboard API
|
|
94
|
-
topTopics: [], // Not available in public API - requires dashboard API
|
|
95
|
-
keyTakeaways: [], // Not available in public API - requires dashboard API
|
|
96
|
-
recentChanges: [], // Not available in public API - requires dashboard API
|
|
97
|
-
lastSync: null, // Not available in public API
|
|
98
|
-
};
|
|
16
|
+
async summary() {
|
|
17
|
+
return this.client.get('/api/v1/public/aggregations');
|
|
99
18
|
}
|
|
100
19
|
}
|
|
101
20
|
exports.InsightsResource = InsightsResource;
|
|
@@ -1,69 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Reviews Resource
|
|
4
|
-
*
|
|
5
|
-
* Handles all review-related API calls
|
|
6
|
-
*/
|
|
7
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.
|
|
9
|
-
class
|
|
3
|
+
exports.Reviews = void 0;
|
|
4
|
+
class Reviews {
|
|
10
5
|
constructor(client) {
|
|
11
6
|
this.client = client;
|
|
12
7
|
}
|
|
13
|
-
/**
|
|
14
|
-
* List reviews
|
|
15
|
-
*
|
|
16
|
-
* @param options - Filter and pagination options
|
|
17
|
-
* @returns Promise with array of reviews
|
|
18
|
-
*/
|
|
8
|
+
/** List reviews with optional filters */
|
|
19
9
|
async list(options) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
if (options?.offset !== undefined) {
|
|
28
|
-
queryParams.offset = options.offset;
|
|
29
|
-
}
|
|
30
|
-
if (options?.minRating !== undefined) {
|
|
31
|
-
queryParams.minRating = options.minRating;
|
|
32
|
-
}
|
|
33
|
-
if (options?.maxRating !== undefined) {
|
|
34
|
-
queryParams.maxRating = options.maxRating;
|
|
35
|
-
}
|
|
36
|
-
if (options?.sentiment) {
|
|
37
|
-
queryParams.sentiment = options.sentiment;
|
|
38
|
-
}
|
|
39
|
-
if (options?.language) {
|
|
40
|
-
queryParams.language = options.language;
|
|
41
|
-
}
|
|
42
|
-
if (options?.sourceId) {
|
|
43
|
-
queryParams.sourceId = options.sourceId;
|
|
44
|
-
}
|
|
45
|
-
if (options?.since) {
|
|
46
|
-
queryParams.since = options.since;
|
|
47
|
-
}
|
|
48
|
-
const response = await this.client.get('/api/v1/public/reviews', {
|
|
49
|
-
queryParams,
|
|
10
|
+
return this.client.get('/api/v1/public/reviews', {
|
|
11
|
+
limit: options?.limit,
|
|
12
|
+
minRating: options?.minRating,
|
|
13
|
+
sentiment: options?.sentiment,
|
|
14
|
+
language: options?.language,
|
|
15
|
+
sourceId: options?.sourceId,
|
|
50
16
|
});
|
|
51
|
-
return response.data;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Get a single review by ID
|
|
55
|
-
*
|
|
56
|
-
* Note: The API doesn't have a direct GET /reviews/:id endpoint,
|
|
57
|
-
* so we fetch the list and filter. This is a convenience method.
|
|
58
|
-
*
|
|
59
|
-
* @param id - Review ID
|
|
60
|
-
* @returns Promise with review or null if not found
|
|
61
|
-
*/
|
|
62
|
-
async get(id) {
|
|
63
|
-
// Since there's no direct GET endpoint, we need to fetch and filter
|
|
64
|
-
// In a real implementation, you might want to cache reviews or use a different approach
|
|
65
|
-
const reviews = await this.list({ limit: 100 });
|
|
66
|
-
return reviews.find((review) => review.id === id) || null;
|
|
67
17
|
}
|
|
68
18
|
}
|
|
69
|
-
exports.
|
|
19
|
+
exports.Reviews = Reviews;
|
|
@@ -1,58 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Widget Resource
|
|
4
|
-
*
|
|
5
|
-
* Handles widget-related API calls
|
|
6
|
-
*/
|
|
7
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.
|
|
9
|
-
class
|
|
3
|
+
exports.Widget = void 0;
|
|
4
|
+
class Widget {
|
|
10
5
|
constructor(client) {
|
|
11
6
|
this.client = client;
|
|
12
7
|
}
|
|
13
|
-
/**
|
|
14
|
-
* Get widget data
|
|
15
|
-
*
|
|
16
|
-
* Returns widget statistics and settings including:
|
|
17
|
-
* - Total reviews
|
|
18
|
-
* - Average rating
|
|
19
|
-
* - Number of platforms
|
|
20
|
-
* - Widget configuration (language, theme, badges, branding)
|
|
21
|
-
*
|
|
22
|
-
* @returns Promise with widget data
|
|
23
|
-
*/
|
|
8
|
+
/** Get widget data (stats + display settings) */
|
|
24
9
|
async get() {
|
|
25
|
-
|
|
26
|
-
return response.data;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Get widget configuration
|
|
30
|
-
*
|
|
31
|
-
* Returns only the widget settings/configuration.
|
|
32
|
-
* This is a convenience method that extracts settings from get().
|
|
33
|
-
*
|
|
34
|
-
* @returns Promise with widget settings
|
|
35
|
-
*/
|
|
36
|
-
async config() {
|
|
37
|
-
const data = await this.get();
|
|
38
|
-
return data.settings;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Update widget configuration
|
|
42
|
-
*
|
|
43
|
-
* Note: Widget configuration updates typically require dashboard API access.
|
|
44
|
-
* This method is provided for API consistency but may require
|
|
45
|
-
* additional authentication setup.
|
|
46
|
-
*
|
|
47
|
-
* @param options - Widget configuration options
|
|
48
|
-
* @returns Promise with updated widget settings
|
|
49
|
-
*/
|
|
50
|
-
async updateConfig(options) {
|
|
51
|
-
// Note: This endpoint typically requires authentication
|
|
52
|
-
// The public API doesn't support widget config updates
|
|
53
|
-
// This is a placeholder that matches the expected API structure
|
|
54
|
-
const response = await this.client.post('/api/dashboard/widget-settings', options);
|
|
55
|
-
return response.data;
|
|
10
|
+
return this.client.get('/api/v1/public/widget');
|
|
56
11
|
}
|
|
57
12
|
}
|
|
58
|
-
exports.
|
|
13
|
+
exports.Widget = Widget;
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ProofioConfig } from './types';
|
|
2
|
+
export declare class HttpClient {
|
|
3
|
+
private readonly apiKey;
|
|
4
|
+
private readonly baseURL;
|
|
5
|
+
private readonly timeout;
|
|
6
|
+
private readonly maxRetries;
|
|
7
|
+
private readonly retryDelay;
|
|
8
|
+
constructor(config: ProofioConfig);
|
|
9
|
+
get<T>(path: string, params?: Record<string, string | number | undefined>): Promise<T>;
|
|
10
|
+
private buildURL;
|
|
11
|
+
private request;
|
|
12
|
+
}
|
package/dist/error.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare class ProofioError extends Error {
|
|
2
|
+
/** HTTP status code */
|
|
3
|
+
readonly status: number;
|
|
4
|
+
/** Error code from API response */
|
|
5
|
+
readonly code: string;
|
|
6
|
+
/** Retry-After header value in seconds (present on 429) */
|
|
7
|
+
readonly retryAfter: number | null;
|
|
8
|
+
/** Rate limit info from response headers */
|
|
9
|
+
readonly rateLimit: {
|
|
10
|
+
limit: number | null;
|
|
11
|
+
remaining: number | null;
|
|
12
|
+
reset: number | null;
|
|
13
|
+
};
|
|
14
|
+
constructor(message: string, status: number, code: string, headers?: Headers);
|
|
15
|
+
/** Whether this error is retryable (5xx or 429) */
|
|
16
|
+
isRetryable(): boolean;
|
|
17
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { ProofioError } from './error';
|
|
2
|
+
const DEFAULT_BASE_URL = 'https://api.proofio.app';
|
|
3
|
+
const DEFAULT_TIMEOUT = 30000;
|
|
4
|
+
const DEFAULT_MAX_RETRIES = 3;
|
|
5
|
+
const DEFAULT_RETRY_DELAY = 1000;
|
|
6
|
+
export class HttpClient {
|
|
7
|
+
constructor(config) {
|
|
8
|
+
if (!config.apiKey) {
|
|
9
|
+
throw new Error('proofio-sdk: apiKey is required');
|
|
10
|
+
}
|
|
11
|
+
this.apiKey = config.apiKey;
|
|
12
|
+
this.baseURL = (config.baseURL ?? DEFAULT_BASE_URL).replace(/\/+$/, '');
|
|
13
|
+
this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
|
|
14
|
+
this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
15
|
+
this.retryDelay = config.retryDelay ?? DEFAULT_RETRY_DELAY;
|
|
16
|
+
}
|
|
17
|
+
async get(path, params) {
|
|
18
|
+
const url = this.buildURL(path, params);
|
|
19
|
+
return this.request(url);
|
|
20
|
+
}
|
|
21
|
+
buildURL(path, params) {
|
|
22
|
+
const url = new URL(`${this.baseURL}${path}`);
|
|
23
|
+
if (params) {
|
|
24
|
+
for (const [key, value] of Object.entries(params)) {
|
|
25
|
+
if (value !== undefined && value !== null) {
|
|
26
|
+
url.searchParams.set(key, String(value));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return url.toString();
|
|
31
|
+
}
|
|
32
|
+
async request(url, attempt = 0) {
|
|
33
|
+
const controller = new AbortController();
|
|
34
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
35
|
+
try {
|
|
36
|
+
const response = await fetch(url, {
|
|
37
|
+
method: 'GET',
|
|
38
|
+
headers: {
|
|
39
|
+
'x-api-key': this.apiKey,
|
|
40
|
+
'Content-Type': 'application/json',
|
|
41
|
+
},
|
|
42
|
+
signal: controller.signal,
|
|
43
|
+
});
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
const body = await response.json().catch(() => ({ error: response.statusText }));
|
|
46
|
+
const error = new ProofioError(body.message ?? body.error ?? `HTTP ${response.status}`, response.status, body.error ?? 'unknown_error', response.headers);
|
|
47
|
+
// Retry on 5xx or 429 (with backoff)
|
|
48
|
+
if (error.isRetryable() && attempt < this.maxRetries) {
|
|
49
|
+
const delay = error.status === 429 && error.retryAfter
|
|
50
|
+
? error.retryAfter * 1000
|
|
51
|
+
: this.retryDelay * Math.pow(2, attempt);
|
|
52
|
+
await sleep(delay);
|
|
53
|
+
return this.request(url, attempt + 1);
|
|
54
|
+
}
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
return (await response.json());
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
if (err instanceof ProofioError)
|
|
61
|
+
throw err;
|
|
62
|
+
// Network / timeout errors are retryable
|
|
63
|
+
if (attempt < this.maxRetries) {
|
|
64
|
+
await sleep(this.retryDelay * Math.pow(2, attempt));
|
|
65
|
+
return this.request(url, attempt + 1);
|
|
66
|
+
}
|
|
67
|
+
if (err instanceof DOMException && err.name === 'AbortError') {
|
|
68
|
+
throw new ProofioError(`Request timed out after ${this.timeout}ms`, 0, 'timeout');
|
|
69
|
+
}
|
|
70
|
+
throw new ProofioError(err instanceof Error ? err.message : 'Network error', 0, 'network_error');
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
clearTimeout(timeoutId);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function sleep(ms) {
|
|
78
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
79
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export class ProofioError extends Error {
|
|
2
|
+
constructor(message, status, code, headers) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.name = 'ProofioError';
|
|
5
|
+
this.status = status;
|
|
6
|
+
this.code = code;
|
|
7
|
+
const retryAfterHeader = headers?.get('retry-after');
|
|
8
|
+
this.retryAfter = retryAfterHeader ? parseInt(retryAfterHeader, 10) : null;
|
|
9
|
+
this.rateLimit = {
|
|
10
|
+
limit: parseHeaderInt(headers, 'x-ratelimit-limit'),
|
|
11
|
+
remaining: parseHeaderInt(headers, 'x-ratelimit-remaining'),
|
|
12
|
+
reset: parseHeaderInt(headers, 'x-ratelimit-reset'),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/** Whether this error is retryable (5xx or 429) */
|
|
16
|
+
isRetryable() {
|
|
17
|
+
return this.status === 429 || this.status >= 500;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function parseHeaderInt(headers, name) {
|
|
21
|
+
const value = headers?.get(name);
|
|
22
|
+
if (!value)
|
|
23
|
+
return null;
|
|
24
|
+
const parsed = parseInt(value, 10);
|
|
25
|
+
return isNaN(parsed) ? null : parsed;
|
|
26
|
+
}
|