@daski/pay 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/LICENSE +21 -0
- package/README.md +102 -0
- package/dist/bin/daski.d.ts +3 -0
- package/dist/bin/daski.d.ts.map +1 -0
- package/dist/bin/daski.js +187 -0
- package/dist/bin/daski.js.map +1 -0
- package/dist/cli/args.d.ts +11 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +82 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/errors.d.ts +24 -0
- package/dist/cli/errors.d.ts.map +1 -0
- package/dist/cli/errors.js +23 -0
- package/dist/cli/errors.js.map +1 -0
- package/dist/cli/output.d.ts +8 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +76 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/prompt.d.ts +12 -0
- package/dist/cli/prompt.d.ts.map +1 -0
- package/dist/cli/prompt.js +101 -0
- package/dist/cli/prompt.js.map +1 -0
- package/dist/cli/redact.d.ts +26 -0
- package/dist/cli/redact.d.ts.map +1 -0
- package/dist/cli/redact.js +55 -0
- package/dist/cli/redact.js.map +1 -0
- package/dist/commands/buy.d.ts +15 -0
- package/dist/commands/buy.d.ts.map +1 -0
- package/dist/commands/buy.js +276 -0
- package/dist/commands/buy.js.map +1 -0
- package/dist/commands/doctor.d.ts +29 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +173 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/order.d.ts +18 -0
- package/dist/commands/order.d.ts.map +1 -0
- package/dist/commands/order.js +256 -0
- package/dist/commands/order.js.map +1 -0
- package/dist/commands/signPayment.d.ts +10 -0
- package/dist/commands/signPayment.d.ts.map +1 -0
- package/dist/commands/signPayment.js +162 -0
- package/dist/commands/signPayment.js.map +1 -0
- package/dist/commands/wallet.d.ts +11 -0
- package/dist/commands/wallet.d.ts.map +1 -0
- package/dist/commands/wallet.js +104 -0
- package/dist/commands/wallet.js.map +1 -0
- package/dist/config.d.ts +64 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +200 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +36 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +54 -0
- package/dist/context.js.map +1 -0
- package/dist/gateway/balance.d.ts +16 -0
- package/dist/gateway/balance.d.ts.map +1 -0
- package/dist/gateway/balance.js +23 -0
- package/dist/gateway/balance.js.map +1 -0
- package/dist/gateway/catalog.d.ts +49 -0
- package/dist/gateway/catalog.d.ts.map +1 -0
- package/dist/gateway/catalog.js +161 -0
- package/dist/gateway/catalog.js.map +1 -0
- package/dist/gateway/client.d.ts +80 -0
- package/dist/gateway/client.d.ts.map +1 -0
- package/dist/gateway/client.js +128 -0
- package/dist/gateway/client.js.map +1 -0
- package/dist/gateway/lifecycle.d.ts +45 -0
- package/dist/gateway/lifecycle.d.ts.map +1 -0
- package/dist/gateway/lifecycle.js +96 -0
- package/dist/gateway/lifecycle.js.map +1 -0
- package/dist/gateway/purchase.d.ts +119 -0
- package/dist/gateway/purchase.d.ts.map +1 -0
- package/dist/gateway/purchase.js +250 -0
- package/dist/gateway/purchase.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/paths.d.ts +6 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +11 -0
- package/dist/paths.js.map +1 -0
- package/dist/signers/cdp.d.ts +7 -0
- package/dist/signers/cdp.d.ts.map +1 -0
- package/dist/signers/cdp.js +42 -0
- package/dist/signers/cdp.js.map +1 -0
- package/dist/signers/circle.d.ts +53 -0
- package/dist/signers/circle.d.ts.map +1 -0
- package/dist/signers/circle.js +136 -0
- package/dist/signers/circle.js.map +1 -0
- package/dist/signers/index.d.ts +23 -0
- package/dist/signers/index.d.ts.map +1 -0
- package/dist/signers/index.js +22 -0
- package/dist/signers/index.js.map +1 -0
- package/dist/signers/local.d.ts +3 -0
- package/dist/signers/local.d.ts.map +1 -0
- package/dist/signers/local.js +24 -0
- package/dist/signers/local.js.map +1 -0
- package/dist/signers/selfTest.d.ts +46 -0
- package/dist/signers/selfTest.d.ts.map +1 -0
- package/dist/signers/selfTest.js +113 -0
- package/dist/signers/selfTest.js.map +1 -0
- package/dist/store/keystore.d.ts +19 -0
- package/dist/store/keystore.d.ts.map +1 -0
- package/dist/store/keystore.js +226 -0
- package/dist/store/keystore.js.map +1 -0
- package/dist/store/orders.d.ts +39 -0
- package/dist/store/orders.d.ts.map +1 -0
- package/dist/store/orders.js +91 -0
- package/dist/store/orders.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +21 -0
- package/dist/version.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* §4.1 check 4 — independent splitter evidence.
|
|
3
|
+
*
|
|
4
|
+
* The address a challenge asks us to pay must be corroborated twice, by
|
|
5
|
+
* sources that are not the challenge: the outcome's own catalog entry, and
|
|
6
|
+
* the chain manifest at `.well-known/daski-chain.json`. Both are cached with a
|
|
7
|
+
* TTL so the check costs at most one round trip per outcome per window, and
|
|
8
|
+
* neither cache is ever consulted to *satisfy* the check when it is stale.
|
|
9
|
+
*/
|
|
10
|
+
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
11
|
+
import { dirname, join } from "node:path";
|
|
12
|
+
import { getAddress } from "viem";
|
|
13
|
+
import { CliError } from "../cli/errors.js";
|
|
14
|
+
import { daskiHome } from "../paths.js";
|
|
15
|
+
import { GatewayClient } from "./client.js";
|
|
16
|
+
/** How long catalog evidence stays fresh. Short: splitters can be re-listed. */
|
|
17
|
+
export const CATALOG_TTL_SECONDS = 300;
|
|
18
|
+
const cachePath = () => join(daskiHome(), "cache.json");
|
|
19
|
+
function readCache() {
|
|
20
|
+
try {
|
|
21
|
+
const parsed = JSON.parse(readFileSync(cachePath(), "utf8"));
|
|
22
|
+
if (parsed.version !== 1)
|
|
23
|
+
throw new Error("shape");
|
|
24
|
+
return { version: 1, outcomes: parsed.outcomes ?? {}, manifests: parsed.manifests ?? {} };
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return { version: 1, outcomes: {}, manifests: {} };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function writeCache(file) {
|
|
31
|
+
const path = cachePath();
|
|
32
|
+
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
33
|
+
const temporary = `${path}.${process.pid}.tmp`;
|
|
34
|
+
writeFileSync(temporary, `${JSON.stringify(file, null, 2)}\n`, { mode: 0o600 });
|
|
35
|
+
renameSync(temporary, path);
|
|
36
|
+
}
|
|
37
|
+
function fresh(entry, now) {
|
|
38
|
+
return entry && now - entry.fetchedAt < CATALOG_TTL_SECONDS ? entry.value : undefined;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The catalog reader. One instance per command run, so the TTL cache and the
|
|
42
|
+
* call budget are shared across every check a single purchase performs.
|
|
43
|
+
*/
|
|
44
|
+
export class Catalog {
|
|
45
|
+
#client;
|
|
46
|
+
#now;
|
|
47
|
+
constructor(client, now = () => Math.floor(Date.now() / 1_000)) {
|
|
48
|
+
this.#client = client;
|
|
49
|
+
this.#now = now;
|
|
50
|
+
}
|
|
51
|
+
/** `daski_get_outcome`, cached. This is also the price and terms source. */
|
|
52
|
+
async getOutcome(providerAgentId, outcomeId) {
|
|
53
|
+
const key = `${this.#client.gatewayUrl}|${providerAgentId}|${outcomeId}`;
|
|
54
|
+
const cache = readCache();
|
|
55
|
+
const cached = fresh(cache.outcomes[key], this.#now());
|
|
56
|
+
if (cached)
|
|
57
|
+
return cached;
|
|
58
|
+
const result = await this.#client.callTool("daski_get_outcome", {
|
|
59
|
+
providerAgentId,
|
|
60
|
+
outcomeId,
|
|
61
|
+
});
|
|
62
|
+
const body = GatewayClient.json(result);
|
|
63
|
+
if (result.isError || !body) {
|
|
64
|
+
throw new CliError({
|
|
65
|
+
code: "DASKI_OUTCOME_NOT_FOUND",
|
|
66
|
+
message: `The gateway has no outcome ${providerAgentId}/${outcomeId}.`,
|
|
67
|
+
remediation: "List what is purchasable with the gateway's daski_list_outcomes tool, " +
|
|
68
|
+
"then retry with a provider id and outcome id from that list.",
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
const splitter = body.splitter;
|
|
72
|
+
if (typeof body.payTo !== "string" || typeof splitter?.splitterAddress !== "string") {
|
|
73
|
+
throw new CliError({
|
|
74
|
+
code: "DASKI_OUTCOME_MISSING_SPLITTER",
|
|
75
|
+
message: `Outcome ${providerAgentId}/${outcomeId} does not publish a splitter address.`,
|
|
76
|
+
remediation: "Without independent splitter evidence the purchase cannot be validated. " +
|
|
77
|
+
"Report this to the gateway operator.",
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
const service = body.service;
|
|
81
|
+
const skill = body.skill;
|
|
82
|
+
const summary = {
|
|
83
|
+
providerAgentId,
|
|
84
|
+
outcomeId,
|
|
85
|
+
payTo: getAddress(body.payTo),
|
|
86
|
+
splitterAddress: getAddress(splitter.splitterAddress),
|
|
87
|
+
token: getAddress(String(body.token)),
|
|
88
|
+
pricingMode: String(body.pricingMode),
|
|
89
|
+
fixedGrossAmount: typeof body.fixedGrossAmount === "string" ? body.fixedGrossAmount : undefined,
|
|
90
|
+
bindingProfile: typeof body.bindingProfile === "string" ? body.bindingProfile : undefined,
|
|
91
|
+
providerAudience: typeof body.providerAudience === "string" ? body.providerAudience : undefined,
|
|
92
|
+
absoluteResourceUri: typeof body.absoluteResourceUri === "string" ? body.absoluteResourceUri : undefined,
|
|
93
|
+
terms: body.terms,
|
|
94
|
+
commissionBps: typeof body.commissionBps === "number" ? body.commissionBps : undefined,
|
|
95
|
+
serviceName: service?.name,
|
|
96
|
+
skillName: skill?.name,
|
|
97
|
+
requestSchema: body.requestSchema,
|
|
98
|
+
};
|
|
99
|
+
cache.outcomes[key] = { fetchedAt: this.#now(), value: summary };
|
|
100
|
+
writeCache(cache);
|
|
101
|
+
return summary;
|
|
102
|
+
}
|
|
103
|
+
/** `.well-known/daski-chain.json`, cached. The second, independent source. */
|
|
104
|
+
async chainManifest() {
|
|
105
|
+
const key = this.#client.gatewayUrl;
|
|
106
|
+
const cache = readCache();
|
|
107
|
+
const cached = fresh(cache.manifests[key], this.#now());
|
|
108
|
+
if (cached)
|
|
109
|
+
return cached;
|
|
110
|
+
let manifest;
|
|
111
|
+
try {
|
|
112
|
+
const response = await fetch(`${this.#client.gatewayUrl}/.well-known/daski-chain.json`);
|
|
113
|
+
if (!response.ok)
|
|
114
|
+
throw new Error(`HTTP ${response.status}`);
|
|
115
|
+
manifest = await response.json();
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
throw new CliError({
|
|
119
|
+
code: "DASKI_CHAIN_MANIFEST_UNAVAILABLE",
|
|
120
|
+
message: `Could not read ${this.#client.gatewayUrl}/.well-known/daski-chain.json: ` +
|
|
121
|
+
`${error.message}`,
|
|
122
|
+
remediation: "The splitter allowlist needs this manifest as its second, independent " +
|
|
123
|
+
"source. Without it no purchase can be validated. Check connectivity, " +
|
|
124
|
+
"then run: daski doctor --json",
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
if (!Array.isArray(manifest.outcomes)) {
|
|
128
|
+
throw new CliError({
|
|
129
|
+
code: "DASKI_CHAIN_MANIFEST_MALFORMED",
|
|
130
|
+
message: "The chain manifest does not list any outcomes.",
|
|
131
|
+
remediation: "Report this to the gateway operator; purchases cannot be validated.",
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
cache.manifests[key] = { fetchedAt: this.#now(), value: manifest };
|
|
135
|
+
writeCache(cache);
|
|
136
|
+
return manifest;
|
|
137
|
+
}
|
|
138
|
+
/** The two-source evidence the policy validator consumes. */
|
|
139
|
+
async splitterEvidence(providerAgentId, outcomeId) {
|
|
140
|
+
const [outcome, manifest] = await Promise.all([
|
|
141
|
+
this.getOutcome(providerAgentId, outcomeId),
|
|
142
|
+
this.chainManifest(),
|
|
143
|
+
]);
|
|
144
|
+
const listed = manifest.outcomes.find((entry) => entry.providerAgentId === providerAgentId && entry.outcomeId === outcomeId);
|
|
145
|
+
if (!listed) {
|
|
146
|
+
throw new CliError({
|
|
147
|
+
code: "DASKI_OUTCOME_NOT_IN_CHAIN_MANIFEST",
|
|
148
|
+
message: `${providerAgentId}/${outcomeId} is offered by the gateway but is not ` +
|
|
149
|
+
"listed in .well-known/daski-chain.json.",
|
|
150
|
+
remediation: "One source offers it and the other does not, so the splitter cannot be " +
|
|
151
|
+
"corroborated. Do not purchase; report this to the gateway operator.",
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
const fromManifest = listed.splitter?.splitterAddress ?? listed.payTo;
|
|
155
|
+
return {
|
|
156
|
+
fromOutcome: outcome.splitterAddress,
|
|
157
|
+
fromChainManifest: getAddress(String(fromManifest)),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/gateway/catalog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { TransferAuthorization } from "@daski/x402-scheme";
|
|
2
|
+
export interface McpToolResult {
|
|
3
|
+
content: {
|
|
4
|
+
type: string;
|
|
5
|
+
text?: string;
|
|
6
|
+
}[];
|
|
7
|
+
isError?: boolean | undefined;
|
|
8
|
+
_meta?: Record<string, unknown> | undefined;
|
|
9
|
+
}
|
|
10
|
+
export interface GatewayCallLog {
|
|
11
|
+
tool: string;
|
|
12
|
+
at: string;
|
|
13
|
+
/** Request arguments, already redacted by the caller. */
|
|
14
|
+
request: unknown;
|
|
15
|
+
response: unknown;
|
|
16
|
+
isError: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface GatewayClientOptions {
|
|
19
|
+
gatewayUrl: string;
|
|
20
|
+
/** Every call is appended here; the conformance suite byte-logs from it. */
|
|
21
|
+
onCall?: (entry: GatewayCallLog) => void;
|
|
22
|
+
clientName?: string;
|
|
23
|
+
clientVersion?: string;
|
|
24
|
+
}
|
|
25
|
+
/** The x402 v2 challenge as the gateway issues it. */
|
|
26
|
+
export interface PaymentChallenge {
|
|
27
|
+
x402Version: number;
|
|
28
|
+
resource: Record<string, unknown>;
|
|
29
|
+
accepts: PaymentRequirement[];
|
|
30
|
+
extensions?: Record<string, unknown> | undefined;
|
|
31
|
+
}
|
|
32
|
+
export interface PaymentRequirement {
|
|
33
|
+
scheme: string;
|
|
34
|
+
network: string;
|
|
35
|
+
asset: string;
|
|
36
|
+
amount: string;
|
|
37
|
+
payTo: string;
|
|
38
|
+
maxTimeoutSeconds: number;
|
|
39
|
+
extra?: {
|
|
40
|
+
assetTransferMethod?: string;
|
|
41
|
+
name?: string;
|
|
42
|
+
version?: string;
|
|
43
|
+
} | undefined;
|
|
44
|
+
}
|
|
45
|
+
/** The exact five-key payload the gateway accepts. Any other shape is refused. */
|
|
46
|
+
export interface PaymentSubmission {
|
|
47
|
+
x402Version: number;
|
|
48
|
+
resource: Record<string, unknown>;
|
|
49
|
+
accepted: PaymentRequirement;
|
|
50
|
+
payload: {
|
|
51
|
+
authorization: TransferAuthorization;
|
|
52
|
+
signature: string;
|
|
53
|
+
};
|
|
54
|
+
extensions: Record<string, unknown>;
|
|
55
|
+
}
|
|
56
|
+
export declare class GatewayClient {
|
|
57
|
+
#private;
|
|
58
|
+
readonly gatewayUrl: string;
|
|
59
|
+
constructor(options: GatewayClientOptions);
|
|
60
|
+
/** Daski tool calls made on this connection — the §6 budget is counted here. */
|
|
61
|
+
get callCount(): number;
|
|
62
|
+
connect(): Promise<void>;
|
|
63
|
+
close(): Promise<void>;
|
|
64
|
+
/** Tool names the gateway actually advertises, cached per connection. */
|
|
65
|
+
availableTools(): Promise<Set<string>>;
|
|
66
|
+
hasTool(name: string): Promise<boolean>;
|
|
67
|
+
callTool(name: string, args: Record<string, unknown>, meta?: Record<string, unknown>): Promise<McpToolResult>;
|
|
68
|
+
/** The first JSON object in a tool result's content, if there is one. */
|
|
69
|
+
static json(result: McpToolResult): Record<string, unknown> | undefined;
|
|
70
|
+
/** Reads the challenge from `_meta`, falling back to the content body. */
|
|
71
|
+
static challenge(result: McpToolResult): PaymentChallenge | undefined;
|
|
72
|
+
}
|
|
73
|
+
/** Health and version, for `doctor`. Plain HTTP; no MCP session needed. */
|
|
74
|
+
export declare function readiness(gatewayUrl: string, timeoutMs?: number): Promise<{
|
|
75
|
+
reachable: boolean;
|
|
76
|
+
status?: string | undefined;
|
|
77
|
+
version?: string | undefined;
|
|
78
|
+
error?: string | undefined;
|
|
79
|
+
}>;
|
|
80
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/gateway/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The gateway transport.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately hand-rolled rather than delegated to `@x402/mcp`'s payment
|
|
5
|
+
* wrapper: the CLI must sit between the challenge and the signature to run
|
|
6
|
+
* §4, and must own the ambiguous-outcome path so an interrupted purchase gets
|
|
7
|
+
* reconciled instead of re-signed. A wrapper that signs for us would take
|
|
8
|
+
* both of those decisions away.
|
|
9
|
+
*/
|
|
10
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
11
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
12
|
+
import { CliError } from "../cli/errors.js";
|
|
13
|
+
export class GatewayClient {
|
|
14
|
+
gatewayUrl;
|
|
15
|
+
#client;
|
|
16
|
+
#tools;
|
|
17
|
+
#callCount = 0;
|
|
18
|
+
#options;
|
|
19
|
+
constructor(options) {
|
|
20
|
+
this.gatewayUrl = options.gatewayUrl.replace(/\/$/, "");
|
|
21
|
+
this.#options = options;
|
|
22
|
+
}
|
|
23
|
+
/** Daski tool calls made on this connection — the §6 budget is counted here. */
|
|
24
|
+
get callCount() {
|
|
25
|
+
return this.#callCount;
|
|
26
|
+
}
|
|
27
|
+
async connect() {
|
|
28
|
+
if (this.#client)
|
|
29
|
+
return;
|
|
30
|
+
const client = new Client({
|
|
31
|
+
name: this.#options.clientName ?? "daski-pay",
|
|
32
|
+
version: this.#options.clientVersion ?? "0.1.0",
|
|
33
|
+
});
|
|
34
|
+
try {
|
|
35
|
+
await client.connect(new StreamableHTTPClientTransport(new URL(`${this.gatewayUrl}/mcp`)));
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
throw new CliError({
|
|
39
|
+
code: "DASKI_GATEWAY_UNREACHABLE",
|
|
40
|
+
message: `Could not reach the gateway at ${this.gatewayUrl}: ${error.message}`,
|
|
41
|
+
remediation: "Check network access and the profile's gatewayUrl, then run: daski doctor --json",
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
this.#client = client;
|
|
45
|
+
}
|
|
46
|
+
async close() {
|
|
47
|
+
await this.#client?.close();
|
|
48
|
+
this.#client = undefined;
|
|
49
|
+
}
|
|
50
|
+
/** Tool names the gateway actually advertises, cached per connection. */
|
|
51
|
+
async availableTools() {
|
|
52
|
+
if (this.#tools)
|
|
53
|
+
return this.#tools;
|
|
54
|
+
await this.connect();
|
|
55
|
+
const listed = await this.#client.listTools();
|
|
56
|
+
this.#tools = new Set(listed.tools.map((tool) => tool.name));
|
|
57
|
+
return this.#tools;
|
|
58
|
+
}
|
|
59
|
+
async hasTool(name) {
|
|
60
|
+
return (await this.availableTools()).has(name);
|
|
61
|
+
}
|
|
62
|
+
async callTool(name, args, meta) {
|
|
63
|
+
await this.connect();
|
|
64
|
+
this.#callCount += 1;
|
|
65
|
+
const params = { name, arguments: args };
|
|
66
|
+
if (meta)
|
|
67
|
+
params._meta = meta;
|
|
68
|
+
let result;
|
|
69
|
+
try {
|
|
70
|
+
result = await this.#client.callTool(params);
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
this.#options.onCall?.({
|
|
74
|
+
tool: name, at: new Date().toISOString(),
|
|
75
|
+
request: { args, meta }, response: { transportError: error.message },
|
|
76
|
+
isError: true,
|
|
77
|
+
});
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
this.#options.onCall?.({
|
|
81
|
+
tool: name, at: new Date().toISOString(),
|
|
82
|
+
request: { args, meta }, response: result, isError: Boolean(result.isError),
|
|
83
|
+
});
|
|
84
|
+
return result;
|
|
85
|
+
}
|
|
86
|
+
/** The first JSON object in a tool result's content, if there is one. */
|
|
87
|
+
static json(result) {
|
|
88
|
+
for (const item of result.content ?? []) {
|
|
89
|
+
if (item.type !== "text" || typeof item.text !== "string")
|
|
90
|
+
continue;
|
|
91
|
+
try {
|
|
92
|
+
const parsed = JSON.parse(item.text);
|
|
93
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
94
|
+
return parsed;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// Non-JSON text content is informational; keep looking.
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
/** Reads the challenge from `_meta`, falling back to the content body. */
|
|
104
|
+
static challenge(result) {
|
|
105
|
+
const fromMeta = result._meta?.["x402/payment-required"];
|
|
106
|
+
const candidate = (fromMeta ?? GatewayClient.json(result));
|
|
107
|
+
return candidate && Array.isArray(candidate.accepts) ? candidate : undefined;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/** Health and version, for `doctor`. Plain HTTP; no MCP session needed. */
|
|
111
|
+
export async function readiness(gatewayUrl, timeoutMs = 10_000) {
|
|
112
|
+
const controller = new AbortController();
|
|
113
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
114
|
+
try {
|
|
115
|
+
const response = await fetch(`${gatewayUrl.replace(/\/$/, "")}/health/ready`, {
|
|
116
|
+
signal: controller.signal,
|
|
117
|
+
});
|
|
118
|
+
const body = await response.json();
|
|
119
|
+
return { reachable: response.ok, status: body.status, version: body.version };
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
return { reachable: false, error: error.message };
|
|
123
|
+
}
|
|
124
|
+
finally {
|
|
125
|
+
clearTimeout(timer);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/gateway/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The lifecycle round trip: ask, validate, sign, retry.
|
|
3
|
+
*
|
|
4
|
+
* The gateway hands out a short-lived challenge; §4.1 check 8 decides whether
|
|
5
|
+
* it describes the call we actually intend to make; only then does the wallet
|
|
6
|
+
* see it. The handle alone is never authority.
|
|
7
|
+
*/
|
|
8
|
+
import { type OrderAction, type SignerAdapter } from "@daski/x402-scheme";
|
|
9
|
+
import type { Address } from "viem";
|
|
10
|
+
import { GatewayClient } from "./client.js";
|
|
11
|
+
export interface LifecycleCallOptions {
|
|
12
|
+
client: GatewayClient;
|
|
13
|
+
signer: SignerAdapter;
|
|
14
|
+
toolName: string;
|
|
15
|
+
action: OrderAction;
|
|
16
|
+
orderHandle: string;
|
|
17
|
+
request: Record<string, unknown>;
|
|
18
|
+
chainId: number;
|
|
19
|
+
/** The gateway URL, which is also the audience. */
|
|
20
|
+
gatewayUrl: string;
|
|
21
|
+
nowSeconds?: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Runs one authorized lifecycle call. Two gateway calls: the challenge, then
|
|
25
|
+
* the authorized retry.
|
|
26
|
+
*/
|
|
27
|
+
export declare function callAuthorizedLifecycleTool(options: LifecycleCallOptions): Promise<Record<string, unknown>>;
|
|
28
|
+
export interface WalletQueryOptions {
|
|
29
|
+
client: GatewayClient;
|
|
30
|
+
signer: SignerAdapter;
|
|
31
|
+
toolName: string;
|
|
32
|
+
/** The wallet action name, e.g. `list-orders`. */
|
|
33
|
+
action: string;
|
|
34
|
+
payer: Address;
|
|
35
|
+
request: Record<string, unknown>;
|
|
36
|
+
chainId: number;
|
|
37
|
+
gatewayUrl: string;
|
|
38
|
+
nowSeconds?: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Runs one payer-scoped wallet query. The unbound variant is asserted: a
|
|
42
|
+
* wallet challenge must not smuggle a provider binding past a read.
|
|
43
|
+
*/
|
|
44
|
+
export declare function callWalletQuery(options: WalletQueryOptions): Promise<Record<string, unknown>>;
|
|
45
|
+
//# sourceMappingURL=lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../src/gateway/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,aAAa,EACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEpC,OAAO,EAAE,aAAa,EAAsB,MAAM,aAAa,CAAC;AAEhE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAgClC;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CA2BlC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The lifecycle round trip: ask, validate, sign, retry.
|
|
3
|
+
*
|
|
4
|
+
* The gateway hands out a short-lived challenge; §4.1 check 8 decides whether
|
|
5
|
+
* it describes the call we actually intend to make; only then does the wallet
|
|
6
|
+
* see it. The handle alone is never authority.
|
|
7
|
+
*/
|
|
8
|
+
import { orderActionTypedData, validateOrderActionChallenge, validateWalletActionChallenge, walletActionTypedData, } from "@daski/x402-scheme";
|
|
9
|
+
import { CliError } from "../cli/errors.js";
|
|
10
|
+
import { GatewayClient } from "./client.js";
|
|
11
|
+
/**
|
|
12
|
+
* Runs one authorized lifecycle call. Two gateway calls: the challenge, then
|
|
13
|
+
* the authorized retry.
|
|
14
|
+
*/
|
|
15
|
+
export async function callAuthorizedLifecycleTool(options) {
|
|
16
|
+
const { client, toolName, orderHandle, request } = options;
|
|
17
|
+
const challengeResult = await client.callTool(toolName, { orderHandle, request });
|
|
18
|
+
const challengeBody = GatewayClient.json(challengeResult);
|
|
19
|
+
if (!challengeBody) {
|
|
20
|
+
throw lifecycleFailure(toolName, challengeResult);
|
|
21
|
+
}
|
|
22
|
+
// A gateway that answers without asking for authorization has already done
|
|
23
|
+
// the work; there is nothing to sign.
|
|
24
|
+
if (challengeBody.authorizationRequired !== true) {
|
|
25
|
+
if (challengeResult.isError)
|
|
26
|
+
throw lifecycleFailure(toolName, challengeResult);
|
|
27
|
+
return challengeBody;
|
|
28
|
+
}
|
|
29
|
+
const challenge = validateOrderActionChallenge(challengeBody.challenge, {
|
|
30
|
+
orderHandle,
|
|
31
|
+
action: options.action,
|
|
32
|
+
gatewayUrl: options.gatewayUrl,
|
|
33
|
+
request,
|
|
34
|
+
...(options.nowSeconds === undefined ? {} : { nowSeconds: options.nowSeconds }),
|
|
35
|
+
});
|
|
36
|
+
const signature = await options.signer.signTypedData(orderActionTypedData(challenge, options.chainId, options.gatewayUrl));
|
|
37
|
+
const authorized = await client.callTool(toolName, {
|
|
38
|
+
orderHandle,
|
|
39
|
+
request,
|
|
40
|
+
authorization: { ...challenge, signature },
|
|
41
|
+
});
|
|
42
|
+
const body = GatewayClient.json(authorized);
|
|
43
|
+
if (authorized.isError || !body)
|
|
44
|
+
throw lifecycleFailure(toolName, authorized);
|
|
45
|
+
return body;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Runs one payer-scoped wallet query. The unbound variant is asserted: a
|
|
49
|
+
* wallet challenge must not smuggle a provider binding past a read.
|
|
50
|
+
*/
|
|
51
|
+
export async function callWalletQuery(options) {
|
|
52
|
+
const { client, toolName, payer, request } = options;
|
|
53
|
+
const challengeResult = await client.callTool(toolName, { payer, ...request });
|
|
54
|
+
const challengeBody = GatewayClient.json(challengeResult);
|
|
55
|
+
if (!challengeBody)
|
|
56
|
+
throw lifecycleFailure(toolName, challengeResult);
|
|
57
|
+
if (challengeBody.authorizationRequired !== true) {
|
|
58
|
+
if (challengeResult.isError)
|
|
59
|
+
throw lifecycleFailure(toolName, challengeResult);
|
|
60
|
+
return challengeBody;
|
|
61
|
+
}
|
|
62
|
+
const challenge = validateWalletActionChallenge(challengeBody.challenge, options.chainId, {
|
|
63
|
+
payer,
|
|
64
|
+
action: options.action,
|
|
65
|
+
audience: options.gatewayUrl,
|
|
66
|
+
request,
|
|
67
|
+
requireProviderBinding: false,
|
|
68
|
+
...(options.nowSeconds === undefined ? {} : { nowSeconds: options.nowSeconds }),
|
|
69
|
+
});
|
|
70
|
+
const signature = await options.signer.signTypedData(walletActionTypedData(challenge));
|
|
71
|
+
const authorized = await client.callTool(toolName, {
|
|
72
|
+
payer,
|
|
73
|
+
...request,
|
|
74
|
+
authorization: { message: challenge.message, signature },
|
|
75
|
+
});
|
|
76
|
+
const body = GatewayClient.json(authorized);
|
|
77
|
+
if (authorized.isError || !body)
|
|
78
|
+
throw lifecycleFailure(toolName, authorized);
|
|
79
|
+
return body;
|
|
80
|
+
}
|
|
81
|
+
function lifecycleFailure(toolName, result) {
|
|
82
|
+
const body = GatewayClient.json(result);
|
|
83
|
+
const code = typeof body?.code === "string" ? body.code : "DASKI_LIFECYCLE_CALL_FAILED";
|
|
84
|
+
const message = typeof body?.message === "string"
|
|
85
|
+
? body.message
|
|
86
|
+
: `${toolName} was rejected by the gateway.`;
|
|
87
|
+
return new CliError({
|
|
88
|
+
code,
|
|
89
|
+
message,
|
|
90
|
+
remediation: typeof body?.next_action === "string"
|
|
91
|
+
? body.next_action
|
|
92
|
+
: `Run \`daski order status <handle>\` to see the order's current state.`,
|
|
93
|
+
details: { tool: toolName, gateway: body ?? null },
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../src/gateway/lifecycle.ts"],"names":[],"mappings":"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"}
|