@yannelli/nextvisit-sdk 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,399 @@
1
+ # Nextvisit API JavaScript/TypeScript SDK
2
+
3
+ Official JavaScript/TypeScript client library for the [Nextvisit AI Clinical Documentation API](https://developers.nextvisit.app).
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@yannelli/nextvisit-sdk.svg)](https://www.npmjs.com/package/@yannelli/nextvisit-sdk)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## Features
9
+
10
+ - Full TypeScript support with comprehensive type definitions
11
+ - Promise-based async/await API
12
+ - Automatic error handling with typed exceptions
13
+ - Support for both CommonJS and ES Modules
14
+ - Zero runtime dependencies
15
+ - Node.js 18+ support
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install @yannelli/nextvisit-sdk
21
+ ```
22
+
23
+ Or with yarn:
24
+
25
+ ```bash
26
+ yarn add @yannelli/nextvisit-sdk
27
+ ```
28
+
29
+ ## Quick Start
30
+
31
+ ```typescript
32
+ import { NextvisitClient } from "@yannelli/nextvisit-sdk";
33
+
34
+ // Create a client with an existing token
35
+ const client = new NextvisitClient({
36
+ token: "nv-sk-your-token-here"
37
+ });
38
+
39
+ // Get the current user
40
+ const user = await client.users.getCurrentUser();
41
+ console.log(`Logged in as ${user.name}`);
42
+
43
+ // List patients
44
+ const patients = await client.patients.list();
45
+ console.log(`Found ${patients.meta.total} patients`);
46
+ ```
47
+
48
+ ## Configuration
49
+
50
+ ### Client Options
51
+
52
+ ```typescript
53
+ interface NextvisitClientConfig {
54
+ token?: string; // Authentication token
55
+ baseUrl?: string; // API base URL (default: https://nextvisit.app/api)
56
+ fetch?: typeof fetch; // Custom fetch implementation
57
+ timeout?: number; // Request timeout in ms (default: 30000)
58
+ }
59
+ ```
60
+
61
+ ### Examples
62
+
63
+ ```typescript
64
+ // Production client
65
+ const client = new NextvisitClient({
66
+ token: "nv-sk-your-token"
67
+ });
68
+
69
+ // Local development
70
+ const client = new NextvisitClient({
71
+ baseUrl: "http://localhost/api",
72
+ token: "dev-token"
73
+ });
74
+
75
+ // Custom timeout
76
+ const client = new NextvisitClient({
77
+ token: "nv-sk-your-token",
78
+ timeout: 60000 // 60 seconds
79
+ });
80
+ ```
81
+
82
+ ### Token Management
83
+
84
+ ```typescript
85
+ // Set token after initialization
86
+ client.setToken("nv-sk-new-token");
87
+
88
+ // Clear token
89
+ client.clearToken();
90
+
91
+ // Check if authenticated
92
+ if (client.hasToken()) {
93
+ console.log("Client is authenticated");
94
+ }
95
+ ```
96
+
97
+ ## API Reference
98
+
99
+ ### Authentication
100
+
101
+ ```typescript
102
+ // Login and get a token
103
+ const response = await client.auth.createToken({
104
+ email: "user@example.com",
105
+ password: "password",
106
+ device_name: "My App"
107
+ });
108
+ client.setToken(response.token);
109
+
110
+ // List all tokens
111
+ const { tokens } = await client.auth.listTokens();
112
+ tokens.forEach(t => {
113
+ console.log(`${t.name} - Created: ${t.created_at}`);
114
+ });
115
+
116
+ // Logout (revoke current token)
117
+ await client.auth.revokeCurrentToken();
118
+
119
+ // Revoke a specific token
120
+ await client.auth.revokeToken(tokenId);
121
+ ```
122
+
123
+ ### Users
124
+
125
+ ```typescript
126
+ // Get current authenticated user
127
+ const user = await client.users.getCurrentUser();
128
+ console.log(user.id, user.name, user.email);
129
+ ```
130
+
131
+ ### Patients
132
+
133
+ ```typescript
134
+ // List patients with pagination
135
+ const response = await client.patients.list({
136
+ per_page: 25,
137
+ sort: "-created_at" // Descending by creation date
138
+ });
139
+
140
+ // Filter patients
141
+ const filtered = await client.patients.list({
142
+ "filter[last_name]": "Smith",
143
+ "filter[trashed]": "with" // Include soft-deleted
144
+ });
145
+
146
+ // Get a single patient
147
+ const patient = await client.patients.get(patientId);
148
+
149
+ // Create a patient
150
+ const newPatient = await client.patients.create({
151
+ first_name: "John",
152
+ last_name: "Doe",
153
+ date_of_birth: "1990-05-15",
154
+ notes: "Referred for consultation",
155
+ allergies: "Penicillin"
156
+ });
157
+
158
+ // Update a patient
159
+ const updated = await client.patients.update(patientId, {
160
+ first_name: "Jonathan",
161
+ notes: "Updated contact information"
162
+ });
163
+
164
+ // Delete a patient (soft delete)
165
+ await client.patients.delete(patientId);
166
+
167
+ // Search patients
168
+ const results = await client.patients.search(userId, {
169
+ query: "John",
170
+ per_page: 10,
171
+ sort_by: "desc"
172
+ });
173
+ ```
174
+
175
+ ### Progress Notes
176
+
177
+ ```typescript
178
+ // List progress notes
179
+ const notes = await client.progressNotes.list({
180
+ patient_id: patientId,
181
+ per_page: 25,
182
+ sort_by: "latest" // or "oldest"
183
+ });
184
+
185
+ // Get a single progress note
186
+ const note = await client.progressNotes.get(noteId);
187
+
188
+ // Get audio URL for a note
189
+ const { url } = await client.progressNotes.getAudioUrl(noteId);
190
+
191
+ // Create a progress note with audio
192
+ const audioFile = new File([audioBlob], "recording.mp3", {
193
+ type: "audio/mpeg"
194
+ });
195
+
196
+ const note = await client.progressNotes.create({
197
+ name: "Follow-up Visit - John Doe",
198
+ patient_id: patientId,
199
+ file: audioFile,
200
+ model_id: 1 // Optional template
201
+ });
202
+
203
+ // Create a text-only progress note
204
+ const textNote = await client.progressNotes.create({
205
+ name: "Patient Consultation",
206
+ note: "Patient presented with symptoms of...",
207
+ model_id: 1,
208
+ patient_id: patientId
209
+ });
210
+
211
+ // Update a progress note
212
+ const updated = await client.progressNotes.update(noteId, {
213
+ name: "Updated Visit Name",
214
+ transcription: "Corrected transcription..."
215
+ });
216
+
217
+ // Sign/approve a progress note
218
+ const signedNote = await client.progressNotes.sign(noteId);
219
+
220
+ // Delete a progress note
221
+ await client.progressNotes.delete(noteId);
222
+ ```
223
+
224
+ **Supported audio formats:** mp3, mp4, m4a, wav, ogg, webm, flac, aac, pcm, opus
225
+ **Maximum file size:** 200MB
226
+
227
+ ### Billing
228
+
229
+ ```typescript
230
+ // List available plans
231
+ const { plans } = await client.billing.listPlans();
232
+ plans.forEach(plan => {
233
+ console.log(`${plan.name}: ${plan.price_prefix}${plan.price}${plan.price_suffix}`);
234
+ });
235
+
236
+ // Get billing estimate
237
+ const estimate = await client.billing.getEstimate();
238
+ console.log(`Users: ${estimate.users}`);
239
+ console.log(`Total: ${estimate.total_formatted}`);
240
+ console.log(`Renewal: ${estimate.renewal_date}`);
241
+
242
+ // Get usage statistics
243
+ const usage = await client.billing.getUsage("notes");
244
+ console.log(`Plan: ${usage.plan.name} (${usage.plan.status})`);
245
+ console.log(`Usage: ${usage.usage.used} / ${usage.usage.limit}`);
246
+ ```
247
+
248
+ ### Transcription
249
+
250
+ ```typescript
251
+ // Transcribe an audio file
252
+ const response = await client.transcription.transcribeFile({
253
+ file: audioFile // File or Blob
254
+ });
255
+
256
+ if (response.success) {
257
+ console.log(response.text);
258
+ }
259
+
260
+ // Get temporary token for client-side transcription
261
+ const tokenResponse = await client.transcription.getToken();
262
+ if (tokenResponse.success && tokenResponse.token) {
263
+ // Use with Deepgram SDK for real-time transcription
264
+ const deepgram = createClient(tokenResponse.token);
265
+ }
266
+ ```
267
+
268
+ ## Error Handling
269
+
270
+ The SDK provides typed error classes for different failure scenarios:
271
+
272
+ ```typescript
273
+ import {
274
+ NextvisitError,
275
+ NextvisitApiError,
276
+ UnauthorizedError,
277
+ ForbiddenError,
278
+ NotFoundError,
279
+ ValidationError,
280
+ NetworkError
281
+ } from "@yannelli/nextvisit-sdk";
282
+
283
+ try {
284
+ const user = await client.users.getCurrentUser();
285
+ } catch (error) {
286
+ if (error instanceof UnauthorizedError) {
287
+ // 401 - Authentication failed
288
+ console.error("Please log in again");
289
+ } else if (error instanceof ForbiddenError) {
290
+ // 403 - Access denied
291
+ console.error("You don't have permission");
292
+ } else if (error instanceof NotFoundError) {
293
+ // 404 - Resource not found
294
+ console.error("Resource not found");
295
+ } else if (error instanceof ValidationError) {
296
+ // 422 - Validation failed
297
+ console.error("Validation errors:", error.errors);
298
+ } else if (error instanceof NetworkError) {
299
+ // Network request failed
300
+ console.error("Network error:", error.message);
301
+ } else if (error instanceof NextvisitApiError) {
302
+ // Other API error
303
+ console.error(`API error (${error.status}): ${error.message}`);
304
+ }
305
+ }
306
+ ```
307
+
308
+ ### Error Classes
309
+
310
+ | Class | Status Code | Description |
311
+ |-------|-------------|-------------|
312
+ | `NextvisitError` | - | Base error class |
313
+ | `NextvisitApiError` | Any | API error with status code |
314
+ | `UnauthorizedError` | 401 | Authentication required |
315
+ | `ForbiddenError` | 403 | Access denied |
316
+ | `NotFoundError` | 404 | Resource not found |
317
+ | `ValidationError` | 422 | Validation failed (includes `errors` field) |
318
+ | `NetworkError` | - | Network request failure |
319
+
320
+ ## TypeScript Support
321
+
322
+ All API responses are fully typed. Import types directly from the package:
323
+
324
+ ```typescript
325
+ import type {
326
+ User,
327
+ PatientFull,
328
+ ProgressNote,
329
+ PaginatedResponse,
330
+ TokenResponse,
331
+ BillingPlan,
332
+ BillingUsage
333
+ } from "@yannelli/nextvisit-sdk";
334
+
335
+ // Types are inferred from API calls
336
+ const patient = await client.patients.get(123);
337
+ // patient is typed as PatientFull
338
+
339
+ const notes = await client.progressNotes.list();
340
+ // notes is typed as PaginatedResponse<ProgressNote>
341
+ ```
342
+
343
+ ## Development
344
+
345
+ ### Prerequisites
346
+
347
+ - Node.js 18.0.0 or higher
348
+
349
+ ### Setup
350
+
351
+ ```bash
352
+ # Clone the repository
353
+ git clone https://github.com/yannelli/nextvisit-sdk.git
354
+ cd nextvisit-sdk
355
+
356
+ # Install dependencies
357
+ npm install
358
+ ```
359
+
360
+ ### Scripts
361
+
362
+ ```bash
363
+ # Build the package
364
+ npm run build
365
+
366
+ # Run tests
367
+ npm test
368
+
369
+ # Run tests in watch mode
370
+ npm run test:watch
371
+
372
+ # Run tests with coverage
373
+ npm run test:coverage
374
+
375
+ # Type checking
376
+ npm run typecheck
377
+
378
+ # Lint code
379
+ npm run lint
380
+ ```
381
+
382
+ ### Building
383
+
384
+ The package is built using [tsup](https://tsup.egoist.dev/) and outputs:
385
+
386
+ - `dist/index.js` - CommonJS bundle
387
+ - `dist/index.mjs` - ES Module bundle
388
+ - `dist/index.d.ts` - TypeScript declarations
389
+
390
+ ## License
391
+
392
+ MIT License - see [LICENSE](LICENSE) for details.
393
+
394
+ ## Links
395
+
396
+ - [Documentation](https://docs.nextvisitai.com)
397
+ - [Nextvisit AI](https://nextvisitai.com)
398
+ - [npm Package](https://www.npmjs.com/package/@yannelli/nextvisit-sdk)
399
+ - [GitHub Repository](https://github.com/yannelli/nextvisit-sdk)