@paybond/kit 0.2.1 → 0.3.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 +5 -3
- package/dist/index.d.ts +71 -5
- package/dist/index.js +158 -8
- package/dist/principal-intent.d.ts +5 -0
- package/dist/principal-intent.js +14 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# `@paybond/kit`
|
|
2
2
|
|
|
3
|
-
Paybond Kit for TypeScript provides a tenant-bound Harbor client, gateway-backed service-account sessions, capability verification, canonical signing helpers for intent creation and evidence submission, tenant-scoped ledger provenance reads, and tenant-scoped Signal analytics and reputation reads.
|
|
3
|
+
Paybond Kit for TypeScript provides a tenant-bound Harbor client, gateway-backed service-account sessions, capability verification, canonical signing helpers for intent creation and evidence submission, x402 / USDC-on-Base intent funding helpers, tenant-scoped ledger provenance reads, and tenant-scoped Signal analytics and reputation reads.
|
|
4
4
|
|
|
5
5
|
Install the public package with:
|
|
6
6
|
|
|
@@ -56,14 +56,16 @@ try {
|
|
|
56
56
|
## What the package includes
|
|
57
57
|
|
|
58
58
|
- `Paybond.open(...)` for gateway-authenticated, tenant-derived Harbor sessions
|
|
59
|
-
- `HarborClient` for capability verification, intent creation, evidence submission, and ledger reads
|
|
59
|
+
- `HarborClient` for capability verification, intent creation, x402 funding, evidence submission, and ledger reads
|
|
60
60
|
- `GatewaySignalClient` and `ServiceAccountSignalSession` for tenant-scoped Signal reads
|
|
61
61
|
- `paybond.signal` on `Paybond` sessions opened from one service-account API key
|
|
62
|
-
- `PaybondIntents` helpers for principal-signed intent creation and payee-signed evidence submission
|
|
62
|
+
- `PaybondIntents` helpers for principal-signed intent creation, x402 funding, and payee-signed evidence submission
|
|
63
63
|
- Low-level signing helpers exported for advanced callers
|
|
64
64
|
|
|
65
65
|
`allowedTools` values are your own tool or operation names, not a Paybond-owned catalog. Harbor enforces string matching against whatever names you chose when creating the intent.
|
|
66
66
|
|
|
67
|
+
`settlementRail` on intent creation is only a rail request. Stripe destinations and x402 receive addresses stay tenant-owned server-side config and are never supplied by the SDK caller.
|
|
68
|
+
|
|
67
69
|
## What it does not include
|
|
68
70
|
|
|
69
71
|
- No operator-tier settlement or console workflows
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Paybond Kit — TypeScript Harbor client with tenant binding, retries, optional upstream JWT,
|
|
3
3
|
* and gateway service-account token exchange (`POST /v1/auth/harbor-access`).
|
|
4
4
|
*/
|
|
5
|
-
import { type BuildSignedCreateIntentParams } from "./principal-intent.js";
|
|
5
|
+
import { type BuildSignedCreateIntentParams, type SettlementRail } from "./principal-intent.js";
|
|
6
6
|
import { type SignPayeeEvidenceParams } from "./payee-evidence.js";
|
|
7
7
|
export type VerifyCapabilityResult = {
|
|
8
8
|
allow: boolean;
|
|
@@ -18,6 +18,44 @@ export type SubmitEvidenceResult = {
|
|
|
18
18
|
state: string;
|
|
19
19
|
predicatePassed?: boolean;
|
|
20
20
|
};
|
|
21
|
+
export type IntentFundingResult = {
|
|
22
|
+
settlementRail: SettlementRail;
|
|
23
|
+
harborFundEndpoint?: string;
|
|
24
|
+
status?: string;
|
|
25
|
+
paymentSessionId?: string;
|
|
26
|
+
paymentUrl?: string;
|
|
27
|
+
asset?: string;
|
|
28
|
+
network?: string;
|
|
29
|
+
authorizationId?: string;
|
|
30
|
+
captureId?: string;
|
|
31
|
+
voidId?: string;
|
|
32
|
+
refundId?: string;
|
|
33
|
+
sourceAddress?: string;
|
|
34
|
+
targetAddress?: string;
|
|
35
|
+
authorizationExpiresAt?: string;
|
|
36
|
+
captureExpiresAt?: string;
|
|
37
|
+
refundExpiresAt?: string;
|
|
38
|
+
onchainTransactionHashes?: {
|
|
39
|
+
authorizations?: string[];
|
|
40
|
+
captures?: string[];
|
|
41
|
+
voids?: string[];
|
|
42
|
+
refunds?: string[];
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
export type FundIntentResult = {
|
|
46
|
+
statusCode: 200 | 202 | 402;
|
|
47
|
+
paymentRequired?: string;
|
|
48
|
+
paymentResponse?: string;
|
|
49
|
+
intentId: string;
|
|
50
|
+
tenant: string;
|
|
51
|
+
state: string;
|
|
52
|
+
settlementRail: SettlementRail;
|
|
53
|
+
currency: string;
|
|
54
|
+
amountCents: number;
|
|
55
|
+
funded: boolean;
|
|
56
|
+
capabilityToken?: string;
|
|
57
|
+
funding?: IntentFundingResult;
|
|
58
|
+
};
|
|
21
59
|
/** Async supplier for short-lived Harbor JWTs minted by the Paybond gateway. */
|
|
22
60
|
export type HarborBearerSupplier = () => Promise<string | null | undefined>;
|
|
23
61
|
/**
|
|
@@ -172,6 +210,21 @@ export declare class HarborClient {
|
|
|
172
210
|
createIntent(body: Record<string, unknown>, options?: {
|
|
173
211
|
idempotencyKey?: string;
|
|
174
212
|
}): Promise<Record<string, unknown>>;
|
|
213
|
+
/**
|
|
214
|
+
* POST `/intents/{intentId}/fund` for x402 / USDC-on-Base funding.
|
|
215
|
+
*
|
|
216
|
+
* Harbor returns:
|
|
217
|
+
* - `402` with `paymentRequired` details when a facilitator or wallet must sign
|
|
218
|
+
* - `202` while authorization is pending
|
|
219
|
+
* - `200` once the intent is funded and any capability token is available
|
|
220
|
+
*
|
|
221
|
+
* @throws HarborHttpError for non-funding HTTP errors
|
|
222
|
+
* @throws Error when Harbor echoes a different tenant or intent than requested
|
|
223
|
+
*/
|
|
224
|
+
fundIntent(intentId: string, options?: {
|
|
225
|
+
paymentSignature?: string;
|
|
226
|
+
idempotencyKey?: string;
|
|
227
|
+
}): Promise<FundIntentResult>;
|
|
175
228
|
/**
|
|
176
229
|
* POST `/intents/{intentId}/evidence` with a signed evidence JSON body.
|
|
177
230
|
*
|
|
@@ -240,24 +293,37 @@ export declare class ServiceAccountSignalSession {
|
|
|
240
293
|
static open(init: ServiceAccountSignalSessionInit): Promise<ServiceAccountSignalSession>;
|
|
241
294
|
aclose(): Promise<void>;
|
|
242
295
|
}
|
|
243
|
-
/**
|
|
296
|
+
/**
|
|
297
|
+
* Parameters for {@link PaybondIntents.create} (tenant is taken from the bound Harbor client).
|
|
298
|
+
* `settlementRail`, when set, requests one allowed rail; Harbor still resolves the destination
|
|
299
|
+
* from tenant-owned settlement config.
|
|
300
|
+
*/
|
|
244
301
|
export type PaybondCreateIntentParams = Omit<BuildSignedCreateIntentParams, "tenantId" | "intentId"> & {
|
|
245
302
|
intentId?: string;
|
|
246
303
|
};
|
|
247
304
|
/** Parameters for {@link PaybondIntents.submitEvidence} (tenant is taken from the bound Harbor client). */
|
|
248
305
|
export type PaybondSubmitEvidenceParams = Omit<SignPayeeEvidenceParams, "tenantId">;
|
|
249
306
|
/**
|
|
250
|
-
* Ergonomic intent helpers: principal-signed intent create and payee-signed evidence.
|
|
307
|
+
* Ergonomic intent helpers: principal-signed intent create, x402 funding, and payee-signed evidence.
|
|
251
308
|
*/
|
|
252
309
|
export declare class PaybondIntents {
|
|
253
310
|
private readonly harbor;
|
|
254
311
|
constructor(harbor: HarborClient);
|
|
255
312
|
/**
|
|
256
|
-
* Build a principal-signed `POST /intents` body and submit it. `principalSigningSeed` must be
|
|
313
|
+
* Build a principal-signed `POST /intents` body and submit it. `principalSigningSeed` must be
|
|
314
|
+
* 32 bytes. `settlementRail` only requests an allowed rail; destinations stay server-owned.
|
|
257
315
|
*/
|
|
258
316
|
create(params: PaybondCreateIntentParams & {
|
|
259
317
|
idempotencyKey?: string;
|
|
260
318
|
}): Promise<Record<string, unknown>>;
|
|
319
|
+
/**
|
|
320
|
+
* Advance Harbor `/intents/{id}/fund` for x402 / USDC-on-Base intents.
|
|
321
|
+
*/
|
|
322
|
+
fund(params: {
|
|
323
|
+
intentId: string;
|
|
324
|
+
paymentSignature?: string;
|
|
325
|
+
idempotencyKey?: string;
|
|
326
|
+
}): Promise<FundIntentResult>;
|
|
261
327
|
/**
|
|
262
328
|
* Sign payee evidence and POST it. `payeeSigningSeed` must be 32 bytes.
|
|
263
329
|
*/
|
|
@@ -281,5 +347,5 @@ export declare class Paybond {
|
|
|
281
347
|
aclose(): Promise<void>;
|
|
282
348
|
}
|
|
283
349
|
export { normalizeJson, jsonValueDigest } from "./json-digest.js";
|
|
284
|
-
export { buildSignedCreateIntentBody, intentCreationSignBytesRaw, type BuildSignedCreateIntentParams, } from "./principal-intent.js";
|
|
350
|
+
export { buildSignedCreateIntentBody, intentCreationSignBytesRaw, type BuildSignedCreateIntentParams, type SettlementRail, } from "./principal-intent.js";
|
|
285
351
|
export { artifactsDigest, signPayeeEvidenceBinding, type SignPayeeEvidenceParams } from "./payee-evidence.js";
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Paybond Kit — TypeScript Harbor client with tenant binding, retries, optional upstream JWT,
|
|
3
3
|
* and gateway service-account token exchange (`POST /v1/auth/harbor-access`).
|
|
4
4
|
*/
|
|
5
|
-
import { buildSignedCreateIntentBody } from "./principal-intent.js";
|
|
5
|
+
import { buildSignedCreateIntentBody, } from "./principal-intent.js";
|
|
6
6
|
import { signPayeeEvidenceBinding } from "./payee-evidence.js";
|
|
7
7
|
/**
|
|
8
8
|
* Structured HTTP failure from Harbor with operator-facing diagnostics.
|
|
@@ -292,7 +292,7 @@ export class HarborClient {
|
|
|
292
292
|
}
|
|
293
293
|
throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));
|
|
294
294
|
}
|
|
295
|
-
async fetchWithRetries(url, init, { retryBody }) {
|
|
295
|
+
async fetchWithRetries(url, init, { retryBody, retryBodyText, }) {
|
|
296
296
|
let lastErr;
|
|
297
297
|
for (let attempt = 0; attempt < this.maxRetries; attempt++) {
|
|
298
298
|
let res;
|
|
@@ -318,10 +318,18 @@ export class HarborClient {
|
|
|
318
318
|
const raSec = parseRetryAfterSeconds(res.headers.get("retry-after"));
|
|
319
319
|
const delayMs = raSec != null ? raSec * 1000 : backoffMs(attempt);
|
|
320
320
|
await new Promise((r) => setTimeout(r, delayMs));
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
321
|
+
if (retryBodyText !== undefined) {
|
|
322
|
+
init = {
|
|
323
|
+
...init,
|
|
324
|
+
body: retryBodyText,
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
else if (retryBody !== undefined) {
|
|
328
|
+
init = {
|
|
329
|
+
...init,
|
|
330
|
+
body: JSON.stringify(retryBody),
|
|
331
|
+
};
|
|
332
|
+
}
|
|
325
333
|
continue;
|
|
326
334
|
}
|
|
327
335
|
return res;
|
|
@@ -403,6 +411,79 @@ export class HarborClient {
|
|
|
403
411
|
}
|
|
404
412
|
return JSON.parse(text);
|
|
405
413
|
}
|
|
414
|
+
/**
|
|
415
|
+
* POST `/intents/{intentId}/fund` for x402 / USDC-on-Base funding.
|
|
416
|
+
*
|
|
417
|
+
* Harbor returns:
|
|
418
|
+
* - `402` with `paymentRequired` details when a facilitator or wallet must sign
|
|
419
|
+
* - `202` while authorization is pending
|
|
420
|
+
* - `200` once the intent is funded and any capability token is available
|
|
421
|
+
*
|
|
422
|
+
* @throws HarborHttpError for non-funding HTTP errors
|
|
423
|
+
* @throws Error when Harbor echoes a different tenant or intent than requested
|
|
424
|
+
*/
|
|
425
|
+
async fundIntent(intentId, options) {
|
|
426
|
+
const url = `${this.base}intents/${intentId}/fund`;
|
|
427
|
+
const headers = {
|
|
428
|
+
"x-tenant-id": this.tenantId,
|
|
429
|
+
};
|
|
430
|
+
if (options?.idempotencyKey?.trim()) {
|
|
431
|
+
headers["idempotency-key"] = options.idempotencyKey.trim();
|
|
432
|
+
}
|
|
433
|
+
if (options?.paymentSignature?.trim()) {
|
|
434
|
+
headers["payment-signature"] = options.paymentSignature.trim();
|
|
435
|
+
}
|
|
436
|
+
const res = await this.fetchWithRetries(url, {
|
|
437
|
+
method: "POST",
|
|
438
|
+
headers,
|
|
439
|
+
body: "",
|
|
440
|
+
}, { retryBodyText: "" });
|
|
441
|
+
const text = await res.text();
|
|
442
|
+
if (![200, 202, 402].includes(res.status)) {
|
|
443
|
+
throw new HarborHttpError(`Harbor fund intent HTTP ${res.status}: ${text}`, {
|
|
444
|
+
statusCode: res.status,
|
|
445
|
+
url,
|
|
446
|
+
bodyText: text,
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
const body = assertJSONObject(JSON.parse(text));
|
|
450
|
+
const tenant = String(body.tenant ?? "");
|
|
451
|
+
if (tenant !== this.tenantId) {
|
|
452
|
+
throw new Error(`fund tenant mismatch: client=${this.tenantId} harbor=${tenant}`);
|
|
453
|
+
}
|
|
454
|
+
const echoedIntentId = String(body.intent_id ?? "");
|
|
455
|
+
if (echoedIntentId !== intentId) {
|
|
456
|
+
throw new Error(`fund intent mismatch: requested=${intentId} harbor=${echoedIntentId}`);
|
|
457
|
+
}
|
|
458
|
+
if (typeof body.state !== "string" || !body.state.trim()) {
|
|
459
|
+
throw new Error("fund response missing state");
|
|
460
|
+
}
|
|
461
|
+
if (typeof body.currency !== "string" || !body.currency.trim()) {
|
|
462
|
+
throw new Error("fund response missing currency");
|
|
463
|
+
}
|
|
464
|
+
const amountCents = Number(body.amount_cents);
|
|
465
|
+
if (!Number.isFinite(amountCents)) {
|
|
466
|
+
throw new Error("fund response missing amount_cents");
|
|
467
|
+
}
|
|
468
|
+
return {
|
|
469
|
+
statusCode: res.status,
|
|
470
|
+
paymentRequired: res.headers.get("payment-required") ?? undefined,
|
|
471
|
+
paymentResponse: res.headers.get("payment-response") ?? undefined,
|
|
472
|
+
intentId: echoedIntentId,
|
|
473
|
+
tenant,
|
|
474
|
+
state: body.state,
|
|
475
|
+
settlementRail: readSettlementRailValue(body.settlement_rail, "fund settlement_rail"),
|
|
476
|
+
currency: body.currency,
|
|
477
|
+
amountCents,
|
|
478
|
+
funded: Boolean(body.funded),
|
|
479
|
+
capabilityToken: typeof body.capability_token === "string" && body.capability_token.trim()
|
|
480
|
+
? body.capability_token
|
|
481
|
+
: undefined,
|
|
482
|
+
funding: body.funding === undefined || body.funding === null
|
|
483
|
+
? undefined
|
|
484
|
+
: parseIntentFundingResult(body.funding),
|
|
485
|
+
};
|
|
486
|
+
}
|
|
406
487
|
/**
|
|
407
488
|
* POST `/intents/{intentId}/evidence` with a signed evidence JSON body.
|
|
408
489
|
*
|
|
@@ -523,12 +604,71 @@ export class HarborClient {
|
|
|
523
604
|
}
|
|
524
605
|
}
|
|
525
606
|
const DEFAULT_PRINCIPAL_PATH = "/v1/auth/principal";
|
|
607
|
+
const SETTLEMENT_RAIL_VALUES = new Set(["stripe_connect", "x402_usdc_base"]);
|
|
526
608
|
function assertJSONObject(value) {
|
|
527
609
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
528
610
|
throw new Error("expected JSON object");
|
|
529
611
|
}
|
|
530
612
|
return value;
|
|
531
613
|
}
|
|
614
|
+
function readSettlementRailValue(value, field) {
|
|
615
|
+
if (typeof value !== "string" || !SETTLEMENT_RAIL_VALUES.has(value)) {
|
|
616
|
+
throw new Error(`invalid ${field}`);
|
|
617
|
+
}
|
|
618
|
+
return value;
|
|
619
|
+
}
|
|
620
|
+
function readStringArrayValue(value, field) {
|
|
621
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
|
|
622
|
+
throw new Error(`invalid ${field}`);
|
|
623
|
+
}
|
|
624
|
+
return [...value];
|
|
625
|
+
}
|
|
626
|
+
function parseIntentFundingResult(value) {
|
|
627
|
+
const body = assertJSONObject(value);
|
|
628
|
+
const onchainRaw = body.onchain_transaction_hashes;
|
|
629
|
+
const onchain = onchainRaw === undefined || onchainRaw === null
|
|
630
|
+
? undefined
|
|
631
|
+
: (() => {
|
|
632
|
+
const parsed = assertJSONObject(onchainRaw);
|
|
633
|
+
return {
|
|
634
|
+
authorizations: parsed.authorizations === undefined
|
|
635
|
+
? undefined
|
|
636
|
+
: readStringArrayValue(parsed.authorizations, "funding.onchain_transaction_hashes.authorizations"),
|
|
637
|
+
captures: parsed.captures === undefined
|
|
638
|
+
? undefined
|
|
639
|
+
: readStringArrayValue(parsed.captures, "funding.onchain_transaction_hashes.captures"),
|
|
640
|
+
voids: parsed.voids === undefined
|
|
641
|
+
? undefined
|
|
642
|
+
: readStringArrayValue(parsed.voids, "funding.onchain_transaction_hashes.voids"),
|
|
643
|
+
refunds: parsed.refunds === undefined
|
|
644
|
+
? undefined
|
|
645
|
+
: readStringArrayValue(parsed.refunds, "funding.onchain_transaction_hashes.refunds"),
|
|
646
|
+
};
|
|
647
|
+
})();
|
|
648
|
+
const readOptionalString = (field) => {
|
|
649
|
+
const raw = body[field];
|
|
650
|
+
return typeof raw === "string" && raw.trim() ? raw : undefined;
|
|
651
|
+
};
|
|
652
|
+
return {
|
|
653
|
+
settlementRail: readSettlementRailValue(body.settlement_rail, "funding.settlement_rail"),
|
|
654
|
+
harborFundEndpoint: readOptionalString("harbor_fund_endpoint"),
|
|
655
|
+
status: readOptionalString("status"),
|
|
656
|
+
paymentSessionId: readOptionalString("payment_session_id"),
|
|
657
|
+
paymentUrl: readOptionalString("payment_url"),
|
|
658
|
+
asset: readOptionalString("asset"),
|
|
659
|
+
network: readOptionalString("network"),
|
|
660
|
+
authorizationId: readOptionalString("authorization_id"),
|
|
661
|
+
captureId: readOptionalString("capture_id"),
|
|
662
|
+
voidId: readOptionalString("void_id"),
|
|
663
|
+
refundId: readOptionalString("refund_id"),
|
|
664
|
+
sourceAddress: readOptionalString("source_address"),
|
|
665
|
+
targetAddress: readOptionalString("target_address"),
|
|
666
|
+
authorizationExpiresAt: readOptionalString("authorization_expires_at"),
|
|
667
|
+
captureExpiresAt: readOptionalString("capture_expires_at"),
|
|
668
|
+
refundExpiresAt: readOptionalString("refund_expires_at"),
|
|
669
|
+
onchainTransactionHashes: onchain,
|
|
670
|
+
};
|
|
671
|
+
}
|
|
532
672
|
/**
|
|
533
673
|
* Tenant-bound reader for gateway Signal routes.
|
|
534
674
|
*/
|
|
@@ -743,7 +883,7 @@ export class ServiceAccountSignalSession {
|
|
|
743
883
|
}
|
|
744
884
|
}
|
|
745
885
|
/**
|
|
746
|
-
* Ergonomic intent helpers: principal-signed intent create and payee-signed evidence.
|
|
886
|
+
* Ergonomic intent helpers: principal-signed intent create, x402 funding, and payee-signed evidence.
|
|
747
887
|
*/
|
|
748
888
|
export class PaybondIntents {
|
|
749
889
|
harbor;
|
|
@@ -751,7 +891,8 @@ export class PaybondIntents {
|
|
|
751
891
|
this.harbor = harbor;
|
|
752
892
|
}
|
|
753
893
|
/**
|
|
754
|
-
* Build a principal-signed `POST /intents` body and submit it. `principalSigningSeed` must be
|
|
894
|
+
* Build a principal-signed `POST /intents` body and submit it. `principalSigningSeed` must be
|
|
895
|
+
* 32 bytes. `settlementRail` only requests an allowed rail; destinations stay server-owned.
|
|
755
896
|
*/
|
|
756
897
|
async create(params) {
|
|
757
898
|
const { idempotencyKey, intentId: maybeIntentId, ...fields } = params;
|
|
@@ -763,6 +904,15 @@ export class PaybondIntents {
|
|
|
763
904
|
});
|
|
764
905
|
return this.harbor.createIntent(body, { idempotencyKey });
|
|
765
906
|
}
|
|
907
|
+
/**
|
|
908
|
+
* Advance Harbor `/intents/{id}/fund` for x402 / USDC-on-Base intents.
|
|
909
|
+
*/
|
|
910
|
+
async fund(params) {
|
|
911
|
+
return this.harbor.fundIntent(params.intentId, {
|
|
912
|
+
paymentSignature: params.paymentSignature,
|
|
913
|
+
idempotencyKey: params.idempotencyKey,
|
|
914
|
+
});
|
|
915
|
+
}
|
|
766
916
|
/**
|
|
767
917
|
* Sign payee evidence and POST it. `payeeSigningSeed` must be 32 bytes.
|
|
768
918
|
*/
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* Principal intent creation signing for raw `predicate_dsl` (no managed-policy binding).
|
|
3
3
|
* Matches `crates/harbor-intent-escrow/src/signing.rs` (`intent_creation_sign_bytes_raw`).
|
|
4
4
|
*/
|
|
5
|
+
/** Tenant-configured settlement rail names. Clients may request a rail, not a destination. */
|
|
6
|
+
export type SettlementRail = "stripe_connect" | "x402_usdc_base";
|
|
5
7
|
export declare function intentCreationSignBytesRaw(input: {
|
|
6
8
|
tenantId: string;
|
|
7
9
|
intentId: string;
|
|
@@ -30,8 +32,11 @@ export type BuildSignedCreateIntentParams = {
|
|
|
30
32
|
deadlineRfc3339: string;
|
|
31
33
|
allowedTools: string[];
|
|
32
34
|
predicateRef?: string;
|
|
35
|
+
/** Optional rail request for the new intent. Harbor resolves the destination server-side. */
|
|
36
|
+
settlementRail?: SettlementRail;
|
|
33
37
|
};
|
|
34
38
|
/**
|
|
35
39
|
* Build a Harbor `POST /intents` JSON body with principal Ed25519 detached signature.
|
|
40
|
+
* `settlementRail` only requests an allowed rail; destinations remain tenant-owned server-side.
|
|
36
41
|
*/
|
|
37
42
|
export declare function buildSignedCreateIntentBody(params: BuildSignedCreateIntentParams): Record<string, unknown>;
|
package/dist/principal-intent.js
CHANGED
|
@@ -5,6 +5,13 @@
|
|
|
5
5
|
import { sign, getPublicKey } from "@noble/ed25519";
|
|
6
6
|
import { parse as parseUuid } from "uuid";
|
|
7
7
|
import { jsonValueDigest } from "./json-digest.js";
|
|
8
|
+
const SETTLEMENT_RAIL_VALUES = new Set(["stripe_connect", "x402_usdc_base"]);
|
|
9
|
+
function validateSettlementRail(value) {
|
|
10
|
+
if (!SETTLEMENT_RAIL_VALUES.has(value)) {
|
|
11
|
+
throw new Error(`settlementRail must be one of ${[...SETTLEMENT_RAIL_VALUES].join(", ")}`);
|
|
12
|
+
}
|
|
13
|
+
return value;
|
|
14
|
+
}
|
|
8
15
|
function concatBytes(...parts) {
|
|
9
16
|
const n = parts.reduce((a, p) => a + p.length, 0);
|
|
10
17
|
const out = new Uint8Array(n);
|
|
@@ -80,6 +87,7 @@ function bytesToBase64(bytes) {
|
|
|
80
87
|
}
|
|
81
88
|
/**
|
|
82
89
|
* Build a Harbor `POST /intents` JSON body with principal Ed25519 detached signature.
|
|
90
|
+
* `settlementRail` only requests an allowed rail; destinations remain tenant-owned server-side.
|
|
83
91
|
*/
|
|
84
92
|
export function buildSignedCreateIntentBody(params) {
|
|
85
93
|
if (params.principalSigningSeed.length !== 32) {
|
|
@@ -88,6 +96,9 @@ export function buildSignedCreateIntentBody(params) {
|
|
|
88
96
|
if (params.allowedTools.length === 0) {
|
|
89
97
|
throw new Error("allowedTools must be non-empty");
|
|
90
98
|
}
|
|
99
|
+
const settlementRail = params.settlementRail
|
|
100
|
+
? validateSettlementRail(params.settlementRail)
|
|
101
|
+
: undefined;
|
|
91
102
|
const predicateRef = params.predicateRef ?? "";
|
|
92
103
|
const msg = intentCreationSignBytesRaw({
|
|
93
104
|
tenantId: params.tenantId,
|
|
@@ -124,5 +135,8 @@ export function buildSignedCreateIntentBody(params) {
|
|
|
124
135
|
if (predicateRef.trim() !== "") {
|
|
125
136
|
body.predicate_ref = predicateRef;
|
|
126
137
|
}
|
|
138
|
+
if (settlementRail) {
|
|
139
|
+
body.settlement_rail = settlementRail;
|
|
140
|
+
}
|
|
127
141
|
return body;
|
|
128
142
|
}
|
package/package.json
CHANGED