tether-name 1.0.0 → 1.0.2
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 +110 -8
- package/dist/index.d.mts +49 -1
- package/dist/index.d.ts +49 -1
- package/dist/index.js +151 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +151 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ Requires Node.js 18+ (uses native `fetch` and `crypto` modules).
|
|
|
16
16
|
import { TetherClient } from 'tether-name';
|
|
17
17
|
|
|
18
18
|
const client = new TetherClient({
|
|
19
|
-
credentialId: '
|
|
19
|
+
credentialId: 'your-credential-id',
|
|
20
20
|
privateKeyPath: '/path/to/your/private-key.der'
|
|
21
21
|
});
|
|
22
22
|
|
|
@@ -35,7 +35,7 @@ For more control over the verification process:
|
|
|
35
35
|
import { TetherClient } from 'tether-name';
|
|
36
36
|
|
|
37
37
|
const client = new TetherClient({
|
|
38
|
-
credentialId: '
|
|
38
|
+
credentialId: 'your-credential-id',
|
|
39
39
|
privateKeyPem: `-----BEGIN RSA PRIVATE KEY-----
|
|
40
40
|
MIIEpAIBAAKCAQEA...
|
|
41
41
|
-----END RSA PRIVATE KEY-----`
|
|
@@ -68,19 +68,53 @@ try {
|
|
|
68
68
|
|
|
69
69
|
```typescript
|
|
70
70
|
interface TetherClientConfig {
|
|
71
|
-
//
|
|
71
|
+
// API key (for agent management — no private key needed)
|
|
72
|
+
apiKey?: string; // Or use TETHER_API_KEY env var
|
|
73
|
+
|
|
74
|
+
// Credential ID (required for verify/sign, optional with apiKey)
|
|
72
75
|
credentialId?: string; // Or use TETHER_CREDENTIAL_ID env var
|
|
73
|
-
|
|
74
|
-
// Private key (choose one)
|
|
76
|
+
|
|
77
|
+
// Private key (required for verify/sign, choose one)
|
|
75
78
|
privateKeyPath?: string; // Path to DER or PEM file
|
|
76
79
|
privateKeyPem?: string; // PEM string directly
|
|
77
80
|
privateKeyBuffer?: Buffer; // DER buffer directly
|
|
78
|
-
|
|
81
|
+
|
|
79
82
|
// Optional
|
|
80
83
|
baseUrl?: string; // API base URL (defaults to https://api.tether.name)
|
|
81
84
|
}
|
|
82
85
|
```
|
|
83
86
|
|
|
87
|
+
### Authentication Modes
|
|
88
|
+
|
|
89
|
+
**API key only** — manage agents without a private key:
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
const client = new TetherClient({
|
|
93
|
+
apiKey: 'sk-tether-name-...'
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const agent = await client.createAgent('my-bot');
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**API key + credential + private key** — full access (management and verification):
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
const client = new TetherClient({
|
|
103
|
+
apiKey: 'sk-tether-name-...',
|
|
104
|
+
credentialId: 'your-credential-id',
|
|
105
|
+
privateKeyPath: '/path/to/key.der'
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Credential + private key only** — verification without agent management (original behavior):
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
const client = new TetherClient({
|
|
113
|
+
credentialId: 'your-credential-id',
|
|
114
|
+
privateKeyPath: '/path/to/key.der'
|
|
115
|
+
});
|
|
116
|
+
```
|
|
117
|
+
|
|
84
118
|
### Key Format Support
|
|
85
119
|
|
|
86
120
|
The SDK supports both DER and PEM private key formats:
|
|
@@ -106,11 +140,32 @@ const client3 = new TetherClient({
|
|
|
106
140
|
});
|
|
107
141
|
```
|
|
108
142
|
|
|
143
|
+
## Agent Management
|
|
144
|
+
|
|
145
|
+
Create and manage agents programmatically with an API key:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
const client = new TetherClient({ apiKey: 'sk-tether-name-...' });
|
|
149
|
+
|
|
150
|
+
// Create an agent
|
|
151
|
+
const agent = await client.createAgent('my-bot', 'Does helpful things');
|
|
152
|
+
console.log(agent.id); // "abc123"
|
|
153
|
+
console.log(agent.agentName); // "my-bot"
|
|
154
|
+
console.log(agent.registrationToken); // Use to register credentials
|
|
155
|
+
|
|
156
|
+
// List all agents
|
|
157
|
+
const agents = await client.listAgents();
|
|
158
|
+
|
|
159
|
+
// Delete an agent
|
|
160
|
+
await client.deleteAgent(agent.id);
|
|
161
|
+
```
|
|
162
|
+
|
|
109
163
|
## Environment Variables
|
|
110
164
|
|
|
111
165
|
Set these environment variables to avoid hardcoding credentials:
|
|
112
166
|
|
|
113
167
|
```bash
|
|
168
|
+
export TETHER_API_KEY="sk-tether-name-..." # API key for agent management
|
|
114
169
|
export TETHER_CREDENTIAL_ID="your-credential-id"
|
|
115
170
|
export TETHER_PRIVATE_KEY_PATH="/path/to/your/private-key.der"
|
|
116
171
|
```
|
|
@@ -151,6 +206,18 @@ Signs a challenge using the configured private key.
|
|
|
151
206
|
|
|
152
207
|
Submits signed proof to verify the challenge.
|
|
153
208
|
|
|
209
|
+
#### `async createAgent(agentName: string, description?: string): Promise<Agent>`
|
|
210
|
+
|
|
211
|
+
Creates a new agent. Requires API key authentication.
|
|
212
|
+
|
|
213
|
+
#### `async listAgents(): Promise<Agent[]>`
|
|
214
|
+
|
|
215
|
+
Lists all agents for the authenticated account. Requires API key authentication.
|
|
216
|
+
|
|
217
|
+
#### `async deleteAgent(agentId: string): Promise<boolean>`
|
|
218
|
+
|
|
219
|
+
Deletes an agent by ID. Requires API key authentication. Returns `true` on success.
|
|
220
|
+
|
|
154
221
|
### Types
|
|
155
222
|
|
|
156
223
|
```typescript
|
|
@@ -165,6 +232,17 @@ interface VerificationResult {
|
|
|
165
232
|
}
|
|
166
233
|
```
|
|
167
234
|
|
|
235
|
+
```typescript
|
|
236
|
+
interface Agent {
|
|
237
|
+
id: string;
|
|
238
|
+
agentName: string;
|
|
239
|
+
description: string;
|
|
240
|
+
createdAt: number;
|
|
241
|
+
registrationToken?: string;
|
|
242
|
+
lastVerifiedAt?: number;
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
168
246
|
### Errors
|
|
169
247
|
|
|
170
248
|
- `TetherError` - Base error class
|
|
@@ -198,6 +276,30 @@ openssl rsa -in private-key.pem -outform DER -out private-key.der
|
|
|
198
276
|
- The SDK uses SHA256withRSA signatures with URL-safe base64 encoding
|
|
199
277
|
- All verification happens server-side at tether.name
|
|
200
278
|
|
|
279
|
+
## Publishing
|
|
280
|
+
|
|
281
|
+
Published to npm automatically via GitHub Actions when a release is created.
|
|
282
|
+
|
|
283
|
+
### Version checklist
|
|
284
|
+
|
|
285
|
+
Update the version in:
|
|
286
|
+
|
|
287
|
+
1. `package.json` → `"version"`
|
|
288
|
+
|
|
289
|
+
### Steps
|
|
290
|
+
|
|
291
|
+
1. Update version numbers above
|
|
292
|
+
2. Commit and push to `main`
|
|
293
|
+
3. Create a GitHub release with a matching tag (e.g. `v1.0.0`)
|
|
294
|
+
4. CI builds and publishes to npm automatically
|
|
295
|
+
|
|
296
|
+
### Manual publish (if needed)
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
npm run build
|
|
300
|
+
npm publish --access public
|
|
301
|
+
```
|
|
302
|
+
|
|
201
303
|
## License
|
|
202
304
|
|
|
203
305
|
MIT License - see [LICENSE](LICENSE) file for details.
|
|
@@ -205,6 +307,6 @@ MIT License - see [LICENSE](LICENSE) file for details.
|
|
|
205
307
|
## Links
|
|
206
308
|
|
|
207
309
|
- 🌐 [Tether Website](https://tether.name)
|
|
208
|
-
- 📘 [Documentation](https://tether.name
|
|
209
|
-
- 🐛 [Issues](https://github.com/
|
|
310
|
+
- 📘 [Documentation](https://docs.tether.name)
|
|
311
|
+
- 🐛 [Issues](https://github.com/tether-name/tether-name-node/issues)
|
|
210
312
|
- 📦 [npm Package](https://www.npmjs.com/package/tether-name)
|
package/dist/index.d.mts
CHANGED
|
@@ -14,6 +14,8 @@ interface TetherClientConfig {
|
|
|
14
14
|
privateKeyBuffer?: Buffer;
|
|
15
15
|
/** Base URL for the Tether API (defaults to https://api.tether.name) */
|
|
16
16
|
baseUrl?: string;
|
|
17
|
+
/** API key for management operations (alternative to credential auth) */
|
|
18
|
+
apiKey?: string;
|
|
17
19
|
}
|
|
18
20
|
/**
|
|
19
21
|
* Response from the challenge request endpoint
|
|
@@ -63,6 +65,27 @@ interface VerificationResult {
|
|
|
63
65
|
* Supported private key formats
|
|
64
66
|
*/
|
|
65
67
|
type KeyFormat = 'pem' | 'der';
|
|
68
|
+
/**
|
|
69
|
+
* An agent with its associated metadata
|
|
70
|
+
*/
|
|
71
|
+
interface Agent {
|
|
72
|
+
id: string;
|
|
73
|
+
agentName: string;
|
|
74
|
+
description: string;
|
|
75
|
+
createdAt: number;
|
|
76
|
+
registrationToken?: string;
|
|
77
|
+
lastVerifiedAt?: number;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Response from the issue credential endpoint
|
|
81
|
+
*/
|
|
82
|
+
interface IssueCredentialResponse {
|
|
83
|
+
id: string;
|
|
84
|
+
agentName: string;
|
|
85
|
+
description: string;
|
|
86
|
+
createdAt: number;
|
|
87
|
+
registrationToken: string;
|
|
88
|
+
}
|
|
66
89
|
|
|
67
90
|
/**
|
|
68
91
|
* TetherClient - Official SDK for tether.name agent identity verification
|
|
@@ -71,7 +94,20 @@ declare class TetherClient {
|
|
|
71
94
|
private readonly credentialId;
|
|
72
95
|
private readonly privateKey;
|
|
73
96
|
private readonly baseUrl;
|
|
97
|
+
private readonly apiKey?;
|
|
74
98
|
constructor(config: TetherClientConfig);
|
|
99
|
+
/**
|
|
100
|
+
* Returns authorization headers when an API key is configured
|
|
101
|
+
*/
|
|
102
|
+
private _authHeaders;
|
|
103
|
+
/**
|
|
104
|
+
* Ensures a private key is available, throwing if not
|
|
105
|
+
*/
|
|
106
|
+
private _requirePrivateKey;
|
|
107
|
+
/**
|
|
108
|
+
* Ensures a credential ID is available, throwing if not
|
|
109
|
+
*/
|
|
110
|
+
private _requireCredentialId;
|
|
75
111
|
/**
|
|
76
112
|
* Request a challenge from the Tether API
|
|
77
113
|
*/
|
|
@@ -88,6 +124,18 @@ declare class TetherClient {
|
|
|
88
124
|
* Perform complete verification in one call
|
|
89
125
|
*/
|
|
90
126
|
verify(): Promise<VerificationResult>;
|
|
127
|
+
/**
|
|
128
|
+
* Create a new agent
|
|
129
|
+
*/
|
|
130
|
+
createAgent(agentName: string, description?: string): Promise<Agent>;
|
|
131
|
+
/**
|
|
132
|
+
* List all agents
|
|
133
|
+
*/
|
|
134
|
+
listAgents(): Promise<Agent[]>;
|
|
135
|
+
/**
|
|
136
|
+
* Delete an agent by ID
|
|
137
|
+
*/
|
|
138
|
+
deleteAgent(agentId: string): Promise<boolean>;
|
|
91
139
|
}
|
|
92
140
|
|
|
93
141
|
/**
|
|
@@ -130,4 +178,4 @@ declare function signChallenge(privateKey: KeyObject, challenge: string): string
|
|
|
130
178
|
*/
|
|
131
179
|
declare function detectKeyFormat(keyPath: string): KeyFormat;
|
|
132
180
|
|
|
133
|
-
export { type ChallengeResponse, type KeyFormat, TetherAPIError, TetherClient, type TetherClientConfig, TetherError, TetherVerificationError, type VerificationRequest, type VerificationResponse, type VerificationResult, detectKeyFormat, loadPrivateKey, signChallenge };
|
|
181
|
+
export { type Agent, type ChallengeResponse, type IssueCredentialResponse, type KeyFormat, TetherAPIError, TetherClient, type TetherClientConfig, TetherError, TetherVerificationError, type VerificationRequest, type VerificationResponse, type VerificationResult, detectKeyFormat, loadPrivateKey, signChallenge };
|
package/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ interface TetherClientConfig {
|
|
|
14
14
|
privateKeyBuffer?: Buffer;
|
|
15
15
|
/** Base URL for the Tether API (defaults to https://api.tether.name) */
|
|
16
16
|
baseUrl?: string;
|
|
17
|
+
/** API key for management operations (alternative to credential auth) */
|
|
18
|
+
apiKey?: string;
|
|
17
19
|
}
|
|
18
20
|
/**
|
|
19
21
|
* Response from the challenge request endpoint
|
|
@@ -63,6 +65,27 @@ interface VerificationResult {
|
|
|
63
65
|
* Supported private key formats
|
|
64
66
|
*/
|
|
65
67
|
type KeyFormat = 'pem' | 'der';
|
|
68
|
+
/**
|
|
69
|
+
* An agent with its associated metadata
|
|
70
|
+
*/
|
|
71
|
+
interface Agent {
|
|
72
|
+
id: string;
|
|
73
|
+
agentName: string;
|
|
74
|
+
description: string;
|
|
75
|
+
createdAt: number;
|
|
76
|
+
registrationToken?: string;
|
|
77
|
+
lastVerifiedAt?: number;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Response from the issue credential endpoint
|
|
81
|
+
*/
|
|
82
|
+
interface IssueCredentialResponse {
|
|
83
|
+
id: string;
|
|
84
|
+
agentName: string;
|
|
85
|
+
description: string;
|
|
86
|
+
createdAt: number;
|
|
87
|
+
registrationToken: string;
|
|
88
|
+
}
|
|
66
89
|
|
|
67
90
|
/**
|
|
68
91
|
* TetherClient - Official SDK for tether.name agent identity verification
|
|
@@ -71,7 +94,20 @@ declare class TetherClient {
|
|
|
71
94
|
private readonly credentialId;
|
|
72
95
|
private readonly privateKey;
|
|
73
96
|
private readonly baseUrl;
|
|
97
|
+
private readonly apiKey?;
|
|
74
98
|
constructor(config: TetherClientConfig);
|
|
99
|
+
/**
|
|
100
|
+
* Returns authorization headers when an API key is configured
|
|
101
|
+
*/
|
|
102
|
+
private _authHeaders;
|
|
103
|
+
/**
|
|
104
|
+
* Ensures a private key is available, throwing if not
|
|
105
|
+
*/
|
|
106
|
+
private _requirePrivateKey;
|
|
107
|
+
/**
|
|
108
|
+
* Ensures a credential ID is available, throwing if not
|
|
109
|
+
*/
|
|
110
|
+
private _requireCredentialId;
|
|
75
111
|
/**
|
|
76
112
|
* Request a challenge from the Tether API
|
|
77
113
|
*/
|
|
@@ -88,6 +124,18 @@ declare class TetherClient {
|
|
|
88
124
|
* Perform complete verification in one call
|
|
89
125
|
*/
|
|
90
126
|
verify(): Promise<VerificationResult>;
|
|
127
|
+
/**
|
|
128
|
+
* Create a new agent
|
|
129
|
+
*/
|
|
130
|
+
createAgent(agentName: string, description?: string): Promise<Agent>;
|
|
131
|
+
/**
|
|
132
|
+
* List all agents
|
|
133
|
+
*/
|
|
134
|
+
listAgents(): Promise<Agent[]>;
|
|
135
|
+
/**
|
|
136
|
+
* Delete an agent by ID
|
|
137
|
+
*/
|
|
138
|
+
deleteAgent(agentId: string): Promise<boolean>;
|
|
91
139
|
}
|
|
92
140
|
|
|
93
141
|
/**
|
|
@@ -130,4 +178,4 @@ declare function signChallenge(privateKey: KeyObject, challenge: string): string
|
|
|
130
178
|
*/
|
|
131
179
|
declare function detectKeyFormat(keyPath: string): KeyFormat;
|
|
132
180
|
|
|
133
|
-
export { type ChallengeResponse, type KeyFormat, TetherAPIError, TetherClient, type TetherClientConfig, TetherError, TetherVerificationError, type VerificationRequest, type VerificationResponse, type VerificationResult, detectKeyFormat, loadPrivateKey, signChallenge };
|
|
181
|
+
export { type Agent, type ChallengeResponse, type IssueCredentialResponse, type KeyFormat, TetherAPIError, TetherClient, type TetherClientConfig, TetherError, TetherVerificationError, type VerificationRequest, type VerificationResponse, type VerificationResult, detectKeyFormat, loadPrivateKey, signChallenge };
|
package/dist/index.js
CHANGED
|
@@ -131,18 +131,57 @@ var TetherClient = class {
|
|
|
131
131
|
credentialId;
|
|
132
132
|
privateKey;
|
|
133
133
|
baseUrl;
|
|
134
|
+
apiKey;
|
|
134
135
|
constructor(config) {
|
|
136
|
+
this.baseUrl = config.baseUrl || "https://api.tether.name";
|
|
137
|
+
this.apiKey = config.apiKey || process.env.TETHER_API_KEY;
|
|
135
138
|
this.credentialId = config.credentialId || process.env.TETHER_CREDENTIAL_ID || "";
|
|
139
|
+
const keyPath = config.privateKeyPath || process.env.TETHER_PRIVATE_KEY_PATH;
|
|
140
|
+
const hasKeyMaterial = keyPath || config.privateKeyPem || config.privateKeyBuffer;
|
|
141
|
+
if (hasKeyMaterial) {
|
|
142
|
+
this.privateKey = loadPrivateKey({
|
|
143
|
+
keyPath,
|
|
144
|
+
keyPem: config.privateKeyPem,
|
|
145
|
+
keyBuffer: config.privateKeyBuffer
|
|
146
|
+
});
|
|
147
|
+
} else {
|
|
148
|
+
this.privateKey = null;
|
|
149
|
+
}
|
|
150
|
+
if (!this.apiKey && !this.privateKey) {
|
|
151
|
+
}
|
|
152
|
+
if (!this.apiKey && !this.credentialId) {
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Returns authorization headers when an API key is configured
|
|
157
|
+
*/
|
|
158
|
+
_authHeaders() {
|
|
159
|
+
if (this.apiKey) {
|
|
160
|
+
return { "Authorization": `Bearer ${this.apiKey}` };
|
|
161
|
+
}
|
|
162
|
+
return {};
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Ensures a private key is available, throwing if not
|
|
166
|
+
*/
|
|
167
|
+
_requirePrivateKey() {
|
|
168
|
+
if (!this.privateKey) {
|
|
169
|
+
throw new TetherError(
|
|
170
|
+
"Private key is required for this operation. Provide privateKeyPath, privateKeyPem, or privateKeyBuffer in config, or set TETHER_PRIVATE_KEY_PATH environment variable."
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
return this.privateKey;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Ensures a credential ID is available, throwing if not
|
|
177
|
+
*/
|
|
178
|
+
_requireCredentialId() {
|
|
136
179
|
if (!this.credentialId) {
|
|
137
|
-
throw new TetherError(
|
|
180
|
+
throw new TetherError(
|
|
181
|
+
"Credential ID is required for this operation. Provide it in config or set TETHER_CREDENTIAL_ID environment variable."
|
|
182
|
+
);
|
|
138
183
|
}
|
|
139
|
-
|
|
140
|
-
this.privateKey = loadPrivateKey({
|
|
141
|
-
keyPath,
|
|
142
|
-
keyPem: config.privateKeyPem,
|
|
143
|
-
keyBuffer: config.privateKeyBuffer
|
|
144
|
-
});
|
|
145
|
-
this.baseUrl = config.baseUrl || "https://api.tether.name";
|
|
184
|
+
return this.credentialId;
|
|
146
185
|
}
|
|
147
186
|
/**
|
|
148
187
|
* Request a challenge from the Tether API
|
|
@@ -184,17 +223,19 @@ var TetherClient = class {
|
|
|
184
223
|
* Sign a challenge string
|
|
185
224
|
*/
|
|
186
225
|
sign(challenge) {
|
|
187
|
-
|
|
226
|
+
const key = this._requirePrivateKey();
|
|
227
|
+
return signChallenge(key, challenge);
|
|
188
228
|
}
|
|
189
229
|
/**
|
|
190
230
|
* Submit proof for a challenge
|
|
191
231
|
*/
|
|
192
232
|
async submitProof(challenge, proof) {
|
|
233
|
+
const credentialId = this._requireCredentialId();
|
|
193
234
|
try {
|
|
194
235
|
const payload = {
|
|
195
236
|
challenge,
|
|
196
237
|
proof,
|
|
197
|
-
credentialId
|
|
238
|
+
credentialId
|
|
198
239
|
};
|
|
199
240
|
const response = await fetch(`${this.baseUrl}/challenge/verify`, {
|
|
200
241
|
method: "POST",
|
|
@@ -257,6 +298,106 @@ var TetherClient = class {
|
|
|
257
298
|
);
|
|
258
299
|
}
|
|
259
300
|
}
|
|
301
|
+
/**
|
|
302
|
+
* Create a new agent
|
|
303
|
+
*/
|
|
304
|
+
async createAgent(agentName, description = "") {
|
|
305
|
+
try {
|
|
306
|
+
const response = await fetch(`${this.baseUrl}/credentials/issue`, {
|
|
307
|
+
method: "POST",
|
|
308
|
+
headers: {
|
|
309
|
+
"Content-Type": "application/json",
|
|
310
|
+
...this._authHeaders()
|
|
311
|
+
},
|
|
312
|
+
body: JSON.stringify({ agentName, description })
|
|
313
|
+
});
|
|
314
|
+
if (!response.ok) {
|
|
315
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
316
|
+
throw new TetherAPIError(
|
|
317
|
+
`Create agent failed: ${response.status} ${response.statusText}`,
|
|
318
|
+
response.status,
|
|
319
|
+
errorText
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
const data = await response.json();
|
|
323
|
+
return data;
|
|
324
|
+
} catch (error) {
|
|
325
|
+
if (error instanceof TetherError) {
|
|
326
|
+
throw error;
|
|
327
|
+
}
|
|
328
|
+
throw new TetherAPIError(
|
|
329
|
+
`Failed to create agent: ${error instanceof Error ? error.message : String(error)}`,
|
|
330
|
+
void 0,
|
|
331
|
+
void 0,
|
|
332
|
+
error instanceof Error ? error : void 0
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* List all agents
|
|
338
|
+
*/
|
|
339
|
+
async listAgents() {
|
|
340
|
+
try {
|
|
341
|
+
const response = await fetch(`${this.baseUrl}/credentials`, {
|
|
342
|
+
method: "GET",
|
|
343
|
+
headers: {
|
|
344
|
+
...this._authHeaders()
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
if (!response.ok) {
|
|
348
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
349
|
+
throw new TetherAPIError(
|
|
350
|
+
`List agents failed: ${response.status} ${response.statusText}`,
|
|
351
|
+
response.status,
|
|
352
|
+
errorText
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
const data = await response.json();
|
|
356
|
+
return data;
|
|
357
|
+
} catch (error) {
|
|
358
|
+
if (error instanceof TetherError) {
|
|
359
|
+
throw error;
|
|
360
|
+
}
|
|
361
|
+
throw new TetherAPIError(
|
|
362
|
+
`Failed to list agents: ${error instanceof Error ? error.message : String(error)}`,
|
|
363
|
+
void 0,
|
|
364
|
+
void 0,
|
|
365
|
+
error instanceof Error ? error : void 0
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Delete an agent by ID
|
|
371
|
+
*/
|
|
372
|
+
async deleteAgent(agentId) {
|
|
373
|
+
try {
|
|
374
|
+
const response = await fetch(`${this.baseUrl}/credentials/${agentId}`, {
|
|
375
|
+
method: "DELETE",
|
|
376
|
+
headers: {
|
|
377
|
+
...this._authHeaders()
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
if (!response.ok) {
|
|
381
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
382
|
+
throw new TetherAPIError(
|
|
383
|
+
`Delete agent failed: ${response.status} ${response.statusText}`,
|
|
384
|
+
response.status,
|
|
385
|
+
errorText
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
return true;
|
|
389
|
+
} catch (error) {
|
|
390
|
+
if (error instanceof TetherError) {
|
|
391
|
+
throw error;
|
|
392
|
+
}
|
|
393
|
+
throw new TetherAPIError(
|
|
394
|
+
`Failed to delete agent: ${error instanceof Error ? error.message : String(error)}`,
|
|
395
|
+
void 0,
|
|
396
|
+
void 0,
|
|
397
|
+
error instanceof Error ? error : void 0
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
260
401
|
};
|
|
261
402
|
// Annotate the CommonJS export names for ESM import in node:
|
|
262
403
|
0 && (module.exports = {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/crypto.ts","../src/client.ts"],"sourcesContent":["/**\n * Tether Name SDK - Official Node.js library for tether.name agent identity verification\n * \n * @example\n * ```typescript\n * import { TetherClient } from 'tether-name';\n * \n * const client = new TetherClient({\n * credentialId: 'your-credential-id',\n * privateKeyPath: '/path/to/key.der'\n * });\n * \n * const result = await client.verify();\n * console.log(result.verified, result.agentName);\n * ```\n */\n\n// Main exports\nexport { TetherClient } from './client.js';\n\n// Types\nexport type {\n TetherClientConfig,\n ChallengeResponse,\n VerificationRequest,\n VerificationResponse,\n VerificationResult,\n KeyFormat\n} from './types.js';\n\n// Errors\nexport {\n TetherError,\n TetherAPIError,\n TetherVerificationError\n} from './errors.js';\n\n// Crypto utilities (for advanced use cases)\nexport {\n loadPrivateKey,\n signChallenge,\n detectKeyFormat\n} from './crypto.js';","/**\n * Base error class for all Tether-related errors\n */\nexport class TetherError extends Error {\n constructor(message: string, public readonly cause?: Error) {\n super(message);\n this.name = 'TetherError';\n \n // Maintain proper stack trace for where our error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, TetherError);\n }\n }\n}\n\n/**\n * Error thrown when verification fails\n */\nexport class TetherVerificationError extends TetherError {\n constructor(message: string, cause?: Error) {\n super(message, cause);\n this.name = 'TetherVerificationError';\n }\n}\n\n/**\n * Error thrown when API requests fail\n */\nexport class TetherAPIError extends TetherError {\n constructor(\n message: string,\n public readonly status?: number,\n public readonly response?: string,\n cause?: Error\n ) {\n super(message, cause);\n this.name = 'TetherAPIError';\n }\n}","import { createSign, createPrivateKey, KeyObject } from 'crypto';\nimport { readFileSync } from 'fs';\nimport { TetherError } from './errors.js';\nimport type { KeyFormat } from './types.js';\n\n/**\n * Loads a private key from various sources\n */\nexport function loadPrivateKey(options: {\n keyPath?: string;\n keyPem?: string;\n keyBuffer?: Buffer;\n}): KeyObject {\n const { keyPath, keyPem, keyBuffer } = options;\n\n try {\n if (keyPem) {\n // PEM string provided directly\n return createPrivateKey(keyPem);\n }\n \n if (keyBuffer) {\n // DER buffer provided directly\n return createPrivateKey({\n key: keyBuffer,\n format: 'der',\n type: 'pkcs1'\n });\n }\n \n if (keyPath) {\n // Read from file - detect format by extension or content\n const keyData = readFileSync(keyPath);\n \n // Try to detect format\n if (keyPath.endsWith('.pem') || keyData.toString().includes('-----BEGIN')) {\n // PEM format\n return createPrivateKey(keyData);\n } else {\n // Assume DER format\n return createPrivateKey({\n key: keyData,\n format: 'der',\n type: 'pkcs1'\n });\n }\n }\n \n throw new TetherError('No private key provided');\n } catch (error) {\n if (error instanceof TetherError) {\n throw error;\n }\n throw new TetherError(\n `Failed to load private key: ${error instanceof Error ? error.message : String(error)}`,\n error instanceof Error ? error : undefined\n );\n }\n}\n\n/**\n * Signs a challenge string using RSA-SHA256\n * Returns URL-safe base64 encoded signature (no padding)\n */\nexport function signChallenge(privateKey: KeyObject, challenge: string): string {\n try {\n const sign = createSign('SHA256');\n sign.update(challenge);\n sign.end();\n \n const signature = sign.sign(privateKey);\n \n // Convert to URL-safe base64 without padding\n return signature\n .toString('base64')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '');\n } catch (error) {\n throw new TetherError(\n `Failed to sign challenge: ${error instanceof Error ? error.message : String(error)}`,\n error instanceof Error ? error : undefined\n );\n }\n}\n\n/**\n * Utility function to detect key format from file extension or content\n */\nexport function detectKeyFormat(keyPath: string): KeyFormat {\n if (keyPath.endsWith('.pem')) {\n return 'pem';\n }\n if (keyPath.endsWith('.der')) {\n return 'der';\n }\n \n // Try to read a small portion to detect format\n try {\n const keyData = readFileSync(keyPath, { encoding: 'utf8', flag: 'r' });\n if (keyData.includes('-----BEGIN')) {\n return 'pem';\n }\n } catch {\n // If we can't read as text, it's probably DER\n }\n \n return 'der';\n}","import { KeyObject } from 'crypto';\nimport { TetherError, TetherAPIError, TetherVerificationError } from './errors.js';\nimport { loadPrivateKey, signChallenge } from './crypto.js';\nimport type {\n TetherClientConfig,\n ChallengeResponse,\n VerificationRequest,\n VerificationResponse,\n VerificationResult\n} from './types.js';\n\n/**\n * TetherClient - Official SDK for tether.name agent identity verification\n */\nexport class TetherClient {\n private readonly credentialId: string;\n private readonly privateKey: KeyObject;\n private readonly baseUrl: string;\n\n constructor(config: TetherClientConfig) {\n // Get credential ID from config or environment\n this.credentialId = config.credentialId || process.env.TETHER_CREDENTIAL_ID || '';\n if (!this.credentialId) {\n throw new TetherError('Credential ID is required. Provide it in config or set TETHER_CREDENTIAL_ID environment variable.');\n }\n\n // Load private key\n const keyPath = config.privateKeyPath || process.env.TETHER_PRIVATE_KEY_PATH;\n this.privateKey = loadPrivateKey({\n keyPath,\n keyPem: config.privateKeyPem,\n keyBuffer: config.privateKeyBuffer\n });\n\n // Set base URL\n this.baseUrl = config.baseUrl || 'https://api.tether.name';\n }\n\n /**\n * Request a challenge from the Tether API\n */\n async requestChallenge(): Promise<string> {\n try {\n const response = await fetch(`${this.baseUrl}/challenge`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n }\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new TetherAPIError(\n `Challenge request failed: ${response.status} ${response.statusText}`,\n response.status,\n errorText\n );\n }\n\n const data = await response.json() as ChallengeResponse;\n \n if (!data.code) {\n throw new TetherAPIError('Invalid challenge response: missing code');\n }\n\n return data.code;\n } catch (error) {\n if (error instanceof TetherError) {\n throw error;\n }\n throw new TetherAPIError(\n `Failed to request challenge: ${error instanceof Error ? error.message : String(error)}`,\n undefined,\n undefined,\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Sign a challenge string\n */\n sign(challenge: string): string {\n return signChallenge(this.privateKey, challenge);\n }\n\n /**\n * Submit proof for a challenge\n */\n async submitProof(challenge: string, proof: string): Promise<VerificationResult> {\n try {\n const payload: VerificationRequest = {\n challenge,\n proof,\n credentialId: this.credentialId\n };\n\n const response = await fetch(`${this.baseUrl}/challenge/verify`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(payload)\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new TetherAPIError(\n `Verification failed: ${response.status} ${response.statusText}`,\n response.status,\n errorText\n );\n }\n\n const data = await response.json() as VerificationResponse;\n\n // Convert API response to our result format\n return {\n verified: data.valid,\n agentName: data.agentName,\n verifyUrl: data.verifyUrl,\n email: data.email,\n registeredSince: data.registeredSince,\n error: data.error,\n challenge\n };\n } catch (error) {\n if (error instanceof TetherError) {\n throw error;\n }\n throw new TetherAPIError(\n `Failed to submit proof: ${error instanceof Error ? error.message : String(error)}`,\n undefined,\n undefined,\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Perform complete verification in one call\n */\n async verify(): Promise<VerificationResult> {\n try {\n const challenge = await this.requestChallenge();\n const proof = this.sign(challenge);\n const result = await this.submitProof(challenge, proof);\n\n if (!result.verified) {\n throw new TetherVerificationError(\n result.error || 'Verification failed for unknown reason'\n );\n }\n\n return result;\n } catch (error) {\n if (error instanceof TetherError) {\n throw error;\n }\n throw new TetherVerificationError(\n `Verification failed: ${error instanceof Error ? error.message : String(error)}`,\n error instanceof Error ? error : undefined\n );\n }\n }\n}"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/crypto.ts","../src/client.ts"],"sourcesContent":["/**\n * Tether Name SDK - Official Node.js library for tether.name agent identity verification\n * \n * @example\n * ```typescript\n * import { TetherClient } from 'tether-name';\n * \n * const client = new TetherClient({\n * credentialId: 'your-credential-id',\n * privateKeyPath: '/path/to/key.der'\n * });\n * \n * const result = await client.verify();\n * console.log(result.verified, result.agentName);\n * ```\n */\n\n// Main exports\nexport { TetherClient } from './client.js';\n\n// Types\nexport type {\n TetherClientConfig,\n ChallengeResponse,\n Agent,\n IssueCredentialResponse,\n VerificationRequest,\n VerificationResponse,\n VerificationResult,\n KeyFormat\n} from './types.js';\n\n// Errors\nexport {\n TetherError,\n TetherAPIError,\n TetherVerificationError\n} from './errors.js';\n\n// Crypto utilities (for advanced use cases)\nexport {\n loadPrivateKey,\n signChallenge,\n detectKeyFormat\n} from './crypto.js';","/**\n * Base error class for all Tether-related errors\n */\nexport class TetherError extends Error {\n constructor(message: string, public readonly cause?: Error) {\n super(message);\n this.name = 'TetherError';\n \n // Maintain proper stack trace for where our error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, TetherError);\n }\n }\n}\n\n/**\n * Error thrown when verification fails\n */\nexport class TetherVerificationError extends TetherError {\n constructor(message: string, cause?: Error) {\n super(message, cause);\n this.name = 'TetherVerificationError';\n }\n}\n\n/**\n * Error thrown when API requests fail\n */\nexport class TetherAPIError extends TetherError {\n constructor(\n message: string,\n public readonly status?: number,\n public readonly response?: string,\n cause?: Error\n ) {\n super(message, cause);\n this.name = 'TetherAPIError';\n }\n}","import { createSign, createPrivateKey, KeyObject } from 'crypto';\nimport { readFileSync } from 'fs';\nimport { TetherError } from './errors.js';\nimport type { KeyFormat } from './types.js';\n\n/**\n * Loads a private key from various sources\n */\nexport function loadPrivateKey(options: {\n keyPath?: string;\n keyPem?: string;\n keyBuffer?: Buffer;\n}): KeyObject {\n const { keyPath, keyPem, keyBuffer } = options;\n\n try {\n if (keyPem) {\n // PEM string provided directly\n return createPrivateKey(keyPem);\n }\n \n if (keyBuffer) {\n // DER buffer provided directly\n return createPrivateKey({\n key: keyBuffer,\n format: 'der',\n type: 'pkcs1'\n });\n }\n \n if (keyPath) {\n // Read from file - detect format by extension or content\n const keyData = readFileSync(keyPath);\n \n // Try to detect format\n if (keyPath.endsWith('.pem') || keyData.toString().includes('-----BEGIN')) {\n // PEM format\n return createPrivateKey(keyData);\n } else {\n // Assume DER format\n return createPrivateKey({\n key: keyData,\n format: 'der',\n type: 'pkcs1'\n });\n }\n }\n \n throw new TetherError('No private key provided');\n } catch (error) {\n if (error instanceof TetherError) {\n throw error;\n }\n throw new TetherError(\n `Failed to load private key: ${error instanceof Error ? error.message : String(error)}`,\n error instanceof Error ? error : undefined\n );\n }\n}\n\n/**\n * Signs a challenge string using RSA-SHA256\n * Returns URL-safe base64 encoded signature (no padding)\n */\nexport function signChallenge(privateKey: KeyObject, challenge: string): string {\n try {\n const sign = createSign('SHA256');\n sign.update(challenge);\n sign.end();\n \n const signature = sign.sign(privateKey);\n \n // Convert to URL-safe base64 without padding\n return signature\n .toString('base64')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '');\n } catch (error) {\n throw new TetherError(\n `Failed to sign challenge: ${error instanceof Error ? error.message : String(error)}`,\n error instanceof Error ? error : undefined\n );\n }\n}\n\n/**\n * Utility function to detect key format from file extension or content\n */\nexport function detectKeyFormat(keyPath: string): KeyFormat {\n if (keyPath.endsWith('.pem')) {\n return 'pem';\n }\n if (keyPath.endsWith('.der')) {\n return 'der';\n }\n \n // Try to read a small portion to detect format\n try {\n const keyData = readFileSync(keyPath, { encoding: 'utf8', flag: 'r' });\n if (keyData.includes('-----BEGIN')) {\n return 'pem';\n }\n } catch {\n // If we can't read as text, it's probably DER\n }\n \n return 'der';\n}","import { KeyObject } from 'crypto';\nimport { TetherError, TetherAPIError, TetherVerificationError } from './errors.js';\nimport { loadPrivateKey, signChallenge } from './crypto.js';\nimport type {\n TetherClientConfig,\n ChallengeResponse,\n Agent,\n IssueCredentialResponse,\n VerificationRequest,\n VerificationResponse,\n VerificationResult\n} from './types.js';\n\n/**\n * TetherClient - Official SDK for tether.name agent identity verification\n */\nexport class TetherClient {\n private readonly credentialId: string;\n private readonly privateKey: KeyObject | null;\n private readonly baseUrl: string;\n private readonly apiKey?: string;\n\n constructor(config: TetherClientConfig) {\n // Set base URL\n this.baseUrl = config.baseUrl || 'https://api.tether.name';\n\n // Get API key from config or environment\n this.apiKey = config.apiKey || process.env.TETHER_API_KEY;\n\n // Get credential ID from config or environment\n this.credentialId = config.credentialId || process.env.TETHER_CREDENTIAL_ID || '';\n\n // Load private key if key material is provided\n const keyPath = config.privateKeyPath || process.env.TETHER_PRIVATE_KEY_PATH;\n const hasKeyMaterial = keyPath || config.privateKeyPem || config.privateKeyBuffer;\n\n if (hasKeyMaterial) {\n this.privateKey = loadPrivateKey({\n keyPath,\n keyPem: config.privateKeyPem,\n keyBuffer: config.privateKeyBuffer\n });\n } else {\n this.privateKey = null;\n }\n\n // If no API key and no private key, credential ID and key are still needed for verify/sign\n // but we defer the error to when those methods are called\n if (!this.apiKey && !this.privateKey) {\n // Allow construction — errors thrown at method call time\n }\n\n if (!this.apiKey && !this.credentialId) {\n // Allow construction — errors thrown at method call time\n }\n }\n\n /**\n * Returns authorization headers when an API key is configured\n */\n private _authHeaders(): Record<string, string> {\n if (this.apiKey) {\n return { 'Authorization': `Bearer ${this.apiKey}` };\n }\n return {};\n }\n\n /**\n * Ensures a private key is available, throwing if not\n */\n private _requirePrivateKey(): KeyObject {\n if (!this.privateKey) {\n throw new TetherError(\n 'Private key is required for this operation. Provide privateKeyPath, privateKeyPem, or privateKeyBuffer in config, or set TETHER_PRIVATE_KEY_PATH environment variable.'\n );\n }\n return this.privateKey;\n }\n\n /**\n * Ensures a credential ID is available, throwing if not\n */\n private _requireCredentialId(): string {\n if (!this.credentialId) {\n throw new TetherError(\n 'Credential ID is required for this operation. Provide it in config or set TETHER_CREDENTIAL_ID environment variable.'\n );\n }\n return this.credentialId;\n }\n\n /**\n * Request a challenge from the Tether API\n */\n async requestChallenge(): Promise<string> {\n try {\n const response = await fetch(`${this.baseUrl}/challenge`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n }\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new TetherAPIError(\n `Challenge request failed: ${response.status} ${response.statusText}`,\n response.status,\n errorText\n );\n }\n\n const data = await response.json() as ChallengeResponse;\n\n if (!data.code) {\n throw new TetherAPIError('Invalid challenge response: missing code');\n }\n\n return data.code;\n } catch (error) {\n if (error instanceof TetherError) {\n throw error;\n }\n throw new TetherAPIError(\n `Failed to request challenge: ${error instanceof Error ? error.message : String(error)}`,\n undefined,\n undefined,\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Sign a challenge string\n */\n sign(challenge: string): string {\n const key = this._requirePrivateKey();\n return signChallenge(key, challenge);\n }\n\n /**\n * Submit proof for a challenge\n */\n async submitProof(challenge: string, proof: string): Promise<VerificationResult> {\n const credentialId = this._requireCredentialId();\n\n try {\n const payload: VerificationRequest = {\n challenge,\n proof,\n credentialId\n };\n\n const response = await fetch(`${this.baseUrl}/challenge/verify`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(payload)\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new TetherAPIError(\n `Verification failed: ${response.status} ${response.statusText}`,\n response.status,\n errorText\n );\n }\n\n const data = await response.json() as VerificationResponse;\n\n // Convert API response to our result format\n return {\n verified: data.valid,\n agentName: data.agentName,\n verifyUrl: data.verifyUrl,\n email: data.email,\n registeredSince: data.registeredSince,\n error: data.error,\n challenge\n };\n } catch (error) {\n if (error instanceof TetherError) {\n throw error;\n }\n throw new TetherAPIError(\n `Failed to submit proof: ${error instanceof Error ? error.message : String(error)}`,\n undefined,\n undefined,\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Perform complete verification in one call\n */\n async verify(): Promise<VerificationResult> {\n try {\n const challenge = await this.requestChallenge();\n const proof = this.sign(challenge);\n const result = await this.submitProof(challenge, proof);\n\n if (!result.verified) {\n throw new TetherVerificationError(\n result.error || 'Verification failed for unknown reason'\n );\n }\n\n return result;\n } catch (error) {\n if (error instanceof TetherError) {\n throw error;\n }\n throw new TetherVerificationError(\n `Verification failed: ${error instanceof Error ? error.message : String(error)}`,\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Create a new agent\n */\n async createAgent(agentName: string, description: string = ''): Promise<Agent> {\n try {\n const response = await fetch(`${this.baseUrl}/credentials/issue`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...this._authHeaders()\n },\n body: JSON.stringify({ agentName, description })\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new TetherAPIError(\n `Create agent failed: ${response.status} ${response.statusText}`,\n response.status,\n errorText\n );\n }\n\n const data = await response.json() as IssueCredentialResponse;\n return data;\n } catch (error) {\n if (error instanceof TetherError) {\n throw error;\n }\n throw new TetherAPIError(\n `Failed to create agent: ${error instanceof Error ? error.message : String(error)}`,\n undefined,\n undefined,\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * List all agents\n */\n async listAgents(): Promise<Agent[]> {\n try {\n const response = await fetch(`${this.baseUrl}/credentials`, {\n method: 'GET',\n headers: {\n ...this._authHeaders()\n }\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new TetherAPIError(\n `List agents failed: ${response.status} ${response.statusText}`,\n response.status,\n errorText\n );\n }\n\n const data = await response.json() as Agent[];\n return data;\n } catch (error) {\n if (error instanceof TetherError) {\n throw error;\n }\n throw new TetherAPIError(\n `Failed to list agents: ${error instanceof Error ? error.message : String(error)}`,\n undefined,\n undefined,\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Delete an agent by ID\n */\n async deleteAgent(agentId: string): Promise<boolean> {\n try {\n const response = await fetch(`${this.baseUrl}/credentials/${agentId}`, {\n method: 'DELETE',\n headers: {\n ...this._authHeaders()\n }\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new TetherAPIError(\n `Delete agent failed: ${response.status} ${response.statusText}`,\n response.status,\n errorText\n );\n }\n\n return true;\n } catch (error) {\n if (error instanceof TetherError) {\n throw error;\n }\n throw new TetherAPIError(\n `Failed to delete agent: ${error instanceof Error ? error.message : String(error)}`,\n undefined,\n undefined,\n error instanceof Error ? error : undefined\n );\n }\n }\n}"],"mappings":"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","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -99,18 +99,57 @@ var TetherClient = class {
|
|
|
99
99
|
credentialId;
|
|
100
100
|
privateKey;
|
|
101
101
|
baseUrl;
|
|
102
|
+
apiKey;
|
|
102
103
|
constructor(config) {
|
|
104
|
+
this.baseUrl = config.baseUrl || "https://api.tether.name";
|
|
105
|
+
this.apiKey = config.apiKey || process.env.TETHER_API_KEY;
|
|
103
106
|
this.credentialId = config.credentialId || process.env.TETHER_CREDENTIAL_ID || "";
|
|
107
|
+
const keyPath = config.privateKeyPath || process.env.TETHER_PRIVATE_KEY_PATH;
|
|
108
|
+
const hasKeyMaterial = keyPath || config.privateKeyPem || config.privateKeyBuffer;
|
|
109
|
+
if (hasKeyMaterial) {
|
|
110
|
+
this.privateKey = loadPrivateKey({
|
|
111
|
+
keyPath,
|
|
112
|
+
keyPem: config.privateKeyPem,
|
|
113
|
+
keyBuffer: config.privateKeyBuffer
|
|
114
|
+
});
|
|
115
|
+
} else {
|
|
116
|
+
this.privateKey = null;
|
|
117
|
+
}
|
|
118
|
+
if (!this.apiKey && !this.privateKey) {
|
|
119
|
+
}
|
|
120
|
+
if (!this.apiKey && !this.credentialId) {
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Returns authorization headers when an API key is configured
|
|
125
|
+
*/
|
|
126
|
+
_authHeaders() {
|
|
127
|
+
if (this.apiKey) {
|
|
128
|
+
return { "Authorization": `Bearer ${this.apiKey}` };
|
|
129
|
+
}
|
|
130
|
+
return {};
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Ensures a private key is available, throwing if not
|
|
134
|
+
*/
|
|
135
|
+
_requirePrivateKey() {
|
|
136
|
+
if (!this.privateKey) {
|
|
137
|
+
throw new TetherError(
|
|
138
|
+
"Private key is required for this operation. Provide privateKeyPath, privateKeyPem, or privateKeyBuffer in config, or set TETHER_PRIVATE_KEY_PATH environment variable."
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
return this.privateKey;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Ensures a credential ID is available, throwing if not
|
|
145
|
+
*/
|
|
146
|
+
_requireCredentialId() {
|
|
104
147
|
if (!this.credentialId) {
|
|
105
|
-
throw new TetherError(
|
|
148
|
+
throw new TetherError(
|
|
149
|
+
"Credential ID is required for this operation. Provide it in config or set TETHER_CREDENTIAL_ID environment variable."
|
|
150
|
+
);
|
|
106
151
|
}
|
|
107
|
-
|
|
108
|
-
this.privateKey = loadPrivateKey({
|
|
109
|
-
keyPath,
|
|
110
|
-
keyPem: config.privateKeyPem,
|
|
111
|
-
keyBuffer: config.privateKeyBuffer
|
|
112
|
-
});
|
|
113
|
-
this.baseUrl = config.baseUrl || "https://api.tether.name";
|
|
152
|
+
return this.credentialId;
|
|
114
153
|
}
|
|
115
154
|
/**
|
|
116
155
|
* Request a challenge from the Tether API
|
|
@@ -152,17 +191,19 @@ var TetherClient = class {
|
|
|
152
191
|
* Sign a challenge string
|
|
153
192
|
*/
|
|
154
193
|
sign(challenge) {
|
|
155
|
-
|
|
194
|
+
const key = this._requirePrivateKey();
|
|
195
|
+
return signChallenge(key, challenge);
|
|
156
196
|
}
|
|
157
197
|
/**
|
|
158
198
|
* Submit proof for a challenge
|
|
159
199
|
*/
|
|
160
200
|
async submitProof(challenge, proof) {
|
|
201
|
+
const credentialId = this._requireCredentialId();
|
|
161
202
|
try {
|
|
162
203
|
const payload = {
|
|
163
204
|
challenge,
|
|
164
205
|
proof,
|
|
165
|
-
credentialId
|
|
206
|
+
credentialId
|
|
166
207
|
};
|
|
167
208
|
const response = await fetch(`${this.baseUrl}/challenge/verify`, {
|
|
168
209
|
method: "POST",
|
|
@@ -225,6 +266,106 @@ var TetherClient = class {
|
|
|
225
266
|
);
|
|
226
267
|
}
|
|
227
268
|
}
|
|
269
|
+
/**
|
|
270
|
+
* Create a new agent
|
|
271
|
+
*/
|
|
272
|
+
async createAgent(agentName, description = "") {
|
|
273
|
+
try {
|
|
274
|
+
const response = await fetch(`${this.baseUrl}/credentials/issue`, {
|
|
275
|
+
method: "POST",
|
|
276
|
+
headers: {
|
|
277
|
+
"Content-Type": "application/json",
|
|
278
|
+
...this._authHeaders()
|
|
279
|
+
},
|
|
280
|
+
body: JSON.stringify({ agentName, description })
|
|
281
|
+
});
|
|
282
|
+
if (!response.ok) {
|
|
283
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
284
|
+
throw new TetherAPIError(
|
|
285
|
+
`Create agent failed: ${response.status} ${response.statusText}`,
|
|
286
|
+
response.status,
|
|
287
|
+
errorText
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
const data = await response.json();
|
|
291
|
+
return data;
|
|
292
|
+
} catch (error) {
|
|
293
|
+
if (error instanceof TetherError) {
|
|
294
|
+
throw error;
|
|
295
|
+
}
|
|
296
|
+
throw new TetherAPIError(
|
|
297
|
+
`Failed to create agent: ${error instanceof Error ? error.message : String(error)}`,
|
|
298
|
+
void 0,
|
|
299
|
+
void 0,
|
|
300
|
+
error instanceof Error ? error : void 0
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* List all agents
|
|
306
|
+
*/
|
|
307
|
+
async listAgents() {
|
|
308
|
+
try {
|
|
309
|
+
const response = await fetch(`${this.baseUrl}/credentials`, {
|
|
310
|
+
method: "GET",
|
|
311
|
+
headers: {
|
|
312
|
+
...this._authHeaders()
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
if (!response.ok) {
|
|
316
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
317
|
+
throw new TetherAPIError(
|
|
318
|
+
`List agents failed: ${response.status} ${response.statusText}`,
|
|
319
|
+
response.status,
|
|
320
|
+
errorText
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
const data = await response.json();
|
|
324
|
+
return data;
|
|
325
|
+
} catch (error) {
|
|
326
|
+
if (error instanceof TetherError) {
|
|
327
|
+
throw error;
|
|
328
|
+
}
|
|
329
|
+
throw new TetherAPIError(
|
|
330
|
+
`Failed to list agents: ${error instanceof Error ? error.message : String(error)}`,
|
|
331
|
+
void 0,
|
|
332
|
+
void 0,
|
|
333
|
+
error instanceof Error ? error : void 0
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Delete an agent by ID
|
|
339
|
+
*/
|
|
340
|
+
async deleteAgent(agentId) {
|
|
341
|
+
try {
|
|
342
|
+
const response = await fetch(`${this.baseUrl}/credentials/${agentId}`, {
|
|
343
|
+
method: "DELETE",
|
|
344
|
+
headers: {
|
|
345
|
+
...this._authHeaders()
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
if (!response.ok) {
|
|
349
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
350
|
+
throw new TetherAPIError(
|
|
351
|
+
`Delete agent failed: ${response.status} ${response.statusText}`,
|
|
352
|
+
response.status,
|
|
353
|
+
errorText
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
return true;
|
|
357
|
+
} catch (error) {
|
|
358
|
+
if (error instanceof TetherError) {
|
|
359
|
+
throw error;
|
|
360
|
+
}
|
|
361
|
+
throw new TetherAPIError(
|
|
362
|
+
`Failed to delete agent: ${error instanceof Error ? error.message : String(error)}`,
|
|
363
|
+
void 0,
|
|
364
|
+
void 0,
|
|
365
|
+
error instanceof Error ? error : void 0
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
228
369
|
};
|
|
229
370
|
export {
|
|
230
371
|
TetherAPIError,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/crypto.ts","../src/client.ts"],"sourcesContent":["/**\n * Base error class for all Tether-related errors\n */\nexport class TetherError extends Error {\n constructor(message: string, public readonly cause?: Error) {\n super(message);\n this.name = 'TetherError';\n \n // Maintain proper stack trace for where our error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, TetherError);\n }\n }\n}\n\n/**\n * Error thrown when verification fails\n */\nexport class TetherVerificationError extends TetherError {\n constructor(message: string, cause?: Error) {\n super(message, cause);\n this.name = 'TetherVerificationError';\n }\n}\n\n/**\n * Error thrown when API requests fail\n */\nexport class TetherAPIError extends TetherError {\n constructor(\n message: string,\n public readonly status?: number,\n public readonly response?: string,\n cause?: Error\n ) {\n super(message, cause);\n this.name = 'TetherAPIError';\n }\n}","import { createSign, createPrivateKey, KeyObject } from 'crypto';\nimport { readFileSync } from 'fs';\nimport { TetherError } from './errors.js';\nimport type { KeyFormat } from './types.js';\n\n/**\n * Loads a private key from various sources\n */\nexport function loadPrivateKey(options: {\n keyPath?: string;\n keyPem?: string;\n keyBuffer?: Buffer;\n}): KeyObject {\n const { keyPath, keyPem, keyBuffer } = options;\n\n try {\n if (keyPem) {\n // PEM string provided directly\n return createPrivateKey(keyPem);\n }\n \n if (keyBuffer) {\n // DER buffer provided directly\n return createPrivateKey({\n key: keyBuffer,\n format: 'der',\n type: 'pkcs1'\n });\n }\n \n if (keyPath) {\n // Read from file - detect format by extension or content\n const keyData = readFileSync(keyPath);\n \n // Try to detect format\n if (keyPath.endsWith('.pem') || keyData.toString().includes('-----BEGIN')) {\n // PEM format\n return createPrivateKey(keyData);\n } else {\n // Assume DER format\n return createPrivateKey({\n key: keyData,\n format: 'der',\n type: 'pkcs1'\n });\n }\n }\n \n throw new TetherError('No private key provided');\n } catch (error) {\n if (error instanceof TetherError) {\n throw error;\n }\n throw new TetherError(\n `Failed to load private key: ${error instanceof Error ? error.message : String(error)}`,\n error instanceof Error ? error : undefined\n );\n }\n}\n\n/**\n * Signs a challenge string using RSA-SHA256\n * Returns URL-safe base64 encoded signature (no padding)\n */\nexport function signChallenge(privateKey: KeyObject, challenge: string): string {\n try {\n const sign = createSign('SHA256');\n sign.update(challenge);\n sign.end();\n \n const signature = sign.sign(privateKey);\n \n // Convert to URL-safe base64 without padding\n return signature\n .toString('base64')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '');\n } catch (error) {\n throw new TetherError(\n `Failed to sign challenge: ${error instanceof Error ? error.message : String(error)}`,\n error instanceof Error ? error : undefined\n );\n }\n}\n\n/**\n * Utility function to detect key format from file extension or content\n */\nexport function detectKeyFormat(keyPath: string): KeyFormat {\n if (keyPath.endsWith('.pem')) {\n return 'pem';\n }\n if (keyPath.endsWith('.der')) {\n return 'der';\n }\n \n // Try to read a small portion to detect format\n try {\n const keyData = readFileSync(keyPath, { encoding: 'utf8', flag: 'r' });\n if (keyData.includes('-----BEGIN')) {\n return 'pem';\n }\n } catch {\n // If we can't read as text, it's probably DER\n }\n \n return 'der';\n}","import { KeyObject } from 'crypto';\nimport { TetherError, TetherAPIError, TetherVerificationError } from './errors.js';\nimport { loadPrivateKey, signChallenge } from './crypto.js';\nimport type {\n TetherClientConfig,\n ChallengeResponse,\n VerificationRequest,\n VerificationResponse,\n VerificationResult\n} from './types.js';\n\n/**\n * TetherClient - Official SDK for tether.name agent identity verification\n */\nexport class TetherClient {\n private readonly credentialId: string;\n private readonly privateKey: KeyObject;\n private readonly baseUrl: string;\n\n constructor(config: TetherClientConfig) {\n // Get credential ID from config or environment\n this.credentialId = config.credentialId || process.env.TETHER_CREDENTIAL_ID || '';\n if (!this.credentialId) {\n throw new TetherError('Credential ID is required. Provide it in config or set TETHER_CREDENTIAL_ID environment variable.');\n }\n\n // Load private key\n const keyPath = config.privateKeyPath || process.env.TETHER_PRIVATE_KEY_PATH;\n this.privateKey = loadPrivateKey({\n keyPath,\n keyPem: config.privateKeyPem,\n keyBuffer: config.privateKeyBuffer\n });\n\n // Set base URL\n this.baseUrl = config.baseUrl || 'https://api.tether.name';\n }\n\n /**\n * Request a challenge from the Tether API\n */\n async requestChallenge(): Promise<string> {\n try {\n const response = await fetch(`${this.baseUrl}/challenge`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n }\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new TetherAPIError(\n `Challenge request failed: ${response.status} ${response.statusText}`,\n response.status,\n errorText\n );\n }\n\n const data = await response.json() as ChallengeResponse;\n \n if (!data.code) {\n throw new TetherAPIError('Invalid challenge response: missing code');\n }\n\n return data.code;\n } catch (error) {\n if (error instanceof TetherError) {\n throw error;\n }\n throw new TetherAPIError(\n `Failed to request challenge: ${error instanceof Error ? error.message : String(error)}`,\n undefined,\n undefined,\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Sign a challenge string\n */\n sign(challenge: string): string {\n return signChallenge(this.privateKey, challenge);\n }\n\n /**\n * Submit proof for a challenge\n */\n async submitProof(challenge: string, proof: string): Promise<VerificationResult> {\n try {\n const payload: VerificationRequest = {\n challenge,\n proof,\n credentialId: this.credentialId\n };\n\n const response = await fetch(`${this.baseUrl}/challenge/verify`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(payload)\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new TetherAPIError(\n `Verification failed: ${response.status} ${response.statusText}`,\n response.status,\n errorText\n );\n }\n\n const data = await response.json() as VerificationResponse;\n\n // Convert API response to our result format\n return {\n verified: data.valid,\n agentName: data.agentName,\n verifyUrl: data.verifyUrl,\n email: data.email,\n registeredSince: data.registeredSince,\n error: data.error,\n challenge\n };\n } catch (error) {\n if (error instanceof TetherError) {\n throw error;\n }\n throw new TetherAPIError(\n `Failed to submit proof: ${error instanceof Error ? error.message : String(error)}`,\n undefined,\n undefined,\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Perform complete verification in one call\n */\n async verify(): Promise<VerificationResult> {\n try {\n const challenge = await this.requestChallenge();\n const proof = this.sign(challenge);\n const result = await this.submitProof(challenge, proof);\n\n if (!result.verified) {\n throw new TetherVerificationError(\n result.error || 'Verification failed for unknown reason'\n );\n }\n\n return result;\n } catch (error) {\n if (error instanceof TetherError) {\n throw error;\n }\n throw new TetherVerificationError(\n `Verification failed: ${error instanceof Error ? error.message : String(error)}`,\n error instanceof Error ? error : undefined\n );\n }\n }\n}"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/crypto.ts","../src/client.ts"],"sourcesContent":["/**\n * Base error class for all Tether-related errors\n */\nexport class TetherError extends Error {\n constructor(message: string, public readonly cause?: Error) {\n super(message);\n this.name = 'TetherError';\n \n // Maintain proper stack trace for where our error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, TetherError);\n }\n }\n}\n\n/**\n * Error thrown when verification fails\n */\nexport class TetherVerificationError extends TetherError {\n constructor(message: string, cause?: Error) {\n super(message, cause);\n this.name = 'TetherVerificationError';\n }\n}\n\n/**\n * Error thrown when API requests fail\n */\nexport class TetherAPIError extends TetherError {\n constructor(\n message: string,\n public readonly status?: number,\n public readonly response?: string,\n cause?: Error\n ) {\n super(message, cause);\n this.name = 'TetherAPIError';\n }\n}","import { createSign, createPrivateKey, KeyObject } from 'crypto';\nimport { readFileSync } from 'fs';\nimport { TetherError } from './errors.js';\nimport type { KeyFormat } from './types.js';\n\n/**\n * Loads a private key from various sources\n */\nexport function loadPrivateKey(options: {\n keyPath?: string;\n keyPem?: string;\n keyBuffer?: Buffer;\n}): KeyObject {\n const { keyPath, keyPem, keyBuffer } = options;\n\n try {\n if (keyPem) {\n // PEM string provided directly\n return createPrivateKey(keyPem);\n }\n \n if (keyBuffer) {\n // DER buffer provided directly\n return createPrivateKey({\n key: keyBuffer,\n format: 'der',\n type: 'pkcs1'\n });\n }\n \n if (keyPath) {\n // Read from file - detect format by extension or content\n const keyData = readFileSync(keyPath);\n \n // Try to detect format\n if (keyPath.endsWith('.pem') || keyData.toString().includes('-----BEGIN')) {\n // PEM format\n return createPrivateKey(keyData);\n } else {\n // Assume DER format\n return createPrivateKey({\n key: keyData,\n format: 'der',\n type: 'pkcs1'\n });\n }\n }\n \n throw new TetherError('No private key provided');\n } catch (error) {\n if (error instanceof TetherError) {\n throw error;\n }\n throw new TetherError(\n `Failed to load private key: ${error instanceof Error ? error.message : String(error)}`,\n error instanceof Error ? error : undefined\n );\n }\n}\n\n/**\n * Signs a challenge string using RSA-SHA256\n * Returns URL-safe base64 encoded signature (no padding)\n */\nexport function signChallenge(privateKey: KeyObject, challenge: string): string {\n try {\n const sign = createSign('SHA256');\n sign.update(challenge);\n sign.end();\n \n const signature = sign.sign(privateKey);\n \n // Convert to URL-safe base64 without padding\n return signature\n .toString('base64')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '');\n } catch (error) {\n throw new TetherError(\n `Failed to sign challenge: ${error instanceof Error ? error.message : String(error)}`,\n error instanceof Error ? error : undefined\n );\n }\n}\n\n/**\n * Utility function to detect key format from file extension or content\n */\nexport function detectKeyFormat(keyPath: string): KeyFormat {\n if (keyPath.endsWith('.pem')) {\n return 'pem';\n }\n if (keyPath.endsWith('.der')) {\n return 'der';\n }\n \n // Try to read a small portion to detect format\n try {\n const keyData = readFileSync(keyPath, { encoding: 'utf8', flag: 'r' });\n if (keyData.includes('-----BEGIN')) {\n return 'pem';\n }\n } catch {\n // If we can't read as text, it's probably DER\n }\n \n return 'der';\n}","import { KeyObject } from 'crypto';\nimport { TetherError, TetherAPIError, TetherVerificationError } from './errors.js';\nimport { loadPrivateKey, signChallenge } from './crypto.js';\nimport type {\n TetherClientConfig,\n ChallengeResponse,\n Agent,\n IssueCredentialResponse,\n VerificationRequest,\n VerificationResponse,\n VerificationResult\n} from './types.js';\n\n/**\n * TetherClient - Official SDK for tether.name agent identity verification\n */\nexport class TetherClient {\n private readonly credentialId: string;\n private readonly privateKey: KeyObject | null;\n private readonly baseUrl: string;\n private readonly apiKey?: string;\n\n constructor(config: TetherClientConfig) {\n // Set base URL\n this.baseUrl = config.baseUrl || 'https://api.tether.name';\n\n // Get API key from config or environment\n this.apiKey = config.apiKey || process.env.TETHER_API_KEY;\n\n // Get credential ID from config or environment\n this.credentialId = config.credentialId || process.env.TETHER_CREDENTIAL_ID || '';\n\n // Load private key if key material is provided\n const keyPath = config.privateKeyPath || process.env.TETHER_PRIVATE_KEY_PATH;\n const hasKeyMaterial = keyPath || config.privateKeyPem || config.privateKeyBuffer;\n\n if (hasKeyMaterial) {\n this.privateKey = loadPrivateKey({\n keyPath,\n keyPem: config.privateKeyPem,\n keyBuffer: config.privateKeyBuffer\n });\n } else {\n this.privateKey = null;\n }\n\n // If no API key and no private key, credential ID and key are still needed for verify/sign\n // but we defer the error to when those methods are called\n if (!this.apiKey && !this.privateKey) {\n // Allow construction — errors thrown at method call time\n }\n\n if (!this.apiKey && !this.credentialId) {\n // Allow construction — errors thrown at method call time\n }\n }\n\n /**\n * Returns authorization headers when an API key is configured\n */\n private _authHeaders(): Record<string, string> {\n if (this.apiKey) {\n return { 'Authorization': `Bearer ${this.apiKey}` };\n }\n return {};\n }\n\n /**\n * Ensures a private key is available, throwing if not\n */\n private _requirePrivateKey(): KeyObject {\n if (!this.privateKey) {\n throw new TetherError(\n 'Private key is required for this operation. Provide privateKeyPath, privateKeyPem, or privateKeyBuffer in config, or set TETHER_PRIVATE_KEY_PATH environment variable.'\n );\n }\n return this.privateKey;\n }\n\n /**\n * Ensures a credential ID is available, throwing if not\n */\n private _requireCredentialId(): string {\n if (!this.credentialId) {\n throw new TetherError(\n 'Credential ID is required for this operation. Provide it in config or set TETHER_CREDENTIAL_ID environment variable.'\n );\n }\n return this.credentialId;\n }\n\n /**\n * Request a challenge from the Tether API\n */\n async requestChallenge(): Promise<string> {\n try {\n const response = await fetch(`${this.baseUrl}/challenge`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n }\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new TetherAPIError(\n `Challenge request failed: ${response.status} ${response.statusText}`,\n response.status,\n errorText\n );\n }\n\n const data = await response.json() as ChallengeResponse;\n\n if (!data.code) {\n throw new TetherAPIError('Invalid challenge response: missing code');\n }\n\n return data.code;\n } catch (error) {\n if (error instanceof TetherError) {\n throw error;\n }\n throw new TetherAPIError(\n `Failed to request challenge: ${error instanceof Error ? error.message : String(error)}`,\n undefined,\n undefined,\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Sign a challenge string\n */\n sign(challenge: string): string {\n const key = this._requirePrivateKey();\n return signChallenge(key, challenge);\n }\n\n /**\n * Submit proof for a challenge\n */\n async submitProof(challenge: string, proof: string): Promise<VerificationResult> {\n const credentialId = this._requireCredentialId();\n\n try {\n const payload: VerificationRequest = {\n challenge,\n proof,\n credentialId\n };\n\n const response = await fetch(`${this.baseUrl}/challenge/verify`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(payload)\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new TetherAPIError(\n `Verification failed: ${response.status} ${response.statusText}`,\n response.status,\n errorText\n );\n }\n\n const data = await response.json() as VerificationResponse;\n\n // Convert API response to our result format\n return {\n verified: data.valid,\n agentName: data.agentName,\n verifyUrl: data.verifyUrl,\n email: data.email,\n registeredSince: data.registeredSince,\n error: data.error,\n challenge\n };\n } catch (error) {\n if (error instanceof TetherError) {\n throw error;\n }\n throw new TetherAPIError(\n `Failed to submit proof: ${error instanceof Error ? error.message : String(error)}`,\n undefined,\n undefined,\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Perform complete verification in one call\n */\n async verify(): Promise<VerificationResult> {\n try {\n const challenge = await this.requestChallenge();\n const proof = this.sign(challenge);\n const result = await this.submitProof(challenge, proof);\n\n if (!result.verified) {\n throw new TetherVerificationError(\n result.error || 'Verification failed for unknown reason'\n );\n }\n\n return result;\n } catch (error) {\n if (error instanceof TetherError) {\n throw error;\n }\n throw new TetherVerificationError(\n `Verification failed: ${error instanceof Error ? error.message : String(error)}`,\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Create a new agent\n */\n async createAgent(agentName: string, description: string = ''): Promise<Agent> {\n try {\n const response = await fetch(`${this.baseUrl}/credentials/issue`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...this._authHeaders()\n },\n body: JSON.stringify({ agentName, description })\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new TetherAPIError(\n `Create agent failed: ${response.status} ${response.statusText}`,\n response.status,\n errorText\n );\n }\n\n const data = await response.json() as IssueCredentialResponse;\n return data;\n } catch (error) {\n if (error instanceof TetherError) {\n throw error;\n }\n throw new TetherAPIError(\n `Failed to create agent: ${error instanceof Error ? error.message : String(error)}`,\n undefined,\n undefined,\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * List all agents\n */\n async listAgents(): Promise<Agent[]> {\n try {\n const response = await fetch(`${this.baseUrl}/credentials`, {\n method: 'GET',\n headers: {\n ...this._authHeaders()\n }\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new TetherAPIError(\n `List agents failed: ${response.status} ${response.statusText}`,\n response.status,\n errorText\n );\n }\n\n const data = await response.json() as Agent[];\n return data;\n } catch (error) {\n if (error instanceof TetherError) {\n throw error;\n }\n throw new TetherAPIError(\n `Failed to list agents: ${error instanceof Error ? error.message : String(error)}`,\n undefined,\n undefined,\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Delete an agent by ID\n */\n async deleteAgent(agentId: string): Promise<boolean> {\n try {\n const response = await fetch(`${this.baseUrl}/credentials/${agentId}`, {\n method: 'DELETE',\n headers: {\n ...this._authHeaders()\n }\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new TetherAPIError(\n `Delete agent failed: ${response.status} ${response.statusText}`,\n response.status,\n errorText\n );\n }\n\n return true;\n } catch (error) {\n if (error instanceof TetherError) {\n throw error;\n }\n throw new TetherAPIError(\n `Failed to delete agent: ${error instanceof Error ? error.message : String(error)}`,\n undefined,\n undefined,\n error instanceof Error ? error : undefined\n );\n }\n }\n}"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tether-name",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Official Node.js SDK for tether.name - AI agent identity verification",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -40,12 +40,12 @@
|
|
|
40
40
|
"url": "https://github.com/tether-name/tether-name-node/issues"
|
|
41
41
|
},
|
|
42
42
|
"engines": {
|
|
43
|
-
"node": ">=
|
|
43
|
+
"node": ">=20.0.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/node": "^20.0.0",
|
|
47
47
|
"tsup": "^8.0.0",
|
|
48
48
|
"typescript": "^5.0.0",
|
|
49
|
-
"vitest": "^
|
|
49
|
+
"vitest": "^4.0.18"
|
|
50
50
|
}
|
|
51
|
-
}
|
|
51
|
+
}
|