@paybond/kit 0.9.3 → 0.9.4
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 +35 -18
- package/dist/index.d.ts +66 -0
- package/dist/index.js +206 -2
- package/dist/init.js +182 -54
- package/dist/login.d.ts +35 -0
- package/dist/login.js +435 -0
- package/dist/mcp-server.js +119 -1
- package/package.json +2 -1
package/dist/init.js
CHANGED
|
@@ -11,6 +11,7 @@ const FRAMEWORKS = new Set([
|
|
|
11
11
|
"langgraph",
|
|
12
12
|
"mcp",
|
|
13
13
|
]);
|
|
14
|
+
const PRESETS = new Set(["paid-tool-guard"]);
|
|
14
15
|
const FRAMEWORK_NOTES = {
|
|
15
16
|
generic: "Wrap the returned function around any side-effecting tool handler.",
|
|
16
17
|
"provider-agnostic": "Use the guarded handler with OpenAI, Gemini, Claude/Anthropic, local models, or any custom runtime.",
|
|
@@ -25,26 +26,36 @@ const FRAMEWORK_NOTES = {
|
|
|
25
26
|
};
|
|
26
27
|
function usage() {
|
|
27
28
|
return [
|
|
28
|
-
"Usage: paybond-init [--framework generic|provider-agnostic|openai|claude|anthropic|gemini|google-ai|vercel-ai|langgraph|mcp] [--out paybond-
|
|
29
|
+
"Usage: paybond-init [--preset paid-tool-guard] [--framework generic|provider-agnostic|openai|claude|anthropic|gemini|google-ai|vercel-ai|langgraph|mcp] [--out paybond-guardrail-demo.ts] [--force]",
|
|
29
30
|
"",
|
|
30
|
-
"Scaffolds a Paybond
|
|
31
|
+
"Scaffolds a production-shaped Paybond guardrail integration with a sandbox smoke path.",
|
|
31
32
|
].join("\n");
|
|
32
33
|
}
|
|
33
34
|
function parseArgs(argv) {
|
|
34
|
-
let
|
|
35
|
-
let
|
|
35
|
+
let preset = "paid-tool-guard";
|
|
36
|
+
let framework = "provider-agnostic";
|
|
37
|
+
let out = "paybond-guardrail-demo.ts";
|
|
36
38
|
let force = false;
|
|
37
39
|
for (let i = 0; i < argv.length; i += 1) {
|
|
38
40
|
const arg = argv[i];
|
|
39
41
|
if (arg === "--help" || arg === "-h") {
|
|
40
42
|
process.stdout.write(`${usage()}\n`);
|
|
41
43
|
process.exitCode = 0;
|
|
42
|
-
return { framework, out, force };
|
|
44
|
+
return { preset, framework, out, force };
|
|
43
45
|
}
|
|
44
46
|
if (arg === "--force") {
|
|
45
47
|
force = true;
|
|
46
48
|
continue;
|
|
47
49
|
}
|
|
50
|
+
if (arg === "--preset") {
|
|
51
|
+
const raw = argv[i + 1];
|
|
52
|
+
i += 1;
|
|
53
|
+
if (!raw || !PRESETS.has(raw)) {
|
|
54
|
+
throw new Error("invalid --preset");
|
|
55
|
+
}
|
|
56
|
+
preset = raw;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
48
59
|
if (arg === "--framework") {
|
|
49
60
|
const raw = argv[i + 1];
|
|
50
61
|
i += 1;
|
|
@@ -65,71 +76,173 @@ function parseArgs(argv) {
|
|
|
65
76
|
}
|
|
66
77
|
throw new Error(`unknown argument: ${arg}`);
|
|
67
78
|
}
|
|
68
|
-
return { framework, out, force };
|
|
79
|
+
return { preset, framework, out, force };
|
|
69
80
|
}
|
|
70
81
|
function template(framework) {
|
|
71
|
-
return `import {
|
|
82
|
+
return `import {
|
|
83
|
+
Paybond,
|
|
84
|
+
type SandboxGuardrailBootstrapResult,
|
|
85
|
+
type SandboxGuardrailEvidenceResult,
|
|
86
|
+
} from "@paybond/kit";
|
|
87
|
+
|
|
88
|
+
const DEFAULT_OPERATION = "paid_tool.smoke_test";
|
|
89
|
+
const DEFAULT_REQUESTED_SPEND_CENTS = 500;
|
|
72
90
|
|
|
73
|
-
type
|
|
74
|
-
|
|
91
|
+
export type PaidToolHandler<TInput, TResult> = (input: TInput) => TResult | Promise<TResult>;
|
|
92
|
+
|
|
93
|
+
export type SandboxGuardrailIntentOptions = {
|
|
94
|
+
operation?: string;
|
|
95
|
+
requestedSpendCents?: number;
|
|
96
|
+
currency?: string;
|
|
97
|
+
evidenceSchema?: Record<string, unknown>;
|
|
98
|
+
metadata?: Record<string, unknown>;
|
|
99
|
+
idempotencyKey?: string;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export type SubmitSandboxEvidenceOptions = {
|
|
103
|
+
operation?: string;
|
|
104
|
+
requestedSpendCents?: number;
|
|
105
|
+
metadata?: Record<string, unknown>;
|
|
106
|
+
artifacts?: string[];
|
|
107
|
+
idempotencyKey?: string;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export type SmokePaidToolInput = {
|
|
111
|
+
itemId: string;
|
|
75
112
|
maxPriceCents: number;
|
|
76
113
|
};
|
|
77
114
|
|
|
78
|
-
type
|
|
79
|
-
|
|
80
|
-
|
|
115
|
+
export type SmokePaidToolResult = {
|
|
116
|
+
confirmationId: string;
|
|
117
|
+
itemId: string;
|
|
118
|
+
chargedCents: number;
|
|
119
|
+
sandbox: true;
|
|
81
120
|
};
|
|
82
121
|
|
|
83
|
-
export async function
|
|
122
|
+
export async function openPaybondFromEnv(): Promise<Paybond> {
|
|
123
|
+
const apiKey = process.env.PAYBOND_API_KEY?.trim();
|
|
124
|
+
if (!apiKey) {
|
|
125
|
+
throw new Error("PAYBOND_API_KEY is required");
|
|
126
|
+
}
|
|
127
|
+
|
|
84
128
|
return Paybond.open({
|
|
85
|
-
apiKey
|
|
129
|
+
apiKey,
|
|
130
|
+
gatewayBaseUrl: process.env.PAYBOND_GATEWAY_BASE_URL,
|
|
86
131
|
expectedEnvironment: "sandbox",
|
|
87
132
|
});
|
|
88
133
|
}
|
|
89
134
|
|
|
90
|
-
export function
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
135
|
+
export async function bootstrapSandboxGuardrailIntent(
|
|
136
|
+
paybond: Paybond,
|
|
137
|
+
options: SandboxGuardrailIntentOptions = {},
|
|
138
|
+
): Promise<SandboxGuardrailBootstrapResult> {
|
|
139
|
+
return paybond.guardrails.bootstrapSandbox({
|
|
140
|
+
operation: options.operation ?? DEFAULT_OPERATION,
|
|
141
|
+
requestedSpendCents: options.requestedSpendCents ?? DEFAULT_REQUESTED_SPEND_CENTS,
|
|
142
|
+
currency: options.currency ?? "usd",
|
|
143
|
+
evidenceSchema: options.evidenceSchema ?? {
|
|
144
|
+
type: "object",
|
|
145
|
+
required: ["confirmation_id", "charged_cents"],
|
|
146
|
+
properties: {
|
|
147
|
+
confirmation_id: { type: "string" },
|
|
148
|
+
charged_cents: { type: "integer" },
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
metadata: options.metadata,
|
|
152
|
+
idempotencyKey: options.idempotencyKey,
|
|
153
|
+
});
|
|
100
154
|
}
|
|
101
155
|
|
|
102
|
-
export function
|
|
103
|
-
|
|
104
|
-
|
|
156
|
+
export function wrapPaidTool<TInput, TResult>(
|
|
157
|
+
paybond: Paybond,
|
|
158
|
+
guardrail: Pick<
|
|
159
|
+
SandboxGuardrailBootstrapResult,
|
|
160
|
+
"intent_id" | "capability_token" | "operation" | "requested_spend_cents"
|
|
161
|
+
>,
|
|
162
|
+
handler: PaidToolHandler<TInput, TResult>,
|
|
163
|
+
): (input: TInput) => Promise<Awaited<TResult>> {
|
|
164
|
+
if (!guardrail.capability_token.trim()) {
|
|
165
|
+
throw new Error("sandbox guardrail bootstrap did not return a capability token");
|
|
105
166
|
}
|
|
106
|
-
return { intentId: funded.intentId, capabilityToken: funded.capabilityToken };
|
|
107
|
-
}
|
|
108
167
|
|
|
109
|
-
|
|
110
|
-
// Put the side-effecting tool call here.
|
|
111
|
-
return { confirmation: \`demo-\${input.city}-\${input.maxPriceCents}\` };
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export async function buildGuardedHotelTool(params: {
|
|
115
|
-
paybond: Paybond;
|
|
116
|
-
intentId: string;
|
|
117
|
-
capabilityToken: string;
|
|
118
|
-
}): Promise<(input: ToolInput) => Promise<{ confirmation: string }>> {
|
|
119
|
-
if (!params.capabilityToken.trim()) {
|
|
120
|
-
throw new Error("fund the intent before guarding tools");
|
|
121
|
-
}
|
|
122
|
-
const guard = params.paybond.spendGuard(params.intentId, params.capabilityToken);
|
|
168
|
+
const guard = paybond.spendGuard(guardrail.intent_id, guardrail.capability_token);
|
|
123
169
|
|
|
124
170
|
// ${FRAMEWORK_NOTES[framework]}
|
|
125
171
|
return guard.guardTool(
|
|
126
172
|
{
|
|
127
|
-
operation:
|
|
128
|
-
requestedSpendCents:
|
|
173
|
+
operation: guardrail.operation,
|
|
174
|
+
requestedSpendCents: guardrail.requested_spend_cents,
|
|
129
175
|
},
|
|
130
|
-
|
|
176
|
+
handler,
|
|
131
177
|
);
|
|
132
178
|
}
|
|
179
|
+
|
|
180
|
+
export async function submitSandboxEvidence(
|
|
181
|
+
paybond: Paybond,
|
|
182
|
+
guardrail: Pick<SandboxGuardrailBootstrapResult, "intent_id" | "operation" | "requested_spend_cents">,
|
|
183
|
+
payload: Record<string, unknown>,
|
|
184
|
+
options: SubmitSandboxEvidenceOptions = {},
|
|
185
|
+
): Promise<SandboxGuardrailEvidenceResult> {
|
|
186
|
+
return paybond.guardrails.submitSandboxEvidence({
|
|
187
|
+
intentId: guardrail.intent_id,
|
|
188
|
+
payload,
|
|
189
|
+
artifacts: options.artifacts,
|
|
190
|
+
operation: options.operation ?? guardrail.operation,
|
|
191
|
+
requestedSpendCents: options.requestedSpendCents ?? guardrail.requested_spend_cents,
|
|
192
|
+
metadata: options.metadata,
|
|
193
|
+
idempotencyKey: options.idempotencyKey,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export async function replaceableSmokeTestPaidTool(
|
|
198
|
+
input: SmokePaidToolInput,
|
|
199
|
+
): Promise<SmokePaidToolResult> {
|
|
200
|
+
// Replace this sandbox smoke-test function with the real paid side-effecting tool.
|
|
201
|
+
return {
|
|
202
|
+
confirmationId: "sandbox-confirmation-" + input.itemId,
|
|
203
|
+
itemId: input.itemId,
|
|
204
|
+
chargedCents: Math.min(input.maxPriceCents, DEFAULT_REQUESTED_SPEND_CENTS),
|
|
205
|
+
sandbox: true,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export async function runSandboxSmokePath(): Promise<{
|
|
210
|
+
guardrail: SandboxGuardrailBootstrapResult;
|
|
211
|
+
toolResult: SmokePaidToolResult;
|
|
212
|
+
evidence: SandboxGuardrailEvidenceResult;
|
|
213
|
+
}> {
|
|
214
|
+
const paybond = await openPaybondFromEnv();
|
|
215
|
+
const guardrail = await bootstrapSandboxGuardrailIntent(paybond);
|
|
216
|
+
const guardedTool = wrapPaidTool(paybond, guardrail, replaceableSmokeTestPaidTool);
|
|
217
|
+
const toolResult = await guardedTool({
|
|
218
|
+
itemId: "replace-with-your-tool-input",
|
|
219
|
+
maxPriceCents: DEFAULT_REQUESTED_SPEND_CENTS,
|
|
220
|
+
});
|
|
221
|
+
const evidence = await submitSandboxEvidence(paybond, guardrail, {
|
|
222
|
+
confirmation_id: toolResult.confirmationId,
|
|
223
|
+
charged_cents: toolResult.chargedCents,
|
|
224
|
+
item_id: toolResult.itemId,
|
|
225
|
+
sandbox: toolResult.sandbox,
|
|
226
|
+
});
|
|
227
|
+
return { guardrail, toolResult, evidence };
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
async function main(): Promise<void> {
|
|
231
|
+
const result = await runSandboxSmokePath();
|
|
232
|
+
console.log(JSON.stringify(result, null, 2));
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function normalizeFileURL(url: string): string {
|
|
236
|
+
return url.startsWith("file:///var/") ? url.replace("file:///var/", "file:///private/var/") : url;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const invokedPath = process.argv[1] ? normalizeFileURL(new URL("file://" + process.argv[1]).href) : "";
|
|
240
|
+
if (invokedPath && normalizeFileURL(import.meta.url) === invokedPath) {
|
|
241
|
+
main().catch((err) => {
|
|
242
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
243
|
+
process.exitCode = 1;
|
|
244
|
+
});
|
|
245
|
+
}
|
|
133
246
|
`;
|
|
134
247
|
}
|
|
135
248
|
async function writeScaffold(out, body, force) {
|
|
@@ -162,13 +275,28 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
162
275
|
if (argv.includes("--help") || argv.includes("-h")) {
|
|
163
276
|
return 0;
|
|
164
277
|
}
|
|
165
|
-
|
|
166
|
-
|
|
278
|
+
try {
|
|
279
|
+
await writeScaffold(parsed.out, template(parsed.framework), parsed.force);
|
|
280
|
+
}
|
|
281
|
+
catch (err) {
|
|
282
|
+
process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`);
|
|
283
|
+
return 1;
|
|
284
|
+
}
|
|
285
|
+
process.stdout.write(`Created Paybond guardrail integration: ${parsed.out}\n`);
|
|
167
286
|
return 0;
|
|
168
287
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
process.
|
|
174
|
-
|
|
288
|
+
function normalizeFileURL(url) {
|
|
289
|
+
return url.startsWith("file:///var/") ? url.replace("file:///var/", "file:///private/var/") : url;
|
|
290
|
+
}
|
|
291
|
+
function invokedFromCLI() {
|
|
292
|
+
const invokedPath = process.argv[1] ? normalizeFileURL(new URL("file://" + process.argv[1]).href) : "";
|
|
293
|
+
return Boolean(invokedPath && normalizeFileURL(import.meta.url) === invokedPath);
|
|
294
|
+
}
|
|
295
|
+
if (invokedFromCLI()) {
|
|
296
|
+
main().then((code) => {
|
|
297
|
+
process.exitCode = code;
|
|
298
|
+
}, (err) => {
|
|
299
|
+
process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`);
|
|
300
|
+
process.exitCode = 1;
|
|
301
|
+
});
|
|
302
|
+
}
|
package/dist/login.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
type Writable = {
|
|
3
|
+
write(chunk: string): boolean;
|
|
4
|
+
};
|
|
5
|
+
export type DeviceEnvironment = "sandbox" | "live";
|
|
6
|
+
export type LoginOptions = {
|
|
7
|
+
envFile: string;
|
|
8
|
+
gateway: string;
|
|
9
|
+
environment: DeviceEnvironment;
|
|
10
|
+
noOpen: boolean;
|
|
11
|
+
force: boolean;
|
|
12
|
+
};
|
|
13
|
+
type FetchInput = string | URL;
|
|
14
|
+
type FetchInit = {
|
|
15
|
+
method?: string;
|
|
16
|
+
headers?: Record<string, string>;
|
|
17
|
+
body?: string;
|
|
18
|
+
};
|
|
19
|
+
type FetchLike = (input: FetchInput, init?: FetchInit) => Promise<Response>;
|
|
20
|
+
export type LoginDependencies = {
|
|
21
|
+
cwd?: string;
|
|
22
|
+
fetch?: FetchLike;
|
|
23
|
+
sleep?: (ms: number) => Promise<void>;
|
|
24
|
+
openBrowser?: (url: string) => Promise<boolean>;
|
|
25
|
+
stdout?: Writable;
|
|
26
|
+
stderr?: Writable;
|
|
27
|
+
now?: () => number;
|
|
28
|
+
};
|
|
29
|
+
export declare function parseArgs(argv: string[]): LoginOptions | "help";
|
|
30
|
+
export declare function assertGitIgnored(envPath: string, cwd: string): Promise<void>;
|
|
31
|
+
export declare function assertCanWriteEnvFile(envPath: string, force: boolean): Promise<void>;
|
|
32
|
+
export declare function writeEnvFile(envPath: string, rawKey: string, force: boolean): Promise<void>;
|
|
33
|
+
export declare function runLogin(options: LoginOptions, deps?: LoginDependencies): Promise<number>;
|
|
34
|
+
export declare function main(argv?: string[], deps?: LoginDependencies): Promise<number>;
|
|
35
|
+
export {};
|