feat: Phase 1 P1 — Dockerfile, AGNTCY alignment docs, Node.js SDK
Three remaining Phase 1 P1 deliverables: 1. Dockerfile — multi-stage build (builder + production), node:18-alpine, non-root USER node, .dockerignore excluding secrets and dev artifacts 2. AGNTCY alignment docs (docs/agntcy/) — README and alignment.md mapping all 6 AGNTCY domains to AgentIdP features with Phase 2/3 pending items noted 3. Node.js SDK (@sentryagent/idp-sdk) — TypeScript strict, zero any, native fetch (Node 18+), TokenManager with 60s auto-refresh, service clients for all 14 endpoints (agents, credentials, tokens, audit), AgentIdPError typed error hierarchy, full README All three changes tracked under openspec/changes/ with tasks marked complete. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
196
sdk/README.md
Normal file
196
sdk/README.md
Normal file
@@ -0,0 +1,196 @@
|
||||
# @sentryagent/idp-sdk
|
||||
|
||||
Node.js SDK for the [SentryAgent.ai AgentIdP](https://sentryagent.ai) — the open-source Identity Provider for AI agents.
|
||||
|
||||
Handles token acquisition and caching automatically. Covers all 14 AgentIdP API endpoints.
|
||||
|
||||
---
|
||||
|
||||
## Requirements
|
||||
|
||||
- Node.js 18 or later (uses native `fetch`)
|
||||
- A running AgentIdP server
|
||||
- A registered agent with a valid `clientId` and `clientSecret`
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @sentryagent/idp-sdk
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick start
|
||||
|
||||
```typescript
|
||||
import { AgentIdPClient } from '@sentryagent/idp-sdk';
|
||||
|
||||
const client = new AgentIdPClient({
|
||||
baseUrl: 'http://localhost:3000',
|
||||
clientId: 'your-agent-id', // the agent's agentId (UUID)
|
||||
clientSecret: 'your-client-secret',
|
||||
});
|
||||
|
||||
// List agents — token is acquired and cached automatically
|
||||
const { data: agents } = await client.agents.listAgents();
|
||||
console.log(agents);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
```typescript
|
||||
const client = new AgentIdPClient({
|
||||
baseUrl: 'http://localhost:3000',
|
||||
clientId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
|
||||
clientSecret: 'your-client-secret',
|
||||
// Optional: restrict scopes. Defaults to all four scopes.
|
||||
scopes: ['agents:read', 'tokens:read'],
|
||||
});
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
|--------|----------|-------------|
|
||||
| `baseUrl` | Yes | Base URL of the AgentIdP server |
|
||||
| `clientId` | Yes | The agent's `agentId` (UUID) |
|
||||
| `clientSecret` | Yes | The credential secret |
|
||||
| `scopes` | No | OAuth 2.0 scopes to request. Defaults to all four. |
|
||||
|
||||
---
|
||||
|
||||
## Token management
|
||||
|
||||
The SDK fetches and caches access tokens automatically. A new token is requested when the cached token is within 60 seconds of expiry.
|
||||
|
||||
```typescript
|
||||
// Force a fresh token on the next request (e.g. after rotating credentials)
|
||||
client.clearTokenCache();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Agent Registry
|
||||
|
||||
```typescript
|
||||
// Register a new agent
|
||||
const agent = await client.agents.registerAgent({
|
||||
email: 'classifier-v2@myorg.ai',
|
||||
agentType: 'classifier',
|
||||
version: '2.0.0',
|
||||
capabilities: ['text-classification', 'sentiment-analysis'],
|
||||
owner: 'platform-team',
|
||||
deploymentEnv: 'production',
|
||||
});
|
||||
console.log(agent.agentId); // UUID assigned by AgentIdP
|
||||
|
||||
// List agents
|
||||
const { data, total } = await client.agents.listAgents({ status: 'active', limit: 20 });
|
||||
|
||||
// Get a single agent
|
||||
const agent = await client.agents.getAgent('a1b2c3d4-...');
|
||||
|
||||
// Update an agent
|
||||
const updated = await client.agents.updateAgent('a1b2c3d4-...', {
|
||||
version: '2.1.0',
|
||||
capabilities: ['text-classification', 'sentiment-analysis', 'intent-detection'],
|
||||
});
|
||||
|
||||
// Decommission (irreversible)
|
||||
await client.agents.decommissionAgent('a1b2c3d4-...');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Credentials
|
||||
|
||||
```typescript
|
||||
// Generate a credential — clientSecret shown once, store it securely
|
||||
const cred = await client.credentials.generateCredential('a1b2c3d4-...');
|
||||
console.log(cred.clientSecret); // only available here
|
||||
|
||||
// List credentials
|
||||
const { data: creds } = await client.credentials.listCredentials('a1b2c3d4-...');
|
||||
|
||||
// Rotate — same credentialId, new secret, old secret immediately invalid
|
||||
const rotated = await client.credentials.rotateCredential('a1b2c3d4-...', 'cred-uuid');
|
||||
console.log(rotated.clientSecret); // new secret — store immediately
|
||||
|
||||
// Revoke
|
||||
await client.credentials.revokeCredential('a1b2c3d4-...', 'cred-uuid');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Token operations
|
||||
|
||||
```typescript
|
||||
// Introspect — check whether a token is active
|
||||
const result = await client.tokens.introspectToken(someToken);
|
||||
if (result.active) {
|
||||
console.log('Token is valid, expires at', result.exp);
|
||||
} else {
|
||||
console.log('Token is expired or revoked');
|
||||
}
|
||||
|
||||
// Revoke — immediately invalidates the token
|
||||
await client.tokens.revokeToken(someToken);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Audit log
|
||||
|
||||
```typescript
|
||||
// Query audit events
|
||||
const { data: events } = await client.audit.queryAuditLog({
|
||||
agentId: 'a1b2c3d4-...',
|
||||
action: 'token.issued',
|
||||
outcome: 'success',
|
||||
fromDate: '2026-03-01T00:00:00Z',
|
||||
toDate: '2026-03-31T23:59:59Z',
|
||||
limit: 50,
|
||||
});
|
||||
|
||||
// Get a single event
|
||||
const event = await client.audit.getAuditEvent('event-uuid');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error handling
|
||||
|
||||
All API errors are thrown as `AgentIdPError`:
|
||||
|
||||
```typescript
|
||||
import { AgentIdPClient, AgentIdPError } from '@sentryagent/idp-sdk';
|
||||
|
||||
try {
|
||||
await client.agents.getAgent('non-existent-id');
|
||||
} catch (err) {
|
||||
if (err instanceof AgentIdPError) {
|
||||
console.error(err.code); // e.g. 'AgentNotFoundError'
|
||||
console.error(err.httpStatus); // e.g. 404
|
||||
console.error(err.message); // human-readable description
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Available scopes
|
||||
|
||||
| Scope | What it allows |
|
||||
|-------|----------------|
|
||||
| `agents:read` | Read agent records |
|
||||
| `agents:write` | Create, update, decommission agents |
|
||||
| `tokens:read` | Introspect tokens |
|
||||
| `audit:read` | Query audit logs |
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
Apache 2.0 — see [LICENSE](../LICENSE) in the repository root.
|
||||
Reference in New Issue
Block a user