@hipnation-truth/sdk 0.11.0 → 0.13.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/index.d.mts CHANGED
@@ -198,6 +198,30 @@ declare class AttachmentsResource {
198
198
  }>;
199
199
  get(attachmentId: string): Promise<Attachment | null>;
200
200
  listByConversation(conversationId: string): Promise<Attachment[]>;
201
+ /**
202
+ * One-shot upload: presign → PUT to S3 → record in Convex → return a
203
+ * 7-day signed download URL ready to embed in an outbound SMS. Caller
204
+ * passes the resulting `downloadUrl` to `messages.dialpad.sendSms` (or
205
+ * the new `messages.sendAttachmentMessage`) to actually deliver it.
206
+ *
207
+ * Replaces CommHub's NestJS `/send-attachment` controller in a single
208
+ * SDK call — no base64 round-trip, no legacy `/attachments/:id/download`
209
+ * REST endpoint required.
210
+ */
211
+ upload(input: {
212
+ file: Blob | ArrayBuffer | Uint8Array;
213
+ fileName: string;
214
+ mimeType: string;
215
+ size: number;
216
+ conversationId?: string;
217
+ uploadedBy: string;
218
+ /** Download URL TTL in seconds. Default 7 days. */
219
+ downloadExpiresIn?: number;
220
+ }): Promise<{
221
+ attachmentId: string;
222
+ s3Key: string;
223
+ downloadUrl: string;
224
+ }>;
201
225
  }
202
226
 
203
227
  /**
@@ -313,7 +337,21 @@ declare class DialpadResource {
313
337
  }
314
338
  declare class MessagesResource {
315
339
  readonly dialpad: DialpadResource;
340
+ private readonly baseUrl;
341
+ private readonly apiKey;
316
342
  constructor(apiBaseUrl: string, apiKey: string);
343
+ /**
344
+ * End a Dialpad call via the typed oRPC procedure (POST hangup, with
345
+ * 404→`alreadyEnded` so the UI doesn't flash an error on a natural
346
+ * race). Replaces CommHub's `useEndCallMutation` Hasura action.
347
+ *
348
+ * Prefer this over `messages.dialpad.endCall` which goes through the
349
+ * generic proxy (PUT, no 404 handling).
350
+ */
351
+ endCall(callId: number | string): Promise<{
352
+ ok: true;
353
+ alreadyEnded: boolean;
354
+ }>;
317
355
  }
318
356
  declare class DialpadProxyError extends Error {
319
357
  readonly method: string;
@@ -408,11 +446,49 @@ declare class NotesError extends Error {
408
446
  readonly status: number;
409
447
  constructor(operation: string, status: number, message?: string);
410
448
  }
449
+ interface PushConversationToElationInput {
450
+ /** One-of: conversationId (Convex) or phonePair. */
451
+ conversationId?: string;
452
+ phonePair?: string;
453
+ /** Actor user id — recorded on the audit row. */
454
+ initiatedBy: string;
455
+ /** Pre-assembled note body (transcript-style text). */
456
+ noteText: string;
457
+ bullets?: NonVisitNoteBullet[];
458
+ notesPushed?: number;
459
+ messagesPushed?: number;
460
+ tasksPushed?: number;
461
+ }
462
+ interface PushConversationToElationResult {
463
+ success: true;
464
+ batchId: string;
465
+ elationNoteId: number | null;
466
+ notesPushed: number;
467
+ messagesPushed: number;
468
+ tasksPushed: number;
469
+ }
411
470
  declare class NotesResource {
412
471
  private readonly baseUrl;
413
472
  private readonly apiKey;
414
473
  constructor(apiBaseUrl: string, apiKey: string);
474
+ /** 30s upstream timeout — Elation API has occasional slow hops; we
475
+ * don't want a pending mutation to hold the UI thread indefinitely. */
476
+ private static readonly REQUEST_TIMEOUT_MS;
477
+ private post;
478
+ /**
479
+ * Low-level — caller has already resolved Elation patient / physician
480
+ * / practice. Use `pushConversationToElation` if you only have a
481
+ * conversation handle.
482
+ */
415
483
  pushToElation(input: PushNoteToElationInput): Promise<PushNoteToElationResult>;
484
+ /**
485
+ * Orchestrator — pass a conversation handle + pre-assembled note text.
486
+ * Truth resolves the linked patient via Convex, looks up
487
+ * physician/practice in Elation, posts the note, and writes an audit
488
+ * row to `elationSyncEvents`. Replaces CommHub's `pushNotesToElation`
489
+ * Hasura action.
490
+ */
491
+ pushConversationToElation(input: PushConversationToElationInput): Promise<PushConversationToElationResult>;
416
492
  }
417
493
 
418
494
  /**
package/dist/index.d.ts CHANGED
@@ -198,6 +198,30 @@ declare class AttachmentsResource {
198
198
  }>;
199
199
  get(attachmentId: string): Promise<Attachment | null>;
200
200
  listByConversation(conversationId: string): Promise<Attachment[]>;
201
+ /**
202
+ * One-shot upload: presign → PUT to S3 → record in Convex → return a
203
+ * 7-day signed download URL ready to embed in an outbound SMS. Caller
204
+ * passes the resulting `downloadUrl` to `messages.dialpad.sendSms` (or
205
+ * the new `messages.sendAttachmentMessage`) to actually deliver it.
206
+ *
207
+ * Replaces CommHub's NestJS `/send-attachment` controller in a single
208
+ * SDK call — no base64 round-trip, no legacy `/attachments/:id/download`
209
+ * REST endpoint required.
210
+ */
211
+ upload(input: {
212
+ file: Blob | ArrayBuffer | Uint8Array;
213
+ fileName: string;
214
+ mimeType: string;
215
+ size: number;
216
+ conversationId?: string;
217
+ uploadedBy: string;
218
+ /** Download URL TTL in seconds. Default 7 days. */
219
+ downloadExpiresIn?: number;
220
+ }): Promise<{
221
+ attachmentId: string;
222
+ s3Key: string;
223
+ downloadUrl: string;
224
+ }>;
201
225
  }
202
226
 
203
227
  /**
@@ -313,7 +337,21 @@ declare class DialpadResource {
313
337
  }
314
338
  declare class MessagesResource {
315
339
  readonly dialpad: DialpadResource;
340
+ private readonly baseUrl;
341
+ private readonly apiKey;
316
342
  constructor(apiBaseUrl: string, apiKey: string);
343
+ /**
344
+ * End a Dialpad call via the typed oRPC procedure (POST hangup, with
345
+ * 404→`alreadyEnded` so the UI doesn't flash an error on a natural
346
+ * race). Replaces CommHub's `useEndCallMutation` Hasura action.
347
+ *
348
+ * Prefer this over `messages.dialpad.endCall` which goes through the
349
+ * generic proxy (PUT, no 404 handling).
350
+ */
351
+ endCall(callId: number | string): Promise<{
352
+ ok: true;
353
+ alreadyEnded: boolean;
354
+ }>;
317
355
  }
318
356
  declare class DialpadProxyError extends Error {
319
357
  readonly method: string;
@@ -408,11 +446,49 @@ declare class NotesError extends Error {
408
446
  readonly status: number;
409
447
  constructor(operation: string, status: number, message?: string);
410
448
  }
449
+ interface PushConversationToElationInput {
450
+ /** One-of: conversationId (Convex) or phonePair. */
451
+ conversationId?: string;
452
+ phonePair?: string;
453
+ /** Actor user id — recorded on the audit row. */
454
+ initiatedBy: string;
455
+ /** Pre-assembled note body (transcript-style text). */
456
+ noteText: string;
457
+ bullets?: NonVisitNoteBullet[];
458
+ notesPushed?: number;
459
+ messagesPushed?: number;
460
+ tasksPushed?: number;
461
+ }
462
+ interface PushConversationToElationResult {
463
+ success: true;
464
+ batchId: string;
465
+ elationNoteId: number | null;
466
+ notesPushed: number;
467
+ messagesPushed: number;
468
+ tasksPushed: number;
469
+ }
411
470
  declare class NotesResource {
412
471
  private readonly baseUrl;
413
472
  private readonly apiKey;
414
473
  constructor(apiBaseUrl: string, apiKey: string);
474
+ /** 30s upstream timeout — Elation API has occasional slow hops; we
475
+ * don't want a pending mutation to hold the UI thread indefinitely. */
476
+ private static readonly REQUEST_TIMEOUT_MS;
477
+ private post;
478
+ /**
479
+ * Low-level — caller has already resolved Elation patient / physician
480
+ * / practice. Use `pushConversationToElation` if you only have a
481
+ * conversation handle.
482
+ */
415
483
  pushToElation(input: PushNoteToElationInput): Promise<PushNoteToElationResult>;
484
+ /**
485
+ * Orchestrator — pass a conversation handle + pre-assembled note text.
486
+ * Truth resolves the linked patient via Convex, looks up
487
+ * physician/practice in Elation, posts the note, and writes an audit
488
+ * row to `elationSyncEvents`. Replaces CommHub's `pushNotesToElation`
489
+ * Hasura action.
490
+ */
491
+ pushConversationToElation(input: PushConversationToElationInput): Promise<PushConversationToElationResult>;
416
492
  }
417
493
 
418
494
  /**
package/dist/index.js CHANGED
@@ -230,6 +230,65 @@ var AttachmentsResource = class {
230
230
  }
231
231
  });
232
232
  }
233
+ /**
234
+ * One-shot upload: presign → PUT to S3 → record in Convex → return a
235
+ * 7-day signed download URL ready to embed in an outbound SMS. Caller
236
+ * passes the resulting `downloadUrl` to `messages.dialpad.sendSms` (or
237
+ * the new `messages.sendAttachmentMessage`) to actually deliver it.
238
+ *
239
+ * Replaces CommHub's NestJS `/send-attachment` controller in a single
240
+ * SDK call — no base64 round-trip, no legacy `/attachments/:id/download`
241
+ * REST endpoint required.
242
+ */
243
+ upload(input) {
244
+ return __async(this, null, function* () {
245
+ var _a;
246
+ const presigned = yield this.createUploadUrl({
247
+ fileName: input.fileName,
248
+ mimeType: input.mimeType,
249
+ size: input.size,
250
+ conversationId: input.conversationId
251
+ });
252
+ const body = input.file instanceof Blob ? input.file : input.file instanceof Uint8Array ? input.file : new Uint8Array(input.file);
253
+ const abort = new AbortController();
254
+ const timer = setTimeout(() => abort.abort(), 3e4);
255
+ let putRes;
256
+ try {
257
+ putRes = yield fetch(presigned.uploadUrl, {
258
+ method: "PUT",
259
+ headers: { "Content-Type": input.mimeType },
260
+ body,
261
+ signal: abort.signal
262
+ });
263
+ } finally {
264
+ clearTimeout(timer);
265
+ }
266
+ if (!putRes.ok) {
267
+ throw new AttachmentsError(
268
+ "s3-put",
269
+ putRes.status,
270
+ `S3 PUT ${putRes.status} for ${presigned.s3Key}`
271
+ );
272
+ }
273
+ const recorded = yield this.record({
274
+ s3Key: presigned.s3Key,
275
+ fileName: input.fileName,
276
+ mimeType: input.mimeType,
277
+ size: input.size,
278
+ conversationId: input.conversationId,
279
+ uploadedBy: input.uploadedBy
280
+ });
281
+ const signed = yield this.getDownloadUrl(
282
+ presigned.s3Key,
283
+ (_a = input.downloadExpiresIn) != null ? _a : 7 * 24 * 3600
284
+ );
285
+ return {
286
+ attachmentId: recorded.attachmentId,
287
+ s3Key: presigned.s3Key,
288
+ downloadUrl: signed.url
289
+ };
290
+ });
291
+ }
233
292
  };
234
293
 
235
294
  // src/resources/dialpad.ts
@@ -460,6 +519,36 @@ var DialpadResource = class {
460
519
  var MessagesResource = class {
461
520
  constructor(apiBaseUrl, apiKey) {
462
521
  this.dialpad = new DialpadResource(apiBaseUrl, apiKey);
522
+ this.baseUrl = apiBaseUrl;
523
+ this.apiKey = apiKey;
524
+ }
525
+ /**
526
+ * End a Dialpad call via the typed oRPC procedure (POST hangup, with
527
+ * 404→`alreadyEnded` so the UI doesn't flash an error on a natural
528
+ * race). Replaces CommHub's `useEndCallMutation` Hasura action.
529
+ *
530
+ * Prefer this over `messages.dialpad.endCall` which goes through the
531
+ * generic proxy (PUT, no 404 handling).
532
+ */
533
+ endCall(callId) {
534
+ return __async(this, null, function* () {
535
+ const res = yield fetch(`${this.baseUrl}/api/conversations/calls/end`, {
536
+ method: "POST",
537
+ headers: {
538
+ "Content-Type": "application/json",
539
+ Accept: "application/json",
540
+ "X-API-Key": this.apiKey
541
+ },
542
+ body: JSON.stringify({ callId })
543
+ });
544
+ if (!res.ok) {
545
+ const text = yield res.text().catch(() => "");
546
+ throw new Error(
547
+ `messages.endCall failed (HTTP ${res.status}): ${text.slice(0, 200)}`
548
+ );
549
+ }
550
+ return yield res.json();
551
+ });
463
552
  }
464
553
  };
465
554
  var DialpadProxyError = class extends Error {
@@ -609,30 +698,77 @@ var NotesError = class extends Error {
609
698
  this.status = status;
610
699
  }
611
700
  };
612
- var NotesResource = class {
701
+ var _NotesResource = class _NotesResource {
613
702
  constructor(apiBaseUrl, apiKey) {
614
703
  this.baseUrl = apiBaseUrl;
615
704
  this.apiKey = apiKey;
616
705
  }
617
- pushToElation(input) {
706
+ post(path, body) {
618
707
  return __async(this, null, function* () {
619
- const res = yield fetch(`${this.baseUrl}/api/notes/push-to-elation`, {
620
- method: "POST",
621
- headers: {
622
- "Content-Type": "application/json",
623
- Accept: "application/json",
624
- "X-API-Key": this.apiKey
625
- },
626
- body: JSON.stringify(input)
627
- });
708
+ const controller = new AbortController();
709
+ const timeout = setTimeout(
710
+ () => controller.abort(),
711
+ _NotesResource.REQUEST_TIMEOUT_MS
712
+ );
713
+ let res;
714
+ try {
715
+ res = yield fetch(`${this.baseUrl}/api${path}`, {
716
+ method: "POST",
717
+ headers: {
718
+ "Content-Type": "application/json",
719
+ Accept: "application/json",
720
+ "X-API-Key": this.apiKey
721
+ },
722
+ body: JSON.stringify(body),
723
+ signal: controller.signal
724
+ });
725
+ } catch (err) {
726
+ const isAbort = err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError");
727
+ const message = isAbort ? `Notes ${path} timed out after ${_NotesResource.REQUEST_TIMEOUT_MS}ms` : err instanceof Error ? err.message : "Notes request failed before response";
728
+ throw new NotesError(path, 0, message);
729
+ } finally {
730
+ clearTimeout(timeout);
731
+ }
628
732
  if (!res.ok) {
629
733
  const text = yield res.text().catch(() => "");
630
- throw new NotesError("pushToElation", res.status, text.slice(0, 200));
734
+ throw new NotesError(path, res.status, text.slice(0, 200));
631
735
  }
632
736
  return yield res.json();
633
737
  });
634
738
  }
739
+ /**
740
+ * Low-level — caller has already resolved Elation patient / physician
741
+ * / practice. Use `pushConversationToElation` if you only have a
742
+ * conversation handle.
743
+ */
744
+ pushToElation(input) {
745
+ return __async(this, null, function* () {
746
+ return yield this.post(
747
+ "/notes/push-to-elation",
748
+ input
749
+ );
750
+ });
751
+ }
752
+ /**
753
+ * Orchestrator — pass a conversation handle + pre-assembled note text.
754
+ * Truth resolves the linked patient via Convex, looks up
755
+ * physician/practice in Elation, posts the note, and writes an audit
756
+ * row to `elationSyncEvents`. Replaces CommHub's `pushNotesToElation`
757
+ * Hasura action.
758
+ */
759
+ pushConversationToElation(input) {
760
+ return __async(this, null, function* () {
761
+ return yield this.post(
762
+ "/notes/push-conversation-to-elation",
763
+ input
764
+ );
765
+ });
766
+ }
635
767
  };
768
+ /** 30s upstream timeout — Elation API has occasional slow hops; we
769
+ * don't want a pending mutation to hold the UI thread indefinitely. */
770
+ _NotesResource.REQUEST_TIMEOUT_MS = 3e4;
771
+ var NotesResource = _NotesResource;
636
772
 
637
773
  // src/resources/notifications.ts
638
774
  var NotificationsError = class extends Error {