@hipnation-truth/sdk 0.10.0 → 0.12.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.mjs CHANGED
@@ -168,6 +168,65 @@ var AttachmentsResource = class {
168
168
  }
169
169
  });
170
170
  }
171
+ /**
172
+ * One-shot upload: presign → PUT to S3 → record in Convex → return a
173
+ * 7-day signed download URL ready to embed in an outbound SMS. Caller
174
+ * passes the resulting `downloadUrl` to `messages.dialpad.sendSms` (or
175
+ * the new `messages.sendAttachmentMessage`) to actually deliver it.
176
+ *
177
+ * Replaces CommHub's NestJS `/send-attachment` controller in a single
178
+ * SDK call — no base64 round-trip, no legacy `/attachments/:id/download`
179
+ * REST endpoint required.
180
+ */
181
+ upload(input) {
182
+ return __async(this, null, function* () {
183
+ var _a;
184
+ const presigned = yield this.createUploadUrl({
185
+ fileName: input.fileName,
186
+ mimeType: input.mimeType,
187
+ size: input.size,
188
+ conversationId: input.conversationId
189
+ });
190
+ const body = input.file instanceof Blob ? input.file : input.file instanceof Uint8Array ? input.file : new Uint8Array(input.file);
191
+ const abort = new AbortController();
192
+ const timer = setTimeout(() => abort.abort(), 3e4);
193
+ let putRes;
194
+ try {
195
+ putRes = yield fetch(presigned.uploadUrl, {
196
+ method: "PUT",
197
+ headers: { "Content-Type": input.mimeType },
198
+ body,
199
+ signal: abort.signal
200
+ });
201
+ } finally {
202
+ clearTimeout(timer);
203
+ }
204
+ if (!putRes.ok) {
205
+ throw new AttachmentsError(
206
+ "s3-put",
207
+ putRes.status,
208
+ `S3 PUT ${putRes.status} for ${presigned.s3Key}`
209
+ );
210
+ }
211
+ const recorded = yield this.record({
212
+ s3Key: presigned.s3Key,
213
+ fileName: input.fileName,
214
+ mimeType: input.mimeType,
215
+ size: input.size,
216
+ conversationId: input.conversationId,
217
+ uploadedBy: input.uploadedBy
218
+ });
219
+ const signed = yield this.getDownloadUrl(
220
+ presigned.s3Key,
221
+ (_a = input.downloadExpiresIn) != null ? _a : 7 * 24 * 3600
222
+ );
223
+ return {
224
+ attachmentId: recorded.attachmentId,
225
+ s3Key: presigned.s3Key,
226
+ downloadUrl: signed.url
227
+ };
228
+ });
229
+ }
171
230
  };
172
231
 
173
232
  // src/resources/dialpad.ts
@@ -398,6 +457,36 @@ var DialpadResource = class {
398
457
  var MessagesResource = class {
399
458
  constructor(apiBaseUrl, apiKey) {
400
459
  this.dialpad = new DialpadResource(apiBaseUrl, apiKey);
460
+ this.baseUrl = apiBaseUrl;
461
+ this.apiKey = apiKey;
462
+ }
463
+ /**
464
+ * End a Dialpad call via the typed oRPC procedure (POST hangup, with
465
+ * 404→`alreadyEnded` so the UI doesn't flash an error on a natural
466
+ * race). Replaces CommHub's `useEndCallMutation` Hasura action.
467
+ *
468
+ * Prefer this over `messages.dialpad.endCall` which goes through the
469
+ * generic proxy (PUT, no 404 handling).
470
+ */
471
+ endCall(callId) {
472
+ return __async(this, null, function* () {
473
+ const res = yield fetch(`${this.baseUrl}/api/conversations/calls/end`, {
474
+ method: "POST",
475
+ headers: {
476
+ "Content-Type": "application/json",
477
+ Accept: "application/json",
478
+ "X-API-Key": this.apiKey
479
+ },
480
+ body: JSON.stringify({ callId })
481
+ });
482
+ if (!res.ok) {
483
+ const text = yield res.text().catch(() => "");
484
+ throw new Error(
485
+ `messages.endCall failed (HTTP ${res.status}): ${text.slice(0, 200)}`
486
+ );
487
+ }
488
+ return yield res.json();
489
+ });
401
490
  }
402
491
  };
403
492
  var DialpadProxyError = class extends Error {
@@ -547,30 +636,77 @@ var NotesError = class extends Error {
547
636
  this.status = status;
548
637
  }
549
638
  };
550
- var NotesResource = class {
639
+ var _NotesResource = class _NotesResource {
551
640
  constructor(apiBaseUrl, apiKey) {
552
641
  this.baseUrl = apiBaseUrl;
553
642
  this.apiKey = apiKey;
554
643
  }
555
- pushToElation(input) {
644
+ post(path, body) {
556
645
  return __async(this, null, function* () {
557
- const res = yield fetch(`${this.baseUrl}/api/notes/push-to-elation`, {
558
- method: "POST",
559
- headers: {
560
- "Content-Type": "application/json",
561
- Accept: "application/json",
562
- "X-API-Key": this.apiKey
563
- },
564
- body: JSON.stringify(input)
565
- });
646
+ const controller = new AbortController();
647
+ const timeout = setTimeout(
648
+ () => controller.abort(),
649
+ _NotesResource.REQUEST_TIMEOUT_MS
650
+ );
651
+ let res;
652
+ try {
653
+ res = yield fetch(`${this.baseUrl}/api${path}`, {
654
+ method: "POST",
655
+ headers: {
656
+ "Content-Type": "application/json",
657
+ Accept: "application/json",
658
+ "X-API-Key": this.apiKey
659
+ },
660
+ body: JSON.stringify(body),
661
+ signal: controller.signal
662
+ });
663
+ } catch (err) {
664
+ const isAbort = err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError");
665
+ const message = isAbort ? `Notes ${path} timed out after ${_NotesResource.REQUEST_TIMEOUT_MS}ms` : err instanceof Error ? err.message : "Notes request failed before response";
666
+ throw new NotesError(path, 0, message);
667
+ } finally {
668
+ clearTimeout(timeout);
669
+ }
566
670
  if (!res.ok) {
567
671
  const text = yield res.text().catch(() => "");
568
- throw new NotesError("pushToElation", res.status, text.slice(0, 200));
672
+ throw new NotesError(path, res.status, text.slice(0, 200));
569
673
  }
570
674
  return yield res.json();
571
675
  });
572
676
  }
677
+ /**
678
+ * Low-level — caller has already resolved Elation patient / physician
679
+ * / practice. Use `pushConversationToElation` if you only have a
680
+ * conversation handle.
681
+ */
682
+ pushToElation(input) {
683
+ return __async(this, null, function* () {
684
+ return yield this.post(
685
+ "/notes/push-to-elation",
686
+ input
687
+ );
688
+ });
689
+ }
690
+ /**
691
+ * Orchestrator — pass a conversation handle + pre-assembled note text.
692
+ * Truth resolves the linked patient via Convex, looks up
693
+ * physician/practice in Elation, posts the note, and writes an audit
694
+ * row to `elationSyncEvents`. Replaces CommHub's `pushNotesToElation`
695
+ * Hasura action.
696
+ */
697
+ pushConversationToElation(input) {
698
+ return __async(this, null, function* () {
699
+ return yield this.post(
700
+ "/notes/push-conversation-to-elation",
701
+ input
702
+ );
703
+ });
704
+ }
573
705
  };
706
+ /** 30s upstream timeout — Elation API has occasional slow hops; we
707
+ * don't want a pending mutation to hold the UI thread indefinitely. */
708
+ _NotesResource.REQUEST_TIMEOUT_MS = 3e4;
709
+ var NotesResource = _NotesResource;
574
710
 
575
711
  // src/resources/notifications.ts
576
712
  var NotificationsError = class extends Error {