{"_id":"@anomalyarmor/sdk","name":"@anomalyarmor/sdk","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@anomalyarmor/sdk","version":"0.1.0","description":"AnomalyArmor TypeScript SDK for data observability","license":"MIT","author":{"name":"AnomalyArmor","email":"support@anomalyarmor.ai"},"homepage":"https://docs.anomalyarmor.ai/sdk/javascript","repository":{"type":"git","url":"git+https://github.com/anomalyarmor/core.git","directory":"sdk/javascript"},"bugs":{"url":"https://github.com/anomalyarmor/core/issues"},"keywords":["anomalyarmor","data-observability","data-quality","monitoring","sdk","typescript"],"type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"bin":{"anomalyarmor":"dist/bin/anomalyarmor.js"},"scripts":{"build":"tsup","dev":"tsup --watch","test":"vitest run","test:watch":"vitest","typecheck":"tsc --noEmit","lint":"tsc --noEmit","generate-types":"tsx scripts/generate-types.ts","check-spec-drift":"tsx scripts/check-spec-drift.ts","prepublishOnly":"npm run typecheck && npm run test && npm run build"},"engines":{"node":">=18"},"dependencies":{"openapi-fetch":"^0.14.0"},"devDependencies":{"@types/node":"^20.11.0","openapi-typescript":"^7.4.0","tsup":"^8.3.0","tsx":"^4.19.0","typescript":"^5.6.0","vitest":"^2.1.0"},"publishConfig":{"access":"public"},"gitHead":"481bb28e85187f1e7172c701af30bbf0c4952844","_id":"@anomalyarmor/sdk@0.1.0","_nodeVersion":"25.2.1","_npmVersion":"11.6.2","dist":{"integrity":"sha512-S0grWQVozi7E8cwLfaE+UFqtLbGPrBpkKyi6oZtJy6fIntSjahlC2UaWqhup0Fi7I6LHH8i6CXD2ii6jiSJWIg==","shasum":"7157fbe6050e79904674fa0a9198ab70b7ff9678","tarball":"https://registry.npmjs.org/@anomalyarmor/sdk/-/sdk-0.1.0.tgz","fileCount":10,"unpackedSize":2557753,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCrllopHscpMqcQLbQZLTSsAZVkAvzdqIzFreLsTDXFbAIgGvyruJFURaDXMqA452TD/oC5VYuaJNf7ZgD5LJgjD7Y="}]},"_npmUser":{"name":"anomalyarmor","email":"blaine@anomalyarmor.ai"},"directories":{},"maintainers":[{"name":"anomalyarmor","email":"blaine@anomalyarmor.ai"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sdk_0.1.0_1776565399351_0.07987590888171647"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-19T02:23:19.290Z","0.1.0":"2026-04-19T02:23:19.582Z","modified":"2026-04-19T02:23:19.762Z"},"maintainers":[{"name":"anomalyarmor","email":"blaine@anomalyarmor.ai"}],"description":"AnomalyArmor TypeScript SDK for data observability","homepage":"https://docs.anomalyarmor.ai/sdk/javascript","keywords":["anomalyarmor","data-observability","data-quality","monitoring","sdk","typescript"],"repository":{"type":"git","url":"git+https://github.com/anomalyarmor/core.git","directory":"sdk/javascript"},"author":{"name":"AnomalyArmor","email":"support@anomalyarmor.ai"},"bugs":{"url":"https://github.com/anomalyarmor/core/issues"},"license":"MIT","readme":"# @anomalyarmor/sdk\n\nTypeScript SDK for [AnomalyArmor](https://www.anomalyarmor.ai) — data observability for modern data teams.\n\nTypes come straight from our OpenAPI spec via `openapi-typescript`, so every endpoint is typed end-to-end. Runtime is a thin wrapper around `openapi-fetch` with Bearer auth and retry-on-429 middleware.\n\n## Install\n\n```bash\nnpm install @anomalyarmor/sdk\n```\n\n## Quickstart\n\n```ts\nimport { createAnomalyArmorClient } from '@anomalyarmor/sdk';\n\nconst client = createAnomalyArmorClient({\n  apiKey: process.env.ANOMALYARMOR_API_KEY!, // aa_live_...\n});\n\nconst health = await client.health.check();\nconsole.log(health); // { status: 'healthy', ... }\n\nconst overview = await client.alerts.overview();\nconsole.log(`${overview.unresolved_alerts} unresolved alerts`);\n```\n\nGet an API key at [app.anomalyarmor.ai/settings/api-keys](https://app.anomalyarmor.ai/settings/api-keys). Keys start with `aa_live_`.\n\n## CLI\n\n```bash\n# Smoke-check connectivity + auth\nnpx anomalyarmor health --api-key $ANOMALYARMOR_API_KEY\n# or with env var:\nANOMALYARMOR_API_KEY=aa_live_... npx anomalyarmor health\n```\n\nThe CLI reads `ANOMALYARMOR_API_KEY` from env as a convenience. **The SDK library itself never reads env** — construct the client with `{ apiKey }` explicitly so auth is visible at the call site.\n\n## Ergonomic surface\n\nHand-written wrappers for the endpoints used most often, mirroring the Python SDK:\n\n| Method | Endpoint |\n|---|---|\n| `client.health.check()` | `GET /api/v1/health` |\n| `client.alerts.overview()` | `GET /api/v1/alerts/overview` |\n| `client.alerts.history(params?)` | `GET /api/v1/alerts/history` |\n| `client.alerts.inbox()` | `GET /api/v1/alerts/inbox` |\n| `client.alerts.get(alertId)` | `GET /api/v1/alerts/{alert_id}` |\n| `client.alerts.acknowledge(alertId, notes?)` | `POST /api/v1/alerts/{alert_id}/acknowledge` |\n| `client.alerts.resolve(alertId, notes?)` | `POST /api/v1/alerts/{alert_id}/resolve` |\n| `client.freshness.check(assetId)` | `GET /api/v1/assets/{asset_id}/freshness` |\n| `client.freshness.getTable(assetId, tablePath)` | `GET /api/v1/assets/{asset_id}/freshness/{table_path}` |\n| `client.freshness.checkTable(assetId, tablePath)` | `POST /api/v1/assets/{asset_id}/freshness/{table_path}/check` |\n| `client.schema.listChanges(assetId)` | `GET /api/v1/schema-drift/assets/{asset_id}/changes` |\n| `client.schema.getChange(assetId, changeId)` | `GET /api/v1/schema-drift/assets/{asset_id}/changes/{change_id}` |\n| `client.schema.baselineStatus(assetId)` | `GET /api/v1/schema-drift/assets/{asset_id}/baseline-status` |\n| `client.schema.detectChanges(assetId)` | `POST /api/v1/schema-drift/assets/{asset_id}/detect-changes` |\n\n## Advanced: raw openapi-fetch client\n\nThe full typed API surface is available on `client.raw`. Drop down here when the ergonomic wrappers don't cover your case:\n\n```ts\nconst { data, error } = await client.raw.GET('/api/v1/assets/{asset_id}', {\n  params: { path: { asset_id: 'my-asset' } },\n});\n```\n\n`data` and `error` are fully typed via the generated `paths` type.\n\n## Error handling\n\nErgonomic methods throw `AnomalyArmorApiError` on 4xx/5xx responses:\n\n```ts\nimport { AnomalyArmorApiError } from '@anomalyarmor/sdk';\n\ntry {\n  await client.alerts.get('nonexistent');\n} catch (err) {\n  if (err instanceof AnomalyArmorApiError) {\n    console.error(`${err.status}: ${err.message}`);\n  }\n}\n```\n\n## Rate limits\n\nThe SDK retries HTTP 429 responses automatically, honoring `Retry-After`. Retries are bounded — default 3 attempts, each sleep capped at 60s. Retries only apply to idempotent verbs (`GET`, `HEAD`, `PUT`, `DELETE`, `OPTIONS`) so a `POST` failure never duplicates a side effect.\n\nTune or disable:\n\n```ts\nconst client = createAnomalyArmorClient({\n  apiKey: '...',\n  maxRetries: 5,\n  maxRetrySleepSeconds: 120,\n});\n// or disable entirely:\nconst client = createAnomalyArmorClient({ apiKey: '...', maxRetries: 0 });\n```\n\n## Development\n\n```bash\nnpm install\nnpm run generate-types    # regenerate types from the pinned OpenAPI spec\nnpm run typecheck\nnpm test\nnpm run build             # dual ESM + CJS + CLI binary\nnpm run check-spec-drift  # CI gate — fails if types.ts is stale vs the spec\n```\n\nTypes are generated from `https://docs.anomalyarmor.ai/api/openapi.json` (the Mintlify-served, admin-filtered spec). If you bump the API shape, run `npm run generate-types` and bump `package.json` version before merging — the CI drift gate enforces both.\n\n## License\n\nMIT © AnomalyArmor\n","readmeFilename":"README.md","_rev":"1-959bb5b2c66f6d56c5c7b5ecd4e57ff2"}