@alter-ai/alter-sdk 0.2.2 → 0.4.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/README.md +132 -51
- package/dist/index.cjs +543 -80
- package/dist/index.d.cts +100 -18
- package/dist/index.d.ts +100 -18
- package/dist/index.js +529 -80
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
# Alter SDK for TypeScript / Node.js
|
|
2
2
|
|
|
3
|
-
Official TypeScript SDK for [Alter Vault](https://alterai.dev) —
|
|
3
|
+
Official TypeScript SDK for [Alter Vault](https://alterai.dev) — Credential management for agents with policy enforcement.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- **Zero Token Exposure**: Tokens are never exposed to developers — injected automatically
|
|
8
8
|
- **Single Entry Point**: One method (`vault.request()`) for all provider APIs
|
|
9
|
-
- **Type-Safe Enums**: `
|
|
9
|
+
- **Type-Safe Enums**: `HttpMethod` enums with autocomplete
|
|
10
10
|
- **URL Templating**: Path parameter substitution with automatic URL encoding
|
|
11
11
|
- **Automatic Audit Logging**: All API calls logged with request metadata (HTTP method and URL) for full audit trail
|
|
12
12
|
- **Real-time Policy Enforcement**: Every token request checked against current policies
|
|
13
13
|
- **Automatic Token Refresh**: Tokens refreshed transparently by the backend
|
|
14
|
+
- **API Key and Custom Credential Support**: Handles OAuth tokens, API keys, and custom credential formats automatically
|
|
15
|
+
- **AWS SigV4 Support**: Automatic AWS Signature Version 4 signing for S3, Bedrock, DynamoDB, and other AWS services (no AWS SDK required)
|
|
14
16
|
- **Actor Tracking**: First-class support for AI agent and MCP server observability
|
|
17
|
+
- **HMAC Request Signing**: All SDK-to-backend requests are signed with a derived HMAC-SHA256 key for integrity, authenticity, and replay protection
|
|
15
18
|
- **Native Promises**: Built on native `fetch` — no heavy dependencies
|
|
16
19
|
|
|
17
20
|
## Installation
|
|
@@ -23,17 +26,20 @@ npm install @alter-ai/alter-sdk
|
|
|
23
26
|
## Quick Start
|
|
24
27
|
|
|
25
28
|
```typescript
|
|
26
|
-
import { AlterVault, Provider, HttpMethod } from "@alter-ai/alter-sdk";
|
|
29
|
+
import { AlterVault, ActorType, Provider, HttpMethod } from "@alter-ai/alter-sdk";
|
|
27
30
|
|
|
28
|
-
const vault = new AlterVault({
|
|
31
|
+
const vault = new AlterVault({
|
|
32
|
+
apiKey: "alter_key_...",
|
|
33
|
+
actorType: ActorType.AI_AGENT,
|
|
34
|
+
actorIdentifier: "my-agent",
|
|
35
|
+
});
|
|
29
36
|
|
|
30
37
|
// Make API request — token injected automatically, never exposed
|
|
31
38
|
const response = await vault.request(
|
|
32
|
-
|
|
39
|
+
"CONNECTION_ID", // from Alter Connect (see below)
|
|
33
40
|
HttpMethod.GET,
|
|
34
41
|
"https://www.googleapis.com/calendar/v3/calendars/primary/events",
|
|
35
42
|
{
|
|
36
|
-
user: { user_id: "alice" },
|
|
37
43
|
queryParams: { maxResults: "10" },
|
|
38
44
|
},
|
|
39
45
|
);
|
|
@@ -44,16 +50,38 @@ console.log(events);
|
|
|
44
50
|
await vault.close();
|
|
45
51
|
```
|
|
46
52
|
|
|
53
|
+
### Where does `connectionId` come from?
|
|
54
|
+
|
|
55
|
+
**OAuth connections:**
|
|
56
|
+
1. User completes OAuth via [Alter Connect](https://docs.alterai.dev/sdks/javascript/quickstart) (frontend widget)
|
|
57
|
+
2. The `onSuccess` callback returns a `connectionId` (UUID)
|
|
58
|
+
3. You save it in your database, mapped to your user
|
|
59
|
+
4. You pass it to `vault.request()` when making API calls
|
|
60
|
+
|
|
61
|
+
**Managed secrets** (API keys, service tokens):
|
|
62
|
+
1. Store credentials in the [Developer Portal](https://portal.alterai.dev) under **Managed Secrets**
|
|
63
|
+
2. Copy the `connectionId` returned
|
|
64
|
+
3. Use the same `vault.request()` — credentials are injected automatically
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
// You can also discover connectionIds programmatically:
|
|
68
|
+
const result = await vault.listConnections({ providerId: "google" });
|
|
69
|
+
for (const conn of result.connections) {
|
|
70
|
+
console.log(`${conn.id}: ${conn.accountDisplayName}`);
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
47
74
|
## Usage
|
|
48
75
|
|
|
76
|
+
The `request()` method returns the raw `Response` object. The token is injected automatically and never exposed. The backend token response includes `connectionId` and `providerId` for audit correlation.
|
|
77
|
+
|
|
49
78
|
### Simple GET Request
|
|
50
79
|
|
|
51
80
|
```typescript
|
|
52
81
|
const response = await vault.request(
|
|
53
|
-
|
|
82
|
+
connectionId,
|
|
54
83
|
HttpMethod.GET,
|
|
55
84
|
"https://www.googleapis.com/calendar/v3/calendars/primary/events",
|
|
56
|
-
{ user: { user_id: "alice" } },
|
|
57
85
|
);
|
|
58
86
|
```
|
|
59
87
|
|
|
@@ -61,11 +89,10 @@ const response = await vault.request(
|
|
|
61
89
|
|
|
62
90
|
```typescript
|
|
63
91
|
const response = await vault.request(
|
|
64
|
-
|
|
92
|
+
connectionId,
|
|
65
93
|
HttpMethod.POST,
|
|
66
94
|
"https://api.example.com/v1/items",
|
|
67
95
|
{
|
|
68
|
-
user: { user_id: "alice" },
|
|
69
96
|
json: { name: "New Item", price: 99.99 },
|
|
70
97
|
reason: "Creating new item",
|
|
71
98
|
},
|
|
@@ -76,11 +103,10 @@ const response = await vault.request(
|
|
|
76
103
|
|
|
77
104
|
```typescript
|
|
78
105
|
const response = await vault.request(
|
|
79
|
-
|
|
106
|
+
connectionId,
|
|
80
107
|
HttpMethod.PUT,
|
|
81
108
|
"https://api.example.com/v1/items/{item_id}",
|
|
82
109
|
{
|
|
83
|
-
user: { user_id: "alice" },
|
|
84
110
|
pathParams: { item_id: "123" },
|
|
85
111
|
json: { price: 89.99 },
|
|
86
112
|
},
|
|
@@ -91,11 +117,10 @@ const response = await vault.request(
|
|
|
91
117
|
|
|
92
118
|
```typescript
|
|
93
119
|
const response = await vault.request(
|
|
94
|
-
|
|
120
|
+
connectionId,
|
|
95
121
|
HttpMethod.POST,
|
|
96
122
|
"https://api.notion.com/v1/databases/{db_id}/query",
|
|
97
123
|
{
|
|
98
|
-
user: { user_id: "alice" },
|
|
99
124
|
pathParams: { db_id: "abc123" },
|
|
100
125
|
extraHeaders: { "Notion-Version": "2022-06-28" },
|
|
101
126
|
json: { page_size: 10 },
|
|
@@ -103,6 +128,28 @@ const response = await vault.request(
|
|
|
103
128
|
);
|
|
104
129
|
```
|
|
105
130
|
|
|
131
|
+
### Using Managed Secrets
|
|
132
|
+
|
|
133
|
+
For your own APIs with API keys or service tokens (no OAuth flow needed):
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
const vault = new AlterVault({
|
|
137
|
+
apiKey: "alter_key_...",
|
|
138
|
+
actorType: ActorType.BACKEND_SERVICE,
|
|
139
|
+
actorIdentifier: "my-service",
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const response = await vault.request(
|
|
143
|
+
"MANAGED_SECRET_CONNECTION_ID", // from Developer Portal
|
|
144
|
+
HttpMethod.GET,
|
|
145
|
+
"https://api.internal.com/v1/data",
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
await vault.close();
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The credential is injected automatically as the configured header type (Bearer, API Key, Basic Auth).
|
|
152
|
+
|
|
106
153
|
### Connection Management
|
|
107
154
|
|
|
108
155
|
#### List Connections
|
|
@@ -149,18 +196,55 @@ console.log(`Expires in: ${session.expiresIn}s`);
|
|
|
149
196
|
| Parameter | Type | Default | Description |
|
|
150
197
|
|-----------|------|---------|-------------|
|
|
151
198
|
| `endUser` | `{ id: string }` | *required* | End user identity |
|
|
152
|
-
| `attributes` | `Record<string, unknown>` | - | Connection attributes |
|
|
153
199
|
| `allowedProviders` | `string[]` | - | Restrict to specific providers |
|
|
154
200
|
| `returnUrl` | `string` | - | Redirect URL after OAuth flow |
|
|
155
201
|
|
|
156
202
|
Returns `ConnectSession` with: `sessionToken`, `connectUrl`, `expiresIn`, `expiresAt`.
|
|
157
203
|
|
|
204
|
+
#### Headless Connect (from code)
|
|
205
|
+
|
|
206
|
+
For CLI tools, scripts, and server-side applications -- opens the browser, waits for the user to complete OAuth, and returns the result:
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
const results = await vault.connect({
|
|
210
|
+
endUser: { id: "alice" },
|
|
211
|
+
providers: ["google"],
|
|
212
|
+
timeout: 300, // max wait in seconds (default: 5 min)
|
|
213
|
+
openBrowser: true, // set false to print URL instead
|
|
214
|
+
});
|
|
215
|
+
for (const result of results) {
|
|
216
|
+
console.log(`Connected: ${result.connectionId} (${result.providerId})`);
|
|
217
|
+
console.log(`Account: ${result.accountIdentifier}`);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Now use the connectionId with vault.request()
|
|
221
|
+
const response = await vault.request(
|
|
222
|
+
results[0].connectionId,
|
|
223
|
+
HttpMethod.GET,
|
|
224
|
+
"https://www.googleapis.com/calendar/v3/calendars/primary/events",
|
|
225
|
+
);
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
| Parameter | Type | Default | Description |
|
|
229
|
+
|-----------|------|---------|-------------|
|
|
230
|
+
| `endUser` | `{ id: string }` | *required* | End user identity |
|
|
231
|
+
| `providers` | `string[]` | - | Restrict to specific providers |
|
|
232
|
+
| `timeout` | `number` | `300` | Max seconds to wait for completion |
|
|
233
|
+
| `pollInterval` | `number` | `2` | Seconds between status checks |
|
|
234
|
+
| `openBrowser` | `boolean` | `true` | Open browser automatically |
|
|
235
|
+
|
|
236
|
+
Returns `ConnectResult[]` — one per connected provider. Each has: `connectionId`, `providerId`, `accountIdentifier`, `scopes`.
|
|
237
|
+
|
|
238
|
+
Throws `ConnectTimeoutError` if the user doesn't complete in time, `ConnectFlowError` if denied.
|
|
239
|
+
|
|
158
240
|
### AI Agent Actor Tracking
|
|
159
241
|
|
|
160
242
|
```typescript
|
|
243
|
+
import { AlterVault, ActorType, Provider, HttpMethod } from "@alter-ai/alter-sdk";
|
|
244
|
+
|
|
161
245
|
const vault = new AlterVault({
|
|
162
246
|
apiKey: "alter_key_...",
|
|
163
|
-
actorType:
|
|
247
|
+
actorType: ActorType.AI_AGENT,
|
|
164
248
|
actorIdentifier: "email-assistant-v2",
|
|
165
249
|
actorName: "Email Assistant",
|
|
166
250
|
actorVersion: "2.0.0",
|
|
@@ -168,18 +252,19 @@ const vault = new AlterVault({
|
|
|
168
252
|
});
|
|
169
253
|
|
|
170
254
|
const response = await vault.request(
|
|
171
|
-
|
|
255
|
+
connectionId,
|
|
172
256
|
HttpMethod.GET,
|
|
173
257
|
"https://www.googleapis.com/calendar/v3/calendars/primary/events",
|
|
174
258
|
{
|
|
175
|
-
|
|
176
|
-
runId: "550e8400-e29b-41d4-a716-446655440000",
|
|
259
|
+
runId: "550e8400-e29b-41d4-a716-446655440000", // auto-generated UUID if omitted
|
|
177
260
|
threadId: "thread-xyz",
|
|
178
261
|
toolCallId: "call_abc_123",
|
|
179
262
|
},
|
|
180
263
|
);
|
|
181
264
|
```
|
|
182
265
|
|
|
266
|
+
> **Note**: `runId` is auto-generated as a UUID v4 if not provided. All sub-actions within a single `request()` call share the same `runId` for audit log grouping.
|
|
267
|
+
|
|
183
268
|
### Multi-Agent Deployments
|
|
184
269
|
|
|
185
270
|
Each agent must create its own `AlterVault` instance with a unique actor identity. Do not share a single instance across agents.
|
|
@@ -188,29 +273,28 @@ Each agent must create its own `AlterVault` instance with a unique actor identit
|
|
|
188
273
|
// Each agent gets its own vault instance
|
|
189
274
|
const emailAgent = new AlterVault({
|
|
190
275
|
apiKey: "alter_key_...",
|
|
191
|
-
actorType:
|
|
276
|
+
actorType: ActorType.AI_AGENT,
|
|
192
277
|
actorIdentifier: "email-assistant-v2",
|
|
193
278
|
actorName: "Email Assistant",
|
|
194
279
|
});
|
|
195
280
|
|
|
196
281
|
const calendarAgent = new AlterVault({
|
|
197
282
|
apiKey: "alter_key_...",
|
|
198
|
-
actorType:
|
|
283
|
+
actorType: ActorType.AI_AGENT,
|
|
199
284
|
actorIdentifier: "calendar-agent-v1",
|
|
200
285
|
actorName: "Calendar Agent",
|
|
201
286
|
});
|
|
202
287
|
|
|
203
288
|
// Audit logs and policies are tracked per agent
|
|
204
|
-
const user = { user_id: "alice" };
|
|
205
289
|
await emailAgent.request(
|
|
206
|
-
|
|
290
|
+
gmailConnectionId, // from Alter Connect
|
|
291
|
+
HttpMethod.GET,
|
|
207
292
|
"https://gmail.googleapis.com/gmail/v1/users/me/messages",
|
|
208
|
-
{ user },
|
|
209
293
|
);
|
|
210
294
|
await calendarAgent.request(
|
|
211
|
-
|
|
295
|
+
calendarConnectionId, // from Alter Connect
|
|
296
|
+
HttpMethod.GET,
|
|
212
297
|
"https://www.googleapis.com/calendar/v3/calendars/primary/events",
|
|
213
|
-
{ user },
|
|
214
298
|
);
|
|
215
299
|
|
|
216
300
|
// Clean up each instance
|
|
@@ -221,34 +305,35 @@ await calendarAgent.close();
|
|
|
221
305
|
## Configuration
|
|
222
306
|
|
|
223
307
|
```typescript
|
|
308
|
+
import { AlterVault, ActorType } from "@alter-ai/alter-sdk";
|
|
309
|
+
|
|
224
310
|
const vault = new AlterVault({
|
|
225
311
|
apiKey: "alter_key_...", // Required: Alter Vault API key
|
|
226
|
-
|
|
312
|
+
actorType: ActorType.AI_AGENT, // Required: ActorType enum
|
|
313
|
+
actorIdentifier: "my-agent", // Required: Unique identifier
|
|
227
314
|
timeout: 30000, // Optional: HTTP timeout in ms (default: 30000)
|
|
228
|
-
//
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
actorVersion: "1.0.0", // Version string
|
|
233
|
-
framework: "langgraph", // AI framework
|
|
234
|
-
clientType: "cursor", // MCP client type
|
|
315
|
+
actorName: "My Agent", // Optional: Human-readable name
|
|
316
|
+
actorVersion: "1.0.0", // Optional: Version string
|
|
317
|
+
framework: "langgraph", // Optional: AI framework
|
|
318
|
+
clientType: "cursor", // Optional: MCP client type
|
|
235
319
|
});
|
|
236
320
|
```
|
|
237
321
|
|
|
238
322
|
## Error Handling
|
|
239
323
|
|
|
240
|
-
> **Note:** Input validation errors (invalid `apiKey`, invalid `actorType`, invalid URL scheme, missing `pathParams`) throw `AlterSDKError`.
|
|
324
|
+
> **Note:** Input validation errors (invalid `apiKey`, invalid/missing `actorType`, missing `actorIdentifier`, invalid URL scheme, missing `pathParams`) throw `AlterSDKError`.
|
|
241
325
|
|
|
242
326
|
```typescript
|
|
243
327
|
import {
|
|
244
328
|
AlterVault,
|
|
245
|
-
Provider,
|
|
246
329
|
HttpMethod,
|
|
247
|
-
AlterSDKError, // Base error (including validation: apiKey, actorType, URL scheme, pathParams)
|
|
330
|
+
AlterSDKError, // Base error (including validation: apiKey, actorType, actorIdentifier, URL scheme, pathParams)
|
|
248
331
|
PolicyViolationError,
|
|
249
332
|
ConnectionNotFoundError,
|
|
250
333
|
TokenExpiredError,
|
|
251
334
|
TokenRetrievalError,
|
|
335
|
+
ConnectFlowError, // Headless connect() failed (denied, provider error)
|
|
336
|
+
ConnectTimeoutError, // Headless connect() timed out
|
|
252
337
|
NetworkError,
|
|
253
338
|
TimeoutError,
|
|
254
339
|
ProviderAPIError,
|
|
@@ -256,10 +341,9 @@ import {
|
|
|
256
341
|
|
|
257
342
|
try {
|
|
258
343
|
const response = await vault.request(
|
|
259
|
-
|
|
344
|
+
connectionId,
|
|
260
345
|
HttpMethod.GET,
|
|
261
346
|
"https://www.googleapis.com/calendar/v3/calendars/primary/events",
|
|
262
|
-
{ user: { user_id: "alice" } },
|
|
263
347
|
);
|
|
264
348
|
} catch (error) {
|
|
265
349
|
if (error instanceof PolicyViolationError) {
|
|
@@ -282,7 +366,11 @@ try {
|
|
|
282
366
|
|
|
283
367
|
```typescript
|
|
284
368
|
// Manual cleanup (recommended)
|
|
285
|
-
const vault = new AlterVault({
|
|
369
|
+
const vault = new AlterVault({
|
|
370
|
+
apiKey: "alter_key_...",
|
|
371
|
+
actorType: ActorType.BACKEND_SERVICE,
|
|
372
|
+
actorIdentifier: "my-service",
|
|
373
|
+
});
|
|
286
374
|
try {
|
|
287
375
|
const response = await vault.request(...);
|
|
288
376
|
} finally {
|
|
@@ -295,18 +383,11 @@ try {
|
|
|
295
383
|
|
|
296
384
|
## Supported Providers
|
|
297
385
|
|
|
298
|
-
|
|
299
|
-
import { Provider } from "@alter-ai/alter-sdk";
|
|
300
|
-
|
|
301
|
-
Provider.GOOGLE // "google"
|
|
302
|
-
Provider.GITHUB // "github"
|
|
303
|
-
Provider.SLACK // "slack"
|
|
304
|
-
Provider.MICROSOFT // "microsoft"
|
|
305
|
-
Provider.SALESFORCE // "salesforce"
|
|
306
|
-
Provider.SENTRY // "sentry"
|
|
386
|
+
The SDK works with any OAuth provider configured in your Alter Vault dashboard. The first parameter to `vault.request()` is the `connection_id` (UUID) returned when a user connects via Alter Connect.
|
|
307
387
|
|
|
308
|
-
|
|
309
|
-
|
|
388
|
+
```typescript
|
|
389
|
+
// Use the connection_id from Alter Connect
|
|
390
|
+
await vault.request("550e8400-e29b-41d4-a716-446655440000", HttpMethod.GET, url);
|
|
310
391
|
```
|
|
311
392
|
|
|
312
393
|
## Requirements
|