@superblocksteam/sdk-api 0.0.12 → 0.0.13
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/dist/errors.d.ts +36 -3
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +244 -8
- package/dist/errors.js.map +1 -1
- package/dist/errors.test.d.ts +2 -0
- package/dist/errors.test.d.ts.map +1 -0
- package/dist/errors.test.js +189 -0
- package/dist/errors.test.js.map +1 -0
- package/dist/integrations/anthropic/types.d.ts +1 -1
- package/dist/integrations/base/decode-worker-binary-response.d.ts.map +1 -1
- package/dist/integrations/base/decode-worker-binary-response.js +2 -5
- package/dist/integrations/base/decode-worker-binary-response.js.map +1 -1
- package/dist/integrations/base/index.d.ts +2 -1
- package/dist/integrations/base/index.d.ts.map +1 -1
- package/dist/integrations/base/index.js +1 -0
- package/dist/integrations/base/index.js.map +1 -1
- package/dist/integrations/base/request-body.d.ts +29 -0
- package/dist/integrations/base/request-body.d.ts.map +1 -0
- package/dist/integrations/base/request-body.js +238 -0
- package/dist/integrations/base/request-body.js.map +1 -0
- package/dist/integrations/base/request-body.test.d.ts +2 -0
- package/dist/integrations/base/request-body.test.d.ts.map +1 -0
- package/dist/integrations/base/request-body.test.js +466 -0
- package/dist/integrations/base/request-body.test.js.map +1 -0
- package/dist/integrations/base/rest-api-client-base.d.ts.map +1 -1
- package/dist/integrations/base/rest-api-client-base.js +15 -14
- package/dist/integrations/base/rest-api-client-base.js.map +1 -1
- package/dist/integrations/base/rest-api-integration-client.d.ts.map +1 -1
- package/dist/integrations/base/rest-api-integration-client.js +2 -5
- package/dist/integrations/base/rest-api-integration-client.js.map +1 -1
- package/dist/integrations/base/types.d.ts +32 -5
- package/dist/integrations/base/types.d.ts.map +1 -1
- package/dist/integrations/base/types.js +7 -0
- package/dist/integrations/base/types.js.map +1 -1
- package/dist/integrations/cosmosdb/client.d.ts.map +1 -1
- package/dist/integrations/cosmosdb/client.js +2 -5
- package/dist/integrations/cosmosdb/client.js.map +1 -1
- package/dist/integrations/documentation-resolver.test.js +106 -1
- package/dist/integrations/documentation-resolver.test.js.map +1 -1
- package/dist/integrations/documentation.test.js +10 -0
- package/dist/integrations/documentation.test.js.map +1 -1
- package/dist/integrations/dynamodb/client.d.ts.map +1 -1
- package/dist/integrations/dynamodb/client.js +2 -5
- package/dist/integrations/dynamodb/client.js.map +1 -1
- package/dist/integrations/gcs/client.d.ts.map +1 -1
- package/dist/integrations/gcs/client.js +2 -5
- package/dist/integrations/gcs/client.js.map +1 -1
- package/dist/integrations/gsheets/client.d.ts.map +1 -1
- package/dist/integrations/gsheets/client.js +2 -5
- package/dist/integrations/gsheets/client.js.map +1 -1
- package/dist/integrations/mongodb/client.d.ts.map +1 -1
- package/dist/integrations/mongodb/client.js +2 -5
- package/dist/integrations/mongodb/client.js.map +1 -1
- package/dist/integrations/restapiintegration/client.body-types.test.d.ts +2 -0
- package/dist/integrations/restapiintegration/client.body-types.test.d.ts.map +1 -0
- package/dist/integrations/restapiintegration/client.body-types.test.js +227 -0
- package/dist/integrations/restapiintegration/client.body-types.test.js.map +1 -0
- package/dist/integrations/restapiintegration/client.test.js +16 -0
- package/dist/integrations/restapiintegration/client.test.js.map +1 -1
- package/dist/integrations/s3/client.d.ts.map +1 -1
- package/dist/integrations/s3/client.js +2 -5
- package/dist/integrations/s3/client.js.map +1 -1
- package/dist/integrations/salesforce/client.d.ts.map +1 -1
- package/dist/integrations/salesforce/client.js +2 -5
- package/dist/integrations/salesforce/client.js.map +1 -1
- package/dist/integrations/slack/client.d.ts.map +1 -1
- package/dist/integrations/slack/client.js +4 -13
- package/dist/integrations/slack/client.js.map +1 -1
- package/dist/integrations/slack/client.test.js +20 -0
- package/dist/integrations/slack/client.test.js.map +1 -1
- package/dist/integrations/utils.d.ts +8 -3
- package/dist/integrations/utils.d.ts.map +1 -1
- package/dist/integrations/utils.js +42 -1
- package/dist/integrations/utils.js.map +1 -1
- package/package.json +3 -3
- package/src/errors.test.ts +257 -0
- package/src/errors.ts +304 -10
- package/src/integrations/anthropic/README.md +12 -59
- package/src/integrations/anthropic/types.ts +1 -1
- package/src/integrations/base/decode-worker-binary-response.ts +5 -7
- package/src/integrations/base/index.ts +2 -0
- package/src/integrations/base/request-body.test.ts +565 -0
- package/src/integrations/base/request-body.ts +392 -0
- package/src/integrations/base/rest-api-client-base.ts +24 -19
- package/src/integrations/base/rest-api-integration-client.ts +8 -7
- package/src/integrations/base/types.ts +41 -5
- package/src/integrations/box/README.md +4 -60
- package/src/integrations/cosmosdb/client.ts +8 -7
- package/src/integrations/documentation-resolver.test.ts +130 -1
- package/src/integrations/documentation.test.ts +12 -0
- package/src/integrations/dropbox/README.md +1 -71
- package/src/integrations/dropbox/docs.manifest.json +10 -1
- package/src/integrations/dropbox/overlays/upload-unsupported.md +3 -0
- package/src/integrations/dropbox/overlays/upload.md +89 -0
- package/src/integrations/dynamodb/client.ts +8 -7
- package/src/integrations/elasticsearch/README.md +0 -80
- package/src/integrations/elasticsearch/docs.manifest.json +10 -1
- package/src/integrations/elasticsearch/overlays/bulk-unsupported.md +3 -0
- package/src/integrations/elasticsearch/overlays/bulk.md +80 -0
- package/src/integrations/gcs/client.ts +8 -7
- package/src/integrations/googledrive/README.md +10 -36
- package/src/integrations/gsheets/client.ts +8 -7
- package/src/integrations/jira/README.md +0 -26
- package/src/integrations/jira/docs.manifest.json +10 -1
- package/src/integrations/jira/overlays/attachments-unsupported.md +3 -0
- package/src/integrations/jira/overlays/attachments.md +30 -0
- package/src/integrations/mongodb/client.ts +8 -7
- package/src/integrations/restapiintegration/client.body-types.test.ts +323 -0
- package/src/integrations/restapiintegration/client.test.ts +23 -0
- package/src/integrations/restapiintegration/docs.manifest.json +8 -0
- package/src/integrations/restapiintegration/overlays/request-body-types-unsupported.md +7 -0
- package/src/integrations/restapiintegration/overlays/request-body-types.md +115 -0
- package/src/integrations/s3/client.ts +8 -7
- package/src/integrations/salesforce/client.ts +9 -7
- package/src/integrations/slack/client.test.ts +30 -0
- package/src/integrations/slack/client.ts +13 -19
- package/src/integrations/stabilityai/README.md +0 -87
- package/src/integrations/stabilityai/docs.manifest.json +10 -1
- package/src/integrations/stabilityai/overlays/image-uploads-unsupported.md +3 -0
- package/src/integrations/stabilityai/overlays/image-uploads.md +120 -0
- package/src/integrations/stripe/README.md +0 -201
- package/src/integrations/stripe/docs.manifest.json +10 -1
- package/src/integrations/stripe/overlays/request-bodies-unsupported.md +3 -0
- package/src/integrations/stripe/overlays/request-bodies.md +204 -0
- package/src/integrations/utils.ts +51 -1
|
@@ -10,57 +10,6 @@ Process payments, manage customers, and interact with Stripe's payment platform.
|
|
|
10
10
|
|
|
11
11
|
## Usage
|
|
12
12
|
|
|
13
|
-
### Create a Customer
|
|
14
|
-
|
|
15
|
-
```typescript
|
|
16
|
-
import { api, z, stripe } from "@superblocksteam/sdk-api";
|
|
17
|
-
|
|
18
|
-
// Integration ID from the integrations panel
|
|
19
|
-
const PROD_STRIPE = "a1b2c3d4-5678-90ab-cdef-stripe000001";
|
|
20
|
-
|
|
21
|
-
const CustomerSchema = z.object({
|
|
22
|
-
id: z.string(),
|
|
23
|
-
object: z.literal("customer"),
|
|
24
|
-
email: z.string().nullable(),
|
|
25
|
-
name: z.string().nullable(),
|
|
26
|
-
created: z.number(),
|
|
27
|
-
metadata: z.record(z.string()),
|
|
28
|
-
default_source: z.string().nullable(),
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
export default api({
|
|
32
|
-
name: "StripeExample",
|
|
33
|
-
integrations: {
|
|
34
|
-
stripe: stripe(PROD_STRIPE),
|
|
35
|
-
},
|
|
36
|
-
input: z.object({
|
|
37
|
-
email: z.string().email(),
|
|
38
|
-
name: z.string(),
|
|
39
|
-
}),
|
|
40
|
-
output: z.object({
|
|
41
|
-
customerId: z.string(),
|
|
42
|
-
}),
|
|
43
|
-
async run(ctx, { email, name }) {
|
|
44
|
-
const result = await ctx.integrations.stripe.apiRequest(
|
|
45
|
-
{
|
|
46
|
-
method: "POST",
|
|
47
|
-
path: "/v1/customers",
|
|
48
|
-
body: {
|
|
49
|
-
email: email,
|
|
50
|
-
name: name,
|
|
51
|
-
metadata: {
|
|
52
|
-
source: "api",
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
{ response: CustomerSchema },
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
return { customerId: result.id };
|
|
60
|
-
},
|
|
61
|
-
});
|
|
62
|
-
```
|
|
63
|
-
|
|
64
13
|
### Get a Customer
|
|
65
14
|
|
|
66
15
|
```typescript
|
|
@@ -75,43 +24,6 @@ const customer = await ctx.integrations.stripe.apiRequest(
|
|
|
75
24
|
console.log(`Customer: ${customer.name} (${customer.email})`);
|
|
76
25
|
```
|
|
77
26
|
|
|
78
|
-
### Create a Payment Intent
|
|
79
|
-
|
|
80
|
-
```typescript
|
|
81
|
-
const PaymentIntentSchema = z.object({
|
|
82
|
-
id: z.string(),
|
|
83
|
-
object: z.literal("payment_intent"),
|
|
84
|
-
amount: z.number(),
|
|
85
|
-
currency: z.string(),
|
|
86
|
-
status: z.string(),
|
|
87
|
-
client_secret: z.string(),
|
|
88
|
-
customer: z.string().nullable(),
|
|
89
|
-
metadata: z.record(z.string()),
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
const paymentIntent = await ctx.integrations.stripe.apiRequest(
|
|
93
|
-
{
|
|
94
|
-
method: "POST",
|
|
95
|
-
path: "/v1/payment_intents",
|
|
96
|
-
body: {
|
|
97
|
-
amount: 2000, // Amount in cents ($20.00)
|
|
98
|
-
currency: "usd",
|
|
99
|
-
customer: customerId,
|
|
100
|
-
automatic_payment_methods: {
|
|
101
|
-
enabled: true,
|
|
102
|
-
},
|
|
103
|
-
metadata: {
|
|
104
|
-
order_id: "order_123",
|
|
105
|
-
},
|
|
106
|
-
},
|
|
107
|
-
},
|
|
108
|
-
{ response: PaymentIntentSchema },
|
|
109
|
-
);
|
|
110
|
-
|
|
111
|
-
// Return client_secret to frontend for Stripe.js
|
|
112
|
-
console.log(`Client secret: ${paymentIntent.client_secret}`);
|
|
113
|
-
```
|
|
114
|
-
|
|
115
27
|
### List Charges
|
|
116
28
|
|
|
117
29
|
```typescript
|
|
@@ -151,67 +63,6 @@ charges.data.forEach((charge) => {
|
|
|
151
63
|
});
|
|
152
64
|
```
|
|
153
65
|
|
|
154
|
-
### Create a Subscription
|
|
155
|
-
|
|
156
|
-
```typescript
|
|
157
|
-
const SubscriptionSchema = z.object({
|
|
158
|
-
id: z.string(),
|
|
159
|
-
object: z.literal("subscription"),
|
|
160
|
-
customer: z.string(),
|
|
161
|
-
status: z.string(), // active, past_due, canceled, etc.
|
|
162
|
-
current_period_start: z.number(),
|
|
163
|
-
current_period_end: z.number(),
|
|
164
|
-
items: z.object({
|
|
165
|
-
data: z.array(
|
|
166
|
-
z.object({
|
|
167
|
-
id: z.string(),
|
|
168
|
-
price: z.object({ id: z.string() }),
|
|
169
|
-
}),
|
|
170
|
-
),
|
|
171
|
-
}),
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
const subscription = await ctx.integrations.stripe.apiRequest(
|
|
175
|
-
{
|
|
176
|
-
method: "POST",
|
|
177
|
-
path: "/v1/subscriptions",
|
|
178
|
-
body: {
|
|
179
|
-
customer: customerId,
|
|
180
|
-
items: [{ price: "price_abc123" }],
|
|
181
|
-
payment_behavior: "default_incomplete",
|
|
182
|
-
expand: ["latest_invoice.payment_intent"],
|
|
183
|
-
},
|
|
184
|
-
},
|
|
185
|
-
{ response: SubscriptionSchema },
|
|
186
|
-
);
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
### Create a Refund
|
|
190
|
-
|
|
191
|
-
```typescript
|
|
192
|
-
const RefundSchema = z.object({
|
|
193
|
-
id: z.string(),
|
|
194
|
-
object: z.literal("refund"),
|
|
195
|
-
amount: z.number(),
|
|
196
|
-
charge: z.string(),
|
|
197
|
-
status: z.string(), // succeeded, pending, failed, canceled
|
|
198
|
-
created: z.number(),
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
const refund = await ctx.integrations.stripe.apiRequest(
|
|
202
|
-
{
|
|
203
|
-
method: "POST",
|
|
204
|
-
path: "/v1/refunds",
|
|
205
|
-
body: {
|
|
206
|
-
charge: chargeId,
|
|
207
|
-
amount: 1000, // Partial refund of $10.00
|
|
208
|
-
reason: "requested_by_customer",
|
|
209
|
-
},
|
|
210
|
-
},
|
|
211
|
-
{ response: RefundSchema },
|
|
212
|
-
);
|
|
213
|
-
```
|
|
214
|
-
|
|
215
66
|
### List Products
|
|
216
67
|
|
|
217
68
|
```typescript
|
|
@@ -243,58 +94,6 @@ const products = await ctx.integrations.stripe.apiRequest(
|
|
|
243
94
|
);
|
|
244
95
|
```
|
|
245
96
|
|
|
246
|
-
### Create Invoice
|
|
247
|
-
|
|
248
|
-
```typescript
|
|
249
|
-
const InvoiceSchema = z.object({
|
|
250
|
-
id: z.string(),
|
|
251
|
-
object: z.literal("invoice"),
|
|
252
|
-
customer: z.string(),
|
|
253
|
-
status: z.string(), // draft, open, paid, uncollectible, void
|
|
254
|
-
total: z.number(),
|
|
255
|
-
amount_due: z.number(),
|
|
256
|
-
hosted_invoice_url: z.string().nullable(),
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
const invoice = await ctx.integrations.stripe.apiRequest(
|
|
260
|
-
{
|
|
261
|
-
method: "POST",
|
|
262
|
-
path: "/v1/invoices",
|
|
263
|
-
body: {
|
|
264
|
-
customer: customerId,
|
|
265
|
-
collection_method: "send_invoice",
|
|
266
|
-
days_until_due: 30,
|
|
267
|
-
},
|
|
268
|
-
},
|
|
269
|
-
{ response: InvoiceSchema },
|
|
270
|
-
);
|
|
271
|
-
|
|
272
|
-
// Add line items
|
|
273
|
-
await ctx.integrations.stripe.apiRequest(
|
|
274
|
-
{
|
|
275
|
-
method: "POST",
|
|
276
|
-
path: "/v1/invoiceitems",
|
|
277
|
-
body: {
|
|
278
|
-
customer: customerId,
|
|
279
|
-
invoice: invoice.id,
|
|
280
|
-
amount: 5000,
|
|
281
|
-
currency: "usd",
|
|
282
|
-
description: "Consulting services",
|
|
283
|
-
},
|
|
284
|
-
},
|
|
285
|
-
{ response: z.object({ id: z.string() }) },
|
|
286
|
-
);
|
|
287
|
-
|
|
288
|
-
// Finalize and send
|
|
289
|
-
await ctx.integrations.stripe.apiRequest(
|
|
290
|
-
{
|
|
291
|
-
method: "POST",
|
|
292
|
-
path: `/v1/invoices/${invoice.id}/finalize`,
|
|
293
|
-
},
|
|
294
|
-
{ response: InvoiceSchema },
|
|
295
|
-
);
|
|
296
|
-
```
|
|
297
|
-
|
|
298
97
|
## Trace Metadata
|
|
299
98
|
|
|
300
99
|
All methods accept an optional `metadata` parameter as the last argument for diagnostics labeling. See the [root SDK README](../../../README.md#trace-metadata) for details.
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"pluginId": "stripe",
|
|
3
3
|
"base": "README.md",
|
|
4
|
-
"overlays": [
|
|
4
|
+
"overlays": [
|
|
5
|
+
{
|
|
6
|
+
"file": "overlays/request-bodies.md",
|
|
7
|
+
"sdkVersionRange": ">=0.0.7"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"file": "overlays/request-bodies-unsupported.md",
|
|
11
|
+
"sdkVersionRange": "<0.0.7"
|
|
12
|
+
}
|
|
13
|
+
]
|
|
5
14
|
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
## Creating Customers, Payment Intents, Subscriptions, Refunds, and Invoices
|
|
2
|
+
|
|
3
|
+
Stripe rejects any request whose body is not `application/x-www-form-urlencoded`. This agent's sdk-api cannot send that encoding through `apiRequest()` because it serializes every body as JSON, so creating a customer, payment intent, subscription, refund, or invoice always fails. Do not generate Stripe write code until the agent is upgraded. Getting a customer, listing charges, and listing products work as documented above; they send no body.
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
## Creating Customers, Payment Intents, Subscriptions, Refunds, and Invoices
|
|
2
|
+
|
|
3
|
+
Stripe expects `application/x-www-form-urlencoded` bodies, not JSON, so pass `bodyType: "formUrlencoded"` on every write request. Flatten nested fields with bracket notation, such as `"metadata[order_id]"`. An array field whose API name ends in `[]`, such as `expand`, needs the brackets in the key: `"expand[]": [...]`. The SDK adds `Content-Type: application/x-www-form-urlencoded` unless you already provided a `Content-Type` header.
|
|
4
|
+
|
|
5
|
+
### Create a Customer
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { api, z, stripe } from "@superblocksteam/sdk-api";
|
|
9
|
+
|
|
10
|
+
// Integration ID from the integrations panel
|
|
11
|
+
const PROD_STRIPE = "a1b2c3d4-5678-90ab-cdef-stripe000001";
|
|
12
|
+
|
|
13
|
+
const CustomerSchema = z.object({
|
|
14
|
+
id: z.string(),
|
|
15
|
+
object: z.literal("customer"),
|
|
16
|
+
email: z.string().nullable(),
|
|
17
|
+
name: z.string().nullable(),
|
|
18
|
+
created: z.number(),
|
|
19
|
+
metadata: z.record(z.string()),
|
|
20
|
+
default_source: z.string().nullable(),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export default api({
|
|
24
|
+
name: "StripeExample",
|
|
25
|
+
integrations: {
|
|
26
|
+
stripe: stripe(PROD_STRIPE),
|
|
27
|
+
},
|
|
28
|
+
input: z.object({
|
|
29
|
+
email: z.string().email(),
|
|
30
|
+
name: z.string(),
|
|
31
|
+
}),
|
|
32
|
+
output: z.object({
|
|
33
|
+
customerId: z.string(),
|
|
34
|
+
}),
|
|
35
|
+
async run(ctx, { email, name }) {
|
|
36
|
+
const result = await ctx.integrations.stripe.apiRequest(
|
|
37
|
+
{
|
|
38
|
+
method: "POST",
|
|
39
|
+
path: "/v1/customers",
|
|
40
|
+
bodyType: "formUrlencoded",
|
|
41
|
+
body: {
|
|
42
|
+
email: email,
|
|
43
|
+
name: name,
|
|
44
|
+
"metadata[source]": "api",
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
{ response: CustomerSchema },
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
return { customerId: result.id };
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Create a Payment Intent
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
const PaymentIntentSchema = z.object({
|
|
59
|
+
id: z.string(),
|
|
60
|
+
object: z.literal("payment_intent"),
|
|
61
|
+
amount: z.number(),
|
|
62
|
+
currency: z.string(),
|
|
63
|
+
status: z.string(),
|
|
64
|
+
client_secret: z.string(),
|
|
65
|
+
customer: z.string().nullable(),
|
|
66
|
+
metadata: z.record(z.string()),
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const paymentIntent = await ctx.integrations.stripe.apiRequest(
|
|
70
|
+
{
|
|
71
|
+
method: "POST",
|
|
72
|
+
path: "/v1/payment_intents",
|
|
73
|
+
bodyType: "formUrlencoded",
|
|
74
|
+
body: {
|
|
75
|
+
amount: 2000, // Amount in cents ($20.00)
|
|
76
|
+
currency: "usd",
|
|
77
|
+
customer: customerId,
|
|
78
|
+
"automatic_payment_methods[enabled]": true,
|
|
79
|
+
"metadata[order_id]": "order_123",
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
{ response: PaymentIntentSchema },
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
// Return client_secret to frontend for Stripe.js
|
|
86
|
+
console.log(`Client secret: ${paymentIntent.client_secret}`);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Create a Subscription
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
const SubscriptionSchema = z.object({
|
|
93
|
+
id: z.string(),
|
|
94
|
+
object: z.literal("subscription"),
|
|
95
|
+
customer: z.string(),
|
|
96
|
+
status: z.string(), // active, past_due, canceled, etc.
|
|
97
|
+
current_period_start: z.number(),
|
|
98
|
+
current_period_end: z.number(),
|
|
99
|
+
items: z.object({
|
|
100
|
+
data: z.array(
|
|
101
|
+
z.object({
|
|
102
|
+
id: z.string(),
|
|
103
|
+
price: z.object({ id: z.string() }),
|
|
104
|
+
}),
|
|
105
|
+
),
|
|
106
|
+
}),
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const subscription = await ctx.integrations.stripe.apiRequest(
|
|
110
|
+
{
|
|
111
|
+
method: "POST",
|
|
112
|
+
path: "/v1/subscriptions",
|
|
113
|
+
bodyType: "formUrlencoded",
|
|
114
|
+
body: {
|
|
115
|
+
customer: customerId,
|
|
116
|
+
"items[0][price]": "price_abc123",
|
|
117
|
+
payment_behavior: "default_incomplete",
|
|
118
|
+
"expand[]": ["latest_invoice.payment_intent"],
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
{ response: SubscriptionSchema },
|
|
122
|
+
);
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Create a Refund
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
const RefundSchema = z.object({
|
|
129
|
+
id: z.string(),
|
|
130
|
+
object: z.literal("refund"),
|
|
131
|
+
amount: z.number(),
|
|
132
|
+
charge: z.string(),
|
|
133
|
+
status: z.string(), // succeeded, pending, failed, canceled
|
|
134
|
+
created: z.number(),
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const refund = await ctx.integrations.stripe.apiRequest(
|
|
138
|
+
{
|
|
139
|
+
method: "POST",
|
|
140
|
+
path: "/v1/refunds",
|
|
141
|
+
bodyType: "formUrlencoded",
|
|
142
|
+
body: {
|
|
143
|
+
charge: chargeId,
|
|
144
|
+
amount: 1000, // Partial refund of $10.00
|
|
145
|
+
reason: "requested_by_customer",
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
{ response: RefundSchema },
|
|
149
|
+
);
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Create Invoice
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
const InvoiceSchema = z.object({
|
|
156
|
+
id: z.string(),
|
|
157
|
+
object: z.literal("invoice"),
|
|
158
|
+
customer: z.string(),
|
|
159
|
+
status: z.string(), // draft, open, paid, uncollectible, void
|
|
160
|
+
total: z.number(),
|
|
161
|
+
amount_due: z.number(),
|
|
162
|
+
hosted_invoice_url: z.string().nullable(),
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
const invoice = await ctx.integrations.stripe.apiRequest(
|
|
166
|
+
{
|
|
167
|
+
method: "POST",
|
|
168
|
+
path: "/v1/invoices",
|
|
169
|
+
bodyType: "formUrlencoded",
|
|
170
|
+
body: {
|
|
171
|
+
customer: customerId,
|
|
172
|
+
collection_method: "send_invoice",
|
|
173
|
+
days_until_due: 30,
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
{ response: InvoiceSchema },
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
// Add line items
|
|
180
|
+
await ctx.integrations.stripe.apiRequest(
|
|
181
|
+
{
|
|
182
|
+
method: "POST",
|
|
183
|
+
path: "/v1/invoiceitems",
|
|
184
|
+
bodyType: "formUrlencoded",
|
|
185
|
+
body: {
|
|
186
|
+
customer: customerId,
|
|
187
|
+
invoice: invoice.id,
|
|
188
|
+
amount: 5000,
|
|
189
|
+
currency: "usd",
|
|
190
|
+
description: "Consulting services",
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
{ response: z.object({ id: z.string() }) },
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
// Finalize and send; this call has no body
|
|
197
|
+
await ctx.integrations.stripe.apiRequest(
|
|
198
|
+
{
|
|
199
|
+
method: "POST",
|
|
200
|
+
path: `/v1/invoices/${invoice.id}/finalize`,
|
|
201
|
+
},
|
|
202
|
+
{ response: InvoiceSchema },
|
|
203
|
+
);
|
|
204
|
+
```
|
|
@@ -1,7 +1,23 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import { isBinaryData, RestApiValidationError } from "../errors.js";
|
|
4
|
+
|
|
5
|
+
const MAX_OPTION_VALUE_CHARS = 64;
|
|
6
|
+
|
|
1
7
|
/**
|
|
2
8
|
* Integration utility functions.
|
|
3
9
|
*/
|
|
4
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Truncates a string to at most `max` characters, appending "..." when it
|
|
13
|
+
* was cut. The single place that defines how caller-supplied strings are
|
|
14
|
+
* bounded for display (`describeType`, `describeOptionValue`) and for the
|
|
15
|
+
* Zod issue `path` (`boundedPathSegment`).
|
|
16
|
+
*/
|
|
17
|
+
function truncate(value: string, max = MAX_OPTION_VALUE_CHARS): string {
|
|
18
|
+
return value.length > max ? `${value.slice(0, max)}...` : value;
|
|
19
|
+
}
|
|
20
|
+
|
|
5
21
|
/**
|
|
6
22
|
* Produces a safe, human-readable description of a value's type
|
|
7
23
|
* without exposing potentially sensitive data.
|
|
@@ -18,8 +34,42 @@ export function describeType(value: unknown): string {
|
|
|
18
34
|
if (t === "object") {
|
|
19
35
|
const keys = Object.keys(value as Record<string, unknown>);
|
|
20
36
|
if (keys.length === 0) return "empty object";
|
|
21
|
-
|
|
37
|
+
const shown = keys.slice(0, 5).map((k) => truncate(k));
|
|
38
|
+
return `object with keys [${shown.join(", ")}${keys.length > 5 ? ", ..." : ""}]`;
|
|
22
39
|
}
|
|
23
40
|
|
|
24
41
|
return t;
|
|
25
42
|
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Describes a caller-supplied option value for an error message with bounded
|
|
46
|
+
* length. Strings are quoted and truncated; everything else is described by type
|
|
47
|
+
* so arbitrary payloads never land in the message.
|
|
48
|
+
*/
|
|
49
|
+
export function describeOptionValue(value: unknown): string {
|
|
50
|
+
if (isBinaryData(value)) {
|
|
51
|
+
return `binary data (${value.byteLength} bytes)`;
|
|
52
|
+
}
|
|
53
|
+
if (typeof value !== "string") return describeType(value);
|
|
54
|
+
return JSON.stringify(truncate(value));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function boundedPathSegment(segment: string | number): string | number {
|
|
58
|
+
return typeof segment === "string" ? truncate(segment) : segment;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function validationError(
|
|
62
|
+
message: string,
|
|
63
|
+
path: (string | number)[],
|
|
64
|
+
): RestApiValidationError {
|
|
65
|
+
return new RestApiValidationError(message, {
|
|
66
|
+
data: undefined,
|
|
67
|
+
zodError: new z.ZodError([
|
|
68
|
+
{
|
|
69
|
+
code: z.ZodIssueCode.custom,
|
|
70
|
+
message,
|
|
71
|
+
path: path.map(boundedPathSegment),
|
|
72
|
+
},
|
|
73
|
+
]),
|
|
74
|
+
});
|
|
75
|
+
}
|