@catena/sdk 0.0.0-alpha-20260724191736

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.
@@ -0,0 +1,597 @@
1
+ import { p256KeypairFromPrivateKeyHex, p256PointFromCompressedHex, p256PublicKeyThumbprintFromPoint } from "./keypair.mjs";
2
+ import { ApiKeyStamper } from "@turnkey/api-key-stamper";
3
+ import * as v from "valibot";
4
+ import { createHash, createPrivateKey, randomBytes, sign } from "node:crypto";
5
+ //#region src/request-signing.ts
6
+ const COVERED_COMPONENTS = "(\"@method\" \"@target-uri\" \"content-digest\" \"signature-agent\")";
7
+ const ALGORITHM = "ecdsa-p256-sha256";
8
+ const IDENTITY_URL = /^https?:\/\/[\x21\x23-\x7e]{1,255}$/;
9
+ const NONCE = /^[\x21\x23-\x3a\x3c-\x7e]{1,128}$/;
10
+ function agentKeyIdentityUrl(bankUrl, keyId) {
11
+ return `${bankUrl.replace(/\/+$/, "")}/agent-keys/${keyId}`;
12
+ }
13
+ function createAgentRequestSigner(options) {
14
+ const key = buildSignerKey(options.keypair);
15
+ const state = {
16
+ ...key,
17
+ identityUrl: validatedIdentityUrl(options.identityUrl ?? agentKeyIdentityUrl(options.baseUrl, key.keyId))
18
+ };
19
+ return { sign: async (request) => {
20
+ const body = new Uint8Array(await request.clone().arrayBuffer());
21
+ const signatureHeaders = signRequest(state, {
22
+ method: request.method,
23
+ url: request.url,
24
+ body
25
+ }, {
26
+ nonce: randomBytes(16).toString("base64url"),
27
+ createdAt: new Date()
28
+ });
29
+ const headers = new Headers(request.headers);
30
+ for (const [name, value] of Object.entries(signatureHeaders)) headers.set(name, value);
31
+ return new Request(request, { headers });
32
+ } };
33
+ }
34
+ function buildSignerKey(keypair) {
35
+ const point = p256PointFromCompressedHex(keypair.publicKeyHex);
36
+ if (point === null) throw new Error("signer keypair has an invalid P-256 public key");
37
+ return {
38
+ signingKey: p256SigningKey(point, keypair.privateKeyHex),
39
+ keyId: p256PublicKeyThumbprintFromPoint(point)
40
+ };
41
+ }
42
+ function validatedIdentityUrl(identityUrl) {
43
+ if (!IDENTITY_URL.test(identityUrl)) throw new Error(`identity URL is outside the signature profile: "${identityUrl}"`);
44
+ return identityUrl;
45
+ }
46
+ function signRequest(state, request, params) {
47
+ if (!NONCE.test(params.nonce)) throw new Error("nonce is outside the signature profile");
48
+ const contentDigest = contentDigestHeader(request.body);
49
+ const signatureAgent = `"${state.identityUrl}"`;
50
+ const signatureParams = `${COVERED_COMPONENTS};created=${Math.floor(params.createdAt.getTime() / 1e3)};keyid="${state.keyId}";nonce="${params.nonce}";alg="${ALGORITHM}"`;
51
+ const signatureBase = [
52
+ `"@method": ${request.method.toUpperCase()}`,
53
+ `"@target-uri": ${canonicalTargetUri(new URL(request.url))}`,
54
+ `"content-digest": ${contentDigest}`,
55
+ `"signature-agent": ${signatureAgent}`,
56
+ `"@signature-params": ${signatureParams}`
57
+ ].join("\n");
58
+ const signature = sign("sha256", Buffer.from(signatureBase, "utf8"), {
59
+ key: state.signingKey,
60
+ dsaEncoding: "ieee-p1363"
61
+ });
62
+ return {
63
+ "Content-Digest": contentDigest,
64
+ "Signature-Agent": signatureAgent,
65
+ "Signature-Input": `sig=${signatureParams}`,
66
+ Signature: `sig=:${signature.toString("base64")}:`
67
+ };
68
+ }
69
+ function contentDigestHeader(body) {
70
+ return `sha-256=:${createHash("sha256").update(body ?? "").digest("base64")}:`;
71
+ }
72
+ function canonicalTargetUri(url) {
73
+ return `${url.protocol}//${stripDefaultPort(url)}${url.pathname}${url.search}`;
74
+ }
75
+ function stripDefaultPort(url) {
76
+ const host = url.host.toLowerCase();
77
+ if (url.protocol === "https:" && url.port === "443" || url.protocol === "http:" && url.port === "80") return url.hostname.toLowerCase();
78
+ return host;
79
+ }
80
+ function p256SigningKey(point, privateKeyHex) {
81
+ return createPrivateKey({
82
+ key: {
83
+ kty: "EC",
84
+ crv: "P-256",
85
+ d: Buffer.from(privateKeyHex, "hex").toString("base64url"),
86
+ x: point.subarray(1, 33).toString("base64url"),
87
+ y: point.subarray(33, 65).toString("base64url")
88
+ },
89
+ format: "jwk"
90
+ });
91
+ }
92
+ //#endregion
93
+ //#region package.json
94
+ var version = "0.0.0-alpha-20260724191736";
95
+ //#endregion
96
+ //#region src/user-agent.ts
97
+ const HTTP_TOKEN_RE = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
98
+ const AGENT_CLIENT_VERSION = version;
99
+ function assertHttpToken(value, field) {
100
+ if (!HTTP_TOKEN_RE.test(value)) throw new Error(`${field} must be a valid HTTP token`);
101
+ }
102
+ function assertUaCommentSafe(value, field) {
103
+ let hasUnrepresentableCharacter = false;
104
+ for (let i = 0; i < value.length; i += 1) {
105
+ const code = value.charCodeAt(i);
106
+ if (code < 32 || code === 127 || code > 255) {
107
+ hasUnrepresentableCharacter = true;
108
+ break;
109
+ }
110
+ }
111
+ if (hasUnrepresentableCharacter || /[()\\]/.test(value)) throw new Error(`${field} must not contain parentheses, backslashes, control characters, or characters outside Latin-1`);
112
+ }
113
+ function buildUserAgent(appInfo) {
114
+ const sdkProduct = `catena-agent-client/${AGENT_CLIENT_VERSION}`;
115
+ if (!appInfo) return sdkProduct;
116
+ assertHttpToken(appInfo.name, "appInfo.name");
117
+ if (appInfo.version !== void 0) assertHttpToken(appInfo.version, "appInfo.version");
118
+ if (appInfo.url !== void 0) assertUaCommentSafe(appInfo.url, "appInfo.url");
119
+ const product = appInfo.version === void 0 ? appInfo.name : `${appInfo.name}/${appInfo.version}`;
120
+ return `${appInfo.url === void 0 ? product : `${product} (${appInfo.url})`} ${sdkProduct}`;
121
+ }
122
+ //#endregion
123
+ //#region src/schemas.ts
124
+ const moneyJsonSchema = v.object({
125
+ amount: v.string(),
126
+ asset_id: v.string()
127
+ });
128
+ const isoTimestampSchema = v.pipe(v.string(), v.isoTimestamp());
129
+ const okSuccessResponseSchema = v.object({ success: v.literal(true) });
130
+ const agentSchema = v.object({
131
+ id: v.string(),
132
+ name: v.string(),
133
+ status: v.string(),
134
+ organizationId: v.string(),
135
+ operatorEmail: v.nullable(v.string())
136
+ });
137
+ const whoamiResponseSchema = v.object({ agent: agentSchema });
138
+ const policyRuleSchema = v.object({
139
+ id: v.string(),
140
+ ruleType: v.picklist([
141
+ "per_transaction_amount",
142
+ "daily_amount",
143
+ "weekly_amount",
144
+ "monthly_amount",
145
+ "hourly_count",
146
+ "daily_count"
147
+ ]),
148
+ thresholdAmount: v.optional(moneyJsonSchema),
149
+ thresholdCount: v.optional(v.number()),
150
+ action: v.picklist(["block", "require_approval"]),
151
+ requiredApprovals: v.number(),
152
+ accountAggregationScope: v.picklist(["per_account", "across_accounts"]),
153
+ actorAggregationScope: v.picklist(["per_agent", "per_policy"]),
154
+ displayOrder: v.number()
155
+ });
156
+ const policyCapabilitySchema = v.object({
157
+ id: v.string(),
158
+ organizationId: v.string(),
159
+ policyId: v.string(),
160
+ capability: v.picklist([
161
+ "query_balance",
162
+ "read",
163
+ "send",
164
+ "transfer"
165
+ ]),
166
+ accountId: v.string(),
167
+ rules: v.array(policyRuleSchema),
168
+ createdAt: isoTimestampSchema,
169
+ updatedAt: isoTimestampSchema
170
+ });
171
+ const counterpartyRulesSchema = v.object({
172
+ mode: v.picklist(["open", "restricted"]),
173
+ allowedCounterparties: v.optional(v.array(v.string())),
174
+ createAction: v.optional(v.picklist([
175
+ "allow",
176
+ "block",
177
+ "require_approval"
178
+ ])),
179
+ allowCreate: v.optional(v.boolean())
180
+ });
181
+ const policySchema = v.object({
182
+ id: v.optional(v.string()),
183
+ description: v.optional(v.string()),
184
+ version: v.optional(v.number()),
185
+ name: v.string(),
186
+ capabilities: v.array(v.string()),
187
+ counterpartyRules: v.optional(counterpartyRulesSchema),
188
+ policyCapabilities: v.array(policyCapabilitySchema)
189
+ });
190
+ const policyResponseSchema = v.object({ policy: policySchema });
191
+ const accountsResponseSchema = v.object({ accounts: v.array(v.object({
192
+ id: v.string(),
193
+ name: v.string(),
194
+ type: v.string(),
195
+ currency: v.string()
196
+ })) });
197
+ const accountBalanceResponseSchema = v.object({
198
+ accountId: v.string(),
199
+ balance: moneyJsonSchema,
200
+ balances: v.optional(v.object({
201
+ total: moneyJsonSchema,
202
+ available: moneyJsonSchema
203
+ }))
204
+ });
205
+ const accountTransactionSchema = v.object({
206
+ id: v.string(),
207
+ type: v.picklist([
208
+ "operator-send",
209
+ "operator-transfer",
210
+ "operator-deposit",
211
+ "operator-refund",
212
+ "microdeposit"
213
+ ]),
214
+ action: v.optional(v.string()),
215
+ status: v.picklist([
216
+ "pending",
217
+ "processing",
218
+ "completed",
219
+ "failed",
220
+ "reversed"
221
+ ]),
222
+ movementStatus: v.picklist([
223
+ "initiated",
224
+ "provider_pending",
225
+ "processing",
226
+ "completed",
227
+ "failed",
228
+ "reversed",
229
+ "manual_review"
230
+ ]),
231
+ direction: v.picklist(["incoming", "outgoing"]),
232
+ amount: moneyJsonSchema,
233
+ fee: moneyJsonSchema,
234
+ currency: v.string(),
235
+ counterpartyName: v.optional(v.string()),
236
+ method: v.optional(v.picklist([
237
+ "ach",
238
+ "wire",
239
+ "on-chain"
240
+ ])),
241
+ memo: v.optional(v.string()),
242
+ description: v.optional(v.string()),
243
+ txHash: v.optional(v.string()),
244
+ createdAt: isoTimestampSchema,
245
+ completedAt: v.optional(isoTimestampSchema)
246
+ });
247
+ const accountTransactionsResponseSchema = v.object({
248
+ accountId: v.string(),
249
+ transactions: v.array(accountTransactionSchema),
250
+ total: v.number()
251
+ });
252
+ const accountDepositAddressResponseSchema = v.object({
253
+ accountId: v.string(),
254
+ address: v.string(),
255
+ liquidationAddressId: v.optional(v.string()),
256
+ source: v.picklist(["wallet", "liquidation"])
257
+ });
258
+ const counterpartySchema = v.object({
259
+ id: v.string(),
260
+ name: v.string(),
261
+ rails: v.array(v.object({
262
+ id: v.string(),
263
+ type: v.string(),
264
+ walletAddress: v.optional(v.string()),
265
+ network: v.optional(v.string()),
266
+ bankName: v.optional(v.string()),
267
+ accountNumber: v.optional(v.string())
268
+ }))
269
+ });
270
+ const counterpartiesResponseSchema = v.object({ counterparties: v.array(counterpartySchema) });
271
+ const intentStatusSchema = v.picklist([
272
+ "pending",
273
+ "processing",
274
+ "completed",
275
+ "blocked",
276
+ "failed"
277
+ ]);
278
+ const intentNextActionSchema = v.object({
279
+ type: v.literal("submit_stamp"),
280
+ signingRequestId: v.string(),
281
+ signer: v.object({
282
+ algorithm: v.literal("p256"),
283
+ publicKeyHex: v.string()
284
+ }),
285
+ preparedBody: v.object({
286
+ body: v.string(),
287
+ bodyHash: v.string(),
288
+ expiresAt: isoTimestampSchema,
289
+ prepareToken: v.string()
290
+ })
291
+ });
292
+ const wireIntentResultSchema = v.object({
293
+ id: v.string(),
294
+ type: v.picklist([
295
+ "send",
296
+ "transfer",
297
+ "wallet_send",
298
+ "create_counterparty",
299
+ "x402"
300
+ ]),
301
+ status: intentStatusSchema,
302
+ reasons: v.array(v.string()),
303
+ expiresAt: v.optional(v.nullable(isoTimestampSchema), null),
304
+ data: v.optional(v.nullable(v.record(v.string(), v.unknown())), null),
305
+ metadata: v.optional(v.object({ dataUrl: v.nullable(v.string()) })),
306
+ nextAction: v.optional(intentNextActionSchema)
307
+ });
308
+ function toIntentResult(wire) {
309
+ const { nextAction: _nextAction, ...intent } = wire;
310
+ return intent;
311
+ }
312
+ const SEND_METHODS = [
313
+ "ach",
314
+ "wire",
315
+ "on-chain"
316
+ ];
317
+ const sendMethodSchema = v.picklist(SEND_METHODS);
318
+ const sendActionSchema = v.object({
319
+ type: v.literal("send"),
320
+ accountId: v.string(),
321
+ counterpartyRailId: v.string(),
322
+ amount: v.string(),
323
+ method: sendMethodSchema,
324
+ memo: v.optional(v.string()),
325
+ description: v.optional(v.string())
326
+ });
327
+ const transferActionSchema = v.object({
328
+ type: v.literal("transfer"),
329
+ accountId: v.string(),
330
+ toAccountId: v.string(),
331
+ amount: v.string(),
332
+ memo: v.optional(v.string()),
333
+ description: v.optional(v.string())
334
+ });
335
+ const createCounterpartyActionSchema = v.object({
336
+ type: v.literal("create_counterparty"),
337
+ name: v.string(),
338
+ email: v.optional(v.string()),
339
+ rail: v.unknown()
340
+ });
341
+ const x402PaymentRequirementsSchema = v.looseObject({
342
+ scheme: v.string(),
343
+ network: v.string(),
344
+ asset: v.string(),
345
+ amount: v.string(),
346
+ payTo: v.string(),
347
+ maxTimeoutSeconds: v.number()
348
+ });
349
+ const x402ResourceSchema = v.looseObject({
350
+ url: v.string(),
351
+ serviceName: v.fallback(v.optional(v.pipe(v.string(), v.maxLength(255))), void 0)
352
+ });
353
+ const x402ActionSchema = v.object({
354
+ type: v.literal("x402"),
355
+ accountId: v.string(),
356
+ paymentRequirements: x402PaymentRequirementsSchema,
357
+ resource: v.optional(x402ResourceSchema)
358
+ });
359
+ v.variant("type", [
360
+ sendActionSchema,
361
+ transferActionSchema,
362
+ createCounterpartyActionSchema,
363
+ x402ActionSchema
364
+ ]);
365
+ function toWireAction(action) {
366
+ if (action.type === "send" || action.type === "transfer") return {
367
+ ...action,
368
+ amount: {
369
+ amount: action.amount,
370
+ asset_id: "USD"
371
+ }
372
+ };
373
+ return action;
374
+ }
375
+ const submitStampResponseSchema = v.object({ intent: wireIntentResultSchema });
376
+ //#endregion
377
+ //#region src/client.ts
378
+ var ApiError = class extends Error {
379
+ status;
380
+ code;
381
+ constructor(status, message, code) {
382
+ super(code ? `API error ${status} [${code}]: ${message}` : `API error ${status}: ${message}`);
383
+ this.name = "ApiError";
384
+ this.status = status;
385
+ this.code = code;
386
+ }
387
+ };
388
+ const errorBodySchema = v.object({
389
+ error: v.nullish(v.string()),
390
+ message: v.nullish(v.string()),
391
+ code: v.nullish(v.string())
392
+ });
393
+ async function apiErrorFromResponse(res) {
394
+ const parsed = v.safeParse(errorBodySchema, await res.json().catch(() => void 0));
395
+ const body = parsed.success ? parsed.output : {};
396
+ if (body.error != null && body.message != null) return new ApiError(res.status, body.message, body.code ?? body.error);
397
+ return new ApiError(res.status, body.error ?? body.message ?? res.statusText, body.code ?? void 0);
398
+ }
399
+ async function parseApiResponse(res, schema) {
400
+ if (!res.ok) throw await apiErrorFromResponse(res);
401
+ return v.parse(schema, await res.json());
402
+ }
403
+ var IntentSubmitError = class extends Error {
404
+ intentId;
405
+ outcome;
406
+ constructor(params) {
407
+ const detail = params.cause instanceof Error ? params.cause.message : String(params.cause);
408
+ super(params.outcome === "not-submitted" ? `Intent ${params.intentId} was created but never submitted; no money moved: ${detail}` : `Intent ${params.intentId} submission could not be confirmed: ${detail}; poll getIntent("${params.intentId}") to a terminal status and resubmit only after blocked or failed`, { cause: params.cause });
409
+ this.name = "IntentSubmitError";
410
+ this.intentId = params.intentId;
411
+ this.outcome = params.outcome;
412
+ }
413
+ };
414
+ const DEFAULT_BASE_URL = "https://api.catena.com";
415
+ var CatenaClient = class {
416
+ #baseUrl;
417
+ #userAgent;
418
+ #defaultHeaders;
419
+ #keypair;
420
+ #signer;
421
+ #fetch;
422
+ constructor(opts) {
423
+ this.#baseUrl = opts.baseUrl ?? DEFAULT_BASE_URL;
424
+ this.#userAgent = buildUserAgent(opts.appInfo);
425
+ this.#defaultHeaders = opts.defaultHeaders ?? {};
426
+ this.#keypair = p256KeypairFromPrivateKeyHex(opts.privateKeyHex);
427
+ this.#fetch = (opts.fetch ?? globalThis.fetch).bind(globalThis);
428
+ this.#signer = createAgentRequestSigner({
429
+ keypair: this.#keypair,
430
+ baseUrl: this.#baseUrl,
431
+ identityUrl: opts.identityUrl
432
+ });
433
+ }
434
+ #buildRequestHeaders(requestHeaders) {
435
+ const headers = new Headers({ "Content-Type": "application/json" });
436
+ for (const [name, value] of Object.entries(this.#defaultHeaders)) headers.set(name, value);
437
+ for (const [name, value] of Object.entries(requestHeaders ?? {})) headers.set(name, value);
438
+ headers.set("User-Agent", this.#userAgent);
439
+ headers.delete("Authorization");
440
+ return headers;
441
+ }
442
+ async #signedRequest(options) {
443
+ const url = new URL(`${this.#baseUrl}/v1/agent-api${options.path}`);
444
+ for (const [key, value] of Object.entries(options.query ?? {})) if (value !== void 0) url.searchParams.set(key, value);
445
+ const request = new Request(url, {
446
+ method: options.method,
447
+ headers: this.#buildRequestHeaders(options.headers),
448
+ body: options.body !== void 0 ? JSON.stringify(options.body) : null
449
+ });
450
+ return this.#signer.sign(request);
451
+ }
452
+ async #request(options, schema) {
453
+ return parseApiResponse(await this.#fetch(await this.#signedRequest(options)), schema);
454
+ }
455
+ async whoami() {
456
+ return (await this.#request({
457
+ method: "GET",
458
+ path: "/me"
459
+ }, whoamiResponseSchema)).agent;
460
+ }
461
+ async submitFeedback(body) {
462
+ await this.#request({
463
+ method: "POST",
464
+ path: "/feedback",
465
+ body: { body }
466
+ }, okSuccessResponseSchema);
467
+ }
468
+ async getPolicy() {
469
+ return (await this.#request({
470
+ method: "GET",
471
+ path: "/policy"
472
+ }, policyResponseSchema)).policy;
473
+ }
474
+ async listAccounts() {
475
+ return this.#request({
476
+ method: "GET",
477
+ path: "/accounts"
478
+ }, accountsResponseSchema);
479
+ }
480
+ async getAccountBalance(accountId) {
481
+ return this.#request({
482
+ method: "GET",
483
+ path: `/accounts/${encodeURIComponent(accountId)}/balance`
484
+ }, accountBalanceResponseSchema);
485
+ }
486
+ async listAccountTransactions(accountId, params = {}) {
487
+ return this.#request({
488
+ method: "GET",
489
+ path: `/accounts/${encodeURIComponent(accountId)}/transactions`,
490
+ query: {
491
+ start: params.start,
492
+ end: params.end,
493
+ limit: params.limit?.toString(),
494
+ offset: params.offset?.toString()
495
+ }
496
+ }, accountTransactionsResponseSchema);
497
+ }
498
+ async getAccountDepositAddress(accountId, params) {
499
+ return this.#request({
500
+ method: "GET",
501
+ path: `/accounts/${encodeURIComponent(accountId)}/deposit-address`,
502
+ query: {
503
+ network: params.network,
504
+ asset: params.asset
505
+ }
506
+ }, accountDepositAddressResponseSchema);
507
+ }
508
+ async listCounterparties(params = {}) {
509
+ return this.#request({
510
+ method: "GET",
511
+ path: "/counterparties",
512
+ query: {
513
+ address: params.address,
514
+ network: params.network
515
+ }
516
+ }, counterpartiesResponseSchema);
517
+ }
518
+ async submitIntent(params) {
519
+ const created = await this.#createIntentRaw(params);
520
+ const nextAction = created.nextAction;
521
+ if (!nextAction) return toIntentResult(created);
522
+ let submitRequest;
523
+ try {
524
+ const stamp = await this.#stampNextAction(nextAction);
525
+ submitRequest = await this.#signedRequest({
526
+ method: "POST",
527
+ path: `/intents/${encodeURIComponent(created.id)}/submit-stamp`,
528
+ body: {
529
+ preparedBody: nextAction.preparedBody,
530
+ stamp
531
+ }
532
+ });
533
+ } catch (cause) {
534
+ throw new IntentSubmitError({
535
+ intentId: created.id,
536
+ outcome: "not-submitted",
537
+ cause
538
+ });
539
+ }
540
+ try {
541
+ return await this.#submitStamp(submitRequest);
542
+ } catch (cause) {
543
+ throw new IntentSubmitError({
544
+ intentId: created.id,
545
+ outcome: "unknown",
546
+ cause
547
+ });
548
+ }
549
+ }
550
+ async #createIntentRaw(params) {
551
+ return this.#request({
552
+ method: "POST",
553
+ path: "/intents",
554
+ body: { action: toWireAction(params.action) },
555
+ ...params.idempotencyKey !== void 0 && { headers: { "Idempotency-Key": params.idempotencyKey } }
556
+ }, wireIntentResultSchema);
557
+ }
558
+ async #stampNextAction(nextAction) {
559
+ if (nextAction.signer.publicKeyHex.toLowerCase() !== this.#keypair.publicKeyHex.toLowerCase()) throw new Error(`Local signer public key does not match requested signer ${nextAction.signer.publicKeyHex}; linked credential has ${this.#keypair.publicKeyHex}`);
560
+ const stamp = await new ApiKeyStamper({
561
+ apiPublicKey: this.#keypair.publicKeyHex,
562
+ apiPrivateKey: this.#keypair.privateKeyHex
563
+ }).stamp(nextAction.preparedBody.body);
564
+ return {
565
+ publicKeyHex: this.#keypair.publicKeyHex,
566
+ stampHeaderName: stamp.stampHeaderName,
567
+ stampHeaderValue: stamp.stampHeaderValue
568
+ };
569
+ }
570
+ async #submitStamp(request) {
571
+ return toIntentResult((await parseApiResponse(await this.#fetch(request), submitStampResponseSchema)).intent);
572
+ }
573
+ async getIntent(id) {
574
+ return toIntentResult(await this.#request({
575
+ method: "GET",
576
+ path: `/intents/${encodeURIComponent(id)}`
577
+ }, wireIntentResultSchema));
578
+ }
579
+ async unlinkAgent() {
580
+ await this.#request({
581
+ method: "POST",
582
+ path: "/unlink"
583
+ }, okSuccessResponseSchema);
584
+ }
585
+ async reportSettlement(params) {
586
+ await this.#request({
587
+ method: "POST",
588
+ path: `/intents/${encodeURIComponent(params.intentId)}/settlement-report`,
589
+ body: { txHash: params.txHash }
590
+ }, okSuccessResponseSchema);
591
+ }
592
+ };
593
+ function createCatenaClient(options) {
594
+ return new CatenaClient(options);
595
+ }
596
+ //#endregion
597
+ export { x402PaymentRequirementsSchema as a, SEND_METHODS as i, IntentSubmitError as n, x402ResourceSchema as o, createCatenaClient as r, ApiError as t };
@@ -0,0 +1,2 @@
1
+ import { C as SendMethod, E as AppInfo, S as SEND_METHODS, T as X402Resource, _ as IntentAction, a as IntentSubmitError, b as OnchainNetworkInput, c as AccountDepositAddressParams, d as AccountTransactionsResponse, f as AccountsResponse, g as Counterparty, h as CounterpartiesResponse, i as FetchLike, l as AccountDepositAddressResponse, m as CounterpartiesParams, n as CatenaClient, o as createCatenaClient, p as Agent, r as CatenaClientOptions, s as AccountBalanceResponse, t as ApiError, u as AccountTransactionsParams, v as IntentResult, w as X402PaymentRequirements, x as Policy, y as OnchainAssetInput } from "./client-DZHdFs_y.mjs";
2
+ export { type AccountBalanceResponse, type AccountDepositAddressParams, type AccountDepositAddressResponse, type AccountTransactionsParams, type AccountTransactionsResponse, type AccountsResponse, type Agent, ApiError, type AppInfo, type CatenaClient, CatenaClientOptions, type CounterpartiesParams, type CounterpartiesResponse, type Counterparty, FetchLike, type IntentAction, type IntentResult, IntentSubmitError, type OnchainAssetInput, type OnchainNetworkInput, type Policy, SEND_METHODS, type SendMethod, type X402PaymentRequirements, type X402Resource, createCatenaClient };
@@ -0,0 +1,2 @@
1
+ import { i as SEND_METHODS, n as IntentSubmitError, r as createCatenaClient, t as ApiError } from "./client-G-8NfBx_.mjs";
2
+ export { ApiError, IntentSubmitError, SEND_METHODS, createCatenaClient };
@@ -0,0 +1,29 @@
1
+ //#region src/keypair.d.ts
2
+ interface P256Keypair {
3
+ algorithm: "p256";
4
+ privateKeyHex: string;
5
+ publicKeyHex: string;
6
+ }
7
+ /**
8
+ * Generate a fresh agent credential. Feed `privateKeyHex` to
9
+ * `createCatenaClient`; the public half (or its thumbprint) is what gets
10
+ * registered with Catena when the agent is linked. The SDK never persists
11
+ * keys — storage is the caller's responsibility.
12
+ */
13
+ declare function generateP256Keypair(): P256Keypair;
14
+ /**
15
+ * Derive the full keypair from the private scalar alone, so a corrupt key
16
+ * throws at construction instead of surfacing as bank-side invalid_signature
17
+ * 401s — and a mismatched pair cannot exist at all.
18
+ */
19
+ declare function p256KeypairFromPrivateKeyHex(privateKeyHex: string): P256Keypair;
20
+ declare function p256PointFromCompressedHex(publicKeyHex: string): Buffer | null;
21
+ /**
22
+ * RFC 7638 JWK thumbprint of a P-256 public key — the stable id the API
23
+ * knows a linked credential by. Returns null when the input is not a valid
24
+ * P-256 point.
25
+ */
26
+ declare function computeP256PublicKeyThumbprint(publicKeyHex: string): string | null;
27
+ declare function p256PublicKeyThumbprintFromPoint(point: Buffer): string;
28
+ //#endregion
29
+ export { P256Keypair, computeP256PublicKeyThumbprint, generateP256Keypair, p256KeypairFromPrivateKeyHex, p256PointFromCompressedHex, p256PublicKeyThumbprintFromPoint };
@@ -0,0 +1,43 @@
1
+ import { ECDH, createECDH, createHash } from "node:crypto";
2
+ //#region src/keypair.ts
3
+ function generateP256Keypair() {
4
+ const ecdh = createECDH("prime256v1");
5
+ ecdh.generateKeys();
6
+ return p256KeypairFromPrivateKeyHex(ecdh.getPrivateKey().toString("hex").padStart(64, "0"));
7
+ }
8
+ const PRIVATE_KEY_HEX = /^[0-9a-f]{64}$/i;
9
+ function p256KeypairFromPrivateKeyHex(privateKeyHex) {
10
+ if (!PRIVATE_KEY_HEX.test(privateKeyHex)) throw new Error("P-256 private key must be 64 hex characters");
11
+ const normalized = privateKeyHex.toLowerCase();
12
+ const ecdh = createECDH("prime256v1");
13
+ try {
14
+ ecdh.setPrivateKey(Buffer.from(normalized, "hex"));
15
+ } catch {
16
+ throw new Error("value is not a valid P-256 private key (scalar out of range)");
17
+ }
18
+ return {
19
+ algorithm: "p256",
20
+ privateKeyHex: normalized,
21
+ publicKeyHex: ecdh.getPublicKey("hex", "compressed")
22
+ };
23
+ }
24
+ function p256PointFromCompressedHex(publicKeyHex) {
25
+ try {
26
+ const uncompressed = ECDH.convertKey(publicKeyHex, "prime256v1", "hex", "hex", "uncompressed");
27
+ const point = Buffer.isBuffer(uncompressed) ? uncompressed : Buffer.from(uncompressed, "hex");
28
+ return point.length === 65 ? point : null;
29
+ } catch {
30
+ return null;
31
+ }
32
+ }
33
+ function computeP256PublicKeyThumbprint(publicKeyHex) {
34
+ const point = p256PointFromCompressedHex(publicKeyHex);
35
+ return point === null ? null : p256PublicKeyThumbprintFromPoint(point);
36
+ }
37
+ function p256PublicKeyThumbprintFromPoint(point) {
38
+ const x = point.subarray(1, 33).toString("base64url");
39
+ const y = point.subarray(33, 65).toString("base64url");
40
+ return createHash("sha256").update(`{"crv":"P-256","kty":"EC","x":"${x}","y":"${y}"}`, "utf8").digest("base64url");
41
+ }
42
+ //#endregion
43
+ export { computeP256PublicKeyThumbprint, generateP256Keypair, p256KeypairFromPrivateKeyHex, p256PointFromCompressedHex, p256PublicKeyThumbprintFromPoint };