@superblocksteam/sdk-api 2.0.165-next.0 → 2.0.166-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -2
- 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/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 +2 -2
- package/dist/integrations/base/rest-api-integration-client.d.ts.map +1 -1
- package/dist/integrations/base/rest-api-integration-client.js +5 -6
- package/dist/integrations/base/rest-api-integration-client.js.map +1 -1
- package/dist/integrations/base/types.d.ts +55 -11
- 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/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 +56 -30
- 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 +2 -2
- package/src/errors.test.ts +257 -0
- package/src/errors.ts +304 -10
- package/src/integrations/base/decode-worker-binary-response.ts +5 -7
- package/src/integrations/base/index.ts +3 -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 +14 -10
- package/src/integrations/base/types.ts +66 -11
- 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/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/lakebase/README.md +1 -3
- package/src/integrations/mongodb/client.ts +8 -7
- package/src/integrations/postgres/README.md +1 -3
- package/src/integrations/restapiintegration/client.body-types.test.ts +323 -0
- package/src/integrations/restapiintegration/client.test.ts +68 -32
- 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/restapiintegration/overlays/response-types-binary.md +4 -8
- 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/snowflakepostgres/README.md +1 -3
- 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
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
## Image-to-Image, Upscale, and Inpainting
|
|
2
|
+
|
|
3
|
+
The `/image-to-image`, `/image-to-image/upscale`, and `/image-to-image/masking` endpoints expect `multipart/form-data`, so pass `bodyType: "multipartForm"`. Image parts are `{ value, filename }` with raw bytes. Multipart fields are flat, so `text_prompts` uses bracketed keys such as `"text_prompts[0][text]"`. Do not set `Content-Type`. The worker generates the multipart boundary.
|
|
4
|
+
|
|
5
|
+
For an uploaded file, pass `await file.readContentsAsync("raw")` as the part value. For an image returned by a previous generation, decode its `base64` artifact with `Buffer.from(artifact.base64, "base64")`.
|
|
6
|
+
|
|
7
|
+
The engine/model ID is part of the URL path:
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
// Image-to-image
|
|
11
|
+
const path = "/v1/generation/stable-diffusion-xl-1024-v1-0/image-to-image";
|
|
12
|
+
|
|
13
|
+
// Upscaling
|
|
14
|
+
const path = "/v1/generation/esrgan-v1-x2plus/image-to-image/upscale";
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Image-to-Image (Transform Existing Image)
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
const source = input.upload.files[0];
|
|
21
|
+
|
|
22
|
+
const result = await ctx.integrations.stability.apiRequest(
|
|
23
|
+
{
|
|
24
|
+
method: "POST",
|
|
25
|
+
path: "/v1/generation/stable-diffusion-xl-1024-v1-0/image-to-image",
|
|
26
|
+
bodyType: "multipartForm",
|
|
27
|
+
body: {
|
|
28
|
+
init_image: {
|
|
29
|
+
value: await source.readContentsAsync("raw"),
|
|
30
|
+
filename: source.name,
|
|
31
|
+
},
|
|
32
|
+
"text_prompts[0][text]": "A vibrant oil painting style",
|
|
33
|
+
"text_prompts[0][weight]": 1,
|
|
34
|
+
image_strength: 0.35, // How much to modify (0-1)
|
|
35
|
+
cfg_scale: 7,
|
|
36
|
+
samples: 1,
|
|
37
|
+
steps: 30,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
{ response: GenerationResponseSchema },
|
|
41
|
+
);
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Upscale an Image
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
const UpscaleResponseSchema = z.object({
|
|
48
|
+
artifacts: z.array(
|
|
49
|
+
z.object({
|
|
50
|
+
base64: z.string(),
|
|
51
|
+
finishReason: z.string(),
|
|
52
|
+
seed: z.number(),
|
|
53
|
+
}),
|
|
54
|
+
),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Response of an earlier text-to-image apiRequest call.
|
|
58
|
+
const generated = await ctx.integrations.stability.apiRequest(
|
|
59
|
+
{
|
|
60
|
+
method: "POST",
|
|
61
|
+
path: "/v1/generation/stable-diffusion-xl-1024-v1-0/text-to-image",
|
|
62
|
+
body: {
|
|
63
|
+
text_prompts: [{ text: "A vibrant oil painting style", weight: 1 }],
|
|
64
|
+
cfg_scale: 7,
|
|
65
|
+
samples: 1,
|
|
66
|
+
steps: 30,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
{ response: GenerationResponseSchema },
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const result = await ctx.integrations.stability.apiRequest(
|
|
73
|
+
{
|
|
74
|
+
method: "POST",
|
|
75
|
+
path: "/v1/generation/esrgan-v1-x2plus/image-to-image/upscale",
|
|
76
|
+
bodyType: "multipartForm",
|
|
77
|
+
body: {
|
|
78
|
+
image: {
|
|
79
|
+
value: Buffer.from(generated.artifacts[0].base64, "base64"),
|
|
80
|
+
filename: "generated.png",
|
|
81
|
+
},
|
|
82
|
+
width: 2048, // Target width (optional)
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
{ response: UpscaleResponseSchema },
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const upscaledImage = result.artifacts[0].base64;
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Inpainting (Edit Parts of an Image)
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
const [source, mask] = input.upload.files;
|
|
95
|
+
|
|
96
|
+
const result = await ctx.integrations.stability.apiRequest(
|
|
97
|
+
{
|
|
98
|
+
method: "POST",
|
|
99
|
+
path: "/v1/generation/stable-diffusion-xl-1024-v1-0/image-to-image/masking",
|
|
100
|
+
bodyType: "multipartForm",
|
|
101
|
+
body: {
|
|
102
|
+
init_image: {
|
|
103
|
+
value: await source.readContentsAsync("raw"),
|
|
104
|
+
filename: source.name,
|
|
105
|
+
},
|
|
106
|
+
mask_image: {
|
|
107
|
+
value: await mask.readContentsAsync("raw"),
|
|
108
|
+
filename: mask.name,
|
|
109
|
+
},
|
|
110
|
+
mask_source: "MASK_IMAGE_WHITE", // White areas will be regenerated
|
|
111
|
+
"text_prompts[0][text]": "A golden retriever sitting",
|
|
112
|
+
"text_prompts[0][weight]": 1,
|
|
113
|
+
cfg_scale: 7,
|
|
114
|
+
samples: 1,
|
|
115
|
+
steps: 30,
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
{ response: GenerationResponseSchema },
|
|
119
|
+
);
|
|
120
|
+
```
|
|
@@ -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
|
+
}
|