{"_id":"@astermd-hq/sdk","name":"@astermd-hq/sdk","dist-tags":{"latest":"0.0.2"},"versions":{"0.0.2":{"name":"@astermd-hq/sdk","version":"0.0.2","description":"Official Node.js SDK for the AsterMD order-flow API.","keywords":["astermd","sdk","api-client","telehealth","healthcare","emr","typescript"],"license":"MIT","author":{"name":"AsterMD","email":"admin@astermd.com"},"homepage":"https://www.astermd.com","repository":{"type":"git","url":"git+https://github.com/astermd/npm-sdk.git"},"bugs":{"url":"https://github.com/astermd/npm-sdk/issues","email":"info@astermd.com"},"type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./package.json":"./package.json"},"engines":{"node":">=22"},"sideEffects":false,"publishConfig":{"access":"public","provenance":true},"scripts":{"lint":"eslint . --max-warnings 0","fix":"eslint . --fix && prettier --write .","format:check":"prettier --check .","typecheck":"tsc --noEmit","test":"vitest run","test:watch":"vitest","coverage":"vitest run --coverage","build":"tsup","ci":"npm run lint && npm run format:check && npm run typecheck && npm run test && npm run build && publint","scrub":"bash scripts/scrub.sh"},"devDependencies":{"@eslint/js":"^10.0.1","@types/node":"^22.14.0","@vitest/coverage-v8":"^5.0.0","eslint":"^10.10.0","eslint-config-prettier":"^10.1.8","prettier":"^3.6.2","publint":"^0.3.14","tsup":"^8.5.0","typescript":"^5.9.2","typescript-eslint":"^8.70.0","vitest":"^5.0.0"},"_id":"@astermd-hq/sdk@0.0.2","gitHead":"be53b5aa1d2171a39dc151261a1981a365ba47ec","_nodeVersion":"22.23.2","_npmVersion":"10.9.8","dist":{"integrity":"sha512-LpiCTMsSd6NteWzvIJAi/j8Wlzsg5puQW6DmCIdC5u/Ch4sIJa6TKcbskRhZxLY04en0UFVqMXJqS5nVOikRMA==","shasum":"38a08768756d9c2087ad1392ce348ad3dd275689","tarball":"https://registry.npmjs.org/@astermd-hq/sdk/-/sdk-0.0.2.tgz","fileCount":9,"unpackedSize":1020984,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@astermd-hq%2fsdk@0.0.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIC1LKIgXzT88iOz2V7JcET47l1OgormmD/1uh846AXUBAiAybbxeKHBoDQGeSTVaN6kFEKXwKYAiocY+kTTcY3xoLw=="}]},"_npmUser":{"name":"astermd","email":"admin@astermd.com"},"directories":{},"maintainers":[{"name":"astermd","email":"admin@astermd.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sdk_0.0.2_1789056945888_0.38010254253031706"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-10T16:15:45.689Z","0.0.2":"2026-09-10T16:15:46.022Z","modified":"2026-09-10T16:15:46.560Z"},"maintainers":[{"name":"astermd","email":"admin@astermd.com"}],"description":"Official Node.js SDK for the AsterMD order-flow API.","homepage":"https://www.astermd.com","keywords":["astermd","sdk","api-client","telehealth","healthcare","emr","typescript"],"repository":{"type":"git","url":"git+https://github.com/astermd/npm-sdk.git"},"author":{"name":"AsterMD","email":"admin@astermd.com"},"bugs":{"url":"https://github.com/astermd/npm-sdk/issues","email":"info@astermd.com"},"license":"MIT","readme":"# AsterMD Node.js SDK\n\nSlim, framework-agnostic TypeScript SDK for the AsterMD order-flow API.\n\n- Node `>=22`\n- **Zero runtime dependencies** - the platform `fetch`, `node:crypto`, and `node:fs` only\n- Dual ESM + CJS builds with full type declarations\n- Bring your own HTTP client if you prefer\n\n## Install\n\n```bash\nnpm install @astermd-hq/sdk\n```\n\n## Quick start\n\n```ts\nimport { AsterMDClient, Event } from '@astermd-hq/sdk';\n\nconst client = new AsterMDClient({\n  clientId: process.env.ASTERMD_CLIENT_ID!,\n  clientSecret: process.env.ASTERMD_CLIENT_SECRET!,\n});\n\n// 1. Start a session (implicit `visit_page` event server-side)\nconst { session } = (await client.sessions().create<{ session: string }>()).data();\n\n// 2. Pre-qualifying form\nawait client.intakeSubmissions().create({\n  session,\n  event: Event.PreQualifyingInitiated,\n  teleformId: 'your-teleform-id',\n  // `data` is a list of field objects: id / name / label / type / value\n  data: [{ id: 'name-1', name: 'name', label: 'Full name', type: 'text', value: [{ value: 'Jane' }] }],\n});\n\n// 3. Create the opportunity, attaching the session\nconst opportunity = await client.opportunities().create({\n  first_name: 'Jane',\n  email: 'jane@example.com',\n  sessions: [session],\n});\n\n// 4. Intake\nawait client.intakeSubmissions().update({\n  session,\n  event: Event.IntakeCompleted,\n  teleformId: 'your-teleform-id',\n  data: [\n    { id: 'name-1', name: 'name', label: 'Full name', type: 'text', value: [{ value: 'Jane' }] },\n    {\n      id: 'dob-1',\n      name: 'dob',\n      label: 'Date of birth',\n      type: 'date',\n      value: [{ value: '1990-01-15' }],\n    },\n  ],\n});\n\n// 5. After external payment settles, create the treatment (= order)\nawait client.treatments().create({\n  external_order_id: 'EXT-123',\n  patient: { id: '...' },\n  product: { id: '...' },\n});\n```\n\nCredentials are issued from your AsterMD dashboard, which is also where the full\nAPI reference lives. Load the secret from an environment variable or a secrets\nmanager - never commit it, and never ship it to a browser. This SDK is\nserver-side only.\n\nConstruct the client once and share it: it caches the bearer token, so a client\nper request throws that cache away.\n\n## Resources\n\n`sessions`, `intakeSubmissions`, `carts`, `checkoutEvents`, `teleforms`,\n`patients`, `opportunities`, `treatments`, `doctorsNetworks`, `channels`,\n`products`, `categories`, `labTests`, `medications`, `shippings`,\n`verification`, `geo`.\n\n## Errors\n\nEvery error extends `AsterMDError`:\n\n- `TransportError` - network failure, no response received\n- `AuthenticationError` - 401\n- `NotFoundError` - 404\n- `ValidationError` - 422 (`.fieldErrors()`)\n- `RateLimitError` - 429 (`.retryAfter()`)\n- `ApiError` - other 4xx/5xx (`.statusCode()`, `.envelope()`)\n\n```ts\nimport { RateLimitError, ValidationError } from '@astermd-hq/sdk';\n\ntry {\n  await client.patients().create({/* ... */});\n} catch (error) {\n  if (error instanceof ValidationError) {\n    console.error(error.fieldErrors());\n  } else if (error instanceof RateLimitError) {\n    await new Promise(resolve => setTimeout(resolve, (error.retryAfter() ?? 5) * 1000));\n  } else {\n    throw error;\n  }\n}\n```\n\n## Token storage\n\nBy default the bearer token is cached in memory for the life of the process,\nwhich is what a long-running server wants. Where each request runs in a fresh\nprocess or isolate, that cache is never hit - use `FileTokenStore`, or implement\n`TokenStore` against Redis or any other shared store.\n\n```ts\nimport { AsterMDClient, FileTokenStore } from '@astermd-hq/sdk';\n\nconst client = new AsterMDClient({\n  clientId: process.env.ASTERMD_CLIENT_ID!,\n  clientSecret: process.env.ASTERMD_CLIENT_SECRET!,\n  tokenStore: new FileTokenStore('/var/cache/astermd/token.json'),\n});\n```\n\n## Debugging\n\nPass `debug: true` with a `debugFile` to log every request as a copy-pasteable\ncurl command plus its response.\n\n```ts\nconst client = new AsterMDClient({\n  clientId: process.env.ASTERMD_CLIENT_ID!,\n  clientSecret: process.env.ASTERMD_CLIENT_SECRET!,\n  debug: true,\n  debugFile: '/var/log/astermd/sdk.log',\n});\n```\n\n**Credentials are redacted by default.** Bearer tokens, the client secret, PHI\nverification tokens, and the bodies of `patients/*` calls are replaced with\n`[REDACTED]`:\n\n```\ncurl --location --request POST 'https://api.astermd.com/v1/sales/sessions/create' \\\n  --header 'authorization: Bearer [REDACTED]' \\\n  --header 'content-type: application/json' \\\n  --data '{}'\n\n# Response: HTTP 200\n{\"success\":true,\"message\":\"ok\",\"data\":{\"session\":\"...\"}}\n```\n\nPass `debugRedact: false` to log verbatim, including the live JWT. Never do that\nin production. Note that redaction covers headers and bodies but not the URL, so\nendpoints taking their input as a query parameter log that input.\n\n### Log rotation\n\n`debugFile` is a _base path_. The SDK writes one file per day derived from it and\ndeletes files older than `debugRetentionDays` (default 7; `0` keeps everything):\n\n```\n/var/log/astermd/sdk-2026-09-08.log\n/var/log/astermd/sdk-2026-09-07.log\n```\n\nPruning happens once per sink instance, and only files matching the SDK's own\n`{name}-YYYY-MM-DD.{ext}` pattern are ever removed.\n\n### Sending logs somewhere else\n\nSupply a `debugSink` and the SDK writes no files at all - retention and delivery\nbecome yours. This works with any destination: a logger, a hosted log service, a\ncloud provider's logging API, a queue.\n\n```ts\nconst client = new AsterMDClient({\n  clientId: process.env.ASTERMD_CLIENT_ID!,\n  clientSecret: process.env.ASTERMD_CLIENT_SECRET!,\n  debug: true,\n  debugSink: entry => logger.debug(entry),\n});\n```\n\nSee [`docs/INTEGRATION_GUIDE.md`](docs/INTEGRATION_GUIDE.md) for worked examples.\n\n## Bringing your own HTTP client\n\nThe SDK talks to one small interface, so anything that can send a `Request` can\nbe swapped in - a proxy agent, your own retry policy, a test stub.\n\n```ts\nimport { AsterMDClient, type HttpClient } from '@astermd-hq/sdk';\n\nclass InstrumentedHttpClient implements HttpClient {\n  async sendRequest(request: Request): Promise<Response> {\n    const started = performance.now();\n    try {\n      return await fetch(request);\n    } finally {\n      metrics.timing('astermd.request', performance.now() - started);\n    }\n  }\n}\n\nconst client = new AsterMDClient({\n  clientId: process.env.ASTERMD_CLIENT_ID!,\n  clientSecret: process.env.ASTERMD_CLIENT_SECRET!,\n  httpClient: new InstrumentedHttpClient(),\n});\n```\n\n## Development\n\n```bash\nnpm install\nnpm run ci        # lint → format → typecheck → test → build → publint\n# also: npm test, npm run lint, npm run fix, npm run typecheck, npm run coverage\n```\n\nA `Makefile` wraps the same scripts (`make install`, `make ci`, `make test`) if\nyou prefer.\n\n## Compliance\n\nThis SDK is a client for an API that carries personal and protected health\ninformation. Using it does not by itself make your application HIPAA compliant -\nthat depends on your own infrastructure, policies, and agreements. Contact\ninfo@astermd.com regarding a Business Associate Agreement.\n\nSee [`SECURITY.md`](SECURITY.md) for vulnerability reporting and\ncredential-handling guidance.\n\n## Further reading\n\n| Audience                            | Document                                                                                                            |\n| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------- |\n| **Integrators building on the SDK** | [`docs/INTEGRATION_GUIDE.md`](docs/INTEGRATION_GUIDE.md) - order flow, resources, auth lifecycle, framework recipes |\n| Contributors                        | [`CONTRIBUTING.md`](CONTRIBUTING.md) - local setup, how to add an endpoint                                          |\n| Architecture                        | [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) - single-page overview                                               |\n| Changes                             | [`CHANGELOG.md`](CHANGELOG.md)                                                                                      |\n\n## Support\n\nQuestions, access requests, and licensing enquiries: **info@astermd.com**\n\n## License\n\n[MIT](LICENSE) © 2026 AsterMD\n","readmeFilename":"README.md","_rev":"1-8687f8ae179598e1b30360309b808a97"}