@reqvet-sdk/sdk 2.2.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,516 @@
1
+ # @reqvet/sdk — Technical Reference
2
+
3
+ Complete parameter and response documentation for all SDK methods.
4
+
5
+ ---
6
+
7
+ ## 1) Instantiation
8
+
9
+ ```ts
10
+ import ReqVet from '@reqvet/sdk';
11
+
12
+ const reqvet = new ReqVet(process.env.REQVET_API_KEY!, {
13
+ baseUrl: process.env.REQVET_BASE_URL ?? 'https://api.reqvet.com',
14
+ pollInterval: 5000, // polling interval in ms (default: 5000)
15
+ timeout: 5 * 60 * 1000, // max polling wait in ms (default: 300 000 = 5 min)
16
+ });
17
+ ```
18
+
19
+ The API key must start with `rqv_`. An `Error` is thrown immediately if it doesn't.
20
+
21
+ ---
22
+
23
+ ## 2) Before your first call
24
+
25
+ ### Get your credentials
26
+
27
+ Your ReqVet account manager will provide:
28
+ - `REQVET_API_KEY` — your org API key (`rqv_live_...`)
29
+ - `REQVET_BASE_URL` — the API base URL
30
+ - `REQVET_WEBHOOK_SECRET` — your webhook signing secret (if using webhooks)
31
+
32
+ ### Discover your templates
33
+
34
+ Every job requires a `templateId`. Before generating reports, list the templates available to your organization:
35
+
36
+ ```ts
37
+ const { custom, system } = await reqvet.listTemplates();
38
+ // system = templates created by ReqVet, available to all organizations (read-only)
39
+ // custom = templates created by your organization
40
+ const templateId = system[0].id; // or custom[0].id
41
+ ```
42
+
43
+ ---
44
+
45
+ ## 3) Integration patterns
46
+
47
+ ### A) Webhook-first (recommended for production)
48
+
49
+ ```
50
+ uploadAudio() → createJob({ callbackUrl }) → ReqVet POSTs result to your endpoint
51
+ ```
52
+
53
+ The user can close the browser — the result arrives on your server asynchronously.
54
+
55
+ ### B) Polling (development / simple integrations)
56
+
57
+ ```
58
+ uploadAudio() → createJob() → waitForJob() → report
59
+ ```
60
+
61
+ Or use the convenience wrapper:
62
+
63
+ ```ts
64
+ const report = await reqvet.generateReport({ audio, animalName, templateId, waitForResult: true });
65
+ ```
66
+
67
+ ---
68
+
69
+ ## 4) Methods
70
+
71
+ ### `uploadAudio(audio, fileName?)`
72
+
73
+ Upload an audio file to ReqVet storage.
74
+
75
+ **Parameters:**
76
+ | Name | Type | Required | Description |
77
+ |------|------|----------|-------------|
78
+ | `audio` | `Blob \| File \| Buffer` | ✅ | Audio data |
79
+ | `fileName` | `string` | — | File name, used to infer MIME type (default: `audio.webm`) |
80
+
81
+ **Response:**
82
+ ```ts
83
+ {
84
+ audio_file: string; // canonical storage path — pass this to createJob()
85
+ path: string; // alias of audio_file
86
+ size_bytes: number;
87
+ content_type: string;
88
+ }
89
+ ```
90
+
91
+ Supported formats: `mp3`, `wav`, `webm`, `ogg`, `m4a`, `aac`, `flac`. Max size: 100 MB.
92
+
93
+ ---
94
+
95
+ ### `generateReport(params)`
96
+
97
+ Convenience wrapper: `uploadAudio → createJob`. Optionally waits for completion.
98
+
99
+ **Parameters:**
100
+ | Name | Type | Required | Description |
101
+ |------|------|----------|-------------|
102
+ | `audio` | `Blob \| File \| Buffer` | ✅ | Audio data |
103
+ | `animalName` | `string` | ✅ | Name of the animal |
104
+ | `templateId` | `string` | ✅ | Template UUID (from `listTemplates()`) |
105
+ | `fileName` | `string` | — | File name |
106
+ | `callbackUrl` | `string` | — | Your webhook endpoint (HTTPS, publicly reachable) |
107
+ | `metadata` | `Record<string, unknown>` | — | Passthrough data (e.g. `{ consultationId, vetId }`) |
108
+ | `extraInstructions` | `string` | — | Additional generation instructions injected into the prompt |
109
+ | `waitForResult` | `boolean` | — | If `true`, polls and returns the final report. Default: `false` |
110
+ | `onStatus` | `(status: string) => void` | — | Called on each poll (only when `waitForResult: true`) |
111
+
112
+ **Response:**
113
+ - `waitForResult: false` (default): `{ job_id: string, status: 'pending' }`
114
+ - `waitForResult: true`: `ReqVetReport` (see `waitForJob`)
115
+
116
+ ---
117
+
118
+ ### `createJob(params)`
119
+
120
+ Start a transcription + report generation pipeline.
121
+
122
+ **Parameters:**
123
+ | Name | Type | Required | Description |
124
+ |------|------|----------|-------------|
125
+ | `audioFile` | `string` | ✅ | Value of `uploadAudio().path` |
126
+ | `animalName` | `string` | ✅ | Name of the animal |
127
+ | `templateId` | `string` | ✅ | Template UUID |
128
+ | `callbackUrl` | `string` | — | Webhook URL (HTTPS, publicly reachable). Falls back to the org default webhook if omitted. |
129
+ | `metadata` | `Record<string, unknown>` | — | Passthrough data — correlate with your own records |
130
+ | `extraInstructions` | `string` | — | Extra generation instructions (max 5 000 chars) |
131
+
132
+ **Response:**
133
+ ```ts
134
+ { job_id: string; status: 'pending' }
135
+ ```
136
+
137
+ > **Rate limit**: 10 000 requests/minute per organization.
138
+
139
+ ---
140
+
141
+ ### `listJobs(options?)`
142
+
143
+ List jobs for the authenticated organization, with pagination and filtering.
144
+
145
+ **Parameters:**
146
+ | Name | Type | Default | Description |
147
+ |------|------|---------|-------------|
148
+ | `limit` | `number` | `20` | Results per page (1–100) |
149
+ | `offset` | `number` | `0` | Pagination offset |
150
+ | `status` | `string` | — | Filter: `pending` `transcribing` `generating` `completed` `failed` `amending` |
151
+ | `sort` | `string` | `created_at` | Sort field: `created_at` or `updated_at` |
152
+ | `order` | `string` | `desc` | Direction: `asc` or `desc` |
153
+
154
+ **Response:**
155
+ ```ts
156
+ {
157
+ jobs: JobSummary[];
158
+ pagination: { total: number; limit: number; offset: number; has_more: boolean };
159
+ }
160
+ ```
161
+
162
+ ---
163
+
164
+ ### `getJob(jobId)`
165
+
166
+ Get the current state and result of a job.
167
+
168
+ **Response fields by status:**
169
+
170
+ | Field | `pending` | `transcribing` | `generating` | `completed` | `failed` |
171
+ |-------|:---------:|:--------------:|:------------:|:-----------:|:--------:|
172
+ | `job_id` | ✅ | ✅ | ✅ | ✅ | ✅ |
173
+ | `status` | ✅ | ✅ | ✅ | ✅ | ✅ |
174
+ | `animal_name` | ✅ | ✅ | ✅ | ✅ | ✅ |
175
+ | `metadata` | ✅ | ✅ | ✅ | ✅ | ✅ |
176
+ | `transcription` | — | — | ✅ | ✅ | — |
177
+ | `result.html` | — | — | — | ✅ | — |
178
+ | `result.fields` | — | — | — | ✅* | — |
179
+ | `cost` | — | — | — | ✅ | — |
180
+ | `error` | — | — | — | — | ✅ |
181
+
182
+ *`result.fields` is only present if your organization has a `field_schema` configured (structured data extraction). It is `null` otherwise. See [Field schema](#field-schema) below.
183
+
184
+ **Cost structure (completed jobs):**
185
+ ```ts
186
+ cost: {
187
+ transcription_usd: number;
188
+ generation_usd: number;
189
+ total_usd: number;
190
+ }
191
+ ```
192
+
193
+ > **Note**: `cost` is available via `getJob()` and `waitForJob()`, but is **not** included in webhook payloads. Retrieve it with `getJob()` after receiving a `job.completed` event if needed.
194
+
195
+ ---
196
+
197
+ ### `waitForJob(jobId, onStatus?)`
198
+
199
+ Poll until a job reaches `completed` or `failed`. Respects `pollInterval` and `timeout`.
200
+
201
+ **Response (`ReqVetReport`):**
202
+ ```ts
203
+ {
204
+ jobId: string;
205
+ html: string; // generated report HTML
206
+ fields: ExtractedFields | null; // null if no field_schema configured
207
+ transcription: string;
208
+ animalName: string;
209
+ cost: { transcription_usd: number; generation_usd: number; total_usd: number };
210
+ metadata: Record<string, unknown>;
211
+ }
212
+ ```
213
+
214
+ Throws `ReqVetError` if the job fails or the timeout is exceeded.
215
+
216
+ ---
217
+
218
+ ### `regenerateJob(jobId, options?)`
219
+
220
+ Regenerate the report for a completed job — e.g. with different instructions or a different template.
221
+
222
+ **Parameters:**
223
+ | Name | Type | Description |
224
+ |------|------|-------------|
225
+ | `extraInstructions` | `string` | New instructions (max 2 000 chars) |
226
+ | `templateId` | `string` | Switch to a different template |
227
+
228
+ **Response:**
229
+ ```ts
230
+ { job_id: string; status: 'completed'; result: { html: string; fields?: ExtractedFields } }
231
+ ```
232
+
233
+ Triggers a `job.regenerated` webhook event if a `callbackUrl` is configured.
234
+
235
+ > **Rate limit**: 30 requests/minute per organization.
236
+
237
+ ---
238
+
239
+ ### `amendJob(jobId, params)`
240
+
241
+ Add an audio complement to a completed job. The new audio is transcribed, merged with the existing transcription, and the report is regenerated.
242
+
243
+ **Parameters:**
244
+ | Name | Type | Required | Description |
245
+ |------|------|----------|-------------|
246
+ | `audioFile` | `string` | ✅ | Value of `uploadAudio().path` |
247
+ | `templateId` | `string` | — | Switch to a different template |
248
+
249
+ **Response:**
250
+ ```ts
251
+ { job_id: string; status: 'amending'; amendment_number: number; message: string }
252
+ ```
253
+
254
+ The job returns to `completed` when the amendment finishes. Use `waitForJob()` or listen for the `job.amended` webhook event. Multiple amendments are supported — each one appends to the full transcription.
255
+
256
+ ---
257
+
258
+ ### `reformulateReport(jobId, params)`
259
+
260
+ Generate an alternative version of a completed report for a specific audience.
261
+
262
+ **Parameters:**
263
+ | Name | Type | Required | Description |
264
+ |------|------|----------|-------------|
265
+ | `purpose` | `string` | ✅ | `owner` `referral` `summary` `custom` `diagnostic_hypothesis` |
266
+ | `customInstructions` | `string` | If `purpose: 'custom'` | Reformulation instructions |
267
+
268
+ **Purpose values:**
269
+ | Value | Output |
270
+ |-------|--------|
271
+ | `owner` | Simplified version for the pet owner |
272
+ | `referral` | Clinical summary for a specialist |
273
+ | `summary` | Short internal note |
274
+ | `diagnostic_hypothesis` | Differential diagnosis list |
275
+ | `custom` | Defined by `customInstructions` |
276
+
277
+ **Response (`ReqVetReformulation`):**
278
+ ```ts
279
+ {
280
+ id: string;
281
+ job_id: string;
282
+ purpose: string;
283
+ html: string;
284
+ custom_instructions?: string;
285
+ cost: { model: string; prompt_tokens: number; completion_tokens: number; cost_usd: number };
286
+ created_at: string;
287
+ }
288
+ ```
289
+
290
+ > **Rate limit**: 30 requests/minute per organization.
291
+
292
+ ---
293
+
294
+ ### `listReformulations(jobId)`
295
+
296
+ **Response:** `{ reformulations: ReqVetReformulation[] }`
297
+
298
+ ---
299
+
300
+ ### Templates
301
+
302
+ #### `listTemplates()` → `{ custom: Template[], system: Template[] }`
303
+
304
+ - **`system`** — templates created by ReqVet, visible to all organizations. Read-only. Start here to find available `templateId` values.
305
+ - **`custom`** — templates created by your organization. Editable via `createTemplate` / `updateTemplate`.
306
+
307
+ #### `getTemplate(templateId)` → `Template`
308
+
309
+ #### `createTemplate(params)` → `Template`
310
+
311
+ | Name | Type | Required |
312
+ |------|------|----------|
313
+ | `name` | `string` | ✅ |
314
+ | `content` | `string` | ✅ |
315
+ | `description` | `string` | — |
316
+ | `is_default` | `boolean` | — |
317
+
318
+ #### `updateTemplate(templateId, updates)` → `Template`
319
+
320
+ All fields optional (partial update). Same fields as `createTemplate`.
321
+
322
+ #### `deleteTemplate(templateId)` → `{ success: true }`
323
+
324
+ ---
325
+
326
+ ### `health()`
327
+
328
+ **Response:** `{ status: 'ok' | 'degraded'; timestamp: string }`
329
+
330
+ ---
331
+
332
+ ## 5) Field schema
333
+
334
+ If your organization has a `field_schema` configured, ReqVet extracts structured fields from each consultation in addition to generating the HTML report.
335
+
336
+ Example `result.fields` for a standard checkup:
337
+
338
+ ```json
339
+ {
340
+ "espece": "Chien",
341
+ "race": "Labrador",
342
+ "poids": 28.5,
343
+ "temperature": 38.6,
344
+ "traitements": ["Frontline", "Milbemax"],
345
+ "sterilise": true,
346
+ "prochain_rdv": "Dans 6 mois"
347
+ }
348
+ ```
349
+
350
+ `fields` is `null` if no `field_schema` is configured for your organization. Contact your ReqVet account manager to enable and configure structured extraction.
351
+
352
+ ---
353
+
354
+ ## 6) Webhook events
355
+
356
+ ReqVet POSTs to your `callbackUrl` when a job changes state. All events share the same format.
357
+
358
+ ### Headers
359
+
360
+ ```
361
+ Content-Type: application/json
362
+ X-ReqVet-Signature: sha256=<hex> (only if org has a webhook_secret)
363
+ X-ReqVet-Timestamp: <unix_ms> (only if org has a webhook_secret)
364
+ ```
365
+
366
+ ### Event types and payloads
367
+
368
+ #### `job.completed`
369
+
370
+ ```json
371
+ {
372
+ "event": "job.completed",
373
+ "job_id": "a1b2c3d4-...",
374
+ "animal_name": "Rex",
375
+ "transcription": "Le vétérinaire examine Rex, labrador de 5 ans...",
376
+ "html": "<section class=\"cr\">...</section>",
377
+ "fields": { "espece": "Chien", "poids": 28.5 },
378
+ "metadata": { "consultationId": "abc123", "vetId": "v42" }
379
+ }
380
+ ```
381
+
382
+ > `fields` is absent if the organization has no `field_schema`. `cost` is not in the webhook — retrieve it with `getJob()` if needed.
383
+
384
+ ---
385
+
386
+ #### `job.failed`
387
+
388
+ ```json
389
+ {
390
+ "event": "job.failed",
391
+ "job_id": "a1b2c3d4-...",
392
+ "animal_name": "Rex",
393
+ "error": "Transcription failed",
394
+ "metadata": { "consultationId": "abc123" }
395
+ }
396
+ ```
397
+
398
+ ---
399
+
400
+ #### `job.amended`
401
+
402
+ Sent when an amendment (`amendJob`) completes successfully.
403
+
404
+ ```json
405
+ {
406
+ "event": "job.amended",
407
+ "job_id": "a1b2c3d4-...",
408
+ "animal_name": "Rex",
409
+ "transcription": "...full transcription including amendment...",
410
+ "html": "<section class=\"cr\">...</section>",
411
+ "amendment_number": 1,
412
+ "fields": { "espece": "Chien", "poids": 28.5 },
413
+ "metadata": { "consultationId": "abc123" }
414
+ }
415
+ ```
416
+
417
+ ---
418
+
419
+ #### `job.amend_failed`
420
+
421
+ Sent when amendment transcription fails. The original report is preserved.
422
+
423
+ ```json
424
+ {
425
+ "event": "job.amend_failed",
426
+ "job_id": "a1b2c3d4-...",
427
+ "animal_name": "Rex",
428
+ "error": "Amendment transcription failed",
429
+ "metadata": { "consultationId": "abc123" }
430
+ }
431
+ ```
432
+
433
+ ---
434
+
435
+ #### `job.regenerated`
436
+
437
+ Sent when `regenerateJob()` completes.
438
+
439
+ ```json
440
+ {
441
+ "event": "job.regenerated",
442
+ "job_id": "a1b2c3d4-...",
443
+ "animal_name": "Rex",
444
+ "html": "<section class=\"cr\">...</section>",
445
+ "fields": { "espece": "Chien", "poids": 28.5 },
446
+ "metadata": { "consultationId": "abc123" }
447
+ }
448
+ ```
449
+
450
+ ---
451
+
452
+ ### Retry policy
453
+
454
+ ReqVet retries failed webhook deliveries **3 times** with delays of 0s, 2s, and 5s. After 3 failures, the event is marked as undelivered. Implement idempotency in your handler (deduplicate on `job_id + event`).
455
+
456
+ ---
457
+
458
+ ## 7) Webhook verification
459
+
460
+ ```ts
461
+ import { verifyWebhookSignature } from '@reqvet/sdk/webhooks';
462
+
463
+ const { ok, reason } = verifyWebhookSignature({
464
+ secret: process.env.REQVET_WEBHOOK_SECRET!,
465
+ rawBody, // raw request body string — read BEFORE JSON.parse
466
+ signature, // X-ReqVet-Signature header value
467
+ timestamp, // X-ReqVet-Timestamp header value
468
+ maxSkewMs: 5 * 60 * 1000, // reject events older than 5 min (default)
469
+ });
470
+ ```
471
+
472
+ Rejection reasons: `missing_headers` `invalid_timestamp` `stale_timestamp` `invalid_signature`
473
+
474
+ See [SECURITY.md](./SECURITY.md) for a complete Next.js implementation example.
475
+
476
+ ---
477
+
478
+ ## 8) Error handling
479
+
480
+ All methods throw `ReqVetError` on HTTP errors or network failures:
481
+
482
+ ```ts
483
+ import { ReqVetError } from '@reqvet/sdk';
484
+
485
+ try {
486
+ const report = await reqvet.waitForJob(jobId);
487
+ } catch (err) {
488
+ if (err instanceof ReqVetError) {
489
+ console.error(err.message); // human-readable message
490
+ console.error(err.status); // HTTP status (0 for network/timeout errors)
491
+ console.error(err.body); // raw response body
492
+ }
493
+ }
494
+ ```
495
+
496
+ | Status | Meaning |
497
+ |--------|---------|
498
+ | `400` | Validation error — check `err.body.issues` |
499
+ | `401` | Invalid or missing API key |
500
+ | `403` | Monthly quota exceeded |
501
+ | `404` | Job or template not found |
502
+ | `429` | Rate limit exceeded — back off and retry |
503
+ | `500` | ReqVet internal error |
504
+
505
+ ---
506
+
507
+ ## 9) Integration checklist
508
+
509
+ - [ ] SDK used **server-side only** — API key never in browser bundles
510
+ - [ ] `listTemplates()` called at startup to discover available `templateId` values
511
+ - [ ] `metadata` used to correlate ReqVet jobs with your own records (`consultationId`, `vetId`, etc.)
512
+ - [ ] Webhook endpoint handles all 5 event types: `job.completed`, `job.failed`, `job.amended`, `job.amend_failed`, `job.regenerated`
513
+ - [ ] Webhook signature verified on every incoming event
514
+ - [ ] Timestamp anti-replay check enabled (`maxSkewMs`)
515
+ - [ ] Idempotency implemented — deduplicate on `job_id + event`
516
+ - [ ] `REQVET_API_KEY` and `REQVET_WEBHOOK_SECRET` stored in environment variables, never hardcoded
package/SECURITY.md ADDED
@@ -0,0 +1,119 @@
1
+ # Security
2
+
3
+ ## API key management
4
+
5
+ Your ReqVet API key (`rqv_live_...`) grants full access to your organization's data and quota. Treat it like a password.
6
+
7
+ **Never** expose it in:
8
+ - Client-side JavaScript (React, Vue, browser bundles)
9
+ - Mobile app binaries
10
+ - Public repositories
11
+ - Logs or error messages
12
+
13
+ **Always** load it from environment variables server-side:
14
+
15
+ ```ts
16
+ const reqvet = new ReqVet(process.env.REQVET_API_KEY!);
17
+ ```
18
+
19
+ ## Proxy pattern (required for browser integrations)
20
+
21
+ If your frontend records audio in the browser, use a server-side proxy — your backend calls ReqVet, never the browser directly:
22
+
23
+ ```
24
+ Browser → your server (proxy) → ReqVet API
25
+ ```
26
+
27
+ Example proxy route (Next.js App Router):
28
+
29
+ ```ts
30
+ // app/api/reqvet/generate/route.ts
31
+ import { NextRequest, NextResponse } from 'next/server';
32
+ import ReqVet from '@reqvet/sdk';
33
+
34
+ const reqvet = new ReqVet(process.env.REQVET_API_KEY!);
35
+
36
+ export async function POST(req: NextRequest) {
37
+ const form = await req.formData();
38
+ const audio = form.get('audio') as File;
39
+
40
+ const { path } = await reqvet.uploadAudio(audio, audio.name);
41
+ const job = await reqvet.createJob({
42
+ audioFile: path,
43
+ animalName: form.get('animalName') as string,
44
+ templateId: form.get('templateId') as string,
45
+ callbackUrl: process.env.REQVET_WEBHOOK_URL,
46
+ });
47
+
48
+ return NextResponse.json(job);
49
+ }
50
+ ```
51
+
52
+ ## Webhook signature verification
53
+
54
+ Every ReqVet webhook is signed with HMAC-SHA256. Always verify the signature before processing.
55
+
56
+ ```ts
57
+ import { verifyWebhookSignature } from '@reqvet/sdk/webhooks';
58
+
59
+ export async function POST(req: NextRequest) {
60
+ const rawBody = await req.text();
61
+ const signature = req.headers.get('x-reqvet-signature') ?? '';
62
+ const timestamp = req.headers.get('x-reqvet-timestamp') ?? '';
63
+
64
+ const { ok, reason } = verifyWebhookSignature({
65
+ secret: process.env.REQVET_WEBHOOK_SECRET!,
66
+ rawBody,
67
+ signature,
68
+ timestamp,
69
+ maxSkewMs: 5 * 60 * 1000, // reject events older than 5 minutes
70
+ });
71
+
72
+ if (!ok) {
73
+ console.warn('Webhook rejected:', reason);
74
+ return new Response('Unauthorized', { status: 401 });
75
+ }
76
+
77
+ const event = JSON.parse(rawBody);
78
+ // process event.job_id, event.status, event.result ...
79
+ }
80
+ ```
81
+
82
+ **Signature format:**
83
+ - Header `X-ReqVet-Signature: sha256=<hex>`
84
+ - Header `X-ReqVet-Timestamp: <unix_ms>`
85
+ - Signed message: `HMAC_SHA256(secret, "${timestamp}.${rawBody}")`
86
+
87
+ **Rejection reasons:**
88
+ | `reason` | Cause |
89
+ |----------|-------|
90
+ | `missing_headers` | Signature or timestamp header absent |
91
+ | `invalid_timestamp` | Timestamp is not a valid number |
92
+ | `stale_timestamp` | Event is outside the allowed time window |
93
+ | `invalid_signature` | HMAC does not match |
94
+
95
+ ## Idempotency
96
+
97
+ Webhooks may be delivered more than once. Use `job_id` + `event` as a deduplication key before processing:
98
+
99
+ ```ts
100
+ const key = `${event.job_id}:${event.event}`;
101
+ if (await cache.has(key)) return new Response('OK'); // already processed
102
+ await cache.set(key, true, { ttl: 86400 });
103
+ // process...
104
+ ```
105
+
106
+ ## API key rotation
107
+
108
+ If a key is compromised:
109
+
110
+ 1. Generate a new key from your ReqVet admin panel
111
+ 2. Update `REQVET_API_KEY` in your environment variables
112
+ 3. Redeploy your application
113
+ 4. Revoke the old key
114
+
115
+ ## Responsible disclosure
116
+
117
+ If you discover a security vulnerability in this SDK or the ReqVet API, report it privately to **security@reqvet.com**. Do not open a public GitHub issue for security vulnerabilities.
118
+
119
+ We commit to acknowledging reports within 48 hours and providing a fix timeline within 7 days for critical issues.
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@reqvet-sdk/sdk",
3
+ "version": "2.2.0",
4
+ "description": "Official JavaScript SDK for the ReqVet veterinary report generation API.",
5
+ "type": "module",
6
+ "main": "./src/index.js",
7
+ "types": "./src/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./src/index.js",
11
+ "types": "./src/index.d.ts",
12
+ "default": "./src/index.js"
13
+ },
14
+ "./webhooks": {
15
+ "import": "./src/webhooks.js",
16
+ "types": "./src/webhooks.d.ts",
17
+ "default": "./src/webhooks.js"
18
+ },
19
+ "./package.json": "./package.json"
20
+ },
21
+ "files": ["src/", "README.md", "SDK_REFERENCE.md", "CHANGELOG.md", "SECURITY.md"],
22
+ "keywords": [
23
+ "reqvet",
24
+ "veterinary",
25
+ "transcription",
26
+ "ai",
27
+ "sdk"
28
+ ],
29
+ "author": "ReqVet <contact@reqvet.com>",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "https://github.com/reqvet/reqvet-sdk.git"
33
+ },
34
+ "homepage": "https://github.com/reqvet/reqvet-sdk#readme",
35
+ "bugs": {
36
+ "url": "https://github.com/reqvet/reqvet-sdk/issues"
37
+ },
38
+ "license": "MIT",
39
+ "engines": {
40
+ "node": ">=18.0.0"
41
+ }
42
+ }