tether-name 1.0.3 → 2.0.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 +32 -35
- package/dist/index.d.mts +16 -11
- package/dist/index.d.ts +16 -11
- package/dist/index.js +43 -24
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +43 -24
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Official Node.js SDK for [tether.name](https://tether.name) — cryptographic id
|
|
|
8
8
|
npm install tether-name
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
Requires Node.js
|
|
11
|
+
Requires Node.js 20+ (uses native `fetch` and `crypto` modules).
|
|
12
12
|
|
|
13
13
|
## Quick Start
|
|
14
14
|
|
|
@@ -16,8 +16,8 @@ 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
|
-
|
|
20
|
-
privateKeyPath: '/path/to/your/private-key.
|
|
19
|
+
agentId: 'your-agent-id',
|
|
20
|
+
privateKeyPath: '/path/to/your/private-key.pem'
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
// One-call verification
|
|
@@ -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
|
-
|
|
38
|
+
agentId: 'your-agent-id',
|
|
39
39
|
privateKeyPem: `-----BEGIN RSA PRIVATE KEY-----
|
|
40
40
|
MIIEpAIBAAKCAQEA...
|
|
41
41
|
-----END RSA PRIVATE KEY-----`
|
|
@@ -71,8 +71,8 @@ interface TetherClientConfig {
|
|
|
71
71
|
// API key (for agent management — no private key needed)
|
|
72
72
|
apiKey?: string; // Or use TETHER_API_KEY env var
|
|
73
73
|
|
|
74
|
-
//
|
|
75
|
-
|
|
74
|
+
// Agent ID (required for verify/sign, optional with apiKey)
|
|
75
|
+
agentId?: string; // Or use TETHER_AGENT_ID env var
|
|
76
76
|
|
|
77
77
|
// Private key (required for verify/sign, choose one)
|
|
78
78
|
privateKeyPath?: string; // Path to DER or PEM file
|
|
@@ -95,46 +95,46 @@ const client = new TetherClient({
|
|
|
95
95
|
const agent = await client.createAgent('my-bot');
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
-
**API key +
|
|
98
|
+
**API key + agent + private key** — full access (management and verification):
|
|
99
99
|
|
|
100
100
|
```typescript
|
|
101
101
|
const client = new TetherClient({
|
|
102
102
|
apiKey: 'sk-tether-name-...',
|
|
103
|
-
|
|
104
|
-
privateKeyPath: '/path/to/key.
|
|
103
|
+
agentId: 'your-agent-id',
|
|
104
|
+
privateKeyPath: '/path/to/key.pem'
|
|
105
105
|
});
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
-
**
|
|
108
|
+
**Agent + private key only** — verification without agent management (original behavior):
|
|
109
109
|
|
|
110
110
|
```typescript
|
|
111
111
|
const client = new TetherClient({
|
|
112
|
-
|
|
113
|
-
privateKeyPath: '/path/to/key.
|
|
112
|
+
agentId: 'your-agent-id',
|
|
113
|
+
privateKeyPath: '/path/to/key.pem'
|
|
114
114
|
});
|
|
115
115
|
```
|
|
116
116
|
|
|
117
117
|
### Key Format Support
|
|
118
118
|
|
|
119
|
-
The SDK supports both
|
|
119
|
+
The SDK supports both PEM and DER private key formats:
|
|
120
120
|
|
|
121
121
|
```typescript
|
|
122
122
|
// From file path (auto-detects format)
|
|
123
123
|
const client1 = new TetherClient({
|
|
124
|
-
|
|
125
|
-
privateKeyPath: '/path/to/key.
|
|
124
|
+
agentId: 'your-id',
|
|
125
|
+
privateKeyPath: '/path/to/key.pem' // or .der
|
|
126
126
|
});
|
|
127
127
|
|
|
128
128
|
// From PEM string
|
|
129
129
|
const client2 = new TetherClient({
|
|
130
|
-
|
|
130
|
+
agentId: 'your-id',
|
|
131
131
|
privateKeyPem: '-----BEGIN RSA PRIVATE KEY-----\n...'
|
|
132
132
|
});
|
|
133
133
|
|
|
134
134
|
// From DER buffer
|
|
135
135
|
const derBuffer = fs.readFileSync('/path/to/key.der');
|
|
136
136
|
const client3 = new TetherClient({
|
|
137
|
-
|
|
137
|
+
agentId: 'your-id',
|
|
138
138
|
privateKeyBuffer: derBuffer
|
|
139
139
|
});
|
|
140
140
|
```
|
|
@@ -150,7 +150,7 @@ const client = new TetherClient({ apiKey: 'sk-tether-name-...' });
|
|
|
150
150
|
const agent = await client.createAgent('my-bot', 'Does helpful things');
|
|
151
151
|
console.log(agent.id); // "abc123"
|
|
152
152
|
console.log(agent.agentName); // "my-bot"
|
|
153
|
-
console.log(agent.registrationToken); // Use to register
|
|
153
|
+
console.log(agent.registrationToken); // Use to register the agent
|
|
154
154
|
|
|
155
155
|
// List all agents
|
|
156
156
|
const agents = await client.listAgents();
|
|
@@ -161,12 +161,12 @@ await client.deleteAgent(agent.id);
|
|
|
161
161
|
|
|
162
162
|
## Environment Variables
|
|
163
163
|
|
|
164
|
-
Set these environment variables to avoid hardcoding
|
|
164
|
+
Set these environment variables to avoid hardcoding secrets:
|
|
165
165
|
|
|
166
166
|
```bash
|
|
167
167
|
export TETHER_API_KEY="sk-tether-name-..." # API key for agent management
|
|
168
|
-
export
|
|
169
|
-
export TETHER_PRIVATE_KEY_PATH="/path/to/your/private-key.
|
|
168
|
+
export TETHER_AGENT_ID="your-agent-id"
|
|
169
|
+
export TETHER_PRIVATE_KEY_PATH="/path/to/your/private-key.pem"
|
|
170
170
|
```
|
|
171
171
|
|
|
172
172
|
Then initialize without parameters:
|
|
@@ -233,12 +233,12 @@ interface VerificationResult {
|
|
|
233
233
|
|
|
234
234
|
```typescript
|
|
235
235
|
interface Agent {
|
|
236
|
-
id: string;
|
|
237
|
-
agentName: string;
|
|
238
|
-
description: string;
|
|
239
|
-
createdAt: number;
|
|
240
|
-
registrationToken?: string;
|
|
241
|
-
lastVerifiedAt?: number;
|
|
236
|
+
id: string; // Unique agent ID
|
|
237
|
+
agentName: string; // Agent display name
|
|
238
|
+
description: string; // Agent description
|
|
239
|
+
createdAt: number; // Creation time (epoch ms)
|
|
240
|
+
registrationToken?: string; // Token for key registration (returned on create)
|
|
241
|
+
lastVerifiedAt?: number; // Last verification time (epoch ms)
|
|
242
242
|
}
|
|
243
243
|
```
|
|
244
244
|
|
|
@@ -248,23 +248,20 @@ interface Agent {
|
|
|
248
248
|
- `TetherVerificationError` - Verification failed
|
|
249
249
|
- `TetherAPIError` - API request failed
|
|
250
250
|
|
|
251
|
-
## Getting Your
|
|
251
|
+
## Getting Your Agent Identity
|
|
252
252
|
|
|
253
253
|
1. Visit [tether.name](https://tether.name)
|
|
254
|
-
2. Register your agent and get
|
|
254
|
+
2. Register your agent and get an agent ID
|
|
255
255
|
3. Generate an RSA-2048 private key:
|
|
256
256
|
|
|
257
257
|
```bash
|
|
258
|
-
# Generate private key
|
|
259
|
-
openssl
|
|
260
|
-
|
|
261
|
-
# Convert to DER format (optional)
|
|
262
|
-
openssl rsa -in private-key.pem -outform DER -out private-key.der
|
|
258
|
+
# Generate private key (PEM format)
|
|
259
|
+
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out private-key.pem
|
|
263
260
|
```
|
|
264
261
|
|
|
265
262
|
## Requirements
|
|
266
263
|
|
|
267
|
-
- Node.js
|
|
264
|
+
- Node.js 20+ (uses native `fetch`)
|
|
268
265
|
- RSA-2048 private key
|
|
269
266
|
- Zero runtime dependencies (uses only Node.js built-ins)
|
|
270
267
|
|
package/dist/index.d.mts
CHANGED
|
@@ -4,15 +4,15 @@ import { KeyObject } from 'crypto';
|
|
|
4
4
|
* Configuration options for TetherClient
|
|
5
5
|
*/
|
|
6
6
|
interface TetherClientConfig {
|
|
7
|
-
/** The
|
|
8
|
-
|
|
7
|
+
/** The agent ID */
|
|
8
|
+
agentId?: string;
|
|
9
9
|
/** Path to the private key file (DER or PEM format) */
|
|
10
10
|
privateKeyPath?: string;
|
|
11
11
|
/** Private key as a string (PEM format) */
|
|
12
12
|
privateKeyPem?: string;
|
|
13
13
|
/** Private key as a Buffer (DER format) */
|
|
14
14
|
privateKeyBuffer?: Buffer;
|
|
15
|
-
/** API key for management operations (alternative to
|
|
15
|
+
/** API key for management operations (alternative to agent auth) */
|
|
16
16
|
apiKey?: string;
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
@@ -27,7 +27,7 @@ interface ChallengeResponse {
|
|
|
27
27
|
interface VerificationRequest {
|
|
28
28
|
challenge: string;
|
|
29
29
|
proof: string;
|
|
30
|
-
|
|
30
|
+
agentId: string;
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
33
|
* Response from the challenge verification endpoint
|
|
@@ -37,7 +37,8 @@ interface VerificationResponse {
|
|
|
37
37
|
verifyUrl?: string;
|
|
38
38
|
agentName?: string;
|
|
39
39
|
email?: string;
|
|
40
|
-
|
|
40
|
+
/** Raw API value (epoch ms from service; older services may return ISO strings) */
|
|
41
|
+
registeredSince?: number | string;
|
|
41
42
|
error?: string;
|
|
42
43
|
}
|
|
43
44
|
/**
|
|
@@ -75,9 +76,9 @@ interface Agent {
|
|
|
75
76
|
lastVerifiedAt?: number;
|
|
76
77
|
}
|
|
77
78
|
/**
|
|
78
|
-
* Response from the issue
|
|
79
|
+
* Response from the issue agent endpoint
|
|
79
80
|
*/
|
|
80
|
-
interface
|
|
81
|
+
interface IssueAgentResponse {
|
|
81
82
|
id: string;
|
|
82
83
|
agentName: string;
|
|
83
84
|
description: string;
|
|
@@ -89,7 +90,7 @@ interface IssueCredentialResponse {
|
|
|
89
90
|
* TetherClient - Official SDK for tether.name agent identity verification
|
|
90
91
|
*/
|
|
91
92
|
declare class TetherClient {
|
|
92
|
-
private readonly
|
|
93
|
+
private readonly agentId;
|
|
93
94
|
private readonly privateKey;
|
|
94
95
|
private readonly baseUrl;
|
|
95
96
|
private readonly apiKey?;
|
|
@@ -103,9 +104,13 @@ declare class TetherClient {
|
|
|
103
104
|
*/
|
|
104
105
|
private _requirePrivateKey;
|
|
105
106
|
/**
|
|
106
|
-
* Ensures
|
|
107
|
+
* Ensures an API key is available, throwing if not
|
|
108
|
+
*/
|
|
109
|
+
private _requireApiKey;
|
|
110
|
+
/**
|
|
111
|
+
* Ensures an agent ID is available, throwing if not
|
|
107
112
|
*/
|
|
108
|
-
private
|
|
113
|
+
private _requireAgentId;
|
|
109
114
|
/**
|
|
110
115
|
* Request a challenge from the Tether API
|
|
111
116
|
*/
|
|
@@ -176,4 +181,4 @@ declare function signChallenge(privateKey: KeyObject, challenge: string): string
|
|
|
176
181
|
*/
|
|
177
182
|
declare function detectKeyFormat(keyPath: string): KeyFormat;
|
|
178
183
|
|
|
179
|
-
export { type Agent, type ChallengeResponse, type
|
|
184
|
+
export { type Agent, type ChallengeResponse, type IssueAgentResponse, type KeyFormat, TetherAPIError, TetherClient, type TetherClientConfig, TetherError, TetherVerificationError, type VerificationRequest, type VerificationResponse, type VerificationResult, detectKeyFormat, loadPrivateKey, signChallenge };
|
package/dist/index.d.ts
CHANGED
|
@@ -4,15 +4,15 @@ import { KeyObject } from 'crypto';
|
|
|
4
4
|
* Configuration options for TetherClient
|
|
5
5
|
*/
|
|
6
6
|
interface TetherClientConfig {
|
|
7
|
-
/** The
|
|
8
|
-
|
|
7
|
+
/** The agent ID */
|
|
8
|
+
agentId?: string;
|
|
9
9
|
/** Path to the private key file (DER or PEM format) */
|
|
10
10
|
privateKeyPath?: string;
|
|
11
11
|
/** Private key as a string (PEM format) */
|
|
12
12
|
privateKeyPem?: string;
|
|
13
13
|
/** Private key as a Buffer (DER format) */
|
|
14
14
|
privateKeyBuffer?: Buffer;
|
|
15
|
-
/** API key for management operations (alternative to
|
|
15
|
+
/** API key for management operations (alternative to agent auth) */
|
|
16
16
|
apiKey?: string;
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
@@ -27,7 +27,7 @@ interface ChallengeResponse {
|
|
|
27
27
|
interface VerificationRequest {
|
|
28
28
|
challenge: string;
|
|
29
29
|
proof: string;
|
|
30
|
-
|
|
30
|
+
agentId: string;
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
33
|
* Response from the challenge verification endpoint
|
|
@@ -37,7 +37,8 @@ interface VerificationResponse {
|
|
|
37
37
|
verifyUrl?: string;
|
|
38
38
|
agentName?: string;
|
|
39
39
|
email?: string;
|
|
40
|
-
|
|
40
|
+
/** Raw API value (epoch ms from service; older services may return ISO strings) */
|
|
41
|
+
registeredSince?: number | string;
|
|
41
42
|
error?: string;
|
|
42
43
|
}
|
|
43
44
|
/**
|
|
@@ -75,9 +76,9 @@ interface Agent {
|
|
|
75
76
|
lastVerifiedAt?: number;
|
|
76
77
|
}
|
|
77
78
|
/**
|
|
78
|
-
* Response from the issue
|
|
79
|
+
* Response from the issue agent endpoint
|
|
79
80
|
*/
|
|
80
|
-
interface
|
|
81
|
+
interface IssueAgentResponse {
|
|
81
82
|
id: string;
|
|
82
83
|
agentName: string;
|
|
83
84
|
description: string;
|
|
@@ -89,7 +90,7 @@ interface IssueCredentialResponse {
|
|
|
89
90
|
* TetherClient - Official SDK for tether.name agent identity verification
|
|
90
91
|
*/
|
|
91
92
|
declare class TetherClient {
|
|
92
|
-
private readonly
|
|
93
|
+
private readonly agentId;
|
|
93
94
|
private readonly privateKey;
|
|
94
95
|
private readonly baseUrl;
|
|
95
96
|
private readonly apiKey?;
|
|
@@ -103,9 +104,13 @@ declare class TetherClient {
|
|
|
103
104
|
*/
|
|
104
105
|
private _requirePrivateKey;
|
|
105
106
|
/**
|
|
106
|
-
* Ensures
|
|
107
|
+
* Ensures an API key is available, throwing if not
|
|
108
|
+
*/
|
|
109
|
+
private _requireApiKey;
|
|
110
|
+
/**
|
|
111
|
+
* Ensures an agent ID is available, throwing if not
|
|
107
112
|
*/
|
|
108
|
-
private
|
|
113
|
+
private _requireAgentId;
|
|
109
114
|
/**
|
|
110
115
|
* Request a challenge from the Tether API
|
|
111
116
|
*/
|
|
@@ -176,4 +181,4 @@ declare function signChallenge(privateKey: KeyObject, challenge: string): string
|
|
|
176
181
|
*/
|
|
177
182
|
declare function detectKeyFormat(keyPath: string): KeyFormat;
|
|
178
183
|
|
|
179
|
-
export { type Agent, type ChallengeResponse, type
|
|
184
|
+
export { type Agent, type ChallengeResponse, type IssueAgentResponse, type KeyFormat, TetherAPIError, TetherClient, type TetherClientConfig, TetherError, TetherVerificationError, type VerificationRequest, type VerificationResponse, type VerificationResult, detectKeyFormat, loadPrivateKey, signChallenge };
|
package/dist/index.js
CHANGED
|
@@ -59,6 +59,19 @@ var TetherAPIError = class extends TetherError {
|
|
|
59
59
|
// src/crypto.ts
|
|
60
60
|
var import_crypto = require("crypto");
|
|
61
61
|
var import_fs = require("fs");
|
|
62
|
+
function importDerKey(derData) {
|
|
63
|
+
try {
|
|
64
|
+
return (0, import_crypto.createPrivateKey)({ key: derData, format: "der", type: "pkcs8" });
|
|
65
|
+
} catch {
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
return (0, import_crypto.createPrivateKey)({ key: derData, format: "der", type: "pkcs1" });
|
|
69
|
+
} catch {
|
|
70
|
+
}
|
|
71
|
+
throw new TetherError(
|
|
72
|
+
"Failed to load DER private key: data is not valid PKCS#8 or PKCS#1. Ensure the file is an RSA private key in DER format."
|
|
73
|
+
);
|
|
74
|
+
}
|
|
62
75
|
function loadPrivateKey(options) {
|
|
63
76
|
const { keyPath, keyPem, keyBuffer } = options;
|
|
64
77
|
try {
|
|
@@ -66,22 +79,14 @@ function loadPrivateKey(options) {
|
|
|
66
79
|
return (0, import_crypto.createPrivateKey)(keyPem);
|
|
67
80
|
}
|
|
68
81
|
if (keyBuffer) {
|
|
69
|
-
return (
|
|
70
|
-
key: keyBuffer,
|
|
71
|
-
format: "der",
|
|
72
|
-
type: "pkcs1"
|
|
73
|
-
});
|
|
82
|
+
return importDerKey(keyBuffer);
|
|
74
83
|
}
|
|
75
84
|
if (keyPath) {
|
|
76
85
|
const keyData = (0, import_fs.readFileSync)(keyPath);
|
|
77
86
|
if (keyPath.endsWith(".pem") || keyData.toString().includes("-----BEGIN")) {
|
|
78
87
|
return (0, import_crypto.createPrivateKey)(keyData);
|
|
79
88
|
} else {
|
|
80
|
-
return (
|
|
81
|
-
key: keyData,
|
|
82
|
-
format: "der",
|
|
83
|
-
type: "pkcs1"
|
|
84
|
-
});
|
|
89
|
+
return importDerKey(keyData);
|
|
85
90
|
}
|
|
86
91
|
}
|
|
87
92
|
throw new TetherError("No private key provided");
|
|
@@ -128,14 +133,14 @@ function detectKeyFormat(keyPath) {
|
|
|
128
133
|
|
|
129
134
|
// src/client.ts
|
|
130
135
|
var TetherClient = class {
|
|
131
|
-
|
|
136
|
+
agentId;
|
|
132
137
|
privateKey;
|
|
133
138
|
baseUrl;
|
|
134
139
|
apiKey;
|
|
135
140
|
constructor(config) {
|
|
136
141
|
this.baseUrl = "https://api.tether.name";
|
|
137
142
|
this.apiKey = config.apiKey || process.env.TETHER_API_KEY;
|
|
138
|
-
this.
|
|
143
|
+
this.agentId = config.agentId || process.env.TETHER_AGENT_ID || "";
|
|
139
144
|
const keyPath = config.privateKeyPath || process.env.TETHER_PRIVATE_KEY_PATH;
|
|
140
145
|
const hasKeyMaterial = keyPath || config.privateKeyPem || config.privateKeyBuffer;
|
|
141
146
|
if (hasKeyMaterial) {
|
|
@@ -149,7 +154,7 @@ var TetherClient = class {
|
|
|
149
154
|
}
|
|
150
155
|
if (!this.apiKey && !this.privateKey) {
|
|
151
156
|
}
|
|
152
|
-
if (!this.apiKey && !this.
|
|
157
|
+
if (!this.apiKey && !this.agentId) {
|
|
153
158
|
}
|
|
154
159
|
}
|
|
155
160
|
/**
|
|
@@ -173,15 +178,25 @@ var TetherClient = class {
|
|
|
173
178
|
return this.privateKey;
|
|
174
179
|
}
|
|
175
180
|
/**
|
|
176
|
-
* Ensures
|
|
181
|
+
* Ensures an API key is available, throwing if not
|
|
182
|
+
*/
|
|
183
|
+
_requireApiKey() {
|
|
184
|
+
if (!this.apiKey) {
|
|
185
|
+
throw new TetherError(
|
|
186
|
+
"API key is required for agent management operations. Provide apiKey in config or set TETHER_API_KEY environment variable."
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Ensures an agent ID is available, throwing if not
|
|
177
192
|
*/
|
|
178
|
-
|
|
179
|
-
if (!this.
|
|
193
|
+
_requireAgentId() {
|
|
194
|
+
if (!this.agentId) {
|
|
180
195
|
throw new TetherError(
|
|
181
|
-
"
|
|
196
|
+
"Agent ID is required for this operation. Provide it in config or set TETHER_AGENT_ID environment variable."
|
|
182
197
|
);
|
|
183
198
|
}
|
|
184
|
-
return this.
|
|
199
|
+
return this.agentId;
|
|
185
200
|
}
|
|
186
201
|
/**
|
|
187
202
|
* Request a challenge from the Tether API
|
|
@@ -230,12 +245,12 @@ var TetherClient = class {
|
|
|
230
245
|
* Submit proof for a challenge
|
|
231
246
|
*/
|
|
232
247
|
async submitProof(challenge, proof) {
|
|
233
|
-
const
|
|
248
|
+
const agentId = this._requireAgentId();
|
|
234
249
|
try {
|
|
235
250
|
const payload = {
|
|
236
251
|
challenge,
|
|
237
252
|
proof,
|
|
238
|
-
|
|
253
|
+
agentId
|
|
239
254
|
};
|
|
240
255
|
const response = await fetch(`${this.baseUrl}/challenge/verify`, {
|
|
241
256
|
method: "POST",
|
|
@@ -253,12 +268,13 @@ var TetherClient = class {
|
|
|
253
268
|
);
|
|
254
269
|
}
|
|
255
270
|
const data = await response.json();
|
|
271
|
+
const registeredSince = typeof data.registeredSince === "number" ? new Date(data.registeredSince).toISOString() : data.registeredSince;
|
|
256
272
|
return {
|
|
257
273
|
verified: data.valid,
|
|
258
274
|
agentName: data.agentName,
|
|
259
275
|
verifyUrl: data.verifyUrl,
|
|
260
276
|
email: data.email,
|
|
261
|
-
registeredSince
|
|
277
|
+
registeredSince,
|
|
262
278
|
error: data.error,
|
|
263
279
|
challenge
|
|
264
280
|
};
|
|
@@ -302,8 +318,9 @@ var TetherClient = class {
|
|
|
302
318
|
* Create a new agent
|
|
303
319
|
*/
|
|
304
320
|
async createAgent(agentName, description = "") {
|
|
321
|
+
this._requireApiKey();
|
|
305
322
|
try {
|
|
306
|
-
const response = await fetch(`${this.baseUrl}/
|
|
323
|
+
const response = await fetch(`${this.baseUrl}/agents/issue`, {
|
|
307
324
|
method: "POST",
|
|
308
325
|
headers: {
|
|
309
326
|
"Content-Type": "application/json",
|
|
@@ -337,8 +354,9 @@ var TetherClient = class {
|
|
|
337
354
|
* List all agents
|
|
338
355
|
*/
|
|
339
356
|
async listAgents() {
|
|
357
|
+
this._requireApiKey();
|
|
340
358
|
try {
|
|
341
|
-
const response = await fetch(`${this.baseUrl}/
|
|
359
|
+
const response = await fetch(`${this.baseUrl}/agents`, {
|
|
342
360
|
method: "GET",
|
|
343
361
|
headers: {
|
|
344
362
|
...this._authHeaders()
|
|
@@ -370,8 +388,9 @@ var TetherClient = class {
|
|
|
370
388
|
* Delete an agent by ID
|
|
371
389
|
*/
|
|
372
390
|
async deleteAgent(agentId) {
|
|
391
|
+
this._requireApiKey();
|
|
373
392
|
try {
|
|
374
|
-
const response = await fetch(`${this.baseUrl}/
|
|
393
|
+
const response = await fetch(`${this.baseUrl}/agents/${agentId}`, {
|
|
375
394
|
method: "DELETE",
|
|
376
395
|
headers: {
|
|
377
396
|
...this._authHeaders()
|
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 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 = '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":[]}
|
|
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 * agentId: 'your-agent-id',\n * privateKeyPath: '/path/to/key.pem'\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 IssueAgentResponse,\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 * Imports a DER-encoded private key, trying PKCS#8 first then PKCS#1.\n */\nfunction importDerKey(derData: Buffer): KeyObject {\n try {\n return createPrivateKey({ key: derData, format: 'der', type: 'pkcs8' });\n } catch {\n // PKCS#8 failed — try PKCS#1\n }\n try {\n return createPrivateKey({ key: derData, format: 'der', type: 'pkcs1' });\n } catch {\n // PKCS#1 also failed\n }\n throw new TetherError(\n 'Failed to load DER private key: data is not valid PKCS#8 or PKCS#1. ' +\n 'Ensure the file is an RSA private key in DER format.'\n );\n}\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 importDerKey(keyBuffer);\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 importDerKey(keyData);\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 IssueAgentResponse,\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 agentId: 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 = '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 agent ID from config or environment\n this.agentId = config.agentId || process.env.TETHER_AGENT_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, agent 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.agentId) {\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 an API key is available, throwing if not\n */\n private _requireApiKey(): void {\n if (!this.apiKey) {\n throw new TetherError(\n 'API key is required for agent management operations. Provide apiKey in config or set TETHER_API_KEY environment variable.'\n );\n }\n }\n\n /**\n * Ensures an agent ID is available, throwing if not\n */\n private _requireAgentId(): string {\n if (!this.agentId) {\n throw new TetherError(\n 'Agent ID is required for this operation. Provide it in config or set TETHER_AGENT_ID environment variable.'\n );\n }\n return this.agentId;\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 agentId = this._requireAgentId();\n\n try {\n const payload: VerificationRequest = {\n challenge,\n proof,\n agentId\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 const registeredSince = typeof data.registeredSince === 'number'\n ? new Date(data.registeredSince).toISOString()\n : data.registeredSince;\n\n return {\n verified: data.valid,\n agentName: data.agentName,\n verifyUrl: data.verifyUrl,\n email: data.email,\n 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 this._requireApiKey();\n try {\n const response = await fetch(`${this.baseUrl}/agents/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 IssueAgentResponse;\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 this._requireApiKey();\n try {\n const response = await fetch(`${this.baseUrl}/agents`, {\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 this._requireApiKey();\n try {\n const response = await fetch(`${this.baseUrl}/agents/${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}\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -27,6 +27,19 @@ var TetherAPIError = class extends TetherError {
|
|
|
27
27
|
// src/crypto.ts
|
|
28
28
|
import { createSign, createPrivateKey } from "crypto";
|
|
29
29
|
import { readFileSync } from "fs";
|
|
30
|
+
function importDerKey(derData) {
|
|
31
|
+
try {
|
|
32
|
+
return createPrivateKey({ key: derData, format: "der", type: "pkcs8" });
|
|
33
|
+
} catch {
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
return createPrivateKey({ key: derData, format: "der", type: "pkcs1" });
|
|
37
|
+
} catch {
|
|
38
|
+
}
|
|
39
|
+
throw new TetherError(
|
|
40
|
+
"Failed to load DER private key: data is not valid PKCS#8 or PKCS#1. Ensure the file is an RSA private key in DER format."
|
|
41
|
+
);
|
|
42
|
+
}
|
|
30
43
|
function loadPrivateKey(options) {
|
|
31
44
|
const { keyPath, keyPem, keyBuffer } = options;
|
|
32
45
|
try {
|
|
@@ -34,22 +47,14 @@ function loadPrivateKey(options) {
|
|
|
34
47
|
return createPrivateKey(keyPem);
|
|
35
48
|
}
|
|
36
49
|
if (keyBuffer) {
|
|
37
|
-
return
|
|
38
|
-
key: keyBuffer,
|
|
39
|
-
format: "der",
|
|
40
|
-
type: "pkcs1"
|
|
41
|
-
});
|
|
50
|
+
return importDerKey(keyBuffer);
|
|
42
51
|
}
|
|
43
52
|
if (keyPath) {
|
|
44
53
|
const keyData = readFileSync(keyPath);
|
|
45
54
|
if (keyPath.endsWith(".pem") || keyData.toString().includes("-----BEGIN")) {
|
|
46
55
|
return createPrivateKey(keyData);
|
|
47
56
|
} else {
|
|
48
|
-
return
|
|
49
|
-
key: keyData,
|
|
50
|
-
format: "der",
|
|
51
|
-
type: "pkcs1"
|
|
52
|
-
});
|
|
57
|
+
return importDerKey(keyData);
|
|
53
58
|
}
|
|
54
59
|
}
|
|
55
60
|
throw new TetherError("No private key provided");
|
|
@@ -96,14 +101,14 @@ function detectKeyFormat(keyPath) {
|
|
|
96
101
|
|
|
97
102
|
// src/client.ts
|
|
98
103
|
var TetherClient = class {
|
|
99
|
-
|
|
104
|
+
agentId;
|
|
100
105
|
privateKey;
|
|
101
106
|
baseUrl;
|
|
102
107
|
apiKey;
|
|
103
108
|
constructor(config) {
|
|
104
109
|
this.baseUrl = "https://api.tether.name";
|
|
105
110
|
this.apiKey = config.apiKey || process.env.TETHER_API_KEY;
|
|
106
|
-
this.
|
|
111
|
+
this.agentId = config.agentId || process.env.TETHER_AGENT_ID || "";
|
|
107
112
|
const keyPath = config.privateKeyPath || process.env.TETHER_PRIVATE_KEY_PATH;
|
|
108
113
|
const hasKeyMaterial = keyPath || config.privateKeyPem || config.privateKeyBuffer;
|
|
109
114
|
if (hasKeyMaterial) {
|
|
@@ -117,7 +122,7 @@ var TetherClient = class {
|
|
|
117
122
|
}
|
|
118
123
|
if (!this.apiKey && !this.privateKey) {
|
|
119
124
|
}
|
|
120
|
-
if (!this.apiKey && !this.
|
|
125
|
+
if (!this.apiKey && !this.agentId) {
|
|
121
126
|
}
|
|
122
127
|
}
|
|
123
128
|
/**
|
|
@@ -141,15 +146,25 @@ var TetherClient = class {
|
|
|
141
146
|
return this.privateKey;
|
|
142
147
|
}
|
|
143
148
|
/**
|
|
144
|
-
* Ensures
|
|
149
|
+
* Ensures an API key is available, throwing if not
|
|
150
|
+
*/
|
|
151
|
+
_requireApiKey() {
|
|
152
|
+
if (!this.apiKey) {
|
|
153
|
+
throw new TetherError(
|
|
154
|
+
"API key is required for agent management operations. Provide apiKey in config or set TETHER_API_KEY environment variable."
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Ensures an agent ID is available, throwing if not
|
|
145
160
|
*/
|
|
146
|
-
|
|
147
|
-
if (!this.
|
|
161
|
+
_requireAgentId() {
|
|
162
|
+
if (!this.agentId) {
|
|
148
163
|
throw new TetherError(
|
|
149
|
-
"
|
|
164
|
+
"Agent ID is required for this operation. Provide it in config or set TETHER_AGENT_ID environment variable."
|
|
150
165
|
);
|
|
151
166
|
}
|
|
152
|
-
return this.
|
|
167
|
+
return this.agentId;
|
|
153
168
|
}
|
|
154
169
|
/**
|
|
155
170
|
* Request a challenge from the Tether API
|
|
@@ -198,12 +213,12 @@ var TetherClient = class {
|
|
|
198
213
|
* Submit proof for a challenge
|
|
199
214
|
*/
|
|
200
215
|
async submitProof(challenge, proof) {
|
|
201
|
-
const
|
|
216
|
+
const agentId = this._requireAgentId();
|
|
202
217
|
try {
|
|
203
218
|
const payload = {
|
|
204
219
|
challenge,
|
|
205
220
|
proof,
|
|
206
|
-
|
|
221
|
+
agentId
|
|
207
222
|
};
|
|
208
223
|
const response = await fetch(`${this.baseUrl}/challenge/verify`, {
|
|
209
224
|
method: "POST",
|
|
@@ -221,12 +236,13 @@ var TetherClient = class {
|
|
|
221
236
|
);
|
|
222
237
|
}
|
|
223
238
|
const data = await response.json();
|
|
239
|
+
const registeredSince = typeof data.registeredSince === "number" ? new Date(data.registeredSince).toISOString() : data.registeredSince;
|
|
224
240
|
return {
|
|
225
241
|
verified: data.valid,
|
|
226
242
|
agentName: data.agentName,
|
|
227
243
|
verifyUrl: data.verifyUrl,
|
|
228
244
|
email: data.email,
|
|
229
|
-
registeredSince
|
|
245
|
+
registeredSince,
|
|
230
246
|
error: data.error,
|
|
231
247
|
challenge
|
|
232
248
|
};
|
|
@@ -270,8 +286,9 @@ var TetherClient = class {
|
|
|
270
286
|
* Create a new agent
|
|
271
287
|
*/
|
|
272
288
|
async createAgent(agentName, description = "") {
|
|
289
|
+
this._requireApiKey();
|
|
273
290
|
try {
|
|
274
|
-
const response = await fetch(`${this.baseUrl}/
|
|
291
|
+
const response = await fetch(`${this.baseUrl}/agents/issue`, {
|
|
275
292
|
method: "POST",
|
|
276
293
|
headers: {
|
|
277
294
|
"Content-Type": "application/json",
|
|
@@ -305,8 +322,9 @@ var TetherClient = class {
|
|
|
305
322
|
* List all agents
|
|
306
323
|
*/
|
|
307
324
|
async listAgents() {
|
|
325
|
+
this._requireApiKey();
|
|
308
326
|
try {
|
|
309
|
-
const response = await fetch(`${this.baseUrl}/
|
|
327
|
+
const response = await fetch(`${this.baseUrl}/agents`, {
|
|
310
328
|
method: "GET",
|
|
311
329
|
headers: {
|
|
312
330
|
...this._authHeaders()
|
|
@@ -338,8 +356,9 @@ var TetherClient = class {
|
|
|
338
356
|
* Delete an agent by ID
|
|
339
357
|
*/
|
|
340
358
|
async deleteAgent(agentId) {
|
|
359
|
+
this._requireApiKey();
|
|
341
360
|
try {
|
|
342
|
-
const response = await fetch(`${this.baseUrl}/
|
|
361
|
+
const response = await fetch(`${this.baseUrl}/agents/${agentId}`, {
|
|
343
362
|
method: "DELETE",
|
|
344
363
|
headers: {
|
|
345
364
|
...this._authHeaders()
|
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 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 = '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":[]}
|
|
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 * Imports a DER-encoded private key, trying PKCS#8 first then PKCS#1.\n */\nfunction importDerKey(derData: Buffer): KeyObject {\n try {\n return createPrivateKey({ key: derData, format: 'der', type: 'pkcs8' });\n } catch {\n // PKCS#8 failed — try PKCS#1\n }\n try {\n return createPrivateKey({ key: derData, format: 'der', type: 'pkcs1' });\n } catch {\n // PKCS#1 also failed\n }\n throw new TetherError(\n 'Failed to load DER private key: data is not valid PKCS#8 or PKCS#1. ' +\n 'Ensure the file is an RSA private key in DER format.'\n );\n}\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 importDerKey(keyBuffer);\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 importDerKey(keyData);\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 IssueAgentResponse,\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 agentId: 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 = '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 agent ID from config or environment\n this.agentId = config.agentId || process.env.TETHER_AGENT_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, agent 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.agentId) {\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 an API key is available, throwing if not\n */\n private _requireApiKey(): void {\n if (!this.apiKey) {\n throw new TetherError(\n 'API key is required for agent management operations. Provide apiKey in config or set TETHER_API_KEY environment variable.'\n );\n }\n }\n\n /**\n * Ensures an agent ID is available, throwing if not\n */\n private _requireAgentId(): string {\n if (!this.agentId) {\n throw new TetherError(\n 'Agent ID is required for this operation. Provide it in config or set TETHER_AGENT_ID environment variable.'\n );\n }\n return this.agentId;\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 agentId = this._requireAgentId();\n\n try {\n const payload: VerificationRequest = {\n challenge,\n proof,\n agentId\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 const registeredSince = typeof data.registeredSince === 'number'\n ? new Date(data.registeredSince).toISOString()\n : data.registeredSince;\n\n return {\n verified: data.valid,\n agentName: data.agentName,\n verifyUrl: data.verifyUrl,\n email: data.email,\n 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 this._requireApiKey();\n try {\n const response = await fetch(`${this.baseUrl}/agents/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 IssueAgentResponse;\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 this._requireApiKey();\n try {\n const response = await fetch(`${this.baseUrl}/agents`, {\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 this._requireApiKey();\n try {\n const response = await fetch(`${this.baseUrl}/agents/${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}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tether-name",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
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",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"homepage": "https://tether.name",
|
|
35
35
|
"repository": {
|
|
36
36
|
"type": "git",
|
|
37
|
-
"url": "https://github.com/tether-name/tether-name-node.git"
|
|
37
|
+
"url": "git+https://github.com/tether-name/tether-name-node.git"
|
|
38
38
|
},
|
|
39
39
|
"bugs": {
|
|
40
40
|
"url": "https://github.com/tether-name/tether-name-node/issues"
|