@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.
@@ -0,0 +1,4 @@
1
+
2
+ > @verifyapi/sdk@0.1.0 build /Users/jjfisher/verifyapi_v1/packages/sdk
3
+ > tsc
4
+
@@ -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
+  RUN  v4.1.0 /Users/jjfisher/verifyapi_v1/packages/sdk
7
+
8
+ ✓ src/__tests__/errors.test.ts (8 tests) 8ms
9
+ ✓ src/__tests__/webhooks.test.ts (11 tests) 19ms
10
+ ✓ src/__tests__/client.test.ts (31 tests) 3285ms
11
+ ✓ retries on 429 and succeeds  1100ms
12
+ ✓ retries on 500 and eventually throws after max retries  1073ms
13
+ ✓ retries on connection error  1090ms
14
+
15
+  Test Files  3 passed (3)
16
+  Tests  50 passed (50)
17
+  Start at  18:18:26
18
+  Duration  3.62s (transform 236ms, setup 0ms, import 378ms, tests 3.31s, environment 0ms)
19
+
@@ -0,0 +1,4 @@
1
+
2
+ > @verifyapi/sdk@0.1.0 typecheck /Users/jjfisher/verifyapi_v1/packages/sdk
3
+ > tsc --noEmit
4
+
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
@@ -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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"}
@@ -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"}