@withgordon/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,148 @@
1
+ # @withgordon/core
2
+
3
+ TypeScript SDK for Gordon agent payments.
4
+
5
+ Gordon lets agents call policy-governed paid services, including x402 APIs, without holding private keys. The SDK is a thin client: it detects provider `402 Payment Required` responses, asks the Gordon Platform to authorize and sign payment from the agent wallet, retries the provider request with payment headers, and returns a receipt.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @withgordon/core
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```ts
16
+ import { Gordon } from "@withgordon/core";
17
+
18
+ const gordon = new Gordon({
19
+ evaluatorUrl: "https://evaluator.withgordon.ai",
20
+ platformUrl: "https://api.withgordon.ai",
21
+ agentApiKey: process.env.GORDON_AGENT_KEY!,
22
+ agentApiSecret: process.env.GORDON_AGENT_SECRET!,
23
+ });
24
+
25
+ const { response, receipt } = await gordon.fetch("https://api.exa.ai/search", {
26
+ method: "POST",
27
+ headers: { "content-type": "application/json" },
28
+ body: JSON.stringify({
29
+ query: "latest x402 integrations",
30
+ numResults: 3,
31
+ }),
32
+ serviceId: "exa",
33
+ operationId: "search.web",
34
+ maxPaymentUnits: 20_000, // $0.02 cap; 1,000,000 units = $1.00
35
+ });
36
+
37
+ const data = await response.json();
38
+ console.log(data, receipt);
39
+ ```
40
+
41
+ For normal non-402 responses, `receipt` is `null` and the original `Response` is returned unchanged.
42
+
43
+ ## Payment Flow
44
+
45
+ 1. The SDK makes the original HTTP request.
46
+ 2. If the provider returns `402`, the SDK parses the x402 payment requirement.
47
+ 3. The SDK sends `{ paymentRequirement, requestMetadata }` to the Gordon Platform.
48
+ 4. The Platform checks the agent's policy and signs payment from the agent's custodial wallet.
49
+ 5. The SDK retries the original provider request with the returned payment headers.
50
+ 6. The SDK completes the settlement and returns `{ response, receipt }`.
51
+
52
+ The SDK does not sign payments and never handles private keys.
53
+
54
+ ## `gordon.fetch()`
55
+
56
+ ```ts
57
+ const result = await gordon.fetch(url, options);
58
+ ```
59
+
60
+ `options` extends standard `RequestInit` with Gordon fields:
61
+
62
+ | Option | Type | Purpose |
63
+ | --- | --- | --- |
64
+ | `serviceId` | `string` | Catalog service slug, such as `exa` or `firecrawl`. |
65
+ | `operationId` | `string` | Catalog operation ID, such as `search.web` or `scrape.url`. |
66
+ | `maxPaymentUnits` | `number` | Maximum spend for this call. `1_000_000 = $1.00`. Defaults to `$0.10`. |
67
+ | `idempotencyKey` | `string` | Stable key for safe retries without double-paying. |
68
+ | `targetUrl` | `string` | For scrape/crawl calls, the customer URL being scraped. Used for domain policy. |
69
+ | `allowUnconfirmed` | `boolean` | Development escape hatch for providers that return `2xx` without x402 receipt proof. Leave false in production. |
70
+
71
+ ## Receipts
72
+
73
+ When payment succeeds, `receipt` contains:
74
+
75
+ ```ts
76
+ {
77
+ settlement_id: string;
78
+ transaction_id: string;
79
+ amount_units: number;
80
+ network: string;
81
+ pay_to: string;
82
+ confirmed: boolean;
83
+ }
84
+ ```
85
+
86
+ `confirmed: true` means the provider returned payment proof and the Platform accepted completion.
87
+
88
+ ## Policy Guard
89
+
90
+ The SDK also exposes the lower-level policy evaluator guard:
91
+
92
+ ```ts
93
+ import { Gordon, GordonBlockedError, GordonEscalateError } from "@withgordon/core";
94
+
95
+ await gordon.guard(
96
+ {
97
+ action_type: "purchase",
98
+ vendor: "example.com",
99
+ amount: 45_000_000, // $45.00
100
+ currency: "USD",
101
+ category: "software",
102
+ metadata: { invoice: "inv_123" },
103
+ },
104
+ async () => {
105
+ // Only runs when policy allows.
106
+ return doThePurchase();
107
+ },
108
+ );
109
+ ```
110
+
111
+ ## Money Units
112
+
113
+ Gordon uses integer micro-units:
114
+
115
+ ```ts
116
+ import { MICRO_PER_USD, formatMoney, parseMoney } from "@withgordon/core/currency";
117
+
118
+ MICRO_PER_USD; // 1_000_000
119
+ formatMoney(7_000); // "$0.007"
120
+ parseMoney("$0.02"); // 20000
121
+ ```
122
+
123
+ This matches USDC's six-decimal base-unit precision.
124
+
125
+ ## Public Exports
126
+
127
+ ```ts
128
+ import { Gordon } from "@withgordon/core";
129
+ import type { X402PaymentRequirement } from "@withgordon/core/types";
130
+ import { formatMoney } from "@withgordon/core/currency";
131
+ ```
132
+
133
+ ## Runtime Support
134
+
135
+ This package is ESM and uses `fetch`, `Response`, and `Headers`.
136
+
137
+ Recommended runtime:
138
+
139
+ - Node.js 18+
140
+ - Modern edge/server runtimes with Fetch API support
141
+ - TypeScript 5+
142
+
143
+ ## Security Notes
144
+
145
+ - Do not expose `GORDON_AGENT_SECRET` in browser code.
146
+ - Keep agent secrets server-side or inside trusted agent runtimes.
147
+ - Rotate any key that has been pasted into logs, chat, or a ticket.
148
+ - Leave `allowUnconfirmed` disabled for production payment flows.
@@ -0,0 +1,32 @@
1
+ /**
2
+ * One source of truth for the system's money representation.
3
+ *
4
+ * Money is stored as a non-negative integer count of "micro-units":
5
+ * 1 micro-unit = 0.000001 USD = 1/100th of a milli-cent
6
+ * 1,000,000 units = 1 USD
7
+ *
8
+ * This matches USDC's 6-decimal base-unit precision exactly, so no conversion
9
+ * is needed between on-chain USDC atoms and Gordon's internal ledger amounts.
10
+ * The integer-only contract makes sums exact and avoids float drift.
11
+ *
12
+ * Per-currency precision is intentionally global here (matches the
13
+ * multi-currency naivety flagged as audit gap #5 in CLAUDE.md). When real
14
+ * multi-currency support lands, this becomes a per-currency `decimals` lookup
15
+ * (Stripe-style).
16
+ */
17
+ export declare const MICRO_PER_USD = 1000000;
18
+ /**
19
+ * Render an integer micro-unit amount as a localized currency string.
20
+ *
21
+ * Adaptive precision: at least 2 decimals (so `$50.00` doesn't look broken),
22
+ * at most 4 (so `$0.0003` keeps its precision). Trailing zeros past the
23
+ * 2-decimal floor are trimmed by `Intl.NumberFormat`.
24
+ */
25
+ export declare function formatMoney(units: number, currency?: string): string;
26
+ /**
27
+ * Parse a user-typed dollar string into integer micro-units. Strips currency
28
+ * symbols, commas, and whitespace. Returns null on unparseable / negative
29
+ * input so callers can drive UI validation.
30
+ */
31
+ export declare function parseMoney(text: string): number | null;
32
+ //# sourceMappingURL=currency.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"currency.d.ts","sourceRoot":"","sources":["../currency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,aAAa,UAAY,CAAC;AAEvC;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,SAAQ,GAAG,MAAM,CAanE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMtD"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * One source of truth for the system's money representation.
3
+ *
4
+ * Money is stored as a non-negative integer count of "micro-units":
5
+ * 1 micro-unit = 0.000001 USD = 1/100th of a milli-cent
6
+ * 1,000,000 units = 1 USD
7
+ *
8
+ * This matches USDC's 6-decimal base-unit precision exactly, so no conversion
9
+ * is needed between on-chain USDC atoms and Gordon's internal ledger amounts.
10
+ * The integer-only contract makes sums exact and avoids float drift.
11
+ *
12
+ * Per-currency precision is intentionally global here (matches the
13
+ * multi-currency naivety flagged as audit gap #5 in CLAUDE.md). When real
14
+ * multi-currency support lands, this becomes a per-currency `decimals` lookup
15
+ * (Stripe-style).
16
+ */
17
+ export const MICRO_PER_USD = 1_000_000;
18
+ /**
19
+ * Render an integer micro-unit amount as a localized currency string.
20
+ *
21
+ * Adaptive precision: at least 2 decimals (so `$50.00` doesn't look broken),
22
+ * at most 4 (so `$0.0003` keeps its precision). Trailing zeros past the
23
+ * 2-decimal floor are trimmed by `Intl.NumberFormat`.
24
+ */
25
+ export function formatMoney(units, currency = 'USD') {
26
+ const major = units / MICRO_PER_USD;
27
+ try {
28
+ return new Intl.NumberFormat('en-US', {
29
+ style: 'currency',
30
+ currency,
31
+ currencyDisplay: 'narrowSymbol',
32
+ minimumFractionDigits: 2,
33
+ maximumFractionDigits: 6,
34
+ }).format(major);
35
+ }
36
+ catch {
37
+ return `${major.toFixed(2)} ${currency}`;
38
+ }
39
+ }
40
+ /**
41
+ * Parse a user-typed dollar string into integer micro-units. Strips currency
42
+ * symbols, commas, and whitespace. Returns null on unparseable / negative
43
+ * input so callers can drive UI validation.
44
+ */
45
+ export function parseMoney(text) {
46
+ const cleaned = text.trim().replace(/[^0-9.\-]/g, '');
47
+ if (cleaned === '' || cleaned === '-' || cleaned === '.')
48
+ return null;
49
+ const parsed = Number(cleaned);
50
+ if (!Number.isFinite(parsed) || parsed < 0)
51
+ return null;
52
+ return Math.round(parsed * MICRO_PER_USD);
53
+ }
54
+ //# sourceMappingURL=currency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"currency.js","sourceRoot":"","sources":["../currency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,SAAS,CAAC;AAEvC;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,QAAQ,GAAG,KAAK;IACzD,MAAM,KAAK,GAAG,KAAK,GAAG,aAAa,CAAC;IACpC,IAAI,CAAC;QACH,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE;YACpC,KAAK,EAAE,UAAU;YACjB,QAAQ;YACR,eAAe,EAAE,cAAc;YAC/B,qBAAqB,EAAE,CAAC;YACxB,qBAAqB,EAAE,CAAC;SACzB,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,QAAQ,EAAE,CAAC;IAC3C,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACtD,IAAI,OAAO,KAAK,EAAE,IAAI,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IACtE,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAC/B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACxD,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,aAAa,CAAC,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,141 @@
1
+ import type { TransactionRequest, Decision, EvaluateResponse, ApprovalStatus } from '../types.js';
2
+ export interface GordonConfig {
3
+ evaluatorUrl: string;
4
+ /** Platform API base URL (e.g. https://api.withgordon.ai). Required for gordon.fetch(). */
5
+ platformUrl?: string;
6
+ agentApiKey: string;
7
+ agentApiSecret: string;
8
+ fetch?: typeof fetch;
9
+ }
10
+ export interface GordonFetchOptions extends RequestInit {
11
+ /** Catalog service slug (e.g. 'firecrawl'). Omit for unlisted endpoints. */
12
+ serviceId?: string;
13
+ /** Catalog operation id (e.g. 'scrape.url'). Required when serviceId is set. */
14
+ operationId?: string;
15
+ /**
16
+ * Caller-supplied idempotency key. A stable UUID for this logical request —
17
+ * the same key on retry returns the existing authorization without re-paying.
18
+ * Defaults to a random UUID per call if not provided.
19
+ */
20
+ idempotencyKey?: string;
21
+ /**
22
+ * Maximum amount (micro-units, 1,000,000 = $1.00) this call is allowed to spend.
23
+ * Gordon rejects any 402 whose amount exceeds this ceiling.
24
+ * Defaults to 100,000 ($0.10).
25
+ */
26
+ maxPaymentUnits?: number;
27
+ /**
28
+ * For scrape/crawl operations: the URL being fetched by the provider
29
+ * (not the provider's own API endpoint). Gordon uses this for
30
+ * allowed_domains policy enforcement. Example: for a Firecrawl scrape of
31
+ * https://example.com/page, set targetUrl to that URL while `url` stays
32
+ * as https://api.firecrawl.dev/v1/scrape.
33
+ */
34
+ targetUrl?: string;
35
+ /**
36
+ * Development escape hatch for providers that return 2xx but omit
37
+ * X-Payment-Response. Production callers should leave this false so a
38
+ * provider result is not mistaken for a confirmed settlement.
39
+ */
40
+ allowUnconfirmed?: boolean;
41
+ }
42
+ export interface GordonFetchResult {
43
+ response: Response;
44
+ /** Set when a payment was made. Null for non-402 responses. */
45
+ receipt: {
46
+ settlement_id: string;
47
+ transaction_id: string;
48
+ amount_units: number;
49
+ network: string;
50
+ pay_to: string;
51
+ /**
52
+ * True when the Platform accepted the /complete call and flipped the
53
+ * settlement to confirmed. False when the provider returned a 2xx but
54
+ * Platform rejected completion (e.g. no X-Payment-Response in production
55
+ * mode) — the settlement remains pending and will expire.
56
+ */
57
+ confirmed: boolean;
58
+ } | null;
59
+ }
60
+ /** Body fields the agent supplies to /evaluate. `agent_id` comes from the
61
+ * Bearer credential; `timestamp` is server-stamped (closes audit gap #4). */
62
+ export type RequestPayload = Omit<TransactionRequest, 'agent_id' | 'timestamp'>;
63
+ export interface GuardOptions {
64
+ /** Pass the approval_id from a prior `GordonEscalateError` to retry that
65
+ * same logical transaction. The evaluator gates the call against the
66
+ * approval's resolved state — see evaluator/server.ts for full semantics. */
67
+ approvalId?: string;
68
+ }
69
+ export declare class GordonBlockedError extends Error {
70
+ readonly decision: EvaluateResponse;
71
+ readonly name = "GordonBlockedError";
72
+ constructor(decision: EvaluateResponse);
73
+ }
74
+ export declare class GordonEscalateError extends Error {
75
+ readonly decision: EvaluateResponse;
76
+ readonly name = "GordonEscalateError";
77
+ readonly approvalId: string | null;
78
+ constructor(decision: EvaluateResponse);
79
+ }
80
+ /**
81
+ * Gordon SDK — single HTTP call per transaction.
82
+ *
83
+ * The evaluator is the single source of truth for "this decision happened":
84
+ * it generates the transaction_id (always) and approval_id (on escalate),
85
+ * pushes the record to a Redis stream, and returns both IDs in the response.
86
+ * The ledger worker drains the stream into Postgres asynchronously.
87
+ *
88
+ * Escalate retry pattern:
89
+ * try { await gordon.guard(req, exec) }
90
+ * catch (e) {
91
+ * if (e instanceof GordonEscalateError) {
92
+ * // poll until resolved (or webhook, or whatever the agent runtime supports)
93
+ * while ((await gordon.checkApproval(e.approvalId!)).status === 'pending') {
94
+ * await sleep(2000);
95
+ * }
96
+ * // retry with the approvalId — evaluator gates against the resolved state
97
+ * await gordon.guard(req, exec, { approvalId: e.approvalId! });
98
+ * }
99
+ * }
100
+ */
101
+ export declare class Gordon {
102
+ private readonly cfg;
103
+ private readonly fetchImpl;
104
+ private readonly authHeader;
105
+ constructor(cfg: GordonConfig);
106
+ evaluate(request: RequestPayload, opts?: GuardOptions): Promise<EvaluateResponse>;
107
+ guard<T>(request: RequestPayload, exec: () => Promise<T>, opts?: GuardOptions): Promise<T>;
108
+ /**
109
+ * Poll the status of an approval the evaluator previously issued.
110
+ * Returns `{status: 'pending'}` for unknown ids — the worker may not have
111
+ * drained yet, or the cache may have expired (7-day TTL).
112
+ */
113
+ checkApproval(approvalId: string): Promise<{
114
+ status: ApprovalStatus;
115
+ resolvedAt: number | null;
116
+ resolvedBy: string | null;
117
+ }>;
118
+ /**
119
+ * Drop-in replacement for `fetch` that handles the x402 payment cycle.
120
+ *
121
+ * Flow:
122
+ * 1. Make the original request.
123
+ * 2. If 402, extract `X-Payment-Required`, call Platform /x402/authorize.
124
+ * 3. Retry the original request with the `X-Payment` header.
125
+ * 4. On success (2xx), call Platform /x402/settlements/:id/complete.
126
+ * 5. Return the provider response + a Gordon receipt.
127
+ *
128
+ * Non-402 responses are returned as-is (receipt: null).
129
+ * If Platform rejects the payment (policy, spend limit, etc.), throws
130
+ * `GordonPaymentError` — do not retry without user intervention.
131
+ */
132
+ fetch(url: string, options?: GordonFetchOptions): Promise<GordonFetchResult>;
133
+ }
134
+ export declare class GordonPaymentError extends Error {
135
+ readonly statusCode?: number | undefined;
136
+ readonly body?: Record<string, unknown> | undefined;
137
+ readonly name = "GordonPaymentError";
138
+ constructor(message: string, statusCode?: number | undefined, body?: Record<string, unknown> | undefined);
139
+ }
140
+ export type { Decision, EvaluateResponse, ApprovalStatus };
141
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../sdk/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,300 @@
1
+ import { createHash, randomBytes } from 'node:crypto';
2
+ import { normalizeX402PaymentRequirement } from '../types.js';
3
+ export class GordonBlockedError extends Error {
4
+ decision;
5
+ name = 'GordonBlockedError';
6
+ constructor(decision) {
7
+ super(`gordon_blocked: ${decision.reason}`);
8
+ this.decision = decision;
9
+ }
10
+ }
11
+ export class GordonEscalateError extends Error {
12
+ decision;
13
+ name = 'GordonEscalateError';
14
+ approvalId;
15
+ constructor(decision) {
16
+ super(`gordon_escalate: ${decision.reason}`);
17
+ this.decision = decision;
18
+ this.approvalId = decision.approval_id;
19
+ }
20
+ }
21
+ const failClosed = (reason) => ({
22
+ result: 'block',
23
+ reason,
24
+ rule_triggered: null,
25
+ latency_ms: 0,
26
+ transaction_id: '00000000-0000-0000-0000-000000000000',
27
+ approval_id: null,
28
+ });
29
+ /**
30
+ * Gordon SDK — single HTTP call per transaction.
31
+ *
32
+ * The evaluator is the single source of truth for "this decision happened":
33
+ * it generates the transaction_id (always) and approval_id (on escalate),
34
+ * pushes the record to a Redis stream, and returns both IDs in the response.
35
+ * The ledger worker drains the stream into Postgres asynchronously.
36
+ *
37
+ * Escalate retry pattern:
38
+ * try { await gordon.guard(req, exec) }
39
+ * catch (e) {
40
+ * if (e instanceof GordonEscalateError) {
41
+ * // poll until resolved (or webhook, or whatever the agent runtime supports)
42
+ * while ((await gordon.checkApproval(e.approvalId!)).status === 'pending') {
43
+ * await sleep(2000);
44
+ * }
45
+ * // retry with the approvalId — evaluator gates against the resolved state
46
+ * await gordon.guard(req, exec, { approvalId: e.approvalId! });
47
+ * }
48
+ * }
49
+ */
50
+ export class Gordon {
51
+ cfg;
52
+ fetchImpl;
53
+ authHeader;
54
+ constructor(cfg) {
55
+ this.cfg = cfg;
56
+ const globalFetch = globalThis.fetch;
57
+ if (cfg.fetch) {
58
+ this.fetchImpl = cfg.fetch;
59
+ }
60
+ else if (globalFetch) {
61
+ this.fetchImpl = globalFetch.bind(globalThis);
62
+ }
63
+ else {
64
+ throw new Error('Gordon SDK requires a Fetch API runtime. Use Node.js 18+ or pass a custom fetch implementation.');
65
+ }
66
+ this.authHeader = `Bearer ${cfg.agentApiKey}:${cfg.agentApiSecret}`;
67
+ }
68
+ async evaluate(request, opts) {
69
+ try {
70
+ const body = { request };
71
+ if (opts?.approvalId)
72
+ body.idempotency_key = opts.approvalId;
73
+ const res = await this.fetchImpl(`${this.cfg.evaluatorUrl}/evaluate`, {
74
+ method: 'POST',
75
+ headers: {
76
+ 'content-type': 'application/json',
77
+ authorization: this.authHeader,
78
+ },
79
+ body: JSON.stringify(body),
80
+ });
81
+ if (!res.ok)
82
+ return failClosed(`evaluator_status_${res.status}`);
83
+ return (await res.json());
84
+ }
85
+ catch {
86
+ return failClosed('evaluator_unreachable');
87
+ }
88
+ }
89
+ async guard(request, exec, opts) {
90
+ const decision = await this.evaluate(request, opts);
91
+ if (decision.result === 'block')
92
+ throw new GordonBlockedError(decision);
93
+ if (decision.result === 'escalate')
94
+ throw new GordonEscalateError(decision);
95
+ return await exec();
96
+ }
97
+ /**
98
+ * Poll the status of an approval the evaluator previously issued.
99
+ * Returns `{status: 'pending'}` for unknown ids — the worker may not have
100
+ * drained yet, or the cache may have expired (7-day TTL).
101
+ */
102
+ async checkApproval(approvalId) {
103
+ try {
104
+ const res = await this.fetchImpl(`${this.cfg.evaluatorUrl}/approvals/${encodeURIComponent(approvalId)}`, {
105
+ method: 'GET',
106
+ headers: { authorization: this.authHeader },
107
+ });
108
+ if (res.status === 404) {
109
+ return { status: 'pending', resolvedAt: null, resolvedBy: null };
110
+ }
111
+ if (!res.ok) {
112
+ return { status: 'pending', resolvedAt: null, resolvedBy: null };
113
+ }
114
+ const body = (await res.json());
115
+ return {
116
+ status: body.status,
117
+ resolvedAt: body.resolved_at,
118
+ resolvedBy: body.resolved_by,
119
+ };
120
+ }
121
+ catch {
122
+ return { status: 'pending', resolvedAt: null, resolvedBy: null };
123
+ }
124
+ }
125
+ /**
126
+ * Drop-in replacement for `fetch` that handles the x402 payment cycle.
127
+ *
128
+ * Flow:
129
+ * 1. Make the original request.
130
+ * 2. If 402, extract `X-Payment-Required`, call Platform /x402/authorize.
131
+ * 3. Retry the original request with the `X-Payment` header.
132
+ * 4. On success (2xx), call Platform /x402/settlements/:id/complete.
133
+ * 5. Return the provider response + a Gordon receipt.
134
+ *
135
+ * Non-402 responses are returned as-is (receipt: null).
136
+ * If Platform rejects the payment (policy, spend limit, etc.), throws
137
+ * `GordonPaymentError` — do not retry without user intervention.
138
+ */
139
+ async fetch(url, options = {}) {
140
+ const platformUrl = this.cfg.platformUrl;
141
+ if (!platformUrl) {
142
+ throw new Error('gordon.fetch() requires GordonConfig.platformUrl');
143
+ }
144
+ const { serviceId, operationId, idempotencyKey, maxPaymentUnits = 100_000, targetUrl, ...fetchOpts } = options;
145
+ const idemKey = idempotencyKey ?? randomBytes(16).toString('hex');
146
+ // ── 1. Initial request ──────────────────────────────────────────────
147
+ const originalRes = await this.fetchImpl(url, fetchOpts);
148
+ if (originalRes.status !== 402) {
149
+ return { response: originalRes, receipt: null };
150
+ }
151
+ // ── 2. Parse x402 payment requirement ──────────────────────────────
152
+ // x402v1: requirement comes as `X-Payment-Required` base64-encoded header.
153
+ // x402v2: requirement comes in the 402 response body (e.g. Exa, most CDP Bazaar providers).
154
+ // Try header first, fall back to body.
155
+ const paymentReqHeader = originalRes.headers.get('X-Payment-Required') ??
156
+ originalRes.headers.get('x-payment-required') ??
157
+ originalRes.headers.get('PAYMENT-REQUIRED');
158
+ let paymentRequirement;
159
+ try {
160
+ if (paymentReqHeader) {
161
+ // Header path (x402v1 or base64-encoded v2 header)
162
+ let raw;
163
+ try {
164
+ raw = JSON.parse(Buffer.from(paymentReqHeader, 'base64url').toString('utf-8'));
165
+ }
166
+ catch {
167
+ raw = JSON.parse(paymentReqHeader);
168
+ }
169
+ paymentRequirement = normalizeX402PaymentRequirement(raw);
170
+ }
171
+ else {
172
+ // Body path (x402v2 — parse response body as JSON payment requirement)
173
+ let bodyRaw;
174
+ try {
175
+ bodyRaw = await originalRes.clone().json();
176
+ }
177
+ catch {
178
+ // 402 with no parseable body and no header — not our protocol
179
+ return { response: originalRes, receipt: null };
180
+ }
181
+ // Must look like an x402 response (has accepts[], x402Version, or payment fields)
182
+ const looksLikeX402 = Array.isArray(bodyRaw.accepts) ||
183
+ typeof bodyRaw.x402Version === 'number' ||
184
+ typeof bodyRaw.payTo === 'string' ||
185
+ typeof bodyRaw.pay_to === 'string';
186
+ if (!looksLikeX402) {
187
+ return { response: originalRes, receipt: null };
188
+ }
189
+ paymentRequirement = normalizeX402PaymentRequirement(bodyRaw);
190
+ }
191
+ }
192
+ catch {
193
+ throw new GordonPaymentError('failed to parse x402 payment requirement');
194
+ }
195
+ if (!paymentRequirement.pay_to || !paymentRequirement.network) {
196
+ // Looks like x402 but missing required fields — not our protocol
197
+ return { response: originalRes, receipt: null };
198
+ }
199
+ // ── 3. Hash the request body for the authorize call ─────────────────
200
+ let bodyHash = '';
201
+ if (fetchOpts.body) {
202
+ const bodyBytes = typeof fetchOpts.body === 'string'
203
+ ? Buffer.from(fetchOpts.body, 'utf-8')
204
+ : fetchOpts.body instanceof Uint8Array
205
+ ? fetchOpts.body
206
+ : Buffer.from(String(fetchOpts.body), 'utf-8');
207
+ bodyHash = createHash('sha256').update(bodyBytes).digest('hex');
208
+ }
209
+ // ── 4. Call Platform /x402/authorize ────────────────────────────────
210
+ const authorizeBody = {
211
+ agent_id: '', // server derives from key — placeholder satisfies type
212
+ ...(serviceId ? { service_id: serviceId } : {}),
213
+ ...(operationId ? { operation_id: operationId } : {}),
214
+ original_request: {
215
+ url,
216
+ method: (fetchOpts.method ?? 'GET').toUpperCase(),
217
+ body_hash: bodyHash,
218
+ ...(targetUrl ? { target_url: targetUrl } : {}),
219
+ },
220
+ payment_requirement: paymentRequirement,
221
+ max_payment_units: maxPaymentUnits,
222
+ currency: 'USDC',
223
+ idempotency_key: idemKey,
224
+ };
225
+ const authorizeRes = await this.fetchImpl(`${platformUrl}/x402/authorize`, {
226
+ method: 'POST',
227
+ headers: {
228
+ 'content-type': 'application/json',
229
+ authorization: this.authHeader,
230
+ },
231
+ body: JSON.stringify(authorizeBody),
232
+ });
233
+ if (!authorizeRes.ok) {
234
+ const errBody = await authorizeRes.json().catch(() => ({}));
235
+ throw new GordonPaymentError(`platform rejected payment: ${errBody.error ?? authorizeRes.status}`, authorizeRes.status, errBody);
236
+ }
237
+ const authorization = (await authorizeRes.json());
238
+ // ── 5. Retry provider with payment headers ──────────────────────────
239
+ const retryHeaders = new Headers(fetchOpts.headers);
240
+ for (const [k, v] of Object.entries(authorization.payment_headers)) {
241
+ retryHeaders.set(k, v);
242
+ }
243
+ const providerRes = await this.fetchImpl(url, { ...fetchOpts, headers: retryHeaders });
244
+ // ── 6. Report completion to Platform ────────────────────────────────
245
+ // Only flip the settlement to confirmed when the provider accepted the
246
+ // payment (2xx). A rejected retry (4xx/5xx/repeated 402) leaves the
247
+ // settlement in 'pending' — it will expire rather than be confirmed.
248
+ let confirmed = false;
249
+ let completionStatus = 'provider_not_successful';
250
+ if (providerRes.ok) {
251
+ const xPaymentResponse = providerRes.headers.get('X-Payment-Response') ?? providerRes.headers.get('x-payment-response');
252
+ if (xPaymentResponse) {
253
+ const completeRes = await this.fetchImpl(`${platformUrl}/x402/settlements/${authorization.settlement_id}/complete`, {
254
+ method: 'POST',
255
+ headers: {
256
+ 'content-type': 'application/json',
257
+ authorization: this.authHeader,
258
+ },
259
+ body: JSON.stringify({ payment_response_header: xPaymentResponse }),
260
+ }).catch(() => null);
261
+ confirmed = completeRes?.ok === true;
262
+ completionStatus = confirmed ? 'confirmed' : 'platform_completion_failed';
263
+ }
264
+ else {
265
+ completionStatus = 'missing_x_payment_response';
266
+ }
267
+ }
268
+ if (providerRes.ok && !confirmed && !options.allowUnconfirmed) {
269
+ throw new GordonPaymentError(`x402 settlement was not confirmed: ${completionStatus}`, 502, {
270
+ settlement_id: authorization.settlement_id,
271
+ transaction_id: authorization.transaction_id,
272
+ completion_status: completionStatus,
273
+ });
274
+ }
275
+ // USDC base units (10^6) == Gordon micro-units (10^6) — direct cast.
276
+ const amountUnits = Number(paymentRequirement.amount);
277
+ return {
278
+ response: providerRes,
279
+ receipt: {
280
+ settlement_id: authorization.settlement_id,
281
+ transaction_id: authorization.transaction_id,
282
+ amount_units: amountUnits,
283
+ network: paymentRequirement.network,
284
+ pay_to: paymentRequirement.pay_to,
285
+ confirmed,
286
+ },
287
+ };
288
+ }
289
+ }
290
+ export class GordonPaymentError extends Error {
291
+ statusCode;
292
+ body;
293
+ name = 'GordonPaymentError';
294
+ constructor(message, statusCode, body) {
295
+ super(message);
296
+ this.statusCode = statusCode;
297
+ this.body = body;
298
+ }
299
+ }
300
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../sdk/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,140 @@
1
+ export type ActionType = 'purchase' | 'service_call';
2
+ export type ServiceCategory = 'search' | 'scrape' | 'ai' | 'data' | 'infrastructure' | 'security' | 'finance' | 'creative';
3
+ /** State machine: listed → discovered → probe_passed → gordon_verified | disabled */
4
+ export type TrustStatus = 'listed' | 'discovered' | 'probe_passed' | 'gordon_verified' | 'disabled';
5
+ export type X402Scheme = 'exact' | 'upto';
6
+ /** Parsed from the X-Payment-Request header on a 402 response. */
7
+ export interface X402PaymentRequirement {
8
+ scheme: X402Scheme;
9
+ network: string;
10
+ token: string;
11
+ /** Merchant/payTo address. */
12
+ pay_to: string;
13
+ facilitator_url?: string;
14
+ /** Amount in token base units (e.g. USDC has 6 decimals). */
15
+ amount: string;
16
+ /** For upto scheme: maximum the merchant may charge. */
17
+ max_amount?: string;
18
+ /** Opaque nonce from the server — must be echoed in the payment. */
19
+ nonce?: string;
20
+ /** Raw parsed JSON from the header for audit storage. */
21
+ raw: Record<string, unknown>;
22
+ }
23
+ export declare function normalizeX402PaymentRequirement(raw: Record<string, unknown>): X402PaymentRequirement;
24
+ /**
25
+ * SDK → Platform: request to authorize and execute an x402 payment.
26
+ * Must be idempotent: repeated calls with the same idempotency_key
27
+ * return the same response without double-paying.
28
+ */
29
+ export interface X402AuthorizeRequest {
30
+ agent_id: string;
31
+ /** Known slug (e.g. 'firecrawl') — null if calling an unlisted endpoint. */
32
+ service_id?: string;
33
+ /** Known operation (e.g. 'scrape.url') — null if unlisted. */
34
+ operation_id?: string;
35
+ original_request: {
36
+ url: string;
37
+ method: string;
38
+ /** SHA-256 of the request body, hex-encoded. Empty string for GET. */
39
+ body_hash: string;
40
+ /**
41
+ * For scrape/crawl operations: the URL being fetched by the provider,
42
+ * not the provider's own API endpoint. Platform uses this for
43
+ * allowed_domains enforcement. Omit for non-URL operations.
44
+ */
45
+ target_url?: string;
46
+ /**
47
+ * Optional caller-supplied session identifier (e.g. a Claude Managed Agent
48
+ * session_id). When present, Gordon stores it on the settlement row so the
49
+ * dashboard can show per-session spend and activity.
50
+ */
51
+ session_id?: string;
52
+ };
53
+ payment_requirement: X402PaymentRequirement;
54
+ /**
55
+ * SDK-supplied ceiling in micro-units (1,000,000 = $1.00).
56
+ * Platform will reject if the required amount exceeds this.
57
+ */
58
+ max_payment_units: number;
59
+ currency: string;
60
+ /** Caller-supplied UUID, stable across retries. */
61
+ idempotency_key: string;
62
+ }
63
+ /** Platform → SDK: payment approved and signed. SDK retries the original request. */
64
+ export interface X402AuthorizeResponse {
65
+ transaction_id: string;
66
+ settlement_id: string;
67
+ /** Headers to add to the retry request (e.g. X-Payment). */
68
+ payment_headers: Record<string, string>;
69
+ /** ISO timestamp after which this payment proof expires. */
70
+ expires_at: string;
71
+ }
72
+ export interface TransactionRequest {
73
+ agent_id: string;
74
+ action_type: ActionType;
75
+ vendor: string;
76
+ /** Non-negative integer micro-units. 1 unit = 0.000001 USD (1,000,000 = $1.00). See currency.ts. */
77
+ amount: number;
78
+ currency: string;
79
+ category: string;
80
+ metadata: Record<string, unknown>;
81
+ /** Server-set: the evaluator's processing time (ms since epoch) — NOT
82
+ * agent-supplied. Used to compute the UTC daily/monthly spend bucket.
83
+ * Closes audit gap #4 (no clock-skew exploit possible). */
84
+ timestamp: number;
85
+ }
86
+ export type RuleType = 'budget_limit' | 'vendor_allowlist' | 'category_block' | 'approval_required' | 'service_allowlist';
87
+ export type RuleScope = 'per_transaction' | 'daily' | 'monthly';
88
+ export interface Rule {
89
+ id: string;
90
+ type: RuleType;
91
+ scope: RuleScope;
92
+ /** Money rules (`budget_limit`, `approval_required`) carry an integer
93
+ * micro-unit threshold (1 unit = 0.000001 USD; 1,000,000 = $1.00); list rules carry a string
94
+ * array (vendor allowlist, blocked categories, service slugs). */
95
+ value: number | string[];
96
+ priority: number;
97
+ }
98
+ export interface Policy {
99
+ /** Owner — identifies which user this policy belongs to. The engine doesn't
100
+ * read it; it's there for debuggability when inspecting a Redis snapshot. */
101
+ user_id: string;
102
+ rules: Rule[];
103
+ }
104
+ export type DecisionResult = 'allow' | 'block' | 'escalate';
105
+ export interface Decision {
106
+ result: DecisionResult;
107
+ reason: string;
108
+ rule_triggered: string | null;
109
+ latency_ms: number;
110
+ }
111
+ /**
112
+ * The HTTP response body of POST /evaluate. Wraps a pure engine `Decision`
113
+ * with identifiers generated by the evaluator's HTTP handler:
114
+ * - `transaction_id`: always set; the eventual `transactions.id` row
115
+ * - `approval_id`: set on initial escalate AND echoed back on retries
116
+ * that carry an `idempotency_key` (so the agent keeps
117
+ * polling the same approval). Null on plain allow/block.
118
+ *
119
+ * Both are pushed to the `ledger_stream` Redis stream and drained into
120
+ * Postgres asynchronously by the ledger worker. The IDs are returned to
121
+ * the caller immediately so the SDK can throw `GordonEscalateError` with
122
+ * the approval id without waiting on the DB write.
123
+ */
124
+ export interface EvaluateResponse extends Decision {
125
+ transaction_id: string;
126
+ approval_id: string | null;
127
+ }
128
+ export type ApprovalStatus = 'pending' | 'approved' | 'denied';
129
+ /**
130
+ * Response body of GET /approvals/:id on the evaluator. Backed by Redis —
131
+ * see `evaluator/cache.ts → keys.approval`. Polled by agents after they
132
+ * receive a `GordonEscalateError`.
133
+ */
134
+ export interface ApprovalStatusResponse {
135
+ approval_id: string;
136
+ status: ApprovalStatus;
137
+ resolved_at: number | null;
138
+ resolved_by: string | null;
139
+ }
140
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,62 @@
1
+ // Known USDC ERC-20 contract addresses across supported chains.
2
+ // Providers that use x402 v2 (e.g. Exa) send the contract address in the
3
+ // `asset` field instead of the string "USDC". We normalize these back to
4
+ // the canonical token name so the rest of the platform can do a simple
5
+ // string comparison.
6
+ const KNOWN_USDC_ADDRESSES = new Set([
7
+ '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // Base mainnet
8
+ '0x036CbD53842c5426634e7929541eC2318f3dCF7e', // Base Sepolia
9
+ '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // Ethereum mainnet
10
+ '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', // Ethereum Sepolia
11
+ ].map(a => a.toLowerCase()));
12
+ function resolveTokenName(raw, selected) {
13
+ const raw_value = selected.token ?? selected.asset ?? raw.token ?? raw.asset ?? 'USDC';
14
+ const s = String(raw_value);
15
+ // If the token field contains an ERC-20 contract address, map to canonical name
16
+ if (s.startsWith('0x') && KNOWN_USDC_ADDRESSES.has(s.toLowerCase()))
17
+ return 'USDC';
18
+ return s;
19
+ }
20
+ export function normalizeX402PaymentRequirement(raw) {
21
+ const accepts = raw.accepts;
22
+ const selected = Array.isArray(accepts) && accepts.length > 0
23
+ ? accepts.find((entry) => {
24
+ const token = String(entry.token ?? entry.asset ?? '').toUpperCase();
25
+ const scheme = String(entry.scheme ?? 'exact');
26
+ // Accept entries where token is USDC (by name or known address) under exact scheme
27
+ const isUsdc = !token || token === 'USDC' || KNOWN_USDC_ADDRESSES.has(token.toLowerCase());
28
+ return isUsdc && scheme === 'exact';
29
+ }) ?? accepts[0]
30
+ : raw;
31
+ const token = resolveTokenName(raw, selected);
32
+ const payTo = selected.pay_to ??
33
+ selected.payTo ??
34
+ selected.payToAddress ??
35
+ raw.pay_to ??
36
+ raw.payTo ??
37
+ raw.payToAddress;
38
+ const amount = selected.amount ??
39
+ selected.max_amount ??
40
+ selected.maxAmountRequired ??
41
+ selected.maxAmount ??
42
+ raw.amount ??
43
+ raw.max_amount ??
44
+ raw.maxAmountRequired ??
45
+ raw.maxAmount;
46
+ return {
47
+ scheme: (selected.scheme ?? raw.scheme ?? 'exact'),
48
+ network: String(selected.network ?? raw.network ?? ''),
49
+ token: String(token),
50
+ pay_to: String(payTo ?? ''),
51
+ ...(selected.facilitator_url ?? raw.facilitator_url
52
+ ? { facilitator_url: String(selected.facilitator_url ?? raw.facilitator_url) }
53
+ : {}),
54
+ amount: String(amount ?? ''),
55
+ ...(selected.max_amount ?? selected.maxAmountRequired ?? selected.maxAmount ?? raw.max_amount ?? raw.maxAmountRequired ?? raw.maxAmount
56
+ ? { max_amount: String(selected.max_amount ?? selected.maxAmountRequired ?? selected.maxAmount ?? raw.max_amount ?? raw.maxAmountRequired ?? raw.maxAmount) }
57
+ : {}),
58
+ ...(selected.nonce ?? raw.nonce ? { nonce: String(selected.nonce ?? raw.nonce) } : {}),
59
+ raw,
60
+ };
61
+ }
62
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@withgordon/core",
3
+ "version": "0.1.0",
4
+ "description": "Gordon SDK for policy-governed agent payments and x402 service settlement.",
5
+ "type": "module",
6
+ "main": "./dist/sdk/index.js",
7
+ "types": "./dist/sdk/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/sdk/index.d.ts",
11
+ "import": "./dist/sdk/index.js"
12
+ },
13
+ "./sdk": {
14
+ "types": "./dist/sdk/index.d.ts",
15
+ "import": "./dist/sdk/index.js"
16
+ },
17
+ "./types": {
18
+ "types": "./dist/types.d.ts",
19
+ "import": "./dist/types.js"
20
+ },
21
+ "./currency": {
22
+ "types": "./dist/currency.d.ts",
23
+ "import": "./dist/currency.js"
24
+ }
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "README.md"
29
+ ],
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "scripts": {
34
+ "build": "tsc -p tsconfig.build.json",
35
+ "prepack": "npm run build",
36
+ "test": "vitest run",
37
+ "test:watch": "vitest",
38
+ "typecheck": "tsc --noEmit",
39
+ "evaluator:dev": "node --import tsx evaluator/index.ts",
40
+ "platform:dev": "node --import tsx platform/index.ts",
41
+ "worker:ledger:dev": "node --import tsx workers/index.ts",
42
+ "db:init": "node --import tsx scripts/init-db.ts",
43
+ "e2e:buyer-agent": "AUTH_SECRET=buyer-agent-e2e-auth-secret INTERNAL_API_SECRET=buyer-agent-e2e-internal-secret GORDON_X402_ENABLE_EXPERIMENTAL_SIGNER=true node --import tsx scripts/buyer-agent-e2e.ts"
44
+ },
45
+ "devDependencies": {
46
+ "@electric-sql/pglite": "^0.4.5",
47
+ "@types/express": "^5.0.6",
48
+ "@types/ioredis-mock": "^8.2.7",
49
+ "@types/node": "^22.7.5",
50
+ "@types/pg": "^8.20.0",
51
+ "@types/supertest": "^7.2.0",
52
+ "ioredis-mock": "^8.13.1",
53
+ "supertest": "^7.2.2",
54
+ "tsx": "^4.21.0",
55
+ "typescript": "^5.6.3",
56
+ "vitest": "^2.1.3"
57
+ },
58
+ "dependencies": {
59
+ "@coinbase/cdp-sdk": "^1.48.3",
60
+ "@sendgrid/mail": "^8.1.6",
61
+ "dotenv": "^17.4.2",
62
+ "drizzle-orm": "^0.45.2",
63
+ "express": "^5.2.1",
64
+ "fast-jwt": "^6.2.4",
65
+ "fastify": "^5.8.5",
66
+ "ioredis": "^5.10.1",
67
+ "nanoid": "^5.1.11",
68
+ "pg": "^8.20.0"
69
+ }
70
+ }