@alter-ai/alter-sdk 0.2.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 ADDED
@@ -0,0 +1,234 @@
1
+ # Alter SDK for TypeScript / Node.js
2
+
3
+ > **Version**: 0.4.0
4
+
5
+ Official TypeScript SDK for [Alter Vault](https://alterai.dev) — OAuth token management with policy enforcement.
6
+
7
+ ## Features
8
+
9
+ - **Zero Token Exposure**: Tokens are never exposed to developers — injected automatically
10
+ - **Single Entry Point**: One method (`vault.request()`) for all provider APIs
11
+ - **Type-Safe Enums**: `Provider` and `HttpMethod` enums with autocomplete
12
+ - **URL Templating**: Path parameter substitution with automatic URL encoding
13
+ - **Automatic Audit Logging**: All API calls logged as fire-and-forget background tasks
14
+ - **Real-time Policy Enforcement**: Every token request checked against current policies
15
+ - **Automatic Token Refresh**: Tokens refreshed transparently by the backend
16
+ - **Dual HTTP Client Security**: Separate clients prevent credential leakage to providers
17
+ - **Security Hardened (v0.4.0)**: Frozen `HttpClient` prototype, `WeakMap` token storage, unexported module-private token accessors, and hardened `fetch` capture prevent rogue agent token extraction
18
+ - **Actor Tracking**: First-class support for AI agent and MCP server observability
19
+ - **Native Promises**: Built on native `fetch` — no heavy dependencies
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ npm install @alter-ai/alter-sdk
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ```typescript
30
+ import { AlterVault, Provider, HttpMethod } from "@alter-ai/alter-sdk";
31
+
32
+ const vault = new AlterVault({ apiKey: "alter_key_..." });
33
+
34
+ // Make API request — token injected automatically, never exposed
35
+ const response = await vault.request(
36
+ Provider.GOOGLE,
37
+ HttpMethod.GET,
38
+ "https://www.googleapis.com/calendar/v3/calendars/primary/events",
39
+ {
40
+ user: { user_id: "alice" },
41
+ queryParams: { maxResults: "10" },
42
+ },
43
+ );
44
+
45
+ const events = await response.json();
46
+ console.log(events);
47
+
48
+ await vault.close();
49
+ ```
50
+
51
+ ## Usage
52
+
53
+ ### Simple GET Request
54
+
55
+ ```typescript
56
+ const response = await vault.request(
57
+ Provider.GOOGLE,
58
+ HttpMethod.GET,
59
+ "https://www.googleapis.com/calendar/v3/calendars/primary/events",
60
+ { user: { user_id: "alice" } },
61
+ );
62
+ ```
63
+
64
+ ### POST with JSON Body
65
+
66
+ ```typescript
67
+ const response = await vault.request(
68
+ Provider.SALESFORCE,
69
+ HttpMethod.POST,
70
+ "https://api.example.com/v1/items",
71
+ {
72
+ user: { user_id: "alice" },
73
+ json: { name: "New Item", price: 99.99 },
74
+ reason: "Creating new item",
75
+ },
76
+ );
77
+ ```
78
+
79
+ ### URL Path Templating
80
+
81
+ ```typescript
82
+ const response = await vault.request(
83
+ Provider.SALESFORCE,
84
+ HttpMethod.PUT,
85
+ "https://api.example.com/v1/items/{item_id}",
86
+ {
87
+ user: { user_id: "alice" },
88
+ pathParams: { item_id: "123" },
89
+ json: { price: 89.99 },
90
+ },
91
+ );
92
+ ```
93
+
94
+ ### Query Parameters and Extra Headers
95
+
96
+ ```typescript
97
+ const response = await vault.request(
98
+ Provider.GOOGLE,
99
+ HttpMethod.GET,
100
+ "https://api.example.com/v1/items",
101
+ {
102
+ user: { user_id: "alice" },
103
+ queryParams: { fields: "name,price", limit: "10" },
104
+ extraHeaders: { "Notion-Version": "2022-06-28" },
105
+ },
106
+ );
107
+ ```
108
+
109
+ ### AI Agent Actor Tracking
110
+
111
+ ```typescript
112
+ const vault = new AlterVault({
113
+ apiKey: "alter_key_...",
114
+ actorType: "ai_agent",
115
+ actorIdentifier: "email-assistant-v2",
116
+ actorName: "Email Assistant",
117
+ actorVersion: "2.0.0",
118
+ framework: "langgraph",
119
+ });
120
+
121
+ const response = await vault.request(
122
+ Provider.GOOGLE,
123
+ HttpMethod.GET,
124
+ "https://www.googleapis.com/calendar/v3/calendars/primary/events",
125
+ {
126
+ user: { user_id: "alice" },
127
+ runId: "550e8400-e29b-41d4-a716-446655440000",
128
+ threadId: "thread-xyz",
129
+ },
130
+ );
131
+ ```
132
+
133
+ ## Configuration
134
+
135
+ ```typescript
136
+ const vault = new AlterVault({
137
+ apiKey: "alter_key_...", // Required: Alter Vault API key
138
+ baseUrl: "https://api.alter.com", // Optional: Custom API URL
139
+ enableAuditLogging: true, // Optional: Enable audit logs (default: true)
140
+ timeout: 30000, // Optional: HTTP timeout in ms (default: 30000)
141
+ // Actor tracking (optional)
142
+ actorType: "ai_agent", // "ai_agent" or "mcp_server"
143
+ actorIdentifier: "my-agent", // Unique identifier
144
+ actorName: "My Agent", // Human-readable name
145
+ actorVersion: "1.0.0", // Version string
146
+ framework: "langgraph", // AI framework
147
+ clientType: "cursor", // MCP client type
148
+ });
149
+ ```
150
+
151
+ ## Error Handling
152
+
153
+ > **Note:** Input validation errors (invalid `apiKey`, invalid `actorType`, SSRF URL scheme violations, missing `pathParams`) throw `AlterSDKError`.
154
+
155
+ ```typescript
156
+ import {
157
+ AlterVault,
158
+ Provider,
159
+ HttpMethod,
160
+ AlterSDKError, // Base error (including validation: apiKey, actorType, SSRF, pathParams)
161
+ PolicyViolationError,
162
+ ConnectionNotFoundError,
163
+ TokenExpiredError,
164
+ TokenRetrievalError,
165
+ NetworkError,
166
+ TimeoutError,
167
+ ProviderAPIError,
168
+ } from "@alter-ai/alter-sdk";
169
+
170
+ try {
171
+ const response = await vault.request(
172
+ Provider.GOOGLE,
173
+ HttpMethod.GET,
174
+ "https://www.googleapis.com/calendar/v3/calendars/primary/events",
175
+ { user: { user_id: "alice" } },
176
+ );
177
+ } catch (error) {
178
+ if (error instanceof PolicyViolationError) {
179
+ console.error(`Policy denied: ${error.message}`);
180
+ } else if (error instanceof ConnectionNotFoundError) {
181
+ console.error("No OAuth connection — user needs to authenticate");
182
+ } else if (error instanceof TokenExpiredError) {
183
+ console.error(`Token expired for connection: ${error.connectionId}`);
184
+ } else if (error instanceof TimeoutError) {
185
+ console.error(`Request timed out — safe to retry: ${error.message}`);
186
+ } else if (error instanceof NetworkError) {
187
+ console.error(`Network issue: ${error.message}`);
188
+ } else if (error instanceof ProviderAPIError) {
189
+ console.error(`Provider error ${error.statusCode}: ${error.responseBody}`);
190
+ }
191
+ }
192
+ ```
193
+
194
+ ## Resource Management
195
+
196
+ ```typescript
197
+ // Manual cleanup (recommended)
198
+ const vault = new AlterVault({ apiKey: "alter_key_..." });
199
+ try {
200
+ const response = await vault.request(...);
201
+ } finally {
202
+ await vault.close(); // Waits for pending audit logs, cleans up timers
203
+ }
204
+
205
+ // close() is idempotent — safe to call multiple times
206
+ // Calling request() after close() throws AlterSDKError
207
+ ```
208
+
209
+ ## Architecture
210
+
211
+ See [ALTER_TYPESCRIPT_SDK_ARCHITECTURE.md](./ALTER_TYPESCRIPT_SDK_ARCHITECTURE.md) for details on:
212
+ - Dual HTTP client security model
213
+ - Zero token exposure design
214
+ - No SDK-side caching (real-time policy enforcement)
215
+ - SSRF prevention with case-insensitive URL scheme validation
216
+ - Actor tracking and audit logging
217
+
218
+ ## Development
219
+
220
+ ```bash
221
+ npm install
222
+ npm run test # Run tests (70 tests)
223
+ npm run typecheck # Type check
224
+ npm run build # Build for distribution
225
+ ```
226
+
227
+ ## Requirements
228
+
229
+ - Node.js 18+ (uses native `fetch`)
230
+ - TypeScript 5.0+
231
+
232
+ ## License
233
+
234
+ MIT License