@paybond/kit 0.5.0 → 0.6.1
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 +1 -1
- package/dist/ed25519-sync.d.ts +1 -0
- package/dist/ed25519-sync.js +14 -0
- package/dist/index.d.ts +9 -6
- package/dist/index.js +9 -4
- package/dist/mcp-server.js +1 -1
- package/dist/payee-evidence.js +2 -0
- package/dist/principal-intent.d.ts +4 -3
- package/dist/principal-intent.js +11 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -111,7 +111,7 @@ Advanced exports:
|
|
|
111
111
|
|
|
112
112
|
`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.
|
|
113
113
|
|
|
114
|
-
`settlementRail` on intent creation is
|
|
114
|
+
`settlementRail` on intent creation is a principal-signed rail request. Stripe destinations and x402 receive addresses stay tenant-owned server-side config and are never supplied by the SDK caller.
|
|
115
115
|
|
|
116
116
|
The protocol-v2 surface is trust-first: signed mandates, recognition proofs, and receipts work across supported settlement adapters instead of treating any single rail as the product boundary.
|
|
117
117
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function ensureEd25519Sha512Sync(): void;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { etc } from "@noble/ed25519";
|
|
3
|
+
export function ensureEd25519Sha512Sync() {
|
|
4
|
+
if (etc.sha512Sync) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
etc.sha512Sync = (...messages) => {
|
|
8
|
+
const hash = createHash("sha512");
|
|
9
|
+
for (const message of messages) {
|
|
10
|
+
hash.update(message);
|
|
11
|
+
}
|
|
12
|
+
return new Uint8Array(hash.digest());
|
|
13
|
+
};
|
|
14
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -792,8 +792,8 @@ export declare class HarborClient {
|
|
|
792
792
|
*/
|
|
793
793
|
getLedgerAuthority(): Promise<Record<string, unknown>>;
|
|
794
794
|
/**
|
|
795
|
-
* `GET /ledger/v1/events`
|
|
796
|
-
* `limit` is clamped to 1
|
|
795
|
+
* `GET /ledger/v1/events` - protected Harbor append-only history for trusted clients.
|
|
796
|
+
* `afterSeq` is an exclusive cursor; `limit` is clamped to 1..256 to match Harbor.
|
|
797
797
|
*/
|
|
798
798
|
getLedgerEvents(options?: {
|
|
799
799
|
afterSeq?: number;
|
|
@@ -946,14 +946,17 @@ export declare class ServiceAccountFraudSession {
|
|
|
946
946
|
}
|
|
947
947
|
/**
|
|
948
948
|
* Parameters for {@link PaybondIntents.create} (tenant is taken from the bound Harbor client).
|
|
949
|
-
* `settlementRail
|
|
950
|
-
* from tenant-owned settlement config.
|
|
949
|
+
* `settlementRail` is principal-signed and requests one allowed rail; Harbor still resolves the
|
|
950
|
+
* destination from tenant-owned settlement config.
|
|
951
951
|
*/
|
|
952
952
|
export type PaybondCreateIntentParams = Omit<BuildSignedCreateIntentParams, "tenantId" | "intentId"> & {
|
|
953
953
|
intentId?: string;
|
|
954
954
|
};
|
|
955
955
|
/** Parameters for {@link PaybondIntents.submitEvidence} (tenant is taken from the bound Harbor client). */
|
|
956
|
-
export type PaybondSubmitEvidenceParams = Omit<SignPayeeEvidenceParams, "tenantId"
|
|
956
|
+
export type PaybondSubmitEvidenceParams = Omit<SignPayeeEvidenceParams, "tenantId" | "artifactsBlake3Hex" | "submittedAtRfc3339"> & {
|
|
957
|
+
artifactsBlake3Hex?: string[];
|
|
958
|
+
submittedAtRfc3339?: string;
|
|
959
|
+
};
|
|
957
960
|
/**
|
|
958
961
|
* Ergonomic intent helpers: principal-signed intent create, x402 funding, and payee-signed evidence.
|
|
959
962
|
*/
|
|
@@ -962,7 +965,7 @@ export declare class PaybondIntents {
|
|
|
962
965
|
constructor(harbor: HarborClient);
|
|
963
966
|
/**
|
|
964
967
|
* Build a principal-signed `POST /intents` body and submit it. `principalSigningSeed` must be
|
|
965
|
-
* 32 bytes. `settlementRail`
|
|
968
|
+
* 32 bytes. `settlementRail` is signed as the requested rail; destinations stay server-owned.
|
|
966
969
|
*/
|
|
967
970
|
create(params: PaybondCreateIntentParams & {
|
|
968
971
|
idempotencyKey?: string;
|
package/dist/index.js
CHANGED
|
@@ -613,8 +613,8 @@ export class HarborClient {
|
|
|
613
613
|
return body;
|
|
614
614
|
}
|
|
615
615
|
/**
|
|
616
|
-
* `GET /ledger/v1/events`
|
|
617
|
-
* `limit` is clamped to 1
|
|
616
|
+
* `GET /ledger/v1/events` - protected Harbor append-only history for trusted clients.
|
|
617
|
+
* `afterSeq` is an exclusive cursor; `limit` is clamped to 1..256 to match Harbor.
|
|
618
618
|
*/
|
|
619
619
|
async getLedgerEvents(options) {
|
|
620
620
|
const afterSeq = Math.max(0, Math.floor(options?.afterSeq ?? 0));
|
|
@@ -1527,6 +1527,9 @@ export class ServiceAccountFraudSession {
|
|
|
1527
1527
|
await Promise.resolve();
|
|
1528
1528
|
}
|
|
1529
1529
|
}
|
|
1530
|
+
function nowRfc3339Seconds() {
|
|
1531
|
+
return new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
1532
|
+
}
|
|
1530
1533
|
/**
|
|
1531
1534
|
* Ergonomic intent helpers: principal-signed intent create, x402 funding, and payee-signed evidence.
|
|
1532
1535
|
*/
|
|
@@ -1537,7 +1540,7 @@ export class PaybondIntents {
|
|
|
1537
1540
|
}
|
|
1538
1541
|
/**
|
|
1539
1542
|
* Build a principal-signed `POST /intents` body and submit it. `principalSigningSeed` must be
|
|
1540
|
-
* 32 bytes. `settlementRail`
|
|
1543
|
+
* 32 bytes. `settlementRail` is signed as the requested rail; destinations stay server-owned.
|
|
1541
1544
|
*/
|
|
1542
1545
|
async create(params) {
|
|
1543
1546
|
const { idempotencyKey, intentId: maybeIntentId, ...fields } = params;
|
|
@@ -1562,9 +1565,11 @@ export class PaybondIntents {
|
|
|
1562
1565
|
* Sign payee evidence and POST it. `payeeSigningSeed` must be 32 bytes.
|
|
1563
1566
|
*/
|
|
1564
1567
|
async submitEvidence(params) {
|
|
1565
|
-
const { idempotencyKey, ...rest } = params;
|
|
1568
|
+
const { idempotencyKey, artifactsBlake3Hex = [], submittedAtRfc3339 = nowRfc3339Seconds(), ...rest } = params;
|
|
1566
1569
|
const wire = signPayeeEvidenceBinding({
|
|
1567
1570
|
tenantId: this.harbor.tenantId,
|
|
1571
|
+
artifactsBlake3Hex,
|
|
1572
|
+
submittedAtRfc3339,
|
|
1568
1573
|
...rest,
|
|
1569
1574
|
});
|
|
1570
1575
|
return this.harbor.submitEvidence(rest.intentId, wire, { idempotencyKey });
|
package/dist/mcp-server.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { GatewayAuthError, GatewayFraudClient, GatewaySignalClient, HarborHttpError, ServiceAccountHarborSession, SignalHttpError, } from "./index.js";
|
|
3
3
|
const SERVER_NAME = "Paybond MCP";
|
|
4
|
-
const SERVER_VERSION = "0.
|
|
4
|
+
const SERVER_VERSION = "0.6.0";
|
|
5
5
|
const MCP_PROTOCOL_VERSION = "2025-11-25";
|
|
6
6
|
const DEFAULT_HARBOR_ACCESS_PATH = "/v1/auth/harbor-access";
|
|
7
7
|
const DEFAULT_PRINCIPAL_PATH = "/v1/auth/principal";
|
package/dist/payee-evidence.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { sign, getPublicKey } from "@noble/ed25519";
|
|
5
5
|
import { createHash } from "blake3";
|
|
6
6
|
import { parse as parseUuid } from "uuid";
|
|
7
|
+
import { ensureEd25519Sha512Sync } from "./ed25519-sync.js";
|
|
7
8
|
import { jsonValueDigest } from "./json-digest.js";
|
|
8
9
|
function concatBytes(...parts) {
|
|
9
10
|
const n = parts.reduce((a, p) => a + p.length, 0);
|
|
@@ -65,6 +66,7 @@ export function signPayeeEvidenceBinding(params) {
|
|
|
65
66
|
if (params.payeeSigningSeed.length !== 32) {
|
|
66
67
|
throw new Error("payeeSigningSeed must be 32 bytes");
|
|
67
68
|
}
|
|
69
|
+
ensureEd25519Sha512Sync();
|
|
68
70
|
const artifactBin = params.artifactsBlake3Hex.map((h) => hexToBytes(h));
|
|
69
71
|
const payloadDigest = jsonValueDigest(params.payload);
|
|
70
72
|
const artDigest = artifactsDigest(artifactBin);
|
|
@@ -17,6 +17,7 @@ export declare function intentCreationSignBytesRaw(input: {
|
|
|
17
17
|
predicate: Record<string, unknown>;
|
|
18
18
|
predicateRef: string;
|
|
19
19
|
allowedTools: string[];
|
|
20
|
+
settlementRail: SettlementRail;
|
|
20
21
|
}): Uint8Array;
|
|
21
22
|
export type BuildSignedCreateIntentParams = {
|
|
22
23
|
tenantId: string;
|
|
@@ -32,11 +33,11 @@ export type BuildSignedCreateIntentParams = {
|
|
|
32
33
|
deadlineRfc3339: string;
|
|
33
34
|
allowedTools: string[];
|
|
34
35
|
predicateRef?: string;
|
|
35
|
-
/**
|
|
36
|
-
settlementRail
|
|
36
|
+
/** Rail request for the new intent. Harbor resolves the destination server-side. */
|
|
37
|
+
settlementRail: SettlementRail;
|
|
37
38
|
};
|
|
38
39
|
/**
|
|
39
40
|
* Build a Harbor `POST /intents` JSON body with principal Ed25519 detached signature.
|
|
40
|
-
* `settlementRail`
|
|
41
|
+
* `settlementRail` is included in the signature; destinations remain tenant-owned server-side.
|
|
41
42
|
*/
|
|
42
43
|
export declare function buildSignedCreateIntentBody(params: BuildSignedCreateIntentParams): Record<string, unknown>;
|
package/dist/principal-intent.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { sign, getPublicKey } from "@noble/ed25519";
|
|
6
6
|
import { parse as parseUuid } from "uuid";
|
|
7
|
+
import { ensureEd25519Sha512Sync } from "./ed25519-sync.js";
|
|
7
8
|
import { jsonValueDigest } from "./json-digest.js";
|
|
8
9
|
const SETTLEMENT_RAIL_VALUES = new Set(["stripe_connect", "x402_usdc_base"]);
|
|
9
10
|
function validateSettlementRail(value) {
|
|
@@ -49,15 +50,15 @@ function allowedToolsDigest(tools) {
|
|
|
49
50
|
.filter((v, i, a) => a.indexOf(v) === i);
|
|
50
51
|
return jsonValueDigest(sorted);
|
|
51
52
|
}
|
|
52
|
-
/** Bincode payload for principal intent creation (wire format revision byte `
|
|
53
|
+
/** Bincode payload for principal intent creation (wire format revision byte `4`). */
|
|
53
54
|
function encodeIntentCreationSign(input) {
|
|
54
|
-
const version = new Uint8Array([
|
|
55
|
+
const version = new Uint8Array([4]);
|
|
55
56
|
const intentBytes = parseUuid(input.intentId);
|
|
56
57
|
if (intentBytes.length !== 16) {
|
|
57
58
|
throw new Error("intentId must be a UUID string");
|
|
58
59
|
}
|
|
59
60
|
// Serde `Uuid` + bincode uses a u64 length prefix (16) before the raw 16 bytes (matches Rust).
|
|
60
|
-
return concatBytes(version, encodeBincodeString(input.tenantId), encodeU64(16), intentBytes, encodeBincodeString(input.principalDid), encodeBincodeString(input.payeeDid), encodeI64(input.amountCents), encodeBincodeString(input.currency), encodeBincodeString(input.deadlineRfc3339), input.budgetDigest, input.evidenceSchemaDigest, input.predicateDslDigest, encodeBincodeString(input.predicateRef), input.allowedToolsDigest);
|
|
61
|
+
return concatBytes(version, encodeBincodeString(input.tenantId), encodeU64(16), intentBytes, encodeBincodeString(input.principalDid), encodeBincodeString(input.payeeDid), encodeI64(input.amountCents), encodeBincodeString(input.currency), encodeBincodeString(input.deadlineRfc3339), input.budgetDigest, input.evidenceSchemaDigest, input.predicateDslDigest, encodeBincodeString(input.predicateRef), input.allowedToolsDigest, encodeBincodeString(input.settlementRail));
|
|
61
62
|
}
|
|
62
63
|
export function intentCreationSignBytesRaw(input) {
|
|
63
64
|
const budgetDigest = jsonValueDigest(input.budget);
|
|
@@ -77,6 +78,7 @@ export function intentCreationSignBytesRaw(input) {
|
|
|
77
78
|
predicateDslDigest,
|
|
78
79
|
predicateRef: input.predicateRef,
|
|
79
80
|
allowedToolsDigest: allowedDigest,
|
|
81
|
+
settlementRail: input.settlementRail,
|
|
80
82
|
});
|
|
81
83
|
}
|
|
82
84
|
function bytesToBase64(bytes) {
|
|
@@ -87,7 +89,7 @@ function bytesToBase64(bytes) {
|
|
|
87
89
|
}
|
|
88
90
|
/**
|
|
89
91
|
* Build a Harbor `POST /intents` JSON body with principal Ed25519 detached signature.
|
|
90
|
-
* `settlementRail`
|
|
92
|
+
* `settlementRail` is included in the signature; destinations remain tenant-owned server-side.
|
|
91
93
|
*/
|
|
92
94
|
export function buildSignedCreateIntentBody(params) {
|
|
93
95
|
if (params.principalSigningSeed.length !== 32) {
|
|
@@ -96,10 +98,9 @@ export function buildSignedCreateIntentBody(params) {
|
|
|
96
98
|
if (params.allowedTools.length === 0) {
|
|
97
99
|
throw new Error("allowedTools must be non-empty");
|
|
98
100
|
}
|
|
99
|
-
const settlementRail = params.settlementRail
|
|
100
|
-
? validateSettlementRail(params.settlementRail)
|
|
101
|
-
: undefined;
|
|
101
|
+
const settlementRail = validateSettlementRail(params.settlementRail);
|
|
102
102
|
const predicateRef = params.predicateRef ?? "";
|
|
103
|
+
ensureEd25519Sha512Sync();
|
|
103
104
|
const msg = intentCreationSignBytesRaw({
|
|
104
105
|
tenantId: params.tenantId,
|
|
105
106
|
intentId: params.intentId,
|
|
@@ -113,6 +114,7 @@ export function buildSignedCreateIntentBody(params) {
|
|
|
113
114
|
predicate: params.predicate,
|
|
114
115
|
predicateRef,
|
|
115
116
|
allowedTools: params.allowedTools,
|
|
117
|
+
settlementRail,
|
|
116
118
|
});
|
|
117
119
|
const sig = sign(msg, params.principalSigningSeed);
|
|
118
120
|
const pub = getPublicKey(params.principalSigningSeed);
|
|
@@ -128,15 +130,13 @@ export function buildSignedCreateIntentBody(params) {
|
|
|
128
130
|
evidence_schema: params.evidenceSchema,
|
|
129
131
|
deadline: params.deadlineRfc3339,
|
|
130
132
|
predicate_dsl: params.predicate,
|
|
131
|
-
|
|
133
|
+
settlement_rail: settlementRail,
|
|
134
|
+
signing_version: 4,
|
|
132
135
|
policy_binding: null,
|
|
133
136
|
allowed_tools: params.allowedTools,
|
|
134
137
|
};
|
|
135
138
|
if (predicateRef.trim() !== "") {
|
|
136
139
|
body.predicate_ref = predicateRef;
|
|
137
140
|
}
|
|
138
|
-
if (settlementRail) {
|
|
139
|
-
body.settlement_rail = settlementRail;
|
|
140
|
-
}
|
|
141
141
|
return body;
|
|
142
142
|
}
|
package/package.json
CHANGED