@paybond/kit 0.11.11 → 0.12.1
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/completion-presets/catalog.json +10 -5
- package/completion-presets/catalog.sha256 +1 -1
- package/dist/agent/evidence.d.ts +10 -0
- package/dist/agent/evidence.js +16 -0
- package/dist/agent/index.d.ts +3 -2
- package/dist/agent/index.js +2 -1
- package/dist/agent/interceptor.d.ts +9 -0
- package/dist/agent/interceptor.js +181 -1
- package/dist/agent/receipt-client.d.ts +64 -0
- package/dist/agent/receipt-client.js +45 -0
- package/dist/agent/registry.js +1 -0
- package/dist/agent/run.d.ts +5 -0
- package/dist/agent/run.js +52 -0
- package/dist/agent/types.d.ts +70 -0
- package/dist/agent-mandate.d.ts +103 -0
- package/dist/agent-mandate.js +423 -0
- package/dist/agent-receipt-external-attestations.d.ts +56 -0
- package/dist/agent-receipt-external-attestations.js +185 -0
- package/dist/agent-receipt-pdf-export.d.ts +43 -0
- package/dist/agent-receipt-pdf-export.js +109 -0
- package/dist/agent-receipt-prevalidate.d.ts +7 -0
- package/dist/agent-receipt-prevalidate.js +63 -0
- package/dist/agent-receipt.d.ts +154 -0
- package/dist/agent-receipt.js +639 -0
- package/dist/audit/exports.d.ts +15 -1
- package/dist/audit/exports.js +55 -8
- package/dist/audit/index.d.ts +2 -2
- package/dist/audit/wire.d.ts +12 -0
- package/dist/audit/wire.js +13 -1
- package/dist/cli/command-spec.js +54 -3
- package/dist/cli/commands/dev.js +10 -3
- package/dist/cli/commands/discovery.js +17 -6
- package/dist/cli/commands/setup.js +19 -1
- package/dist/cli/commands/shopify.d.ts +53 -0
- package/dist/cli/commands/shopify.js +808 -0
- package/dist/cli/help.d.ts +1 -1
- package/dist/cli/help.js +15 -5
- package/dist/cli/router.js +15 -1
- package/dist/commerce-binding.d.ts +59 -0
- package/dist/commerce-binding.js +129 -0
- package/dist/completion-catalog-digest.d.ts +1 -1
- package/dist/completion-catalog-digest.js +1 -1
- package/dist/doctor-completion.d.ts +16 -0
- package/dist/doctor-completion.js +157 -1
- package/dist/index.d.ts +108 -7
- package/dist/index.js +221 -18
- package/dist/mcp-receipt-resource.d.ts +10 -0
- package/dist/mcp-receipt-resource.js +32 -0
- package/dist/mcp-server.d.ts +7 -0
- package/dist/mcp-server.js +81 -1
- package/dist/mpp-commercial.d.ts +19 -0
- package/dist/mpp-commercial.js +34 -0
- package/dist/mpp-funding.d.ts +71 -0
- package/dist/mpp-funding.js +192 -0
- package/dist/payment-transport.d.ts +30 -0
- package/dist/payment-transport.js +56 -0
- package/dist/policy/intent-spec.js +2 -0
- package/dist/policy/presets.d.ts +1 -1
- package/dist/policy/presets.js +1 -0
- package/dist/principal-intent.d.ts +1 -1
- package/dist/principal-intent.js +4 -1
- package/dist/project-init.d.ts +1 -1
- package/dist/project-init.js +1 -0
- package/dist/protocol-receipt.d.ts +129 -0
- package/dist/protocol-receipt.js +620 -0
- package/dist/shopify/checkout.d.ts +29 -0
- package/dist/shopify/checkout.js +79 -0
- package/dist/shopify/evidence.d.ts +13 -0
- package/dist/shopify/evidence.js +85 -0
- package/dist/shopify/index.d.ts +8 -0
- package/dist/shopify/index.js +6 -0
- package/dist/shopify/instrument.d.ts +61 -0
- package/dist/shopify/instrument.js +52 -0
- package/dist/shopify/order.d.ts +8 -0
- package/dist/shopify/order.js +110 -0
- package/dist/shopify/types.d.ts +82 -0
- package/dist/shopify/types.js +4 -0
- package/dist/solutions/catalog.d.ts +1 -1
- package/dist/solutions/catalog.js +1 -1
- package/dist/stripe-commerce/evidence.d.ts +13 -0
- package/dist/stripe-commerce/evidence.js +164 -0
- package/dist/stripe-commerce/index.d.ts +3 -0
- package/dist/stripe-commerce/index.js +2 -0
- package/dist/stripe-commerce/metadata.d.ts +11 -0
- package/dist/stripe-commerce/metadata.js +34 -0
- package/dist/stripe-commerce/types.d.ts +38 -0
- package/dist/stripe-commerce/types.js +1 -0
- package/dist/template-init.d.ts +1 -1
- package/dist/template-init.js +6 -1
- package/package.json +1 -1
- package/policy/presets/stripe-commerce.yaml +19 -0
- package/solutions/stripe-commerce.json +19 -0
- package/templates/manifest.json +82 -10
- package/templates/openai-shopping-agent/package-lock.json +13 -13
- package/templates/openai-shopping-agent/src/paybond.config.ts +1 -1
- package/templates/paybond-aws-operator/package-lock.json +7 -7
- package/templates/paybond-aws-operator/src/paybond.config.ts +1 -1
- package/templates/paybond-claude-agents-demo/package-lock.json +10 -10
- package/templates/paybond-claude-agents-demo/src/paybond.config.ts +1 -1
- package/templates/paybond-mastra-travel-agent/package-lock.json +33 -33
- package/templates/paybond-mastra-travel-agent/src/paybond.config.ts +1 -1
- package/templates/paybond-mcp-coding-agent/package-lock.json +7 -7
- package/templates/paybond-mcp-coding-agent/src/paybond.config.ts +1 -1
- package/templates/paybond-openai-agents-demo/package-lock.json +13 -13
- package/templates/paybond-openai-agents-demo/src/paybond.config.ts +1 -1
- package/templates/paybond-procurement-agent/package-lock.json +7 -7
- package/templates/paybond-procurement-agent/src/paybond.config.ts +1 -1
- package/templates/paybond-shopify-shopping-agent/.env.example +3 -0
- package/templates/paybond-shopify-shopping-agent/.github/workflows/smoke.yml +20 -0
- package/templates/paybond-shopify-shopping-agent/LICENSE +201 -0
- package/templates/paybond-shopify-shopping-agent/README.md +29 -0
- package/templates/paybond-shopify-shopping-agent/package-lock.json +223 -0
- package/templates/paybond-shopify-shopping-agent/package.json +20 -0
- package/templates/paybond-shopify-shopping-agent/paybond.policy.yaml +22 -0
- package/templates/paybond-shopify-shopping-agent/src/index.ts +54 -0
- package/templates/paybond-shopify-shopping-agent/src/paybond.config.ts +51 -0
- package/templates/paybond-shopify-shopping-agent/tsconfig.json +13 -0
- package/templates/paybond-stripe-agent-demo/.env.example +9 -0
- package/templates/paybond-stripe-agent-demo/.github/workflows/smoke.yml +20 -0
- package/templates/paybond-stripe-agent-demo/LICENSE +201 -0
- package/templates/paybond-stripe-agent-demo/README.md +50 -0
- package/templates/paybond-stripe-agent-demo/package-lock.json +223 -0
- package/templates/paybond-stripe-agent-demo/package.json +20 -0
- package/templates/paybond-stripe-agent-demo/paybond.policy.yaml +22 -0
- package/templates/paybond-stripe-agent-demo/src/charge-customer.ts +237 -0
- package/templates/paybond-stripe-agent-demo/src/index.ts +78 -0
- package/templates/paybond-stripe-agent-demo/src/paybond.config.ts +51 -0
- package/templates/paybond-stripe-agent-demo/tsconfig.json +13 -0
- package/templates/paybond-travel-agent/package-lock.json +13 -13
- package/templates/paybond-travel-agent/src/paybond.config.ts +1 -1
- package/templates/paybond-vercel-shopping-agent/package-lock.json +7 -7
- package/templates/paybond-vercel-shopping-agent/src/paybond.config.ts +1 -1
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "paybond-stripe-agent-demo",
|
|
3
|
+
"lockfileVersion": 3,
|
|
4
|
+
"requires": true,
|
|
5
|
+
"packages": {
|
|
6
|
+
"": {
|
|
7
|
+
"name": "paybond-stripe-agent-demo",
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"@paybond/kit": "^0.12.1"
|
|
10
|
+
},
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"@types/node": "^22.10.1",
|
|
13
|
+
"typescript": "^5.7.2"
|
|
14
|
+
},
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=22"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"node_modules/@noble/ed25519": {
|
|
20
|
+
"version": "2.3.0",
|
|
21
|
+
"resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-2.3.0.tgz",
|
|
22
|
+
"integrity": "sha512-M7dvXL2B92/M7dw9+gzuydL8qn/jiqNHaoR3Q+cb1q1GHV7uwE17WCyFMG+Y+TZb5izcaXk5TdJRrDUxHXL78A==",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"funding": {
|
|
25
|
+
"url": "https://paulmillr.com/funding/"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"node_modules/@noble/hashes": {
|
|
29
|
+
"version": "1.8.0",
|
|
30
|
+
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz",
|
|
31
|
+
"integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": "^14.21.3 || >=16"
|
|
35
|
+
},
|
|
36
|
+
"funding": {
|
|
37
|
+
"url": "https://paulmillr.com/funding/"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"node_modules/@noble/secp256k1": {
|
|
41
|
+
"version": "2.3.0",
|
|
42
|
+
"resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-2.3.0.tgz",
|
|
43
|
+
"integrity": "sha512-0TQed2gcBbIrh7Ccyw+y/uZQvbJwm7Ao4scBUxqpBCcsOlZG0O4KGfjtNAy/li4W8n1xt3dxrwJ0beZ2h2G6Kw==",
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"funding": {
|
|
46
|
+
"url": "https://paulmillr.com/funding/"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"node_modules/@paybond/kit": {
|
|
50
|
+
"version": "0.12.1",
|
|
51
|
+
"resolved": "https://registry.npmjs.org/@paybond/kit/-/kit-0.12.1.tgz",
|
|
52
|
+
"integrity": "sha512-I/IdvsORxy5TE38dSZnPNMeRwe1kgmqoQxHi4IVUE5dCBkcPmIO+Sl/oh+h5qPbzhKMv1eLakIhFKhs+cM9VjQ==",
|
|
53
|
+
"license": "Apache-2.0",
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@noble/ed25519": "^2.2.1",
|
|
56
|
+
"@noble/hashes": "^1.7.1",
|
|
57
|
+
"@noble/secp256k1": "^2.2.3",
|
|
58
|
+
"ajv": "^8.17.1",
|
|
59
|
+
"blake3": "^2.1.7",
|
|
60
|
+
"uuid": "^14.0.0",
|
|
61
|
+
"zod": "^3.25.32 || ^4.2.0"
|
|
62
|
+
},
|
|
63
|
+
"bin": {
|
|
64
|
+
"paybond": "dist/cli.js",
|
|
65
|
+
"paybond-init": "dist/init.js",
|
|
66
|
+
"paybond-kit-login": "dist/login.js",
|
|
67
|
+
"paybond-mcp-server": "dist/mcp-server.js"
|
|
68
|
+
},
|
|
69
|
+
"engines": {
|
|
70
|
+
"node": ">=22"
|
|
71
|
+
},
|
|
72
|
+
"peerDependencies": {
|
|
73
|
+
"@anthropic-ai/claude-agent-sdk": ">=0.2.100",
|
|
74
|
+
"@langchain/core": ">=0.3.0",
|
|
75
|
+
"@langchain/langgraph": ">=0.2.50",
|
|
76
|
+
"@mastra/core": ">=1.0.0",
|
|
77
|
+
"@openai/agents": ">=0.12.0",
|
|
78
|
+
"agents": ">=0.10.0",
|
|
79
|
+
"ai": ">=4.0.0",
|
|
80
|
+
"zod": "^3.25.32 || ^4.2.0"
|
|
81
|
+
},
|
|
82
|
+
"peerDependenciesMeta": {
|
|
83
|
+
"@anthropic-ai/claude-agent-sdk": {
|
|
84
|
+
"optional": true
|
|
85
|
+
},
|
|
86
|
+
"@langchain/core": {
|
|
87
|
+
"optional": true
|
|
88
|
+
},
|
|
89
|
+
"@langchain/langgraph": {
|
|
90
|
+
"optional": true
|
|
91
|
+
},
|
|
92
|
+
"@mastra/core": {
|
|
93
|
+
"optional": true
|
|
94
|
+
},
|
|
95
|
+
"@openai/agents": {
|
|
96
|
+
"optional": true
|
|
97
|
+
},
|
|
98
|
+
"agents": {
|
|
99
|
+
"optional": true
|
|
100
|
+
},
|
|
101
|
+
"ai": {
|
|
102
|
+
"optional": true
|
|
103
|
+
},
|
|
104
|
+
"zod": {
|
|
105
|
+
"optional": true
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"node_modules/@types/node": {
|
|
110
|
+
"version": "22.20.0",
|
|
111
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.0.tgz",
|
|
112
|
+
"integrity": "sha512-QWlFW2wf3nTjC13/DqRnBpR4ZO36VJH/JVBkA/vcnmbTBNQIlnObqyqZE1tUR7+Ni23Lda8R1BxMfbXRpCUx5g==",
|
|
113
|
+
"dev": true,
|
|
114
|
+
"license": "MIT",
|
|
115
|
+
"dependencies": {
|
|
116
|
+
"undici-types": "~6.21.0"
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
"node_modules/ajv": {
|
|
120
|
+
"version": "8.20.0",
|
|
121
|
+
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
|
|
122
|
+
"integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
|
|
123
|
+
"license": "MIT",
|
|
124
|
+
"dependencies": {
|
|
125
|
+
"fast-deep-equal": "^3.1.3",
|
|
126
|
+
"fast-uri": "^3.0.1",
|
|
127
|
+
"json-schema-traverse": "^1.0.0",
|
|
128
|
+
"require-from-string": "^2.0.2"
|
|
129
|
+
},
|
|
130
|
+
"funding": {
|
|
131
|
+
"type": "github",
|
|
132
|
+
"url": "https://github.com/sponsors/epoberezkin"
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
"node_modules/blake3": {
|
|
136
|
+
"version": "2.1.7",
|
|
137
|
+
"resolved": "https://registry.npmjs.org/blake3/-/blake3-2.1.7.tgz",
|
|
138
|
+
"integrity": "sha512-5d+TdKJvju96IyEaGJ0eO6CHbckWi+NBrCezGYM/WsnI3R03aLL2TWfsuZSh1rs0fTv/L3ps/r0vykjYurcIwA==",
|
|
139
|
+
"hasInstallScript": true,
|
|
140
|
+
"license": "MIT"
|
|
141
|
+
},
|
|
142
|
+
"node_modules/fast-deep-equal": {
|
|
143
|
+
"version": "3.1.3",
|
|
144
|
+
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
|
145
|
+
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
|
146
|
+
"license": "MIT"
|
|
147
|
+
},
|
|
148
|
+
"node_modules/fast-uri": {
|
|
149
|
+
"version": "3.1.3",
|
|
150
|
+
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.3.tgz",
|
|
151
|
+
"integrity": "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==",
|
|
152
|
+
"funding": [
|
|
153
|
+
{
|
|
154
|
+
"type": "github",
|
|
155
|
+
"url": "https://github.com/sponsors/fastify"
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"type": "opencollective",
|
|
159
|
+
"url": "https://opencollective.com/fastify"
|
|
160
|
+
}
|
|
161
|
+
],
|
|
162
|
+
"license": "BSD-3-Clause"
|
|
163
|
+
},
|
|
164
|
+
"node_modules/json-schema-traverse": {
|
|
165
|
+
"version": "1.0.0",
|
|
166
|
+
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
|
167
|
+
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
|
168
|
+
"license": "MIT"
|
|
169
|
+
},
|
|
170
|
+
"node_modules/require-from-string": {
|
|
171
|
+
"version": "2.0.2",
|
|
172
|
+
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
|
173
|
+
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
|
|
174
|
+
"license": "MIT",
|
|
175
|
+
"engines": {
|
|
176
|
+
"node": ">=0.10.0"
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
"node_modules/typescript": {
|
|
180
|
+
"version": "5.9.3",
|
|
181
|
+
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
|
182
|
+
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
|
183
|
+
"dev": true,
|
|
184
|
+
"license": "Apache-2.0",
|
|
185
|
+
"bin": {
|
|
186
|
+
"tsc": "bin/tsc",
|
|
187
|
+
"tsserver": "bin/tsserver"
|
|
188
|
+
},
|
|
189
|
+
"engines": {
|
|
190
|
+
"node": ">=14.17"
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
"node_modules/undici-types": {
|
|
194
|
+
"version": "6.21.0",
|
|
195
|
+
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
|
196
|
+
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
|
197
|
+
"dev": true,
|
|
198
|
+
"license": "MIT"
|
|
199
|
+
},
|
|
200
|
+
"node_modules/uuid": {
|
|
201
|
+
"version": "14.0.1",
|
|
202
|
+
"resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.1.tgz",
|
|
203
|
+
"integrity": "sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==",
|
|
204
|
+
"funding": [
|
|
205
|
+
"https://github.com/sponsors/broofa",
|
|
206
|
+
"https://github.com/sponsors/ctavan"
|
|
207
|
+
],
|
|
208
|
+
"license": "MIT",
|
|
209
|
+
"bin": {
|
|
210
|
+
"uuid": "dist-node/bin/uuid"
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
"node_modules/zod": {
|
|
214
|
+
"version": "4.4.3",
|
|
215
|
+
"resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
|
|
216
|
+
"integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
|
|
217
|
+
"license": "MIT",
|
|
218
|
+
"funding": {
|
|
219
|
+
"url": "https://github.com/sponsors/colinhacks"
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "paybond-stripe-agent-demo",
|
|
3
|
+
"private": false,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "tsc -p tsconfig.json",
|
|
7
|
+
"start": "node dist/index.js",
|
|
8
|
+
"smoke": "paybond agent sandbox smoke --policy-file paybond.policy.yaml --operation payments.charge_customer --requested-spend-cents 2500 --result-body '{\"payment_intent_id\":\"pi_smoke\",\"charge_id\":\"ch_smoke\",\"cost_cents\":2500,\"status\":\"succeeded\"}' --format json"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@paybond/kit": "^0.12.1"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"@types/node": "^22.10.1",
|
|
15
|
+
"typescript": "^5.7.2"
|
|
16
|
+
},
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=22"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Reference implementation — edit freely. Regenerate with:
|
|
2
|
+
# paybond policy init --preset stripe-commerce --out paybond.policy.yaml
|
|
3
|
+
|
|
4
|
+
version: 1
|
|
5
|
+
name: stripe-commerce-agent-v1
|
|
6
|
+
default_deny: true
|
|
7
|
+
|
|
8
|
+
tools:
|
|
9
|
+
payments.charge_customer:
|
|
10
|
+
side_effecting: true
|
|
11
|
+
max_spend_cents: 50000
|
|
12
|
+
evidence_preset: stripe_charge
|
|
13
|
+
|
|
14
|
+
payments.list_invoices:
|
|
15
|
+
side_effecting: false
|
|
16
|
+
|
|
17
|
+
intent:
|
|
18
|
+
allowed_tools:
|
|
19
|
+
- payments.charge_customer
|
|
20
|
+
budget:
|
|
21
|
+
currency: usd
|
|
22
|
+
max_spend_usd: 500
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildPaybondStripeMetadata,
|
|
3
|
+
mapStripeToolResultToEvidence,
|
|
4
|
+
type PaybondEnvironment,
|
|
5
|
+
type PaybondStripeSettlementRail,
|
|
6
|
+
type StripeCommerceEvidencePreset,
|
|
7
|
+
type StripeToolResultInput,
|
|
8
|
+
} from "@paybond/kit";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Resolved Paybond session environment used to gate the optional Stripe test-mode charge.
|
|
12
|
+
* `"unknown"` when the gateway did not report one — treated as non-sandbox (fail closed).
|
|
13
|
+
*/
|
|
14
|
+
export type PaybondSessionEnvironment = PaybondEnvironment | "unknown";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Paybond session binding for Stripe metadata — never sourced from client input.
|
|
18
|
+
*
|
|
19
|
+
* Tenant isolation + sandbox-only invariant: `tenantId`/`intentId` come from the authenticated
|
|
20
|
+
* Paybond session (populated after sandbox bind), and `environment` is the server-derived session
|
|
21
|
+
* environment. The optional Stripe test-mode charge is a per-tenant capability that is only valid
|
|
22
|
+
* when `environment === "sandbox"` — a live session must never forward a template-held secret to
|
|
23
|
+
* Stripe.
|
|
24
|
+
*/
|
|
25
|
+
export type PaybondSessionBinding = {
|
|
26
|
+
tenantId: string;
|
|
27
|
+
intentId: string;
|
|
28
|
+
environment: PaybondSessionEnvironment;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type ChargeCustomerArgs = {
|
|
32
|
+
amountCents: number;
|
|
33
|
+
customerId?: string;
|
|
34
|
+
rail?: PaybondStripeSettlementRail;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export type ChargeCustomerResult = StripeToolResultInput & {
|
|
38
|
+
payment_intent_id: string;
|
|
39
|
+
charge_id: string;
|
|
40
|
+
cost_cents: number;
|
|
41
|
+
status: string;
|
|
42
|
+
metadata: Record<string, string>;
|
|
43
|
+
mode: "mock" | "stripe_test";
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
function assertPositiveIntegerAmount(amountCents: number): void {
|
|
47
|
+
if (!Number.isInteger(amountCents) || amountCents <= 0) {
|
|
48
|
+
throw new Error("amountCents must be a positive integer");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function mockSuffix(intentId: string): string {
|
|
53
|
+
return intentId.replace(/-/g, "").slice(0, 12) || "demo";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Offline mock charge — no Stripe secret required.
|
|
58
|
+
*/
|
|
59
|
+
export function mockChargeCustomer(
|
|
60
|
+
metadata: Record<string, string>,
|
|
61
|
+
args: ChargeCustomerArgs,
|
|
62
|
+
intentId: string,
|
|
63
|
+
): ChargeCustomerResult {
|
|
64
|
+
assertPositiveIntegerAmount(args.amountCents);
|
|
65
|
+
const suffix = mockSuffix(intentId);
|
|
66
|
+
return {
|
|
67
|
+
payment_intent_id: `pi_mock_${suffix}`,
|
|
68
|
+
charge_id: `ch_mock_${suffix}`,
|
|
69
|
+
cost_cents: args.amountCents,
|
|
70
|
+
status: "succeeded",
|
|
71
|
+
metadata,
|
|
72
|
+
mode: "mock",
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function stripeMetadataParams(metadata: Record<string, string>): URLSearchParams {
|
|
77
|
+
const params = new URLSearchParams();
|
|
78
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
79
|
+
params.set(`metadata[${key}]`, value);
|
|
80
|
+
}
|
|
81
|
+
return params;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Optional Stripe test-mode PaymentIntent create + confirm via REST (requires `STRIPE_SECRET_KEY`).
|
|
86
|
+
*/
|
|
87
|
+
export async function stripeTestChargeCustomer(
|
|
88
|
+
secretKey: string,
|
|
89
|
+
metadata: Record<string, string>,
|
|
90
|
+
args: ChargeCustomerArgs,
|
|
91
|
+
): Promise<ChargeCustomerResult> {
|
|
92
|
+
assertPositiveIntegerAmount(args.amountCents);
|
|
93
|
+
|
|
94
|
+
const body = stripeMetadataParams(metadata);
|
|
95
|
+
body.set("amount", String(args.amountCents));
|
|
96
|
+
body.set("currency", "usd");
|
|
97
|
+
body.set("confirm", "true");
|
|
98
|
+
body.set("payment_method", "pm_card_visa");
|
|
99
|
+
if (args.customerId?.trim()) {
|
|
100
|
+
body.set("customer", args.customerId.trim());
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const response = await fetch("https://api.stripe.com/v1/payment_intents", {
|
|
104
|
+
method: "POST",
|
|
105
|
+
headers: {
|
|
106
|
+
Authorization: `Bearer ${secretKey}`,
|
|
107
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
108
|
+
},
|
|
109
|
+
body,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const payload = (await response.json()) as Record<string, unknown>;
|
|
113
|
+
if (!response.ok) {
|
|
114
|
+
const message =
|
|
115
|
+
typeof payload.error === "object" &&
|
|
116
|
+
payload.error !== null &&
|
|
117
|
+
"message" in payload.error &&
|
|
118
|
+
typeof payload.error.message === "string"
|
|
119
|
+
? payload.error.message
|
|
120
|
+
: `Stripe API error (${response.status})`;
|
|
121
|
+
throw new Error(message);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const paymentIntentId =
|
|
125
|
+
typeof payload.id === "string" && payload.id.startsWith("pi_") ? payload.id : undefined;
|
|
126
|
+
if (!paymentIntentId) {
|
|
127
|
+
throw new Error("Stripe response missing payment_intent id");
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
let chargeId: string | undefined;
|
|
131
|
+
const latestCharge = payload.latest_charge;
|
|
132
|
+
if (typeof latestCharge === "string" && latestCharge.startsWith("ch_")) {
|
|
133
|
+
chargeId = latestCharge;
|
|
134
|
+
} else if (
|
|
135
|
+
typeof latestCharge === "object" &&
|
|
136
|
+
latestCharge !== null &&
|
|
137
|
+
"id" in latestCharge &&
|
|
138
|
+
typeof latestCharge.id === "string"
|
|
139
|
+
) {
|
|
140
|
+
chargeId = latestCharge.id;
|
|
141
|
+
}
|
|
142
|
+
if (!chargeId) {
|
|
143
|
+
throw new Error("Stripe response missing charge id");
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const status = typeof payload.status === "string" ? payload.status : "succeeded";
|
|
147
|
+
return {
|
|
148
|
+
payment_intent_id: paymentIntentId,
|
|
149
|
+
charge_id: chargeId,
|
|
150
|
+
cost_cents: args.amountCents,
|
|
151
|
+
status,
|
|
152
|
+
metadata,
|
|
153
|
+
mode: "stripe_test",
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Resolve the sandbox-only Stripe test key, enforcing the per-tenant + sandbox-only invariant.
|
|
159
|
+
*
|
|
160
|
+
* Returns the validated `sk_test_...` secret only when a secret is present AND the bound Paybond
|
|
161
|
+
* session environment is `sandbox`. Returns `undefined` when no secret is configured (the default
|
|
162
|
+
* offline mock path). Fails closed with an explanatory message when:
|
|
163
|
+
* - a secret is set but the session is not sandbox (live or unknown environment), or
|
|
164
|
+
* - the secret is not a Stripe TEST key (e.g. a live `sk_live_...` key).
|
|
165
|
+
*
|
|
166
|
+
* This guarantees a live tenant can never forward a template-held secret to Stripe.
|
|
167
|
+
*
|
|
168
|
+
* @param environment Server-derived Paybond session environment (preferred over client hints).
|
|
169
|
+
* @returns The validated Stripe test secret, or `undefined` to use the offline mock.
|
|
170
|
+
*/
|
|
171
|
+
export function resolveSandboxStripeTestKey(
|
|
172
|
+
environment: PaybondSessionEnvironment,
|
|
173
|
+
): string | undefined {
|
|
174
|
+
const stripeSecretKey = process.env.STRIPE_SECRET_KEY?.trim();
|
|
175
|
+
if (!stripeSecretKey) {
|
|
176
|
+
// Default offline path: no secret required, so `paybond dev loop --offline` and the sandbox
|
|
177
|
+
// smoke run with zero secrets.
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (environment !== "sandbox") {
|
|
182
|
+
throw new Error(
|
|
183
|
+
`STRIPE_SECRET_KEY is set but the Paybond session environment is "${environment}". ` +
|
|
184
|
+
"The Stripe test-mode charge is a per-tenant, sandbox-only capability; unset " +
|
|
185
|
+
"STRIPE_SECRET_KEY for live (or unconfirmed) sessions — the mock path needs no secret.",
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (!stripeSecretKey.startsWith("sk_test_")) {
|
|
190
|
+
throw new Error(
|
|
191
|
+
"STRIPE_SECRET_KEY must be a Stripe TEST key (sk_test_...). " +
|
|
192
|
+
"Live keys (sk_live_...) are refused: this sandbox-only demo never charges live Stripe.",
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return stripeSecretKey;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Instrumented `payments.charge_customer` handler: binds Harbor metadata, then charges (mock or Stripe test).
|
|
201
|
+
*
|
|
202
|
+
* `tenantId` and `intentId` must come from Paybond session context after sandbox bind — never from
|
|
203
|
+
* unauthenticated client input. The Stripe test-mode charge is per-tenant + sandbox-only: it is used
|
|
204
|
+
* only when a `sk_test_...` secret is configured AND `binding.environment === "sandbox"`; otherwise
|
|
205
|
+
* this falls back to the offline mock (and fails closed if a secret is misconfigured for live).
|
|
206
|
+
*/
|
|
207
|
+
export async function chargeCustomer(
|
|
208
|
+
binding: PaybondSessionBinding,
|
|
209
|
+
args: ChargeCustomerArgs,
|
|
210
|
+
): Promise<ChargeCustomerResult> {
|
|
211
|
+
if (!binding.tenantId.trim() || !binding.intentId.trim()) {
|
|
212
|
+
throw new Error("Paybond session binding is required before charging");
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const metadata = buildPaybondStripeMetadata({
|
|
216
|
+
tenantId: binding.tenantId,
|
|
217
|
+
intentId: binding.intentId,
|
|
218
|
+
rail: args.rail ?? "stripe_connect",
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
const sandboxStripeTestKey = resolveSandboxStripeTestKey(binding.environment);
|
|
222
|
+
if (sandboxStripeTestKey) {
|
|
223
|
+
return stripeTestChargeCustomer(sandboxStripeTestKey, metadata, args);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return mockChargeCustomer(metadata, args, binding.intentId);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Maps a charge tool result into completion-catalog evidence for the configured preset.
|
|
231
|
+
*/
|
|
232
|
+
export function mapChargeEvidence(
|
|
233
|
+
toolResult: Record<string, unknown>,
|
|
234
|
+
preset: StripeCommerceEvidencePreset = "stripe_charge",
|
|
235
|
+
): ReturnType<typeof mapStripeToolResultToEvidence> {
|
|
236
|
+
return mapStripeToolResultToEvidence(toolResult, { preset });
|
|
237
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stripe commerce agent (generic TypeScript) — instrumented mock `payments.charge_customer`.
|
|
3
|
+
* Uses `buildPaybondStripeMetadata` + `mapStripeToolResultToEvidence` from @paybond/kit.
|
|
4
|
+
* No live LLM required for the sandbox smoke path.
|
|
5
|
+
*/
|
|
6
|
+
import { createPaybondClient } from "./paybond.config.js";
|
|
7
|
+
import {
|
|
8
|
+
chargeCustomer,
|
|
9
|
+
mapChargeEvidence,
|
|
10
|
+
type PaybondSessionBinding,
|
|
11
|
+
} from "./charge-customer.js";
|
|
12
|
+
|
|
13
|
+
const PRIMARY_OPERATION = "payments.charge_customer";
|
|
14
|
+
const REQUESTED_SPEND_CENTS = 2500;
|
|
15
|
+
|
|
16
|
+
async function main(): Promise<void> {
|
|
17
|
+
const paybond = await createPaybondClient();
|
|
18
|
+
try {
|
|
19
|
+
// tenant_id and paybond_intent_id are populated after sandbox bind — never from client input.
|
|
20
|
+
// environment is server-derived (gateway principal); the Stripe test key is sandbox-only.
|
|
21
|
+
const bindingRef: PaybondSessionBinding = {
|
|
22
|
+
tenantId: "",
|
|
23
|
+
intentId: "",
|
|
24
|
+
environment: paybond.environment ?? "unknown",
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const agent = await paybond.agent({
|
|
28
|
+
policy: "./paybond.policy.yaml",
|
|
29
|
+
framework: "generic",
|
|
30
|
+
tools: {
|
|
31
|
+
[PRIMARY_OPERATION]: async (args: { amountCents: number; customerId?: string }) =>
|
|
32
|
+
chargeCustomer(bindingRef, args),
|
|
33
|
+
},
|
|
34
|
+
sandbox: true,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
bindingRef.tenantId = agent.run.tenantId;
|
|
38
|
+
bindingRef.intentId = agent.run.intentId;
|
|
39
|
+
|
|
40
|
+
const tool = agent.tools.find((entry) => entry.name === PRIMARY_OPERATION);
|
|
41
|
+
if (!tool) {
|
|
42
|
+
throw new Error(`missing tool ${PRIMARY_OPERATION}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const result = await tool.execute({
|
|
46
|
+
toolName: PRIMARY_OPERATION,
|
|
47
|
+
toolCallId: "demo-1",
|
|
48
|
+
arguments: { amountCents: REQUESTED_SPEND_CENTS },
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const toolResult =
|
|
52
|
+
typeof result.toolResult === "object" && result.toolResult !== null
|
|
53
|
+
? (result.toolResult as Record<string, unknown>)
|
|
54
|
+
: {};
|
|
55
|
+
|
|
56
|
+
const mappedEvidence = mapChargeEvidence(toolResult, "stripe_charge");
|
|
57
|
+
|
|
58
|
+
console.log(
|
|
59
|
+
JSON.stringify(
|
|
60
|
+
{
|
|
61
|
+
runId: agent.run.runId,
|
|
62
|
+
intentId: agent.run.intentId,
|
|
63
|
+
tenantId: agent.run.tenantId,
|
|
64
|
+
authorization: result.authorization,
|
|
65
|
+
evidence: result.evidence,
|
|
66
|
+
mappedEvidence,
|
|
67
|
+
toolResult: result.toolResult,
|
|
68
|
+
},
|
|
69
|
+
null,
|
|
70
|
+
2,
|
|
71
|
+
),
|
|
72
|
+
);
|
|
73
|
+
} finally {
|
|
74
|
+
await paybond.aclose();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
void main();
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Paybond } from "@paybond/kit";
|
|
2
|
+
|
|
3
|
+
declare const process: {
|
|
4
|
+
env: Record<string, string | undefined>;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
function readEnvValue(body: string, key: string): string | undefined {
|
|
8
|
+
const pattern = new RegExp("^\\s*(?:export\\s+)?" + key + "\\s*=\\s*(.*)$", "m");
|
|
9
|
+
const match = body.match(pattern);
|
|
10
|
+
if (!match) return undefined;
|
|
11
|
+
let value = (match[1] ?? "").trim();
|
|
12
|
+
if (value.startsWith('"') && value.endsWith('"')) {
|
|
13
|
+
try {
|
|
14
|
+
value = JSON.parse(value);
|
|
15
|
+
} catch {
|
|
16
|
+
value = value.slice(1, -1);
|
|
17
|
+
}
|
|
18
|
+
} else if (value.startsWith("'") && value.endsWith("'")) {
|
|
19
|
+
value = value.slice(1, -1);
|
|
20
|
+
}
|
|
21
|
+
return value.trim() || undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function loadPaybondEnvFile(envFile = ".env.local"): Promise<void> {
|
|
25
|
+
if (process.env.PAYBOND_API_KEY?.trim()) return;
|
|
26
|
+
let body: string;
|
|
27
|
+
try {
|
|
28
|
+
const { readFile } = await import("node:fs/promises");
|
|
29
|
+
body = await readFile(envFile, "utf8");
|
|
30
|
+
} catch (err) {
|
|
31
|
+
if ((err as { code?: string }).code === "ENOENT") return;
|
|
32
|
+
throw err;
|
|
33
|
+
}
|
|
34
|
+
const apiKey = readEnvValue(body, "PAYBOND_API_KEY");
|
|
35
|
+
if (apiKey) {
|
|
36
|
+
process.env.PAYBOND_API_KEY = apiKey;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function createPaybondClient(): Promise<Paybond> {
|
|
41
|
+
await loadPaybondEnvFile(".env.local");
|
|
42
|
+
const apiKey = process.env.PAYBOND_API_KEY?.trim();
|
|
43
|
+
if (!apiKey) {
|
|
44
|
+
throw new Error("PAYBOND_API_KEY is required; run paybond login");
|
|
45
|
+
}
|
|
46
|
+
return Paybond.open({
|
|
47
|
+
apiKey,
|
|
48
|
+
gatewayBaseUrl: process.env.PAYBOND_GATEWAY_URL ?? process.env.PAYBOND_GATEWAY_BASE_URL,
|
|
49
|
+
expectedEnvironment: "sandbox",
|
|
50
|
+
});
|
|
51
|
+
}
|