npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@amigo-ai/scribe-typescript-sdk

v0.5.0

Published

Framework-agnostic TypeScript SDK for the Amigo Scribe streaming service

Downloads

724

Readme

@amigo-ai/scribe-typescript-sdk

Framework-agnostic TypeScript SDK for the Amigo Scribe streaming service.

This release ships the CRUD REST client for the full session lifecycle and its per-session artifacts:

Session lifecycle:

  • createSessionPOST /v1/{workspace_id}/sessions
  • allocatePOST /v1/{workspace_id}/sessions/{session_id}/allocate{ host, expires_at }
  • listSessionsGET /v1/{workspace_id}/sessions (cursor-paginated: limit, continuation_token)
  • getSessionGET /v1/{workspace_id}/sessions/{session_id}
  • updateSessionPATCH /v1/{workspace_id}/sessions/{session_id} (mutate external_appointment_id / metadata / mode)
  • endSessionPOST /v1/{workspace_id}/sessions/{session_id}/end (guarded → in-review)
  • cancelSessionPOST /v1/{workspace_id}/sessions/{session_id}/cancel (guarded → cancelled)
  • getTranscriptGET /v1/{workspace_id}/sessions/{session_id}/transcript

Appointments (read-only; each carries a nested session object):

  • listAppointmentsGET /v1/{workspace_id}/appointments (cursor-paginated: limit, continuation_token)
  • getAppointmentGET /v1/{workspace_id}/appointments/{appointment_id}

Artifacts (note / summary / checklist / codes):

  • getNoteGET /v1/{workspace_id}/sessions/{session_id}/note
  • generateNotePOST /v1/{workspace_id}/sessions/{session_id}/note
  • finalizeNotePOST /v1/{workspace_id}/sessions/{session_id}/note/finalize
  • getSummaryGET /v1/{workspace_id}/sessions/{session_id}/summary
  • generateSummaryPOST /v1/{workspace_id}/sessions/{session_id}/summary
  • getChecklistGET /v1/{workspace_id}/sessions/{session_id}/checklist
  • generateChecklistPOST /v1/{workspace_id}/sessions/{session_id}/checklist
  • getCodesGET /v1/{workspace_id}/sessions/{session_id}/codes
  • generateCodesPOST /v1/{workspace_id}/sessions/{session_id}/codes

Assist (in-visit + post-visit AI helpers):

  • getActionsGET /v1/{workspace_id}/sessions/{session_id}/actions (reload-safe poller)
  • generateActionsPOST /v1/{workspace_id}/sessions/{session_id}/actions (async 202/200; auto-enqueued when the note job succeeds)
  • regenerateSectionPOST /v1/{workspace_id}/sessions/{session_id}/note/regenerate-section ({ section_id, instructions?, base_version }202; stale base_version409 version_conflict, post-finalize → 409 invalid_session_state)
  • autoCheckChecklistPOST /v1/{workspace_id}/sessions/{session_id}/checklist/auto-check200 { matches } (persists source='auto' state; coexists with manual toggles)
  • askSessionPOST /v1/{workspace_id}/sessions/{session_id}/ask — a header-authenticated SSE streaming Q&A helper (an async generator of delta {text} frames then a terminal done {generation_id}; not EventSource, not persisted as an artifact)

It also ships the recording-independent streaming WebSocket API client (ScribeStreamClient) — the WS transport/protocol layer that attaches with a short-lived attach ticket, streams caller-supplied PCM16 bytes, receives transcript frames, and handles control frames, app-level keepalive, and resumable reconnect. It has no audio-capture code (no getUserMedia, AudioContext, or mic): a caller feeds it PCM16 via sendAudio. The browser audio-capture recorder that drives the mic into this client is a later addition. Plus the pure transcript core: the wire contract (CLIENT_FRAME, SERVER_MESSAGE, CLOSE_CODE), normalizeTurn, the transcriptReducer (keyed on the server-owned ordinal), and buildWsUrl.

The package is browser-first (esbuild platform: 'neutral', lib = ES2022+DOM, no Node-only imports) but the REST client runs anywhere fetch exists.

Scribe sessions follow REST-create → REST-allocate → WS-attach: create a session, allocate a streaming host, then attach a WebSocket to host. After the session ends, read the transcript and the generated artifacts (note, summary, checklist, codes) via the REST client covered here.

For the browser vs. server split-trust model there are two higher-level clients:

  • ScribeServerClient (backend) — holds the M2M secret; mints per-clinician provider tokens (act-as-by-email), does create/allocate, and mints WS-only attach tickets. Exposes allocate and mintAttachTicket separately plus a prepareConnection helper. Server-side only.
  • ScribeStreamClient (browser) — given a host + attach ticket, manages the WebSocket audio connection.

Integrating as an external customer? See the end-to-end customer integration guide — the split-trust model, copy-pasteable backend + browser examples, security, hosts, and troubleshooting.

Install

npm i @amigo-ai/scribe-typescript-sdk

Requires Node.js ≥ 20 (or any modern browser / runtime with fetch + WebSocket). The package is ESM-only — use import, not require.

Usage

import { ScribeClient, ServiceUnavailableError } from '@amigo-ai/scribe-typescript-sdk'

const scribe = new ScribeClient({
  // Scribe API (CRUD) host — production. (Staging: https://scribe-staging.platform.amigo.ai)
  baseUrl: 'https://scribe.platform.amigo.ai',
  // A provider JWT carrying `scribe:sessions:write` (+ `scribe:sessions:read_own`
  // for transcripts). Pass a string, or a (possibly async) supplier to refresh
  // a short-lived token per request.
  token: async () => getFreshProviderJwt(),
  workspaceId: 'ws_123',
})

// 1. Create a session
const session = await scribe.createSession({
  external_id: 'appointment-42',
  metadata: { clinic: 'north' },
})

// 2. Allocate a streaming host
try {
  const { host, expires_at } = await scribe.allocate(session.id)
  // attach your WebSocket to `wss://${host}/agent/stream/connect?session_id=...`
} catch (err) {
  if (err instanceof ServiceUnavailableError) {
    // Fleet at capacity / cooldown — retry after err.retryAfterSeconds
  }
}

// 3. Read the persisted transcript (after the session is finalized)
const { segments } = await scribe.getTranscript(session.id)

Server client (backend)

ScribeServerClient is the confidential, backend half: it holds the M2M credentials and encapsulates the two mints + CRUD. Never import it into a browser bundle.

import { ScribeServerClient } from '@amigo-ai/scribe-typescript-sdk'

const server = new ScribeServerClient({
  identityBaseUrl: 'https://api.platform.amigo.ai', // identity /token (mints)
  scribeBaseUrl: 'https://scribe.platform.amigo.ai', // Scribe CRUD
  workspaceId: 'ws_123',
  clientId: process.env.AMIGO_M2M_CLIENT_ID!,
  clientSecret: process.env.AMIGO_M2M_CLIENT_SECRET!, // server-side only
})

// `clinicianEmail` comes from YOUR authenticated app session (never the browser).
const session = await server.createSession(clinicianEmail, { external_id: 'appointment-42' })

// Encapsulating helper: one allocate + one ticket mint → the browser-safe bundle.
const { host, ticket } = await server.prepareConnection(clinicianEmail, session.id)

// ...or the pieces separately:
const allocation = await server.allocate(clinicianEmail, session.id) // { host, expiresAt }
const attach = await server.mintAttachTicket(clinicianEmail, session.id) // { ticket, expiresAt }

// Reads (transcript / note / summary / checklist / codes) as the clinician:
const { segments } = await server.scribe(clinicianEmail).getTranscript(session.id)

A 400 invalid_target (BadRequestError with errorCode === 'invalid_target') means the clinician has no active Scribe grant in the workspace.

Streaming WebSocket client (browser)

ScribeStreamClient owns the worker WebSocket: it attaches with an attach ticket, streams caller-supplied PCM16, and handles keepalive + resumable reconnect. Auth is a purpose-built, WS-only attach ticket (aud scribe-streaming, scope scribe:streams:connect, ~5-min TTL) — not a raw provider JWT. The SDK never holds a provider credential or mints tickets; it resolves a host + ticket from your backend via one of three seams (re-invoked on every reconnect):

import { ScribeStreamClient } from '@amigo-ai/scribe-typescript-sdk'

const client = new ScribeStreamClient({
  sessionId: session.id,
  // PREFERRED: one call to your backend route returning { host, ticket }
  // (backed by ScribeServerClient.prepareConnection).
  connectionProvider: async sessionId => fetchConnectionFromYourBackend(sessionId),
  onTurn: segment => render(segment), // normalized SttTranscriptSegment (server ordinal)
  onStateChange: state => console.log(state),
  onReconnect: () => console.log('resumed'),
  onError: err => console.error(err),
})

await client.connect() // resolve host + ticket → open WS
client.sendAudio(pcm16) // ArrayBuffer | Uint8Array — you own capture
client.pause()
client.resume()
client.end() // finalize + clean close (1000)

Instead of connectionProvider you can pass the split allocateProvider + ticketProvider seams, or static host + ticket for a one-shot (not reconnect-safe) connection.

Reconnect is automatic on 1012 / 1006 (never on 1000 / 4009 / 4001): the client re-resolves a fresh host + ticket, reconnects the same session, sends resume_from{acked_offset_bytes}, and resends only the unacked ring-buffer audio. Pair normalizeTurn + transcriptReducer (or your own store) to render by the server-owned ordinal.

Configuration

| Option | Type | Notes | | ---------------- | ------------------------------------------- | -------------------------------------------------------- | | baseUrl | string | Base URL of the Scribe/platform API. | | token | string \| () => string \| Promise<string> | Bearer token or supplier. Needs scribe:sessions:write. | | workspaceId | string | Scopes every request; can be overridden per call. | | fetch | FetchLike? | Injectable transport (defaults to global fetch). | | defaultHeaders | Record<string,string>? | Extra headers merged into every request. |

Errors

Non-2xx responses throw typed errors (all extend ScribeError): BadRequestError (400), AuthenticationError (401), PermissionError (403), NotFoundError (404), ConflictError (409), ValidationError (422), RateLimitError (429), ServerError (500), ServiceUnavailableError (503, with retryAfterSeconds). Transport failures throw NetworkError.

Development

npm install
npm run openapi:sync     # refresh openapi/scribe.json from production (network)
npm run generate:schema  # regenerate src/generated/openapi.ts from openapi/scribe.json
npm run build            # esbuild (ESM) + tsc (.d.ts) + NodeNext .js-extension fixup
npm run lint
npm test                 # unit tests (mocked transport)
npm run test:e2e         # gated E2E — see tests/e2e/README.md (skips without creds)
npm run validate         # publint + attw + npm pack --dry-run (pre-publish checks)

Packaging. The SDK is ESM-only ("type": "module"): a single ESM entry point (dist/index.mjs) built with esbuild plus tsc for the .d.ts types, exported through the exports map (types/import). There is no CommonJS build. tsc emits declarations with extensionless relative imports, which Node's NodeNext ESM resolver rejects; scripts/fix-dts-extensions.mjs rewrites those to explicit .js specifiers post-build so @arethetypeswrong/cli (attw) resolves the types cleanly. Validate with npm run validate (publint + attw + npm pack --dry-run).

Wire types. The REST wire types in src/types.ts are derived from the Scribe service's production OpenAPI document (https://scribe.platform.amigo.ai/v1/openapi.json, vendored at openapi/scribe.json) via openapi-typescript. To refresh types after the API schema changes:

npm run openapi:sync     # re-fetch the spec into openapi/scribe.json
npm run generate:schema  # regenerate src/generated/openapi.ts from that snapshot

Both openapi/scribe.json and the generated src/generated/openapi.ts are committed so the build needs no network. CI runs generate:schema and fails the PR if src/generated/openapi.ts is out of sync with the vendored spec (the "Verify generated API types are committed" step). openapi:sync accepts --url <https url> or --spec <local file> overrides; the default source is the production URL. The generated module is types-only — nothing is added to the runtime bundle.

Versioning & releases

The SDK follows semver. It is published to npm as @amigo-ai/scribe-typescript-sdk with npm provenance.

Releases are cut manually and published by CI (.github/workflows/release.yml), mirroring @amigo-ai/platform-sdk:

  1. Bump the version: npm version <patch|minor|major> (updates package.json
    • package-lock.json and creates a vX.Y.Z git tag).
  2. Push the commit and tag: git push --follow-tags.
  3. Cut a GitHub Release for that tag. Publishing the release triggers release.yml, which re-validates the package (build → typecheck → test → publint + attw + npm pack) and runs npm publish --provenance --access public.

Publishing uses npm trusted publishing (OIDC) — there is no npm token. The workflow authenticates with its id-token: write OIDC token, which also produces the provenance attestation.

Before the first publish can succeed, two one-time setup steps are required (no repo secrets):

  • Configure a trusted publisher for @amigo-ai/scribe-typescript-sdk on npmjs.com (Package → Settings → Trusted Publisher) pointing at this repository (amigo-ai/scribe-typescript-sdk) and workflow (.github/workflows/release.yml). This is the account/ops action that replaces provisioning a token.
  • The repository must be public for OIDC trusted publishing + provenance.

Pre-publish validation can be run locally at any time:

npm run build
npm run validate   # publint + attw (are-the-types-wrong) + npm pack --dry-run

License

MIT