@verifyapi/sdk 0.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/.turbo/turbo-build.log +4 -0
- package/.turbo/turbo-lint.log +11 -0
- package/.turbo/turbo-test$colon$unit.log +19 -0
- package/.turbo/turbo-typecheck.log +4 -0
- package/README.md +78 -0
- package/dist/client.d.ts +124 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +314 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +36 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +38 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/webhooks.d.ts +19 -0
- package/dist/webhooks.d.ts.map +1 -0
- package/dist/webhooks.js +52 -0
- package/dist/webhooks.js.map +1 -0
- package/package.json +49 -0
- package/src/client.ts +478 -0
- package/src/errors.ts +55 -0
- package/src/index.ts +24 -0
- package/src/webhooks.ts +69 -0
- package/tsconfig.json +10 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
|
|
2
|
+
> @verifyapi/sdk@0.1.0 lint /Users/jjfisher/verifyapi_v1/packages/sdk
|
|
3
|
+
> eslint src/
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
/Users/jjfisher/verifyapi_v1/packages/sdk/src/client.ts
|
|
7
|
+
521:15 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion
|
|
8
|
+
522:15 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion
|
|
9
|
+
|
|
10
|
+
✖ 2 problems (0 errors, 2 warnings)
|
|
11
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
|
|
2
|
+
> @verifyapi/sdk@0.1.0 test:unit /Users/jjfisher/verifyapi_v1/packages/sdk
|
|
3
|
+
> vitest run
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
[1m[46m RUN [49m[22m [36mv4.1.0 [39m[90m/Users/jjfisher/verifyapi_v1/packages/sdk[39m
|
|
7
|
+
|
|
8
|
+
[32m✓[39m src/__tests__/errors.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 8[2mms[22m[39m
|
|
9
|
+
[32m✓[39m src/__tests__/webhooks.test.ts [2m([22m[2m11 tests[22m[2m)[22m[32m 19[2mms[22m[39m
|
|
10
|
+
[32m✓[39m src/__tests__/client.test.ts [2m([22m[2m31 tests[22m[2m)[22m[33m 3285[2mms[22m[39m
|
|
11
|
+
[33m[2m✓[22m[39m retries on 429 and succeeds [33m 1100[2mms[22m[39m
|
|
12
|
+
[33m[2m✓[22m[39m retries on 500 and eventually throws after max retries [33m 1073[2mms[22m[39m
|
|
13
|
+
[33m[2m✓[22m[39m retries on connection error [33m 1090[2mms[22m[39m
|
|
14
|
+
|
|
15
|
+
[2m Test Files [22m [1m[32m3 passed[39m[22m[90m (3)[39m
|
|
16
|
+
[2m Tests [22m [1m[32m50 passed[39m[22m[90m (50)[39m
|
|
17
|
+
[2m Start at [22m 18:18:26
|
|
18
|
+
[2m Duration [22m 3.62s[2m (transform 236ms, setup 0ms, import 378ms, tests 3.31s, environment 0ms)[22m
|
|
19
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# @verifyapi/sdk — FirstHandAPI TypeScript SDK
|
|
2
|
+
|
|
3
|
+
Official TypeScript SDK for [FirstHandAPI](https://firsthandapi.com) — the human-in-the-loop (HITL) crowdsourced data collection API.
|
|
4
|
+
|
|
5
|
+
Post jobs via API. Real human workers capture photos, audio, video, and screen recordings. AI ensemble (Claude Vision + Whisper) auto-scores quality. Approved files delivered to your S3 folder. Use cases: UGC collection, ground truth for AI evaluation, LLM training data.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @verifyapi/sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { FirstHandClient } from '@verifyapi/sdk';
|
|
17
|
+
|
|
18
|
+
const client = new FirstHandClient({
|
|
19
|
+
apiKey: 'fh_live_your_key_here',
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// Post a content collection job
|
|
23
|
+
const job = await client.createJob({
|
|
24
|
+
type: 'data_collection',
|
|
25
|
+
description: 'Photos of grocery store shelf labels',
|
|
26
|
+
files_needed: 100,
|
|
27
|
+
accepted_formats: ['image/jpeg', 'image/png'],
|
|
28
|
+
price_per_file_cents: 25,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Wait for completion
|
|
32
|
+
const completed = await client.createJobAndWait({
|
|
33
|
+
...jobData,
|
|
34
|
+
}, 300); // wait up to 5 minutes
|
|
35
|
+
|
|
36
|
+
// Get approved files
|
|
37
|
+
const files = await client.getJobFiles(job.id);
|
|
38
|
+
files.data.forEach(file => {
|
|
39
|
+
console.log(file.download_url);
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Methods
|
|
44
|
+
|
|
45
|
+
### Jobs
|
|
46
|
+
- `createJob(body)` — Post a new job
|
|
47
|
+
- `getJob(id, options?)` — Get job (supports long-poll)
|
|
48
|
+
- `listJobs(params?)` — List jobs
|
|
49
|
+
- `cancelJob(id)` — Cancel and refund
|
|
50
|
+
- `getJobFiles(id)` — Get approved files
|
|
51
|
+
- `getJobSubmissions(id)` — Get submissions
|
|
52
|
+
- `createJobAndWait(body, maxWait)` — Create and poll
|
|
53
|
+
|
|
54
|
+
### Billing
|
|
55
|
+
- `getCreditBalance()` — Check balance
|
|
56
|
+
- `listTransactions(params?)` — Transaction history
|
|
57
|
+
- `purchaseCredits(body)` — Buy credits
|
|
58
|
+
|
|
59
|
+
### Webhooks
|
|
60
|
+
- `createWebhookEndpoint(body)` — Register endpoint
|
|
61
|
+
- `listWebhookEndpoints()` — List endpoints
|
|
62
|
+
- `verifyWebhookSignature(payload, signature, secret)` — Verify webhook
|
|
63
|
+
|
|
64
|
+
### API Keys
|
|
65
|
+
- `createApiKey(body)` — Create key
|
|
66
|
+
- `listApiKeys()` — List keys
|
|
67
|
+
- `rotateApiKey(id)` — Rotate key
|
|
68
|
+
- `revokeApiKey(id)` — Revoke key
|
|
69
|
+
|
|
70
|
+
## Features
|
|
71
|
+
- Auto-retry with exponential backoff (429, 500+)
|
|
72
|
+
- Idempotency key generation
|
|
73
|
+
- Long-poll support
|
|
74
|
+
- TypeScript-native types
|
|
75
|
+
|
|
76
|
+
## License
|
|
77
|
+
|
|
78
|
+
Proprietary
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @firsthandapi/sdk/client
|
|
3
|
+
* @description FirstHandAPI TypeScript SDK client.
|
|
4
|
+
* Typed client wrapping all v1 REST endpoints with auto-retry,
|
|
5
|
+
* idempotency key generation, and proper error handling.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { FirstHandClient } from '@firsthandapi/sdk';
|
|
10
|
+
*
|
|
11
|
+
* const client = new FirstHandClient({ apiKey: 'fh_live_...' });
|
|
12
|
+
* const job = await client.createJob({
|
|
13
|
+
* job_type: 'product_photo',
|
|
14
|
+
* title: 'Product photo for listing #1234',
|
|
15
|
+
* instructions: 'Take a clean photo of the product on white background',
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @see api-contract.md — Full API specification
|
|
20
|
+
*/
|
|
21
|
+
import type { Static } from '@sinclair/typebox';
|
|
22
|
+
import type { CreateJobRequest, JobResponse, JobListParams, CreateApiKeyRequest, CreateApiKeyResponse, ApiKeyListItem, RotateApiKeyResponse, CreateWebhookEndpointRequest, WebhookEndpointResponse, UpdateWebhookEndpointRequest, RotateWebhookSecretResponse, WebhookEventResponse, CreditBalanceResponse, CreditTransaction, PurchaseCreditsRequest, PurchaseCreditsResponse } from '@verifyapi/api-contracts';
|
|
23
|
+
export interface FirstHandClientOptions {
|
|
24
|
+
/** API key (fh_live_* or fh_test_*) */
|
|
25
|
+
apiKey: string;
|
|
26
|
+
/** Base URL (default: https://api.firsthandapi.com) */
|
|
27
|
+
baseUrl?: string;
|
|
28
|
+
/** Request timeout in milliseconds (default: 30000) */
|
|
29
|
+
timeoutMs?: number;
|
|
30
|
+
/** Maximum retry attempts for retryable errors (default: 3) */
|
|
31
|
+
maxRetries?: number;
|
|
32
|
+
/** Custom fetch implementation (default: global fetch) */
|
|
33
|
+
fetch?: typeof globalThis.fetch;
|
|
34
|
+
}
|
|
35
|
+
export interface ListResponse<T> {
|
|
36
|
+
object: 'list';
|
|
37
|
+
data: T[];
|
|
38
|
+
has_more: boolean;
|
|
39
|
+
next_cursor: string | null;
|
|
40
|
+
}
|
|
41
|
+
export interface ListOptions {
|
|
42
|
+
[key: string]: unknown;
|
|
43
|
+
cursor?: string;
|
|
44
|
+
limit?: number;
|
|
45
|
+
}
|
|
46
|
+
export interface GetJobOptions {
|
|
47
|
+
/** Long-poll: wait up to N seconds for job to complete (max 60) */
|
|
48
|
+
waitSeconds?: number;
|
|
49
|
+
}
|
|
50
|
+
export declare class FirstHandClient {
|
|
51
|
+
private readonly apiKey;
|
|
52
|
+
private readonly baseUrl;
|
|
53
|
+
private readonly timeoutMs;
|
|
54
|
+
private readonly maxRetries;
|
|
55
|
+
private readonly fetchFn;
|
|
56
|
+
constructor(options: FirstHandClientOptions);
|
|
57
|
+
/** Create a new job for content collection */
|
|
58
|
+
createJob(body: Static<typeof CreateJobRequest>, idempotencyKey?: string): Promise<Static<typeof JobResponse>>;
|
|
59
|
+
/** Get a job by ID. Supports long-polling via waitSeconds option. */
|
|
60
|
+
getJob(jobId: string, options?: GetJobOptions): Promise<Static<typeof JobResponse>>;
|
|
61
|
+
/** List jobs with optional filters */
|
|
62
|
+
listJobs(params?: Static<typeof JobListParams>): Promise<ListResponse<Static<typeof JobResponse>>>;
|
|
63
|
+
/** Get audit trail for a job */
|
|
64
|
+
getJobAudit(jobId: string): Promise<Record<string, unknown>>;
|
|
65
|
+
/** Cancel a pending job */
|
|
66
|
+
cancelJob(jobId: string): Promise<Static<typeof JobResponse>>;
|
|
67
|
+
/** Get files associated with a job (approved submissions with download URLs) */
|
|
68
|
+
getJobFiles(jobId: string): Promise<ListResponse<unknown>>;
|
|
69
|
+
/** Get submissions for a job */
|
|
70
|
+
getJobSubmissions(jobId: string): Promise<ListResponse<unknown>>;
|
|
71
|
+
/** Rate a completed job (1-5 stars with optional feedback) */
|
|
72
|
+
rateJob(jobId: string, body: {
|
|
73
|
+
rating: number;
|
|
74
|
+
feedback?: string;
|
|
75
|
+
}): Promise<Static<typeof JobResponse>>;
|
|
76
|
+
/**
|
|
77
|
+
* Create a job and wait for it to complete.
|
|
78
|
+
* Polls using long-poll until the job reaches a terminal state or timeout.
|
|
79
|
+
*
|
|
80
|
+
* @param body - Job creation request
|
|
81
|
+
* @param maxWaitSeconds - Maximum total wait time (default: 120)
|
|
82
|
+
* @param pollIntervalSeconds - Long-poll interval per request (default: 30)
|
|
83
|
+
*/
|
|
84
|
+
createJobAndWait(body: Static<typeof CreateJobRequest>, maxWaitSeconds?: number, pollIntervalSeconds?: number): Promise<Static<typeof JobResponse>>;
|
|
85
|
+
/** Create a new API key */
|
|
86
|
+
createApiKey(body: Static<typeof CreateApiKeyRequest>): Promise<Static<typeof CreateApiKeyResponse>>;
|
|
87
|
+
/** List API keys (secrets masked) */
|
|
88
|
+
listApiKeys(options?: ListOptions): Promise<ListResponse<Static<typeof ApiKeyListItem>>>;
|
|
89
|
+
/** Rotate an API key (24h overlap window) */
|
|
90
|
+
rotateApiKey(keyId: string): Promise<Static<typeof RotateApiKeyResponse>>;
|
|
91
|
+
/** Revoke an API key immediately */
|
|
92
|
+
revokeApiKey(keyId: string): Promise<void>;
|
|
93
|
+
/** Create a webhook endpoint */
|
|
94
|
+
createWebhookEndpoint(body: Static<typeof CreateWebhookEndpointRequest>): Promise<Static<typeof WebhookEndpointResponse>>;
|
|
95
|
+
/** List webhook endpoints */
|
|
96
|
+
listWebhookEndpoints(options?: ListOptions): Promise<ListResponse<Static<typeof WebhookEndpointResponse>>>;
|
|
97
|
+
/** Get a webhook endpoint by ID */
|
|
98
|
+
getWebhookEndpoint(endpointId: string): Promise<Static<typeof WebhookEndpointResponse>>;
|
|
99
|
+
/** Update a webhook endpoint */
|
|
100
|
+
updateWebhookEndpoint(endpointId: string, body: Static<typeof UpdateWebhookEndpointRequest>): Promise<Static<typeof WebhookEndpointResponse>>;
|
|
101
|
+
/** Delete a webhook endpoint */
|
|
102
|
+
deleteWebhookEndpoint(endpointId: string): Promise<void>;
|
|
103
|
+
/** Rotate webhook signing secret */
|
|
104
|
+
rotateWebhookSecret(endpointId: string): Promise<Static<typeof RotateWebhookSecretResponse>>;
|
|
105
|
+
/** List webhook events */
|
|
106
|
+
listWebhookEvents(options?: ListOptions & {
|
|
107
|
+
status?: string;
|
|
108
|
+
event_type?: string;
|
|
109
|
+
}): Promise<ListResponse<Static<typeof WebhookEventResponse>>>;
|
|
110
|
+
/** Replay a webhook event */
|
|
111
|
+
replayWebhookEvent(eventId: string): Promise<Static<typeof WebhookEventResponse>>;
|
|
112
|
+
/** Get current credit balance */
|
|
113
|
+
getCreditBalance(): Promise<Static<typeof CreditBalanceResponse>>;
|
|
114
|
+
/** List credit transactions */
|
|
115
|
+
listTransactions(options?: ListOptions & {
|
|
116
|
+
type?: string;
|
|
117
|
+
}): Promise<ListResponse<Static<typeof CreditTransaction>>>;
|
|
118
|
+
/** Initiate credit purchase via Stripe Checkout */
|
|
119
|
+
purchaseCredits(body: Static<typeof PurchaseCreditsRequest>): Promise<Static<typeof PurchaseCreditsResponse>>;
|
|
120
|
+
private request;
|
|
121
|
+
}
|
|
122
|
+
/** Generates a random idempotency key (UUID v4 format) */
|
|
123
|
+
export declare function generateIdempotencyKey(): string;
|
|
124
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @firsthandapi/sdk/client
|
|
3
|
+
* @description FirstHandAPI TypeScript SDK client.
|
|
4
|
+
* Typed client wrapping all v1 REST endpoints with auto-retry,
|
|
5
|
+
* idempotency key generation, and proper error handling.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { FirstHandClient } from '@firsthandapi/sdk';
|
|
10
|
+
*
|
|
11
|
+
* const client = new FirstHandClient({ apiKey: 'fh_live_...' });
|
|
12
|
+
* const job = await client.createJob({
|
|
13
|
+
* job_type: 'product_photo',
|
|
14
|
+
* title: 'Product photo for listing #1234',
|
|
15
|
+
* instructions: 'Take a clean photo of the product on white background',
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @see api-contract.md — Full API specification
|
|
20
|
+
*/
|
|
21
|
+
import { FirstHandApiError, FirstHandConnectionError } from './errors.js';
|
|
22
|
+
// ─── Client ─────────────────────────────────────────────────────────────
|
|
23
|
+
const DEFAULT_BASE_URL = 'https://api.firsthandapi.com';
|
|
24
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
25
|
+
const DEFAULT_MAX_RETRIES = 3;
|
|
26
|
+
const RETRY_BASE_DELAY_MS = 1_000;
|
|
27
|
+
export class FirstHandClient {
|
|
28
|
+
apiKey;
|
|
29
|
+
baseUrl;
|
|
30
|
+
timeoutMs;
|
|
31
|
+
maxRetries;
|
|
32
|
+
fetchFn;
|
|
33
|
+
constructor(options) {
|
|
34
|
+
if (!options.apiKey) {
|
|
35
|
+
throw new Error('apiKey is required');
|
|
36
|
+
}
|
|
37
|
+
this.apiKey = options.apiKey;
|
|
38
|
+
this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, '');
|
|
39
|
+
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
40
|
+
this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
41
|
+
this.fetchFn = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
42
|
+
}
|
|
43
|
+
// ── Jobs ───────────────────────────────────────────────────────────
|
|
44
|
+
/** Create a new job for content collection */
|
|
45
|
+
async createJob(body, idempotencyKey) {
|
|
46
|
+
const key = idempotencyKey ?? generateIdempotencyKey();
|
|
47
|
+
return this.request('POST', '/v1/jobs', {
|
|
48
|
+
body,
|
|
49
|
+
headers: { 'Idempotency-Key': key },
|
|
50
|
+
expectedStatus: 201,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/** Get a job by ID. Supports long-polling via waitSeconds option. */
|
|
54
|
+
async getJob(jobId, options) {
|
|
55
|
+
const headers = {};
|
|
56
|
+
if (options?.waitSeconds) {
|
|
57
|
+
headers['Prefer'] = `wait=${Math.min(options.waitSeconds, 60)}`;
|
|
58
|
+
}
|
|
59
|
+
return this.request('GET', `/v1/jobs/${jobId}`, { headers });
|
|
60
|
+
}
|
|
61
|
+
/** List jobs with optional filters */
|
|
62
|
+
async listJobs(params) {
|
|
63
|
+
return this.request('GET', '/v1/jobs', { query: params });
|
|
64
|
+
}
|
|
65
|
+
/** Get audit trail for a job */
|
|
66
|
+
async getJobAudit(jobId) {
|
|
67
|
+
return this.request('GET', `/v1/jobs/${jobId}/audit`);
|
|
68
|
+
}
|
|
69
|
+
/** Cancel a pending job */
|
|
70
|
+
async cancelJob(jobId) {
|
|
71
|
+
return this.request('POST', `/v1/jobs/${jobId}/cancel`, {
|
|
72
|
+
headers: { 'Idempotency-Key': generateIdempotencyKey() },
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/** Get files associated with a job (approved submissions with download URLs) */
|
|
76
|
+
async getJobFiles(jobId) {
|
|
77
|
+
return this.request('GET', `/v1/jobs/${jobId}/files`);
|
|
78
|
+
}
|
|
79
|
+
/** Get submissions for a job */
|
|
80
|
+
async getJobSubmissions(jobId) {
|
|
81
|
+
return this.request('GET', `/v1/jobs/${jobId}/submissions`);
|
|
82
|
+
}
|
|
83
|
+
/** Rate a completed job (1-5 stars with optional feedback) */
|
|
84
|
+
async rateJob(jobId, body) {
|
|
85
|
+
return this.request('POST', `/v1/jobs/${jobId}/rate`, { body });
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Create a job and wait for it to complete.
|
|
89
|
+
* Polls using long-poll until the job reaches a terminal state or timeout.
|
|
90
|
+
*
|
|
91
|
+
* @param body - Job creation request
|
|
92
|
+
* @param maxWaitSeconds - Maximum total wait time (default: 120)
|
|
93
|
+
* @param pollIntervalSeconds - Long-poll interval per request (default: 30)
|
|
94
|
+
*/
|
|
95
|
+
async createJobAndWait(body, maxWaitSeconds = 120, pollIntervalSeconds = 30) {
|
|
96
|
+
const job = await this.createJob(body);
|
|
97
|
+
const terminalStatuses = new Set(['resolved', 'completed', 'timed_out', 'failed', 'cancelled']);
|
|
98
|
+
if (terminalStatuses.has(job.status)) {
|
|
99
|
+
return job;
|
|
100
|
+
}
|
|
101
|
+
const deadline = Date.now() + maxWaitSeconds * 1000;
|
|
102
|
+
while (Date.now() < deadline) {
|
|
103
|
+
const remaining = Math.ceil((deadline - Date.now()) / 1000);
|
|
104
|
+
const waitSeconds = Math.min(pollIntervalSeconds, remaining, 60);
|
|
105
|
+
if (waitSeconds <= 0)
|
|
106
|
+
break;
|
|
107
|
+
const updated = await this.getJob(job.id, { waitSeconds });
|
|
108
|
+
if (terminalStatuses.has(updated.status)) {
|
|
109
|
+
return updated;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Return latest state even if not terminal
|
|
113
|
+
return this.getJob(job.id);
|
|
114
|
+
}
|
|
115
|
+
// ── API Keys ────────────────────────────────────────────────────────
|
|
116
|
+
/** Create a new API key */
|
|
117
|
+
async createApiKey(body) {
|
|
118
|
+
return this.request('POST', '/v1/api_keys', {
|
|
119
|
+
body,
|
|
120
|
+
headers: { 'Idempotency-Key': generateIdempotencyKey() },
|
|
121
|
+
expectedStatus: 201,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
/** List API keys (secrets masked) */
|
|
125
|
+
async listApiKeys(options) {
|
|
126
|
+
return this.request('GET', '/v1/api_keys', { query: options });
|
|
127
|
+
}
|
|
128
|
+
/** Rotate an API key (24h overlap window) */
|
|
129
|
+
async rotateApiKey(keyId) {
|
|
130
|
+
return this.request('POST', `/v1/api_keys/${keyId}/rotate`, {
|
|
131
|
+
headers: { 'Idempotency-Key': generateIdempotencyKey() },
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
/** Revoke an API key immediately */
|
|
135
|
+
async revokeApiKey(keyId) {
|
|
136
|
+
await this.request('POST', `/v1/api_keys/${keyId}/revoke`, {
|
|
137
|
+
headers: { 'Idempotency-Key': generateIdempotencyKey() },
|
|
138
|
+
expectedStatus: 204,
|
|
139
|
+
parseBody: false,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
// ── Webhooks ────────────────────────────────────────────────────────
|
|
143
|
+
/** Create a webhook endpoint */
|
|
144
|
+
async createWebhookEndpoint(body) {
|
|
145
|
+
return this.request('POST', '/v1/webhook_endpoints', {
|
|
146
|
+
body,
|
|
147
|
+
headers: { 'Idempotency-Key': generateIdempotencyKey() },
|
|
148
|
+
expectedStatus: 201,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
/** List webhook endpoints */
|
|
152
|
+
async listWebhookEndpoints(options) {
|
|
153
|
+
return this.request('GET', '/v1/webhook_endpoints', { query: options });
|
|
154
|
+
}
|
|
155
|
+
/** Get a webhook endpoint by ID */
|
|
156
|
+
async getWebhookEndpoint(endpointId) {
|
|
157
|
+
return this.request('GET', `/v1/webhook_endpoints/${endpointId}`);
|
|
158
|
+
}
|
|
159
|
+
/** Update a webhook endpoint */
|
|
160
|
+
async updateWebhookEndpoint(endpointId, body) {
|
|
161
|
+
return this.request('PATCH', `/v1/webhook_endpoints/${endpointId}`, { body });
|
|
162
|
+
}
|
|
163
|
+
/** Delete a webhook endpoint */
|
|
164
|
+
async deleteWebhookEndpoint(endpointId) {
|
|
165
|
+
await this.request('DELETE', `/v1/webhook_endpoints/${endpointId}`, {
|
|
166
|
+
expectedStatus: 204,
|
|
167
|
+
parseBody: false,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
/** Rotate webhook signing secret */
|
|
171
|
+
async rotateWebhookSecret(endpointId) {
|
|
172
|
+
return this.request('POST', `/v1/webhook_endpoints/${endpointId}/rotate_secret`, {
|
|
173
|
+
headers: { 'Idempotency-Key': generateIdempotencyKey() },
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
// ── Webhook Events ─────────────────────────────────────────────────
|
|
177
|
+
/** List webhook events */
|
|
178
|
+
async listWebhookEvents(options) {
|
|
179
|
+
return this.request('GET', '/v1/webhook_events', { query: options });
|
|
180
|
+
}
|
|
181
|
+
/** Replay a webhook event */
|
|
182
|
+
async replayWebhookEvent(eventId) {
|
|
183
|
+
return this.request('POST', `/v1/webhook_events/${eventId}/replay`, {
|
|
184
|
+
headers: { 'Idempotency-Key': generateIdempotencyKey() },
|
|
185
|
+
expectedStatus: 202,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
// ── Billing ────────────────────────────────────────────────────────
|
|
189
|
+
/** Get current credit balance */
|
|
190
|
+
async getCreditBalance() {
|
|
191
|
+
return this.request('GET', '/v1/billing/credits');
|
|
192
|
+
}
|
|
193
|
+
/** List credit transactions */
|
|
194
|
+
async listTransactions(options) {
|
|
195
|
+
return this.request('GET', '/v1/billing/transactions', { query: options });
|
|
196
|
+
}
|
|
197
|
+
/** Initiate credit purchase via Stripe Checkout */
|
|
198
|
+
async purchaseCredits(body) {
|
|
199
|
+
return this.request('POST', '/v1/billing/credits/purchase', {
|
|
200
|
+
body,
|
|
201
|
+
headers: { 'Idempotency-Key': generateIdempotencyKey() },
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
// ── HTTP Layer ─────────────────────────────────────────────────────
|
|
205
|
+
async request(method, path, options = {}) {
|
|
206
|
+
const { body, query, headers: extraHeaders, expectedStatus, parseBody = true } = options;
|
|
207
|
+
let url = `${this.baseUrl}${path}`;
|
|
208
|
+
if (query) {
|
|
209
|
+
const params = new URLSearchParams();
|
|
210
|
+
for (const [key, value] of Object.entries(query)) {
|
|
211
|
+
if (value !== undefined && value !== null) {
|
|
212
|
+
params.set(key, String(value));
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
const qs = params.toString();
|
|
216
|
+
if (qs)
|
|
217
|
+
url += `?${qs}`;
|
|
218
|
+
}
|
|
219
|
+
const headers = {
|
|
220
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
221
|
+
Accept: 'application/json',
|
|
222
|
+
...extraHeaders,
|
|
223
|
+
};
|
|
224
|
+
if (body) {
|
|
225
|
+
headers['Content-Type'] = 'application/json';
|
|
226
|
+
}
|
|
227
|
+
let lastError;
|
|
228
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
229
|
+
if (attempt > 0) {
|
|
230
|
+
// Exponential backoff with jitter
|
|
231
|
+
const delay = RETRY_BASE_DELAY_MS * Math.pow(2, attempt - 1);
|
|
232
|
+
const jitter = delay * 0.1 * Math.random();
|
|
233
|
+
await sleep(delay + jitter);
|
|
234
|
+
}
|
|
235
|
+
try {
|
|
236
|
+
const controller = new AbortController();
|
|
237
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
238
|
+
let response;
|
|
239
|
+
try {
|
|
240
|
+
response = await this.fetchFn(url, {
|
|
241
|
+
method,
|
|
242
|
+
headers,
|
|
243
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
244
|
+
signal: controller.signal,
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
finally {
|
|
248
|
+
clearTimeout(timer);
|
|
249
|
+
}
|
|
250
|
+
// Success range
|
|
251
|
+
if (response.ok) {
|
|
252
|
+
if (!parseBody || response.status === 204) {
|
|
253
|
+
return undefined;
|
|
254
|
+
}
|
|
255
|
+
return (await response.json());
|
|
256
|
+
}
|
|
257
|
+
// Check expected status
|
|
258
|
+
if (expectedStatus && response.status === expectedStatus) {
|
|
259
|
+
if (!parseBody)
|
|
260
|
+
return undefined;
|
|
261
|
+
return (await response.json());
|
|
262
|
+
}
|
|
263
|
+
// Parse error body
|
|
264
|
+
let errorBody;
|
|
265
|
+
try {
|
|
266
|
+
errorBody = (await response.json());
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
errorBody = {
|
|
270
|
+
error: {
|
|
271
|
+
type: 'unknown',
|
|
272
|
+
message: `HTTP ${response.status}`,
|
|
273
|
+
request_id: 'unknown',
|
|
274
|
+
},
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
const apiError = new FirstHandApiError(response.status, {
|
|
278
|
+
type: errorBody.error?.type ?? 'unknown',
|
|
279
|
+
message: errorBody.error?.message ?? `HTTP ${response.status}`,
|
|
280
|
+
request_id: errorBody.error?.request_id ?? 'unknown',
|
|
281
|
+
details: errorBody.error?.details,
|
|
282
|
+
});
|
|
283
|
+
// Only retry on retryable errors
|
|
284
|
+
if (!apiError.retryable || attempt >= this.maxRetries) {
|
|
285
|
+
throw apiError;
|
|
286
|
+
}
|
|
287
|
+
lastError = apiError;
|
|
288
|
+
}
|
|
289
|
+
catch (err) {
|
|
290
|
+
if (err instanceof FirstHandApiError)
|
|
291
|
+
throw err;
|
|
292
|
+
const connError = new FirstHandConnectionError(`Connection failed: ${err.message}`, err);
|
|
293
|
+
if (attempt >= this.maxRetries)
|
|
294
|
+
throw connError;
|
|
295
|
+
lastError = connError;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
throw lastError ?? new FirstHandConnectionError('Request failed after retries');
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────
|
|
302
|
+
function sleep(ms) {
|
|
303
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
304
|
+
}
|
|
305
|
+
/** Generates a random idempotency key (UUID v4 format) */
|
|
306
|
+
export function generateIdempotencyKey() {
|
|
307
|
+
const bytes = new Uint8Array(16);
|
|
308
|
+
crypto.getRandomValues(bytes);
|
|
309
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x40; // version 4
|
|
310
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80; // variant 1
|
|
311
|
+
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');
|
|
312
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
313
|
+
}
|
|
314
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @firsthandapi/sdk/errors
|
|
3
|
+
* @description SDK error types for FirstHandAPI API responses.
|
|
4
|
+
*/
|
|
5
|
+
export interface FirstHandErrorDetail {
|
|
6
|
+
field?: string;
|
|
7
|
+
message: string;
|
|
8
|
+
code?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface FirstHandErrorBody {
|
|
11
|
+
type: string;
|
|
12
|
+
message: string;
|
|
13
|
+
request_id: string;
|
|
14
|
+
details?: FirstHandErrorDetail[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Error thrown when FirstHandAPI returns a non-2xx response.
|
|
18
|
+
* Contains the parsed error envelope from the response body.
|
|
19
|
+
*/
|
|
20
|
+
export declare class FirstHandApiError extends Error {
|
|
21
|
+
readonly status: number;
|
|
22
|
+
readonly type: string;
|
|
23
|
+
readonly requestId: string;
|
|
24
|
+
readonly details?: FirstHandErrorDetail[];
|
|
25
|
+
constructor(status: number, body: FirstHandErrorBody);
|
|
26
|
+
/** True if the error is retryable (429, 500, 502, 503, 504) */
|
|
27
|
+
get retryable(): boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Error thrown when a network failure or timeout occurs.
|
|
31
|
+
*/
|
|
32
|
+
export declare class FirstHandConnectionError extends Error {
|
|
33
|
+
readonly cause?: Error;
|
|
34
|
+
constructor(message: string, cause?: Error);
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,oBAAoB,EAAE,CAAC;CAClC;AAED;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,oBAAoB,EAAE,CAAC;gBAE9B,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB;IASpD,+DAA+D;IAC/D,IAAI,SAAS,IAAI,OAAO,CAEvB;CACF;AAED;;GAEG;AACH,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;gBAEX,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAK3C"}
|