@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 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) — OAuth token management with policy enforcement.
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**: `Provider` and `HttpMethod` enums with autocomplete
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({ apiKey: "alter_key_..." });
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
- Provider.GOOGLE,
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
- Provider.GOOGLE,
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
- Provider.SALESFORCE,
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
- Provider.SALESFORCE,
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
- "notion",
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: "ai_agent",
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
- Provider.GOOGLE,
255
+ connectionId,
172
256
  HttpMethod.GET,
173
257
  "https://www.googleapis.com/calendar/v3/calendars/primary/events",
174
258
  {
175
- user: { user_id: "alice" },
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: "ai_agent",
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: "ai_agent",
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
- Provider.GOOGLE, HttpMethod.GET,
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
- Provider.GOOGLE, HttpMethod.GET,
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
- baseUrl: "https://api.alter.com", // Optional: Custom API URL
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
- // Actor tracking (optional)
229
- actorType: "ai_agent", // "ai_agent" or "mcp_server"
230
- actorIdentifier: "my-agent", // Unique identifier
231
- actorName: "My Agent", // Human-readable name
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
- Provider.GOOGLE,
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({ apiKey: "alter_key_..." });
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
- ```typescript
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
- // Strings also work for any provider
309
- await vault.request("notion", HttpMethod.GET, url, { user });
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