@paybond/kit 0.6.1 → 0.7.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # `@paybond/kit`
2
2
 
3
- Paybond Kit for TypeScript is the npm package for tenant-bound Paybond integrations. It opens gateway-authenticated Harbor sessions, verifies capability tokens, signs intent and evidence payloads, funds x402 / USDC-on-Base intents, and reads tenant-scoped Signal, fraud, ledger, protocol, and A2A data.
3
+ Paybond Kit for TypeScript is the npm package for tenant-bound Paybond integrations. It opens hosted Gateway sessions, verifies capability tokens, signs intent and evidence payloads, uses Stripe Connect or x402 / USDC-on-Base settlement rails, and reads tenant-scoped Signal, fraud, ledger, protocol, and A2A data.
4
4
 
5
5
  ## Install
6
6
 
@@ -17,17 +17,14 @@ npm install @paybond/kit
17
17
  ## Requirements
18
18
 
19
19
  - Node.js 22+
20
- - A `paybond_sk_...` service-account API key
21
- - Reachable Gateway and Harbor base URLs
20
+ - A `paybond_sk_sandbox_...` or `paybond_sk_live_...` service-account API key
22
21
  - For capability verification: a funded intent id and a capability token minted for that intent
23
22
  - For intent creation or evidence submission: 32-byte Ed25519 signing seeds owned by your application
24
23
 
25
24
  Minimal environment for the quick start:
26
25
 
27
26
  ```bash
28
- export PAYBOND_GATEWAY_URL="https://gateway.example.com"
29
- export PAYBOND_HARBOR_URL="https://harbor.example.com"
30
- export PAYBOND_API_KEY="paybond_sk_..."
27
+ export PAYBOND_API_KEY="paybond_sk_sandbox_..."
31
28
  ```
32
29
 
33
30
  Optional, if you want the quick start to verify a capability:
@@ -39,7 +36,7 @@ export PAYBOND_CAPABILITY="base64-biscuit-token"
39
36
 
40
37
  ## Tenant isolation
41
38
 
42
- Every session is bound to the tenant realm echoed by gateway-authenticated service-account introspection and Harbor access exchange flows.
39
+ Every session is bound to the tenant realm echoed by gateway-authenticated service-account introspection.
43
40
 
44
41
  - Do not pass tenant ids by hand for normal SDK usage.
45
42
  - Construct one `Paybond` session per tenant/service account.
@@ -59,9 +56,8 @@ function requiredEnv(name: string): string {
59
56
  }
60
57
 
61
58
  const paybond = await Paybond.open({
62
- gatewayBaseUrl: requiredEnv("PAYBOND_GATEWAY_URL"),
63
59
  apiKey: requiredEnv("PAYBOND_API_KEY"),
64
- harborBaseUrl: requiredEnv("PAYBOND_HARBOR_URL"),
60
+ expectedEnvironment: "sandbox",
65
61
  });
66
62
 
67
63
  try {
@@ -91,7 +87,7 @@ try {
91
87
 
92
88
  Core SDK:
93
89
 
94
- - `Paybond.open(...)` for gateway-authenticated, tenant-derived Harbor sessions
90
+ - `Paybond.open(...)` for API-key-only, tenant-derived hosted sessions
95
91
  - `HarborClient` for capability verification, intent creation, x402 funding, evidence submission, and ledger reads
96
92
  - `paybond.signal` and `paybond.fraud` on `Paybond` sessions opened from one service-account API key
97
93
  - `PaybondIntents` helpers for principal-signed intent creation, x402 funding, and payee-signed evidence submission
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Paybond Kit — TypeScript Harbor client with tenant binding, retries, optional upstream JWT,
3
- * and gateway service-account token exchange (`POST /v1/auth/harbor-access`).
2
+ * Paybond Kit — TypeScript Gateway client with tenant binding, retries, capability verification,
3
+ * and signed intent/evidence helpers.
4
4
  */
5
5
  import { type BuildSignedCreateIntentParams, type SettlementRail } from "./principal-intent.js";
6
6
  import { type SignPayeeEvidenceParams } from "./payee-evidence.js";
@@ -56,7 +56,8 @@ export type FundIntentResult = {
56
56
  capabilityToken?: string;
57
57
  funding?: IntentFundingResult;
58
58
  };
59
- /** Async supplier for short-lived Harbor JWTs minted by the Paybond gateway. */
59
+ export declare const DEFAULT_PAYBOND_GATEWAY_BASE_URL = "https://api.paybond.ai";
60
+ /** Async supplier for upstream Harbor bearer tokens on low-level direct clients. */
60
61
  export type HarborBearerSupplier = () => Promise<string | null | undefined>;
61
62
  /**
62
63
  * Structured HTTP failure from Harbor with operator-facing diagnostics.
@@ -72,7 +73,7 @@ export declare class HarborHttpError extends Error {
72
73
  });
73
74
  }
74
75
  /**
75
- * Gateway rejected the service-account exchange or returned an unusable harbor-access payload.
76
+ * Gateway rejected service-account credentials or returned an unusable tenant-principal payload.
76
77
  */
77
78
  export declare class GatewayAuthError extends Error {
78
79
  readonly statusCode: number | undefined;
@@ -642,72 +643,23 @@ export declare class ProtocolHttpError extends Error {
642
643
  errorMessage?: string;
643
644
  });
644
645
  }
645
- /**
646
- * Exchanges a `paybond_sk_` API key for short-lived Harbor JWTs and caches tenant realm from the
647
- * gateway response (no separate tenant env var for the default path).
648
- */
649
- export declare class GatewayHarborTokenProvider {
650
- private readonly gatewayBase;
651
- private readonly apiKey;
652
- private readonly path;
653
- private readonly skewMs;
654
- private readonly clock;
655
- private token;
656
- private tenantIdValue;
657
- private notAfterMonotonic;
658
- private refreshTail;
659
- constructor(init: {
660
- gatewayBaseUrl: string;
661
- apiKey: string;
662
- harborAccessPath?: string;
663
- clockSkewSeconds?: number;
664
- /** Injectable monotonic clock (milliseconds) for tests. */
665
- clock?: () => number;
666
- });
667
- get tenantId(): string | null;
668
- /**
669
- * First exchange; returns tenant realm echoed by the gateway.
670
- */
671
- ensureInitial(): Promise<string>;
672
- /** Return a valid Harbor JWT, refreshing when near expiry. */
673
- bearer(): Promise<string>;
674
- /** Force rotation (credential rotation drills). */
675
- forceRotate(): Promise<void>;
676
- private refresh;
677
- private refreshInner;
678
- }
646
+ export type PaybondEnvironment = "live" | "sandbox";
679
647
  /**
680
648
  * Tenant-scoped Harbor binding for one funded intent and one Biscuit capability token.
681
649
  */
682
650
  export declare class PaybondCapabilityBinding {
683
- readonly harbor: HarborClient;
651
+ readonly harbor: Pick<HarborClient | GatewayHarborClient, "tenantId" | "verifyCapability">;
684
652
  readonly intentId: string;
685
653
  readonly capabilityToken: string;
686
- constructor(harbor: HarborClient, intentId: string, capabilityToken: string);
654
+ constructor(harbor: Pick<HarborClient | GatewayHarborClient, "tenantId" | "verifyCapability">, intentId: string, capabilityToken: string);
687
655
  }
688
- export type ServiceAccountHarborSessionInit = {
689
- gatewayBaseUrl: string;
656
+ export type PaybondOpenOptions = {
690
657
  apiKey: string;
691
- harborBaseUrl: string;
692
- harborAccessPath?: string;
693
- clockSkewSeconds?: number;
658
+ gatewayBaseUrl?: string;
659
+ principalPath?: string;
660
+ expectedEnvironment?: PaybondEnvironment;
694
661
  maxRetries?: number;
695
662
  };
696
- /**
697
- * Harbor client plus gateway token lifecycle for one service account.
698
- */
699
- export declare class ServiceAccountHarborSession {
700
- readonly harbor: HarborClient;
701
- private readonly tokens;
702
- private constructor();
703
- /**
704
- * Build a tenant-bound {@link HarborClient} using gateway-derived tenant id and JWT supplier.
705
- */
706
- static open(init: ServiceAccountHarborSessionInit): Promise<ServiceAccountHarborSession>;
707
- rotateHarborToken(): Promise<void>;
708
- /** Reserved for future HTTP client cleanup; safe to call after work completes. */
709
- aclose(): Promise<void>;
710
- }
711
663
  type HarborClientOptions = {
712
664
  harborBearerSupplier?: HarborBearerSupplier;
713
665
  staticHarborBearerToken?: string;
@@ -804,6 +756,43 @@ export declare class HarborClient {
804
756
  */
805
757
  getLedgerMerkleLatest(): Promise<Record<string, unknown>>;
806
758
  }
759
+ type GatewayHarborClientOptions = {
760
+ staticGatewayBearerToken: string;
761
+ maxRetries?: number;
762
+ };
763
+ type GatewayHarborMutationOptions = {
764
+ idempotencyKey?: string;
765
+ recognitionProof?: AgentRecognitionProofV1 | Record<string, unknown>;
766
+ };
767
+ /**
768
+ * Gateway-backed Harbor surface for hosted Paybond integrations.
769
+ *
770
+ * This client sends the service-account API key to the public Gateway. Gateway derives tenant,
771
+ * mints upstream Harbor credentials internally, and applies recognition/guardrail checks before
772
+ * forwarding state-changing Harbor requests.
773
+ */
774
+ export declare class GatewayHarborClient {
775
+ private readonly base;
776
+ readonly tenantId: string;
777
+ private readonly staticGatewayBearerToken;
778
+ private readonly maxRetries;
779
+ constructor(gatewayBaseUrl: string, tenantId: string, options: GatewayHarborClientOptions);
780
+ private headers;
781
+ private fetchWithRetries;
782
+ private postJSON;
783
+ private mutationHeaders;
784
+ verifyCapability(input: {
785
+ intentId: string;
786
+ token: string;
787
+ operation: string;
788
+ requestedSpendCents?: number;
789
+ }): Promise<VerifyCapabilityResult>;
790
+ createIntent(body: Record<string, unknown>, options: GatewayHarborMutationOptions): Promise<Record<string, unknown>>;
791
+ fundIntent(intentId: string, options: GatewayHarborMutationOptions & {
792
+ paymentSignature?: string;
793
+ }): Promise<FundIntentResult>;
794
+ submitEvidence(intentId: string, evidenceBody: Record<string, unknown>, options: GatewayHarborMutationOptions): Promise<SubmitEvidenceResult>;
795
+ }
807
796
  type GatewaySignalClientOptions = {
808
797
  staticGatewayBearerToken: string;
809
798
  maxRetries?: number;
@@ -920,9 +909,10 @@ export declare class GatewayProtocolClient {
920
909
  }): Promise<Record<string, unknown>>;
921
910
  }
922
911
  export type ServiceAccountSignalSessionInit = {
923
- gatewayBaseUrl: string;
924
912
  apiKey: string;
913
+ gatewayBaseUrl?: string;
925
914
  principalPath?: string;
915
+ expectedEnvironment?: PaybondEnvironment;
926
916
  maxRetries?: number;
927
917
  };
928
918
  export type ServiceAccountFraudSessionInit = ServiceAccountSignalSessionInit;
@@ -951,18 +941,20 @@ export declare class ServiceAccountFraudSession {
951
941
  */
952
942
  export type PaybondCreateIntentParams = Omit<BuildSignedCreateIntentParams, "tenantId" | "intentId"> & {
953
943
  intentId?: string;
944
+ recognitionProof: AgentRecognitionProofV1 | Record<string, unknown>;
954
945
  };
955
946
  /** Parameters for {@link PaybondIntents.submitEvidence} (tenant is taken from the bound Harbor client). */
956
947
  export type PaybondSubmitEvidenceParams = Omit<SignPayeeEvidenceParams, "tenantId" | "artifactsBlake3Hex" | "submittedAtRfc3339"> & {
957
948
  artifactsBlake3Hex?: string[];
958
949
  submittedAtRfc3339?: string;
950
+ recognitionProof: AgentRecognitionProofV1 | Record<string, unknown>;
959
951
  };
960
952
  /**
961
953
  * Ergonomic intent helpers: principal-signed intent create, x402 funding, and payee-signed evidence.
962
954
  */
963
955
  export declare class PaybondIntents {
964
956
  private readonly harbor;
965
- constructor(harbor: HarborClient);
957
+ constructor(harbor: HarborClient | GatewayHarborClient);
966
958
  /**
967
959
  * Build a principal-signed `POST /intents` body and submit it. `principalSigningSeed` must be
968
960
  * 32 bytes. `settlementRail` is signed as the requested rail; destinations stay server-owned.
@@ -975,6 +967,7 @@ export declare class PaybondIntents {
975
967
  */
976
968
  fund(params: {
977
969
  intentId: string;
970
+ recognitionProof: AgentRecognitionProofV1 | Record<string, unknown>;
978
971
  paymentSignature?: string;
979
972
  idempotencyKey?: string;
980
973
  }): Promise<FundIntentResult>;
@@ -986,21 +979,19 @@ export declare class PaybondIntents {
986
979
  }): Promise<SubmitEvidenceResult>;
987
980
  }
988
981
  /**
989
- * High-level Kit entrypoint: same session lifecycle as {@link ServiceAccountHarborSession}, plus {@link PaybondIntents}.
982
+ * High-level Kit entrypoint: tenant-bound Gateway clients plus ergonomic intent helpers.
990
983
  */
991
984
  export declare class Paybond {
992
- readonly harbor: HarborClient;
985
+ readonly harbor: GatewayHarborClient;
993
986
  readonly signal: GatewaySignalClient;
994
987
  readonly fraud: GatewayFraudClient;
995
988
  readonly a2a: GatewayA2AClient;
996
989
  readonly protocol: GatewayProtocolClient;
997
990
  readonly intents: PaybondIntents;
998
- private readonly session;
999
991
  private constructor();
1000
- /** Open a tenant-bound session via gateway `harbor-access` exchange. */
1001
- static open(init: ServiceAccountHarborSessionInit): Promise<Paybond>;
1002
- rotateHarborToken(): Promise<void>;
1003
- /** Release HTTP resources (Harbor client + gateway token provider). */
992
+ /** Open a tenant-bound hosted Paybond session from a service-account API key. */
993
+ static open(init: PaybondOpenOptions): Promise<Paybond>;
994
+ /** Reserved for future HTTP client cleanup; safe to call after work completes. */
1004
995
  aclose(): Promise<void>;
1005
996
  }
1006
997
  export { normalizeJson, jsonValueDigest } from "./json-digest.js";
package/dist/index.js CHANGED
@@ -1,9 +1,14 @@
1
1
  /**
2
- * Paybond Kit — TypeScript Harbor client with tenant binding, retries, optional upstream JWT,
3
- * and gateway service-account token exchange (`POST /v1/auth/harbor-access`).
2
+ * Paybond Kit — TypeScript Gateway client with tenant binding, retries, capability verification,
3
+ * and signed intent/evidence helpers.
4
4
  */
5
5
  import { buildSignedCreateIntentBody, } from "./principal-intent.js";
6
6
  import { signPayeeEvidenceBinding } from "./payee-evidence.js";
7
+ export const DEFAULT_PAYBOND_GATEWAY_BASE_URL = "https://api.paybond.ai";
8
+ function defaultGatewayBaseUrl(value) {
9
+ const trimmed = value?.trim();
10
+ return trimmed ? trimmed : DEFAULT_PAYBOND_GATEWAY_BASE_URL;
11
+ }
7
12
  /**
8
13
  * Structured HTTP failure from Harbor with operator-facing diagnostics.
9
14
  */
@@ -20,7 +25,7 @@ export class HarborHttpError extends Error {
20
25
  }
21
26
  }
22
27
  /**
23
- * Gateway rejected the service-account exchange or returned an unusable harbor-access payload.
28
+ * Gateway rejected service-account credentials or returned an unusable tenant-principal payload.
24
29
  */
25
30
  export class GatewayAuthError extends Error {
26
31
  statusCode;
@@ -117,103 +122,26 @@ function parseRetryAfterSeconds(v) {
117
122
  return null;
118
123
  return Math.min(n, 30);
119
124
  }
120
- const DEFAULT_HARBOR_ACCESS_PATH = "/v1/auth/harbor-access";
121
- /**
122
- * Exchanges a `paybond_sk_` API key for short-lived Harbor JWTs and caches tenant realm from the
123
- * gateway response (no separate tenant env var for the default path).
124
- */
125
- export class GatewayHarborTokenProvider {
126
- gatewayBase;
127
- apiKey;
128
- path;
129
- skewMs;
130
- clock;
131
- token = null;
132
- tenantIdValue = null;
133
- notAfterMonotonic = 0;
134
- refreshTail = Promise.resolve();
135
- constructor(init) {
136
- this.gatewayBase = normalizeBase(init.gatewayBaseUrl);
137
- this.apiKey = init.apiKey.trim();
138
- const rawPath = (init.harborAccessPath ?? DEFAULT_HARBOR_ACCESS_PATH).trim();
139
- this.path = rawPath.startsWith("/") ? rawPath : `/${rawPath}`;
140
- this.skewMs = Math.max(0, (init.clockSkewSeconds ?? 90) * 1000);
141
- this.clock = init.clock ?? (() => performance.now());
142
- }
143
- get tenantId() {
144
- return this.tenantIdValue;
145
- }
146
- /**
147
- * First exchange; returns tenant realm echoed by the gateway.
148
- */
149
- async ensureInitial() {
150
- await this.refresh(true);
151
- if (!this.tenantIdValue) {
152
- throw new GatewayAuthError("harbor-access response missing tenant_id; upgrade gateway (PAYBOND-V1-008)");
153
- }
154
- return this.tenantIdValue;
155
- }
156
- /** Return a valid Harbor JWT, refreshing when near expiry. */
157
- async bearer() {
158
- await this.refresh(false);
159
- if (!this.token) {
160
- throw new GatewayAuthError("harbor-access did not return access_token");
161
- }
162
- return this.token;
163
- }
164
- /** Force rotation (credential rotation drills). */
165
- async forceRotate() {
166
- await this.refresh(true);
167
- }
168
- async refresh(force) {
169
- const job = this.refreshTail.then(() => this.refreshInner(force));
170
- this.refreshTail = job.then(() => undefined, () => undefined);
171
- await job;
125
+ function normalizeExpectedEnvironment(value) {
126
+ if (value === undefined)
127
+ return null;
128
+ const env = String(value).trim();
129
+ if (env === "live" || env === "sandbox") {
130
+ return env;
172
131
  }
173
- async refreshInner(force) {
174
- const now = this.clock();
175
- if (!force && this.token && now < this.notAfterMonotonic) {
176
- return;
177
- }
178
- const url = `${this.gatewayBase}${this.path}`;
179
- const res = await fetch(url, {
180
- method: "POST",
181
- headers: {
182
- authorization: `Bearer ${this.apiKey}`,
183
- accept: "application/json",
184
- },
132
+ throw new GatewayAuthError(`expectedEnvironment must be "live" or "sandbox", got ${JSON.stringify(value)}`);
133
+ }
134
+ function assertExpectedEnvironment(source, actualRaw, expected, bodyText) {
135
+ if (!expected)
136
+ return;
137
+ const actual = typeof actualRaw === "string" ? actualRaw.trim() : "";
138
+ if (!actual) {
139
+ throw new GatewayAuthError(`${source} response missing environment`, { bodyText });
140
+ }
141
+ if (actual !== expected) {
142
+ throw new GatewayAuthError(`${source} environment mismatch: expected=${expected} gateway=${actual}`, {
143
+ bodyText,
185
144
  });
186
- const text = await res.text();
187
- if (!res.ok) {
188
- throw new GatewayAuthError(`harbor-access HTTP ${res.status}`, {
189
- statusCode: res.status,
190
- bodyText: text,
191
- });
192
- }
193
- let body;
194
- try {
195
- body = JSON.parse(text);
196
- }
197
- catch {
198
- throw new GatewayAuthError("harbor-access response was not JSON", { bodyText: text });
199
- }
200
- const access = String(body.access_token ?? "").trim();
201
- if (!access) {
202
- throw new GatewayAuthError("harbor-access JSON missing access_token", { bodyText: text });
203
- }
204
- const expIn = Number(body.expires_in ?? 0);
205
- if (!Number.isFinite(expIn) || expIn <= 0) {
206
- throw new GatewayAuthError("harbor-access JSON missing expires_in", { bodyText: text });
207
- }
208
- const tidRaw = body.tenant_id;
209
- if (typeof tidRaw === "string" && tidRaw.trim()) {
210
- this.tenantIdValue = tidRaw.trim();
211
- }
212
- if (!this.tenantIdValue) {
213
- throw new GatewayAuthError("harbor-access response missing tenant_id; upgrade gateway (PAYBOND-V1-008)", { bodyText: text });
214
- }
215
- this.token = access;
216
- this.notAfterMonotonic = now + Math.max(1000, expIn * 1000 - this.skewMs);
217
145
  }
218
146
  }
219
147
  /**
@@ -229,41 +157,6 @@ export class PaybondCapabilityBinding {
229
157
  this.capabilityToken = capabilityToken;
230
158
  }
231
159
  }
232
- /**
233
- * Harbor client plus gateway token lifecycle for one service account.
234
- */
235
- export class ServiceAccountHarborSession {
236
- harbor;
237
- tokens;
238
- constructor(harbor, tokens) {
239
- this.harbor = harbor;
240
- this.tokens = tokens;
241
- }
242
- /**
243
- * Build a tenant-bound {@link HarborClient} using gateway-derived tenant id and JWT supplier.
244
- */
245
- static async open(init) {
246
- const tokens = new GatewayHarborTokenProvider({
247
- gatewayBaseUrl: init.gatewayBaseUrl,
248
- apiKey: init.apiKey,
249
- harborAccessPath: init.harborAccessPath,
250
- clockSkewSeconds: init.clockSkewSeconds,
251
- });
252
- const tenant = await tokens.ensureInitial();
253
- const harbor = new HarborClient(init.harborBaseUrl, tenant, {
254
- harborBearerSupplier: () => tokens.bearer(),
255
- maxRetries: init.maxRetries ?? 3,
256
- });
257
- return new ServiceAccountHarborSession(harbor, tokens);
258
- }
259
- async rotateHarborToken() {
260
- await this.tokens.forceRotate();
261
- }
262
- /** Reserved for future HTTP client cleanup; safe to call after work completes. */
263
- async aclose() {
264
- await Promise.resolve();
265
- }
266
- }
267
160
  /**
268
161
  * HTTP client for Harbor: capability verify, intents, evidence, and tenant-scoped ledger reads
269
162
  * (`GET /ledger/v1/*`, PAYBOND-007).
@@ -657,6 +550,152 @@ export class HarborClient {
657
550
  return body;
658
551
  }
659
552
  }
553
+ /**
554
+ * Gateway-backed Harbor surface for hosted Paybond integrations.
555
+ *
556
+ * This client sends the service-account API key to the public Gateway. Gateway derives tenant,
557
+ * mints upstream Harbor credentials internally, and applies recognition/guardrail checks before
558
+ * forwarding state-changing Harbor requests.
559
+ */
560
+ export class GatewayHarborClient {
561
+ base;
562
+ tenantId;
563
+ staticGatewayBearerToken;
564
+ maxRetries;
565
+ constructor(gatewayBaseUrl, tenantId, options) {
566
+ this.base = `${normalizeBase(gatewayBaseUrl)}/`;
567
+ this.tenantId = tenantId.trim();
568
+ this.staticGatewayBearerToken = options.staticGatewayBearerToken.trim();
569
+ this.maxRetries = Math.max(1, options.maxRetries ?? 3);
570
+ }
571
+ headers(extra) {
572
+ const headers = new Headers(extra);
573
+ headers.set("accept", "application/json");
574
+ headers.set("x-tenant-id", this.tenantId);
575
+ headers.set("authorization", `Bearer ${this.staticGatewayBearerToken}`);
576
+ return headers;
577
+ }
578
+ async fetchWithRetries(url, init) {
579
+ let lastErr;
580
+ for (let attempt = 0; attempt < this.maxRetries; attempt++) {
581
+ let res;
582
+ try {
583
+ res = await fetch(url, init);
584
+ }
585
+ catch (e) {
586
+ lastErr = e;
587
+ if (attempt + 1 >= this.maxRetries)
588
+ throw e;
589
+ await new Promise((r) => setTimeout(r, backoffMs(attempt)));
590
+ continue;
591
+ }
592
+ if ([429, 500, 502, 503, 504].includes(res.status) && attempt + 1 < this.maxRetries) {
593
+ const raSec = parseRetryAfterSeconds(res.headers.get("retry-after"));
594
+ const delayMs = raSec != null ? raSec * 1000 : backoffMs(attempt);
595
+ await new Promise((r) => setTimeout(r, delayMs));
596
+ continue;
597
+ }
598
+ return res;
599
+ }
600
+ throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));
601
+ }
602
+ async postJSON(path, payload, extraHeaders) {
603
+ const url = `${this.base}${path.replace(/^\/+/, "")}`;
604
+ const res = await this.fetchWithRetries(url, {
605
+ method: "POST",
606
+ headers: this.headers({
607
+ "content-type": "application/json",
608
+ ...(extraHeaders ?? {}),
609
+ }),
610
+ body: JSON.stringify(payload),
611
+ });
612
+ const text = await res.text();
613
+ return { res, text, url };
614
+ }
615
+ mutationHeaders(operation, options, headers) {
616
+ const proof = options?.recognitionProof;
617
+ if (!proof || typeof proof !== "object" || Array.isArray(proof)) {
618
+ throw new Error(`${operation} requires recognitionProof`);
619
+ }
620
+ return gatewayMutationHeaders(proof, {
621
+ ...(headers ?? {}),
622
+ ...(options?.idempotencyKey?.trim() ? { "idempotency-key": options.idempotencyKey.trim() } : {}),
623
+ });
624
+ }
625
+ async verifyCapability(input) {
626
+ const payload = {
627
+ intent_id: input.intentId,
628
+ token: input.token,
629
+ operation: input.operation,
630
+ requested_spend_cents: input.requestedSpendCents ?? 0,
631
+ };
632
+ const { res, text, url } = await this.postJSON("/verify", payload);
633
+ if (!res.ok) {
634
+ throw new HarborHttpError(`Gateway verify HTTP ${res.status}: ${text}`, {
635
+ statusCode: res.status,
636
+ url,
637
+ bodyText: text,
638
+ });
639
+ }
640
+ const body = JSON.parse(text);
641
+ if (body.tenant !== this.tenantId) {
642
+ throw new Error(`verify tenant mismatch: client=${this.tenantId} gateway=${body.tenant}`);
643
+ }
644
+ if (body.intent_id !== input.intentId) {
645
+ throw new Error(`verify intent mismatch: requested=${input.intentId} gateway=${body.intent_id}`);
646
+ }
647
+ return {
648
+ allow: body.allow,
649
+ auditId: body.audit_id,
650
+ tenant: body.tenant,
651
+ intentId: body.intent_id,
652
+ code: body.code,
653
+ message: body.message,
654
+ };
655
+ }
656
+ async createIntent(body, options) {
657
+ const { res, text, url } = await this.postJSON("/harbor/intents", body, this.mutationHeaders("createIntent", options));
658
+ if (!res.ok) {
659
+ throw new HarborHttpError(`Gateway Harbor create intent HTTP ${res.status}: ${text}`, {
660
+ statusCode: res.status,
661
+ url,
662
+ bodyText: text,
663
+ });
664
+ }
665
+ return JSON.parse(text);
666
+ }
667
+ async fundIntent(intentId, options) {
668
+ const { res, text, url } = await this.postJSON(`/harbor/intents/${encodeURIComponent(intentId)}/fund`, {}, this.mutationHeaders("fundIntent", options, {
669
+ ...(options.paymentSignature?.trim() ? { "payment-signature": options.paymentSignature.trim() } : {}),
670
+ }));
671
+ if (![200, 202, 402].includes(res.status)) {
672
+ throw new HarborHttpError(`Gateway Harbor fund intent HTTP ${res.status}: ${text}`, {
673
+ statusCode: res.status,
674
+ url,
675
+ bodyText: text,
676
+ });
677
+ }
678
+ return parseFundIntentResponse(assertJSONObject(JSON.parse(text)), {
679
+ tenantId: this.tenantId,
680
+ intentId,
681
+ statusCode: res.status,
682
+ paymentRequired: res.headers.get("payment-required") ?? undefined,
683
+ paymentResponse: res.headers.get("payment-response") ?? undefined,
684
+ source: "gateway",
685
+ });
686
+ }
687
+ async submitEvidence(intentId, evidenceBody, options) {
688
+ const { res, text, url } = await this.postJSON(`/harbor/intents/${encodeURIComponent(intentId)}/evidence`, evidenceBody, this.mutationHeaders("submitEvidence", options));
689
+ if (!res.ok) {
690
+ throw new HarborHttpError(`Gateway Harbor evidence HTTP ${res.status}: ${text}`, {
691
+ statusCode: res.status,
692
+ url,
693
+ bodyText: text,
694
+ });
695
+ }
696
+ return parseSubmitEvidenceResponse(JSON.parse(text));
697
+ }
698
+ }
660
699
  const DEFAULT_PRINCIPAL_PATH = "/v1/auth/principal";
661
700
  const SETTLEMENT_RAIL_VALUES = new Set(["stripe_connect", "x402_usdc_base"]);
662
701
  const FRAUD_REVIEW_EVENT_TYPES = new Set([
@@ -687,6 +726,53 @@ function readStringArrayValue(value, field) {
687
726
  }
688
727
  return [...value];
689
728
  }
729
+ function parseFundIntentResponse(body, init) {
730
+ const tenant = String(body.tenant ?? "");
731
+ if (tenant !== init.tenantId) {
732
+ throw new Error(`fund tenant mismatch: client=${init.tenantId} ${init.source}=${tenant}`);
733
+ }
734
+ const echoedIntentId = String(body.intent_id ?? "");
735
+ if (echoedIntentId !== init.intentId) {
736
+ throw new Error(`fund intent mismatch: requested=${init.intentId} ${init.source}=${echoedIntentId}`);
737
+ }
738
+ if (typeof body.state !== "string" || !body.state.trim()) {
739
+ throw new Error("fund response missing state");
740
+ }
741
+ if (typeof body.currency !== "string" || !body.currency.trim()) {
742
+ throw new Error("fund response missing currency");
743
+ }
744
+ const amountCents = Number(body.amount_cents);
745
+ if (!Number.isFinite(amountCents)) {
746
+ throw new Error("fund response missing amount_cents");
747
+ }
748
+ return {
749
+ statusCode: init.statusCode,
750
+ paymentRequired: init.paymentRequired,
751
+ paymentResponse: init.paymentResponse,
752
+ intentId: echoedIntentId,
753
+ tenant,
754
+ state: body.state,
755
+ settlementRail: readSettlementRailValue(body.settlement_rail, "fund settlement_rail"),
756
+ currency: body.currency,
757
+ amountCents,
758
+ funded: Boolean(body.funded),
759
+ capabilityToken: typeof body.capability_token === "string" && body.capability_token.trim()
760
+ ? body.capability_token
761
+ : undefined,
762
+ funding: body.funding === undefined || body.funding === null
763
+ ? undefined
764
+ : parseIntentFundingResult(body.funding),
765
+ };
766
+ }
767
+ function parseSubmitEvidenceResponse(value) {
768
+ const body = assertJSONObject(value);
769
+ return {
770
+ intentId: String(body.intent_id ?? ""),
771
+ tenant: String(body.tenant ?? ""),
772
+ state: String(body.state ?? ""),
773
+ predicatePassed: typeof body.predicate_passed === "boolean" ? body.predicate_passed : undefined,
774
+ };
775
+ }
690
776
  function parseIntentFundingResult(value) {
691
777
  const body = assertJSONObject(value);
692
778
  const onchainRaw = body.onchain_transaction_hashes;
@@ -1441,10 +1527,11 @@ function gatewayMutationHeaders(recognitionProof, headers) {
1441
1527
  function encodeRecognitionProofHeader(proof) {
1442
1528
  return Buffer.from(JSON.stringify(proof), "utf8").toString("base64url");
1443
1529
  }
1444
- async function resolveGatewayTenantId(gatewayBaseUrl, apiKey, principalPath, maxRetries) {
1530
+ async function resolveGatewayTenantId(gatewayBaseUrl, apiKey, principalPath, maxRetries, expectedEnvironment) {
1445
1531
  const base = normalizeBase(gatewayBaseUrl);
1446
1532
  const path = principalPath.startsWith("/") ? principalPath : `/${principalPath}`;
1447
1533
  const url = `${base}${path}`;
1534
+ const expected = normalizeExpectedEnvironment(expectedEnvironment);
1448
1535
  let lastErr;
1449
1536
  for (let attempt = 0; attempt < maxRetries; attempt++) {
1450
1537
  let res;
@@ -1485,6 +1572,7 @@ async function resolveGatewayTenantId(gatewayBaseUrl, apiKey, principalPath, max
1485
1572
  bodyText: text,
1486
1573
  });
1487
1574
  }
1575
+ assertExpectedEnvironment("gateway principal", body.environment, expected, text);
1488
1576
  return tenant;
1489
1577
  }
1490
1578
  throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));
@@ -1498,8 +1586,9 @@ export class ServiceAccountSignalSession {
1498
1586
  this.signal = signal;
1499
1587
  }
1500
1588
  static async open(init) {
1501
- const tenantId = await resolveGatewayTenantId(init.gatewayBaseUrl, init.apiKey, init.principalPath ?? DEFAULT_PRINCIPAL_PATH, Math.max(1, init.maxRetries ?? 3));
1502
- return new ServiceAccountSignalSession(new GatewaySignalClient(init.gatewayBaseUrl, tenantId, {
1589
+ const gatewayBaseUrl = defaultGatewayBaseUrl(init.gatewayBaseUrl);
1590
+ const tenantId = await resolveGatewayTenantId(gatewayBaseUrl, init.apiKey, init.principalPath ?? DEFAULT_PRINCIPAL_PATH, Math.max(1, init.maxRetries ?? 3), init.expectedEnvironment);
1591
+ return new ServiceAccountSignalSession(new GatewaySignalClient(gatewayBaseUrl, tenantId, {
1503
1592
  staticGatewayBearerToken: init.apiKey,
1504
1593
  maxRetries: init.maxRetries ?? 3,
1505
1594
  }));
@@ -1517,8 +1606,9 @@ export class ServiceAccountFraudSession {
1517
1606
  this.fraud = fraud;
1518
1607
  }
1519
1608
  static async open(init) {
1520
- const tenantId = await resolveGatewayTenantId(init.gatewayBaseUrl, init.apiKey, init.principalPath ?? DEFAULT_PRINCIPAL_PATH, Math.max(1, init.maxRetries ?? 3));
1521
- return new ServiceAccountFraudSession(new GatewayFraudClient(init.gatewayBaseUrl, tenantId, {
1609
+ const gatewayBaseUrl = defaultGatewayBaseUrl(init.gatewayBaseUrl);
1610
+ const tenantId = await resolveGatewayTenantId(gatewayBaseUrl, init.apiKey, init.principalPath ?? DEFAULT_PRINCIPAL_PATH, Math.max(1, init.maxRetries ?? 3), init.expectedEnvironment);
1611
+ return new ServiceAccountFraudSession(new GatewayFraudClient(gatewayBaseUrl, tenantId, {
1522
1612
  staticGatewayBearerToken: init.apiKey,
1523
1613
  maxRetries: init.maxRetries ?? 3,
1524
1614
  }));
@@ -1543,14 +1633,14 @@ export class PaybondIntents {
1543
1633
  * 32 bytes. `settlementRail` is signed as the requested rail; destinations stay server-owned.
1544
1634
  */
1545
1635
  async create(params) {
1546
- const { idempotencyKey, intentId: maybeIntentId, ...fields } = params;
1636
+ const { idempotencyKey, intentId: maybeIntentId, recognitionProof, ...fields } = params;
1547
1637
  const intentId = maybeIntentId ?? globalThis.crypto.randomUUID();
1548
1638
  const body = buildSignedCreateIntentBody({
1549
1639
  tenantId: this.harbor.tenantId,
1550
1640
  intentId,
1551
1641
  ...fields,
1552
1642
  });
1553
- return this.harbor.createIntent(body, { idempotencyKey });
1643
+ return this.harbor.createIntent(body, { idempotencyKey, recognitionProof });
1554
1644
  }
1555
1645
  /**
1556
1646
  * Advance Harbor `/intents/{id}/fund` for x402 / USDC-on-Base intents.
@@ -1559,24 +1649,25 @@ export class PaybondIntents {
1559
1649
  return this.harbor.fundIntent(params.intentId, {
1560
1650
  paymentSignature: params.paymentSignature,
1561
1651
  idempotencyKey: params.idempotencyKey,
1652
+ recognitionProof: params.recognitionProof,
1562
1653
  });
1563
1654
  }
1564
1655
  /**
1565
1656
  * Sign payee evidence and POST it. `payeeSigningSeed` must be 32 bytes.
1566
1657
  */
1567
1658
  async submitEvidence(params) {
1568
- const { idempotencyKey, artifactsBlake3Hex = [], submittedAtRfc3339 = nowRfc3339Seconds(), ...rest } = params;
1659
+ const { idempotencyKey, artifactsBlake3Hex = [], submittedAtRfc3339 = nowRfc3339Seconds(), recognitionProof, ...rest } = params;
1569
1660
  const wire = signPayeeEvidenceBinding({
1570
1661
  tenantId: this.harbor.tenantId,
1571
1662
  artifactsBlake3Hex,
1572
1663
  submittedAtRfc3339,
1573
1664
  ...rest,
1574
1665
  });
1575
- return this.harbor.submitEvidence(rest.intentId, wire, { idempotencyKey });
1666
+ return this.harbor.submitEvidence(rest.intentId, wire, { idempotencyKey, recognitionProof });
1576
1667
  }
1577
1668
  }
1578
1669
  /**
1579
- * High-level Kit entrypoint: same session lifecycle as {@link ServiceAccountHarborSession}, plus {@link PaybondIntents}.
1670
+ * High-level Kit entrypoint: tenant-bound Gateway clients plus ergonomic intent helpers.
1580
1671
  */
1581
1672
  export class Paybond {
1582
1673
  harbor;
@@ -1585,43 +1676,44 @@ export class Paybond {
1585
1676
  a2a;
1586
1677
  protocol;
1587
1678
  intents;
1588
- session;
1589
- constructor(session, signal, fraud, a2a, protocol) {
1590
- this.session = session;
1591
- this.harbor = session.harbor;
1679
+ constructor(harbor, signal, fraud, a2a, protocol) {
1680
+ this.harbor = harbor;
1592
1681
  this.signal = signal;
1593
1682
  this.fraud = fraud;
1594
1683
  this.a2a = a2a;
1595
1684
  this.protocol = protocol;
1596
- this.intents = new PaybondIntents(session.harbor);
1685
+ this.intents = new PaybondIntents(harbor);
1597
1686
  }
1598
- /** Open a tenant-bound session via gateway `harbor-access` exchange. */
1687
+ /** Open a tenant-bound hosted Paybond session from a service-account API key. */
1599
1688
  static async open(init) {
1600
- const session = await ServiceAccountHarborSession.open(init);
1601
- const signal = new GatewaySignalClient(init.gatewayBaseUrl, session.harbor.tenantId, {
1689
+ const gatewayBaseUrl = defaultGatewayBaseUrl(init.gatewayBaseUrl);
1690
+ const maxRetries = Math.max(1, init.maxRetries ?? 3);
1691
+ const tenantId = await resolveGatewayTenantId(gatewayBaseUrl, init.apiKey, init.principalPath ?? DEFAULT_PRINCIPAL_PATH, maxRetries, init.expectedEnvironment);
1692
+ const harbor = new GatewayHarborClient(gatewayBaseUrl, tenantId, {
1602
1693
  staticGatewayBearerToken: init.apiKey,
1603
- maxRetries: init.maxRetries ?? 3,
1694
+ maxRetries,
1604
1695
  });
1605
- const fraud = new GatewayFraudClient(init.gatewayBaseUrl, session.harbor.tenantId, {
1696
+ const signal = new GatewaySignalClient(gatewayBaseUrl, tenantId, {
1606
1697
  staticGatewayBearerToken: init.apiKey,
1607
- maxRetries: init.maxRetries ?? 3,
1698
+ maxRetries,
1608
1699
  });
1609
- const a2a = new GatewayA2AClient(init.gatewayBaseUrl, {
1700
+ const fraud = new GatewayFraudClient(gatewayBaseUrl, tenantId, {
1610
1701
  staticGatewayBearerToken: init.apiKey,
1611
- maxRetries: init.maxRetries ?? 3,
1702
+ maxRetries,
1612
1703
  });
1613
- const protocol = new GatewayProtocolClient(init.gatewayBaseUrl, session.harbor.tenantId, {
1704
+ const a2a = new GatewayA2AClient(gatewayBaseUrl, {
1614
1705
  staticGatewayBearerToken: init.apiKey,
1615
- maxRetries: init.maxRetries ?? 3,
1706
+ maxRetries,
1616
1707
  });
1617
- return new Paybond(session, signal, fraud, a2a, protocol);
1618
- }
1619
- async rotateHarborToken() {
1620
- await this.session.rotateHarborToken();
1708
+ const protocol = new GatewayProtocolClient(gatewayBaseUrl, tenantId, {
1709
+ staticGatewayBearerToken: init.apiKey,
1710
+ maxRetries,
1711
+ });
1712
+ return new Paybond(harbor, signal, fraud, a2a, protocol);
1621
1713
  }
1622
- /** Release HTTP resources (Harbor client + gateway token provider). */
1714
+ /** Reserved for future HTTP client cleanup; safe to call after work completes. */
1623
1715
  async aclose() {
1624
- await this.session.aclose();
1716
+ await Promise.resolve();
1625
1717
  }
1626
1718
  }
1627
1719
  export { normalizeJson, jsonValueDigest } from "./json-digest.js";
@@ -24,13 +24,10 @@ type MCPCallToolResult = {
24
24
  isError?: boolean;
25
25
  };
26
26
  export type PaybondMCPSettings = {
27
- gatewayBaseUrl: string;
28
27
  apiKey: string;
29
- harborBaseUrl?: string;
30
- harborAccessPath?: string;
28
+ gatewayBaseUrl?: string;
31
29
  principalPath?: string;
32
30
  maxRetries?: number;
33
- clockSkewSeconds?: number;
34
31
  };
35
32
  export declare class PaybondMCPServer {
36
33
  private readonly runtime;
@@ -1,9 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { GatewayAuthError, GatewayFraudClient, GatewaySignalClient, HarborHttpError, ServiceAccountHarborSession, SignalHttpError, } from "./index.js";
2
+ import { GatewayAuthError, GatewayFraudClient, GatewaySignalClient, SignalHttpError, DEFAULT_PAYBOND_GATEWAY_BASE_URL, } from "./index.js";
3
3
  const SERVER_NAME = "Paybond MCP";
4
4
  const SERVER_VERSION = "0.6.0";
5
5
  const MCP_PROTOCOL_VERSION = "2025-11-25";
6
- const DEFAULT_HARBOR_ACCESS_PATH = "/v1/auth/harbor-access";
7
6
  const DEFAULT_PRINCIPAL_PATH = "/v1/auth/principal";
8
7
  const DEFAULT_RECOGNITION_VERIFIER_ID = "paybond-gateway";
9
8
  const agentRecognitionProofHeader = "x-paybond-agent-recognition-proof";
@@ -115,16 +114,12 @@ class PaybondMCPRuntime {
115
114
  principalValue = null;
116
115
  signalValue = null;
117
116
  fraudValue = null;
118
- harborValue = null;
119
117
  constructor(settings) {
120
118
  this.settings = {
121
- gatewayBaseUrl: settings.gatewayBaseUrl,
119
+ gatewayBaseUrl: settings.gatewayBaseUrl ?? DEFAULT_PAYBOND_GATEWAY_BASE_URL,
122
120
  apiKey: settings.apiKey,
123
- harborBaseUrl: settings.harborBaseUrl,
124
- harborAccessPath: settings.harborAccessPath ?? DEFAULT_HARBOR_ACCESS_PATH,
125
121
  principalPath: settings.principalPath ?? DEFAULT_PRINCIPAL_PATH,
126
122
  maxRetries: Math.max(1, settings.maxRetries ?? 3),
127
- clockSkewSeconds: Math.max(0, settings.clockSkewSeconds ?? 90),
128
123
  };
129
124
  this.gateway = new GatewayAPIClient({
130
125
  gatewayBaseUrl: this.settings.gatewayBaseUrl,
@@ -158,20 +153,6 @@ class PaybondMCPRuntime {
158
153
  }))();
159
154
  return this.fraudValue;
160
155
  }
161
- async harbor() {
162
- if (!this.settings.harborBaseUrl) {
163
- throw new Error("PAYBOND_HARBOR_URL is required for direct Harbor mutation tools");
164
- }
165
- this.harborValue ??= ServiceAccountHarborSession.open({
166
- gatewayBaseUrl: this.settings.gatewayBaseUrl,
167
- apiKey: this.settings.apiKey,
168
- harborBaseUrl: this.settings.harborBaseUrl,
169
- harborAccessPath: this.settings.harborAccessPath,
170
- clockSkewSeconds: this.settings.clockSkewSeconds,
171
- maxRetries: this.settings.maxRetries,
172
- });
173
- return this.harborValue;
174
- }
175
156
  async listIntents(init) {
176
157
  const params = new URLSearchParams({
177
158
  limit: String(Math.max(1, Math.min(intArg(init.limit ?? 20, "limit"), 200))),
@@ -319,9 +300,6 @@ export class PaybondMCPServer {
319
300
  tools;
320
301
  initialized = false;
321
302
  constructor(settings) {
322
- if (!settings.gatewayBaseUrl.trim()) {
323
- throw new Error("PAYBOND_GATEWAY_URL is required");
324
- }
325
303
  if (!settings.apiKey.trim()) {
326
304
  throw new Error("PAYBOND_API_KEY is required");
327
305
  }
@@ -701,68 +679,27 @@ export class PaybondMCPServer {
701
679
  }),
702
680
  },
703
681
  ];
704
- if (settings.harborBaseUrl?.trim()) {
705
- tools.push({
706
- name: "paybond_create_intent_legacy",
707
- description: "Legacy direct-Harbor fallback for POST /intents. Prefer paybond_create_intent unless you explicitly need PAYBOND_HARBOR_URL direct mode.",
708
- inputSchema: objectSchema({
709
- body: { type: "object", additionalProperties: true },
710
- idempotency_key: { type: "string" },
711
- }, ["body"]),
712
- call: async (args) => (await this.runtime.harbor()).harbor.createIntent(ensureObject(args.body, "body"), { idempotencyKey: optionalString(args.idempotency_key) }),
713
- }, {
714
- name: "paybond_fund_intent_legacy",
715
- description: "Legacy direct-Harbor fallback for POST /intents/{intent_id}/fund.",
716
- inputSchema: objectSchema({
717
- intent_id: { type: "string" },
718
- payment_signature: { type: "string" },
719
- idempotency_key: { type: "string" },
720
- }, ["intent_id"]),
721
- call: async (args) => jsonObjectFromValue(await (await this.runtime.harbor()).harbor.fundIntent(uuidArg(args.intent_id, "intent_id"), {
722
- paymentSignature: optionalString(args.payment_signature),
723
- idempotencyKey: optionalString(args.idempotency_key),
724
- })),
725
- }, {
726
- name: "paybond_submit_evidence_legacy",
727
- description: "Legacy direct-Harbor fallback for POST /intents/{intent_id}/evidence.",
728
- inputSchema: objectSchema({
729
- intent_id: { type: "string" },
730
- body: { type: "object", additionalProperties: true },
731
- idempotency_key: { type: "string" },
732
- }, ["intent_id", "body"]),
733
- call: async (args) => (await this.runtime.harbor()).harbor.submitEvidence(uuidArg(args.intent_id, "intent_id"), ensureObject(args.body, "body"), { idempotencyKey: optionalString(args.idempotency_key) }),
734
- });
735
- }
736
682
  return tools;
737
683
  }
738
684
  }
739
685
  export function settingsFromEnv(env = process.env) {
740
- const gatewayBaseUrl = String(env.PAYBOND_GATEWAY_URL ?? "").trim();
741
686
  const apiKey = String(env.PAYBOND_API_KEY ?? "").trim();
742
- if (!gatewayBaseUrl) {
743
- throw new Error("PAYBOND_GATEWAY_URL is required");
744
- }
745
687
  if (!apiKey) {
746
688
  throw new Error("PAYBOND_API_KEY is required");
747
689
  }
748
690
  return {
749
- gatewayBaseUrl,
691
+ gatewayBaseUrl: DEFAULT_PAYBOND_GATEWAY_BASE_URL,
750
692
  apiKey,
751
- harborBaseUrl: optionalEnv(env.PAYBOND_HARBOR_URL),
752
- harborAccessPath: optionalEnv(env.PAYBOND_HARBOR_ACCESS_PATH) ?? DEFAULT_HARBOR_ACCESS_PATH,
753
693
  principalPath: optionalEnv(env.PAYBOND_PRINCIPAL_PATH) ?? DEFAULT_PRINCIPAL_PATH,
754
694
  maxRetries: optionalEnv(env.PAYBOND_MCP_MAX_RETRIES)
755
695
  ? intArg(optionalEnv(env.PAYBOND_MCP_MAX_RETRIES), "PAYBOND_MCP_MAX_RETRIES")
756
696
  : 3,
757
- clockSkewSeconds: optionalEnv(env.PAYBOND_MCP_CLOCK_SKEW_SECONDS)
758
- ? numberArg(optionalEnv(env.PAYBOND_MCP_CLOCK_SKEW_SECONDS), "PAYBOND_MCP_CLOCK_SKEW_SECONDS")
759
- : 90,
760
697
  };
761
698
  }
762
699
  export function main(argv = process.argv.slice(2)) {
763
700
  if (argv.includes("--help")) {
764
701
  process.stderr.write("Usage: paybond-mcp-server\n\n" +
765
- "Runs the tenant-bound Paybond MCP server over stdio using PAYBOND_GATEWAY_URL and PAYBOND_API_KEY.\n");
702
+ "Runs the tenant-bound Paybond MCP server over stdio using PAYBOND_API_KEY.\n");
766
703
  return 0;
767
704
  }
768
705
  if (argv.length > 0) {
@@ -817,17 +754,6 @@ function intArg(value, field) {
817
754
  }
818
755
  return parsed;
819
756
  }
820
- function numberArg(value, field) {
821
- const parsed = typeof value === "number"
822
- ? value
823
- : typeof value === "string" && value.trim()
824
- ? Number(value)
825
- : Number.NaN;
826
- if (!Number.isFinite(parsed)) {
827
- throw new Error(`${field} must be numeric`);
828
- }
829
- return parsed;
830
- }
831
757
  function uuidArg(value, field) {
832
758
  const raw = stringArg(value, field);
833
759
  if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(raw)) {
@@ -909,7 +835,6 @@ function formatError(err) {
909
835
  if (err instanceof Error ||
910
836
  err instanceof GatewayAuthError ||
911
837
  err instanceof GatewayHTTPError ||
912
- err instanceof HarborHttpError ||
913
838
  err instanceof SignalHttpError) {
914
839
  return err.message;
915
840
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@paybond/kit",
3
- "version": "0.6.1",
4
- "description": "Paybond Kit for TypeScript: tenant-bound Harbor sessions, capability verification, and signed intent/evidence flows.",
3
+ "version": "0.7.0",
4
+ "description": "Paybond Kit for TypeScript: hosted Gateway sessions, capability verification, signed intent/evidence flows, and Stripe Connect or x402 / USDC-on-Base settlement.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",