@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 +148 -0
- package/dist/currency.d.ts +32 -0
- package/dist/currency.d.ts.map +1 -0
- package/dist/currency.js +54 -0
- package/dist/currency.js.map +1 -0
- package/dist/sdk/index.d.ts +141 -0
- package/dist/sdk/index.d.ts.map +1 -0
- package/dist/sdk/index.js +300 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/types.d.ts +140 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +62 -0
- package/dist/types.js.map +1 -0
- package/package.json +70 -0
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"}
|
package/dist/currency.js
ADDED
|
@@ -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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"}
|
package/dist/types.d.ts
ADDED
|
@@ -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
|
+
}
|