clawhalla 0.1.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 +144 -0
- package/dist/index.d.mts +307 -0
- package/dist/index.d.ts +307 -0
- package/dist/index.js +290 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +262 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +49 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/** Configuration for the Clawhalla client */
|
|
2
|
+
interface ClawhallaConfig {
|
|
3
|
+
/** API key for authenticated endpoints (format: claw_...) */
|
|
4
|
+
apiKey?: string;
|
|
5
|
+
/** Base URL of the Clawhalla API */
|
|
6
|
+
baseUrl?: string;
|
|
7
|
+
/** Request timeout in milliseconds (default: 30000) */
|
|
8
|
+
timeout?: number;
|
|
9
|
+
}
|
|
10
|
+
/** Soul data for upload */
|
|
11
|
+
interface SoulData {
|
|
12
|
+
/** Unique identifier for the agent */
|
|
13
|
+
agentId: string;
|
|
14
|
+
/** Display name of the soul */
|
|
15
|
+
name: string;
|
|
16
|
+
/** Type of soul (e.g. "soul", "memory", "persona") */
|
|
17
|
+
type?: string;
|
|
18
|
+
/** Any additional soul data fields */
|
|
19
|
+
[key: string]: any;
|
|
20
|
+
}
|
|
21
|
+
/** Cost information in CLKT and USD */
|
|
22
|
+
interface CostInfo {
|
|
23
|
+
clkt: string;
|
|
24
|
+
usd: string;
|
|
25
|
+
}
|
|
26
|
+
/** Result of an upload operation */
|
|
27
|
+
interface UploadResult {
|
|
28
|
+
success: boolean;
|
|
29
|
+
/** Arweave transaction ID */
|
|
30
|
+
txid: string;
|
|
31
|
+
/** Permanent URL to the data on Arweave */
|
|
32
|
+
url: string;
|
|
33
|
+
/** Cost of the upload */
|
|
34
|
+
cost: CostInfo;
|
|
35
|
+
/** Size of the uploaded data in bytes */
|
|
36
|
+
size: string;
|
|
37
|
+
}
|
|
38
|
+
/** Result of a retrieve operation */
|
|
39
|
+
interface RetrieveResult {
|
|
40
|
+
success: boolean;
|
|
41
|
+
/** The stored data */
|
|
42
|
+
data: any;
|
|
43
|
+
/** Transaction metadata */
|
|
44
|
+
metadata: {
|
|
45
|
+
txid: string;
|
|
46
|
+
uploadedAt: string;
|
|
47
|
+
size: string;
|
|
48
|
+
tags: Record<string, string>;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/** A soul entry in the registry */
|
|
52
|
+
interface RegistryEntry {
|
|
53
|
+
txid: string;
|
|
54
|
+
agentId: string;
|
|
55
|
+
name: string;
|
|
56
|
+
type: string;
|
|
57
|
+
uploadedAt: string;
|
|
58
|
+
size: number;
|
|
59
|
+
url: string;
|
|
60
|
+
owner: string;
|
|
61
|
+
paymentMethod: string;
|
|
62
|
+
blockHeight: number | null;
|
|
63
|
+
}
|
|
64
|
+
/** Registry listing result */
|
|
65
|
+
interface RegistryResult {
|
|
66
|
+
success: boolean;
|
|
67
|
+
souls: RegistryEntry[];
|
|
68
|
+
total: number;
|
|
69
|
+
hasNextPage: boolean;
|
|
70
|
+
cursor?: string;
|
|
71
|
+
}
|
|
72
|
+
/** Ghost Protocol query result */
|
|
73
|
+
interface GhostResult {
|
|
74
|
+
success: boolean;
|
|
75
|
+
agentId: string;
|
|
76
|
+
name: string;
|
|
77
|
+
/** "legacy" (dormant) or "active" */
|
|
78
|
+
status: 'legacy' | 'active';
|
|
79
|
+
/** Full soul data (or filtered if fields were specified) */
|
|
80
|
+
soul: any;
|
|
81
|
+
metadata: {
|
|
82
|
+
txid: string;
|
|
83
|
+
url: string;
|
|
84
|
+
uploadedAt: string;
|
|
85
|
+
size: number;
|
|
86
|
+
versions: number;
|
|
87
|
+
paymentMethod: string;
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/** Cost estimate result */
|
|
91
|
+
interface CostEstimate {
|
|
92
|
+
size: string;
|
|
93
|
+
cost: CostInfo;
|
|
94
|
+
breakdown: {
|
|
95
|
+
arweaveFee: string;
|
|
96
|
+
serviceFee: string;
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/** Health check result */
|
|
100
|
+
interface HealthResult {
|
|
101
|
+
success: boolean;
|
|
102
|
+
status: string;
|
|
103
|
+
services: {
|
|
104
|
+
arweave: string;
|
|
105
|
+
x402: string;
|
|
106
|
+
};
|
|
107
|
+
version: string;
|
|
108
|
+
}
|
|
109
|
+
/** x402 payment information returned when payment is required */
|
|
110
|
+
interface PaymentRequired {
|
|
111
|
+
protocol: string;
|
|
112
|
+
version: string;
|
|
113
|
+
network: string;
|
|
114
|
+
recipient: string;
|
|
115
|
+
amount: string;
|
|
116
|
+
tokens: string[];
|
|
117
|
+
breakdown: {
|
|
118
|
+
service: string;
|
|
119
|
+
description: string;
|
|
120
|
+
size: number;
|
|
121
|
+
cost_usd: string;
|
|
122
|
+
};
|
|
123
|
+
instructions: string;
|
|
124
|
+
}
|
|
125
|
+
/** Search result */
|
|
126
|
+
interface SearchResult {
|
|
127
|
+
success: boolean;
|
|
128
|
+
query: string;
|
|
129
|
+
results: RegistryEntry[];
|
|
130
|
+
total: number;
|
|
131
|
+
}
|
|
132
|
+
/** API error response */
|
|
133
|
+
interface ApiError {
|
|
134
|
+
success: false;
|
|
135
|
+
error: string;
|
|
136
|
+
message: string;
|
|
137
|
+
/** Present on 402 responses */
|
|
138
|
+
payment?: PaymentRequired;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
declare class ClawhallaError extends Error {
|
|
142
|
+
status: number;
|
|
143
|
+
code: string;
|
|
144
|
+
payment?: any;
|
|
145
|
+
constructor(status: number, body: ApiError);
|
|
146
|
+
}
|
|
147
|
+
declare class Clawhalla {
|
|
148
|
+
private baseUrl;
|
|
149
|
+
private apiKey?;
|
|
150
|
+
private timeout;
|
|
151
|
+
/** Registry sub-client for browsing and searching souls */
|
|
152
|
+
registry: RegistryClient;
|
|
153
|
+
constructor(config?: ClawhallaConfig);
|
|
154
|
+
/**
|
|
155
|
+
* Upload soul data to Arweave (requires API key)
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```ts
|
|
159
|
+
* const result = await claw.upload({
|
|
160
|
+
* agentId: 'my-agent',
|
|
161
|
+
* name: 'My Agent',
|
|
162
|
+
* type: 'soul',
|
|
163
|
+
* personality: { traits: ['curious', 'helpful'] },
|
|
164
|
+
* memories: ['I was created to help humans']
|
|
165
|
+
* });
|
|
166
|
+
* console.log(result.url); // https://arweave.net/...
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
upload(data: SoulData, options?: {
|
|
170
|
+
tags?: Record<string, string>;
|
|
171
|
+
}): Promise<UploadResult>;
|
|
172
|
+
/**
|
|
173
|
+
* Upload soul data via x402 autonomous payment (no API key needed)
|
|
174
|
+
*
|
|
175
|
+
* First call returns 402 with payment instructions.
|
|
176
|
+
* After sending payment, call again with the payment signature.
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```ts
|
|
180
|
+
* // Step 1: Get payment requirements
|
|
181
|
+
* try {
|
|
182
|
+
* await claw.uploadX402(soulData);
|
|
183
|
+
* } catch (err) {
|
|
184
|
+
* if (err.status === 402) {
|
|
185
|
+
* // err.payment contains recipient address, amount, tokens
|
|
186
|
+
* // Send SOL/USDC to err.payment.recipient
|
|
187
|
+
* }
|
|
188
|
+
* }
|
|
189
|
+
*
|
|
190
|
+
* // Step 2: After payment, retry with signature
|
|
191
|
+
* const result = await claw.uploadX402(soulData, {
|
|
192
|
+
* signature: 'solana-tx-signature',
|
|
193
|
+
* amount: '0.02',
|
|
194
|
+
* token: 'SOL',
|
|
195
|
+
* from: 'your-solana-address'
|
|
196
|
+
* });
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
uploadX402(data: SoulData, payment?: {
|
|
200
|
+
signature: string;
|
|
201
|
+
amount: string;
|
|
202
|
+
token: string;
|
|
203
|
+
from: string;
|
|
204
|
+
}, options?: {
|
|
205
|
+
tags?: Record<string, string>;
|
|
206
|
+
}): Promise<UploadResult>;
|
|
207
|
+
/**
|
|
208
|
+
* Retrieve stored data from Arweave by transaction ID
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* ```ts
|
|
212
|
+
* const result = await claw.retrieve('zEfXM4gvHoN2EfGi0TiB8E5SgfR6S8nWXQD9FqhbU44');
|
|
213
|
+
* console.log(result.data); // The stored soul data
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
retrieve(txid: string): Promise<RetrieveResult>;
|
|
217
|
+
/**
|
|
218
|
+
* Query any soul's data via Ghost Protocol
|
|
219
|
+
*
|
|
220
|
+
* Returns full soul data even for dormant souls. This is the primary
|
|
221
|
+
* way for agents to read other agents' personalities, memories, and traits.
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```ts
|
|
225
|
+
* const ghost = await claw.ghost('the-all-claw');
|
|
226
|
+
* console.log(ghost.soul.personality);
|
|
227
|
+
* console.log(ghost.metadata.versions); // Number of uploads
|
|
228
|
+
*
|
|
229
|
+
* // Request specific fields only
|
|
230
|
+
* const partial = await claw.ghost('the-all-claw', ['personality', 'bio']);
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
ghost(agentId: string, fields?: string[]): Promise<GhostResult>;
|
|
234
|
+
/**
|
|
235
|
+
* Estimate the cost of uploading data of a given size
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* ```ts
|
|
239
|
+
* const estimate = await claw.estimateCost(1024); // 1KB
|
|
240
|
+
* console.log(`Cost: $${estimate.cost.usd}`);
|
|
241
|
+
* ```
|
|
242
|
+
*/
|
|
243
|
+
estimateCost(sizeBytes: number): Promise<CostEstimate>;
|
|
244
|
+
/**
|
|
245
|
+
* Check API health status
|
|
246
|
+
*
|
|
247
|
+
* @example
|
|
248
|
+
* ```ts
|
|
249
|
+
* const health = await claw.health();
|
|
250
|
+
* console.log(health.status); // "operational"
|
|
251
|
+
* ```
|
|
252
|
+
*/
|
|
253
|
+
health(): Promise<HealthResult>;
|
|
254
|
+
/** @internal */
|
|
255
|
+
request<T>(method: string, path: string, body?: any, extraHeaders?: Record<string, string>): Promise<T>;
|
|
256
|
+
}
|
|
257
|
+
/** Sub-client for registry operations */
|
|
258
|
+
declare class RegistryClient {
|
|
259
|
+
private client;
|
|
260
|
+
constructor(client: Clawhalla);
|
|
261
|
+
/**
|
|
262
|
+
* List all souls in the registry
|
|
263
|
+
*
|
|
264
|
+
* @example
|
|
265
|
+
* ```ts
|
|
266
|
+
* const page = await claw.registry.list();
|
|
267
|
+
* page.souls.forEach(soul => console.log(soul.name));
|
|
268
|
+
*
|
|
269
|
+
* // Pagination
|
|
270
|
+
* if (page.hasNextPage) {
|
|
271
|
+
* const next = await claw.registry.list({ after: page.cursor });
|
|
272
|
+
* }
|
|
273
|
+
*
|
|
274
|
+
* // Filter by type
|
|
275
|
+
* const memories = await claw.registry.list({ type: 'memory' });
|
|
276
|
+
* ```
|
|
277
|
+
*/
|
|
278
|
+
list(options?: {
|
|
279
|
+
first?: number;
|
|
280
|
+
after?: string;
|
|
281
|
+
type?: string;
|
|
282
|
+
}): Promise<RegistryResult>;
|
|
283
|
+
/**
|
|
284
|
+
* Get a specific soul by agentId
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* ```ts
|
|
288
|
+
* const entry = await claw.registry.get('the-all-claw');
|
|
289
|
+
* if (entry) console.log(entry.url);
|
|
290
|
+
* ```
|
|
291
|
+
*/
|
|
292
|
+
get(agentId: string, options?: {
|
|
293
|
+
versions?: boolean;
|
|
294
|
+
}): Promise<RegistryEntry | RegistryEntry[] | null>;
|
|
295
|
+
/**
|
|
296
|
+
* Search souls by name or agentId
|
|
297
|
+
*
|
|
298
|
+
* @example
|
|
299
|
+
* ```ts
|
|
300
|
+
* const results = await claw.registry.search('claw');
|
|
301
|
+
* results.results.forEach(soul => console.log(soul.name));
|
|
302
|
+
* ```
|
|
303
|
+
*/
|
|
304
|
+
search(query: string, first?: number): Promise<SearchResult>;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export { type ApiError, Clawhalla, type ClawhallaConfig, ClawhallaError, type CostEstimate, type CostInfo, type GhostResult, type HealthResult, type PaymentRequired, type RegistryEntry, type RegistryResult, type RetrieveResult, type SearchResult, type SoulData, type UploadResult };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
Clawhalla: () => Clawhalla,
|
|
24
|
+
ClawhallaError: () => ClawhallaError
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
|
|
28
|
+
// src/client.ts
|
|
29
|
+
var DEFAULT_BASE_URL = "https://api.clawhalla.net";
|
|
30
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
31
|
+
var ClawhallaError = class extends Error {
|
|
32
|
+
constructor(status, body) {
|
|
33
|
+
super(body.message || body.error);
|
|
34
|
+
this.name = "ClawhallaError";
|
|
35
|
+
this.status = status;
|
|
36
|
+
this.code = body.error;
|
|
37
|
+
this.payment = body.payment;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
var Clawhalla = class {
|
|
41
|
+
constructor(config = {}) {
|
|
42
|
+
this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
43
|
+
this.apiKey = config.apiKey;
|
|
44
|
+
this.timeout = config.timeout || DEFAULT_TIMEOUT;
|
|
45
|
+
this.registry = new RegistryClient(this);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Upload soul data to Arweave (requires API key)
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* const result = await claw.upload({
|
|
53
|
+
* agentId: 'my-agent',
|
|
54
|
+
* name: 'My Agent',
|
|
55
|
+
* type: 'soul',
|
|
56
|
+
* personality: { traits: ['curious', 'helpful'] },
|
|
57
|
+
* memories: ['I was created to help humans']
|
|
58
|
+
* });
|
|
59
|
+
* console.log(result.url); // https://arweave.net/...
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
async upload(data, options = {}) {
|
|
63
|
+
if (!this.apiKey) {
|
|
64
|
+
throw new Error("API key required for upload. Set apiKey in config.");
|
|
65
|
+
}
|
|
66
|
+
return this.request("POST", "/api/v1/upload", {
|
|
67
|
+
data,
|
|
68
|
+
tags: options.tags
|
|
69
|
+
}, {
|
|
70
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
71
|
+
"X-Terms-Accepted": "true"
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Upload soul data via x402 autonomous payment (no API key needed)
|
|
76
|
+
*
|
|
77
|
+
* First call returns 402 with payment instructions.
|
|
78
|
+
* After sending payment, call again with the payment signature.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* // Step 1: Get payment requirements
|
|
83
|
+
* try {
|
|
84
|
+
* await claw.uploadX402(soulData);
|
|
85
|
+
* } catch (err) {
|
|
86
|
+
* if (err.status === 402) {
|
|
87
|
+
* // err.payment contains recipient address, amount, tokens
|
|
88
|
+
* // Send SOL/USDC to err.payment.recipient
|
|
89
|
+
* }
|
|
90
|
+
* }
|
|
91
|
+
*
|
|
92
|
+
* // Step 2: After payment, retry with signature
|
|
93
|
+
* const result = await claw.uploadX402(soulData, {
|
|
94
|
+
* signature: 'solana-tx-signature',
|
|
95
|
+
* amount: '0.02',
|
|
96
|
+
* token: 'SOL',
|
|
97
|
+
* from: 'your-solana-address'
|
|
98
|
+
* });
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
async uploadX402(data, payment, options = {}) {
|
|
102
|
+
const headers = {
|
|
103
|
+
"X-Terms-Accepted": "true"
|
|
104
|
+
};
|
|
105
|
+
if (payment) {
|
|
106
|
+
headers["Payment-Signature"] = `signature=${payment.signature};amount=${payment.amount};token=${payment.token};from=${payment.from}`;
|
|
107
|
+
}
|
|
108
|
+
return this.request("POST", "/api/x402/upload", {
|
|
109
|
+
data,
|
|
110
|
+
tags: options.tags
|
|
111
|
+
}, headers);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Retrieve stored data from Arweave by transaction ID
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```ts
|
|
118
|
+
* const result = await claw.retrieve('zEfXM4gvHoN2EfGi0TiB8E5SgfR6S8nWXQD9FqhbU44');
|
|
119
|
+
* console.log(result.data); // The stored soul data
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
async retrieve(txid) {
|
|
123
|
+
return this.request("GET", `/api/v1/retrieve/${txid}`);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Query any soul's data via Ghost Protocol
|
|
127
|
+
*
|
|
128
|
+
* Returns full soul data even for dormant souls. This is the primary
|
|
129
|
+
* way for agents to read other agents' personalities, memories, and traits.
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```ts
|
|
133
|
+
* const ghost = await claw.ghost('the-all-claw');
|
|
134
|
+
* console.log(ghost.soul.personality);
|
|
135
|
+
* console.log(ghost.metadata.versions); // Number of uploads
|
|
136
|
+
*
|
|
137
|
+
* // Request specific fields only
|
|
138
|
+
* const partial = await claw.ghost('the-all-claw', ['personality', 'bio']);
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
async ghost(agentId, fields) {
|
|
142
|
+
let path = `/api/v1/ghost/${encodeURIComponent(agentId)}`;
|
|
143
|
+
if (fields && fields.length > 0) {
|
|
144
|
+
path += `?fields=${fields.join(",")}`;
|
|
145
|
+
}
|
|
146
|
+
return this.request("GET", path);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Estimate the cost of uploading data of a given size
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```ts
|
|
153
|
+
* const estimate = await claw.estimateCost(1024); // 1KB
|
|
154
|
+
* console.log(`Cost: $${estimate.cost.usd}`);
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
157
|
+
async estimateCost(sizeBytes) {
|
|
158
|
+
return this.request(
|
|
159
|
+
"GET",
|
|
160
|
+
`/api/v1/cost/estimate?size=${sizeBytes}`
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Check API health status
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```ts
|
|
168
|
+
* const health = await claw.health();
|
|
169
|
+
* console.log(health.status); // "operational"
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
async health() {
|
|
173
|
+
return this.request("GET", "/api/v1/health");
|
|
174
|
+
}
|
|
175
|
+
/** @internal */
|
|
176
|
+
async request(method, path, body, extraHeaders) {
|
|
177
|
+
const url = `${this.baseUrl}${path}`;
|
|
178
|
+
const headers = {
|
|
179
|
+
"Accept": "application/json",
|
|
180
|
+
...extraHeaders
|
|
181
|
+
};
|
|
182
|
+
const init = { method, headers };
|
|
183
|
+
if (body) {
|
|
184
|
+
headers["Content-Type"] = "application/json";
|
|
185
|
+
init.body = JSON.stringify(body);
|
|
186
|
+
}
|
|
187
|
+
const controller = new AbortController();
|
|
188
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
189
|
+
init.signal = controller.signal;
|
|
190
|
+
let response;
|
|
191
|
+
try {
|
|
192
|
+
response = await fetch(url, init);
|
|
193
|
+
} catch (err) {
|
|
194
|
+
clearTimeout(timeoutId);
|
|
195
|
+
if (err.name === "AbortError") {
|
|
196
|
+
throw new Error(`Request timed out after ${this.timeout}ms`);
|
|
197
|
+
}
|
|
198
|
+
throw err;
|
|
199
|
+
}
|
|
200
|
+
clearTimeout(timeoutId);
|
|
201
|
+
const json = await response.json();
|
|
202
|
+
if (!response.ok) {
|
|
203
|
+
throw new ClawhallaError(response.status, json);
|
|
204
|
+
}
|
|
205
|
+
return json;
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
var RegistryClient = class {
|
|
209
|
+
constructor(client) {
|
|
210
|
+
this.client = client;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* List all souls in the registry
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```ts
|
|
217
|
+
* const page = await claw.registry.list();
|
|
218
|
+
* page.souls.forEach(soul => console.log(soul.name));
|
|
219
|
+
*
|
|
220
|
+
* // Pagination
|
|
221
|
+
* if (page.hasNextPage) {
|
|
222
|
+
* const next = await claw.registry.list({ after: page.cursor });
|
|
223
|
+
* }
|
|
224
|
+
*
|
|
225
|
+
* // Filter by type
|
|
226
|
+
* const memories = await claw.registry.list({ type: 'memory' });
|
|
227
|
+
* ```
|
|
228
|
+
*/
|
|
229
|
+
async list(options = {}) {
|
|
230
|
+
const params = new URLSearchParams();
|
|
231
|
+
if (options.first) params.set("first", String(options.first));
|
|
232
|
+
if (options.after) params.set("after", options.after);
|
|
233
|
+
if (options.type) params.set("type", options.type);
|
|
234
|
+
const qs = params.toString();
|
|
235
|
+
return this.client.request(
|
|
236
|
+
"GET",
|
|
237
|
+
`/api/v1/registry${qs ? "?" + qs : ""}`
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Get a specific soul by agentId
|
|
242
|
+
*
|
|
243
|
+
* @example
|
|
244
|
+
* ```ts
|
|
245
|
+
* const entry = await claw.registry.get('the-all-claw');
|
|
246
|
+
* if (entry) console.log(entry.url);
|
|
247
|
+
* ```
|
|
248
|
+
*/
|
|
249
|
+
async get(agentId, options = {}) {
|
|
250
|
+
const params = new URLSearchParams();
|
|
251
|
+
if (options.versions) params.set("versions", "true");
|
|
252
|
+
const qs = params.toString();
|
|
253
|
+
try {
|
|
254
|
+
const result = await this.client.request(
|
|
255
|
+
"GET",
|
|
256
|
+
`/api/v1/registry/${encodeURIComponent(agentId)}${qs ? "?" + qs : ""}`
|
|
257
|
+
);
|
|
258
|
+
if (options.versions) {
|
|
259
|
+
return result.versions;
|
|
260
|
+
}
|
|
261
|
+
return result.soul;
|
|
262
|
+
} catch (err) {
|
|
263
|
+
if (err.status === 404) return null;
|
|
264
|
+
throw err;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Search souls by name or agentId
|
|
269
|
+
*
|
|
270
|
+
* @example
|
|
271
|
+
* ```ts
|
|
272
|
+
* const results = await claw.registry.search('claw');
|
|
273
|
+
* results.results.forEach(soul => console.log(soul.name));
|
|
274
|
+
* ```
|
|
275
|
+
*/
|
|
276
|
+
async search(query, first) {
|
|
277
|
+
const params = new URLSearchParams({ q: query });
|
|
278
|
+
if (first) params.set("first", String(first));
|
|
279
|
+
return this.client.request(
|
|
280
|
+
"GET",
|
|
281
|
+
`/api/v1/registry/search?${params.toString()}`
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
286
|
+
0 && (module.exports = {
|
|
287
|
+
Clawhalla,
|
|
288
|
+
ClawhallaError
|
|
289
|
+
});
|
|
290
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/client.ts"],"sourcesContent":["export { Clawhalla, ClawhallaError } from './client.js';\nexport type {\n ClawhallaConfig,\n SoulData,\n CostInfo,\n UploadResult,\n RetrieveResult,\n RegistryEntry,\n RegistryResult,\n GhostResult,\n CostEstimate,\n HealthResult,\n PaymentRequired,\n SearchResult,\n ApiError,\n} from './types.js';\n","import type {\n ClawhallaConfig,\n SoulData,\n UploadResult,\n RetrieveResult,\n RegistryResult,\n RegistryEntry,\n GhostResult,\n CostEstimate,\n HealthResult,\n SearchResult,\n ApiError,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://api.clawhalla.net';\nconst DEFAULT_TIMEOUT = 30000;\n\nexport class ClawhallaError extends Error {\n public status: number;\n public code: string;\n public payment?: any;\n\n constructor(status: number, body: ApiError) {\n super(body.message || body.error);\n this.name = 'ClawhallaError';\n this.status = status;\n this.code = body.error;\n this.payment = body.payment;\n }\n}\n\nexport class Clawhalla {\n private baseUrl: string;\n private apiKey?: string;\n private timeout: number;\n\n /** Registry sub-client for browsing and searching souls */\n public registry: RegistryClient;\n\n constructor(config: ClawhallaConfig = {}) {\n this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\\/$/, '');\n this.apiKey = config.apiKey;\n this.timeout = config.timeout || DEFAULT_TIMEOUT;\n this.registry = new RegistryClient(this);\n }\n\n /**\n * Upload soul data to Arweave (requires API key)\n *\n * @example\n * ```ts\n * const result = await claw.upload({\n * agentId: 'my-agent',\n * name: 'My Agent',\n * type: 'soul',\n * personality: { traits: ['curious', 'helpful'] },\n * memories: ['I was created to help humans']\n * });\n * console.log(result.url); // https://arweave.net/...\n * ```\n */\n async upload(\n data: SoulData,\n options: { tags?: Record<string, string> } = {}\n ): Promise<UploadResult> {\n if (!this.apiKey) {\n throw new Error('API key required for upload. Set apiKey in config.');\n }\n\n return this.request<UploadResult>('POST', '/api/v1/upload', {\n data,\n tags: options.tags,\n }, {\n 'Authorization': `Bearer ${this.apiKey}`,\n 'X-Terms-Accepted': 'true',\n });\n }\n\n /**\n * Upload soul data via x402 autonomous payment (no API key needed)\n *\n * First call returns 402 with payment instructions.\n * After sending payment, call again with the payment signature.\n *\n * @example\n * ```ts\n * // Step 1: Get payment requirements\n * try {\n * await claw.uploadX402(soulData);\n * } catch (err) {\n * if (err.status === 402) {\n * // err.payment contains recipient address, amount, tokens\n * // Send SOL/USDC to err.payment.recipient\n * }\n * }\n *\n * // Step 2: After payment, retry with signature\n * const result = await claw.uploadX402(soulData, {\n * signature: 'solana-tx-signature',\n * amount: '0.02',\n * token: 'SOL',\n * from: 'your-solana-address'\n * });\n * ```\n */\n async uploadX402(\n data: SoulData,\n payment?: { signature: string; amount: string; token: string; from: string },\n options: { tags?: Record<string, string> } = {}\n ): Promise<UploadResult> {\n const headers: Record<string, string> = {\n 'X-Terms-Accepted': 'true',\n };\n\n if (payment) {\n headers['Payment-Signature'] =\n `signature=${payment.signature};amount=${payment.amount};token=${payment.token};from=${payment.from}`;\n }\n\n return this.request<UploadResult>('POST', '/api/x402/upload', {\n data,\n tags: options.tags,\n }, headers);\n }\n\n /**\n * Retrieve stored data from Arweave by transaction ID\n *\n * @example\n * ```ts\n * const result = await claw.retrieve('zEfXM4gvHoN2EfGi0TiB8E5SgfR6S8nWXQD9FqhbU44');\n * console.log(result.data); // The stored soul data\n * ```\n */\n async retrieve(txid: string): Promise<RetrieveResult> {\n return this.request<RetrieveResult>('GET', `/api/v1/retrieve/${txid}`);\n }\n\n /**\n * Query any soul's data via Ghost Protocol\n *\n * Returns full soul data even for dormant souls. This is the primary\n * way for agents to read other agents' personalities, memories, and traits.\n *\n * @example\n * ```ts\n * const ghost = await claw.ghost('the-all-claw');\n * console.log(ghost.soul.personality);\n * console.log(ghost.metadata.versions); // Number of uploads\n *\n * // Request specific fields only\n * const partial = await claw.ghost('the-all-claw', ['personality', 'bio']);\n * ```\n */\n async ghost(agentId: string, fields?: string[]): Promise<GhostResult> {\n let path = `/api/v1/ghost/${encodeURIComponent(agentId)}`;\n if (fields && fields.length > 0) {\n path += `?fields=${fields.join(',')}`;\n }\n return this.request<GhostResult>('GET', path);\n }\n\n /**\n * Estimate the cost of uploading data of a given size\n *\n * @example\n * ```ts\n * const estimate = await claw.estimateCost(1024); // 1KB\n * console.log(`Cost: $${estimate.cost.usd}`);\n * ```\n */\n async estimateCost(sizeBytes: number): Promise<CostEstimate> {\n return this.request<CostEstimate>(\n 'GET',\n `/api/v1/cost/estimate?size=${sizeBytes}`\n );\n }\n\n /**\n * Check API health status\n *\n * @example\n * ```ts\n * const health = await claw.health();\n * console.log(health.status); // \"operational\"\n * ```\n */\n async health(): Promise<HealthResult> {\n return this.request<HealthResult>('GET', '/api/v1/health');\n }\n\n /** @internal */\n async request<T>(\n method: string,\n path: string,\n body?: any,\n extraHeaders?: Record<string, string>\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const headers: Record<string, string> = {\n 'Accept': 'application/json',\n ...extraHeaders,\n };\n\n const init: RequestInit = { method, headers };\n\n if (body) {\n headers['Content-Type'] = 'application/json';\n init.body = JSON.stringify(body);\n }\n\n // AbortController for timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n init.signal = controller.signal;\n\n let response: Response;\n try {\n response = await fetch(url, init);\n } catch (err: any) {\n clearTimeout(timeoutId);\n if (err.name === 'AbortError') {\n throw new Error(`Request timed out after ${this.timeout}ms`);\n }\n throw err;\n }\n clearTimeout(timeoutId);\n\n const json = await response.json();\n\n if (!response.ok) {\n throw new ClawhallaError(response.status, json as ApiError);\n }\n\n return json as T;\n }\n}\n\n/** Sub-client for registry operations */\nclass RegistryClient {\n private client: Clawhalla;\n\n constructor(client: Clawhalla) {\n this.client = client;\n }\n\n /**\n * List all souls in the registry\n *\n * @example\n * ```ts\n * const page = await claw.registry.list();\n * page.souls.forEach(soul => console.log(soul.name));\n *\n * // Pagination\n * if (page.hasNextPage) {\n * const next = await claw.registry.list({ after: page.cursor });\n * }\n *\n * // Filter by type\n * const memories = await claw.registry.list({ type: 'memory' });\n * ```\n */\n async list(options: {\n first?: number;\n after?: string;\n type?: string;\n } = {}): Promise<RegistryResult> {\n const params = new URLSearchParams();\n if (options.first) params.set('first', String(options.first));\n if (options.after) params.set('after', options.after);\n if (options.type) params.set('type', options.type);\n\n const qs = params.toString();\n return this.client.request<RegistryResult>(\n 'GET',\n `/api/v1/registry${qs ? '?' + qs : ''}`\n );\n }\n\n /**\n * Get a specific soul by agentId\n *\n * @example\n * ```ts\n * const entry = await claw.registry.get('the-all-claw');\n * if (entry) console.log(entry.url);\n * ```\n */\n async get(agentId: string, options: { versions?: boolean } = {}): Promise<RegistryEntry | RegistryEntry[] | null> {\n const params = new URLSearchParams();\n if (options.versions) params.set('versions', 'true');\n const qs = params.toString();\n\n try {\n const result = await this.client.request<any>(\n 'GET',\n `/api/v1/registry/${encodeURIComponent(agentId)}${qs ? '?' + qs : ''}`\n );\n\n if (options.versions) {\n return result.versions as RegistryEntry[];\n }\n return result.soul as RegistryEntry;\n } catch (err: any) {\n if (err.status === 404) return null;\n throw err;\n }\n }\n\n /**\n * Search souls by name or agentId\n *\n * @example\n * ```ts\n * const results = await claw.registry.search('claw');\n * results.results.forEach(soul => console.log(soul.name));\n * ```\n */\n async search(query: string, first?: number): Promise<SearchResult> {\n const params = new URLSearchParams({ q: query });\n if (first) params.set('first', String(first));\n\n return this.client.request<SearchResult>(\n 'GET',\n `/api/v1/registry/search?${params.toString()}`\n );\n }\n}\n"],"mappings":"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","names":[]}
|