@superblocksteam/sdk-api 0.0.12-body-types → 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.
Files changed (152) hide show
  1. package/README.md +23 -0
  2. package/dist/errors.d.ts +36 -3
  3. package/dist/errors.d.ts.map +1 -1
  4. package/dist/errors.js +231 -38
  5. package/dist/errors.js.map +1 -1
  6. package/dist/errors.test.d.ts +2 -0
  7. package/dist/errors.test.d.ts.map +1 -0
  8. package/dist/errors.test.js +189 -0
  9. package/dist/errors.test.js.map +1 -0
  10. package/dist/index.d.ts +1 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/integrations/anthropic/types.d.ts +1 -1
  14. package/dist/integrations/base/decode-worker-binary-response.d.ts.map +1 -1
  15. package/dist/integrations/base/decode-worker-binary-response.js +2 -5
  16. package/dist/integrations/base/decode-worker-binary-response.js.map +1 -1
  17. package/dist/integrations/base/index.d.ts +1 -1
  18. package/dist/integrations/base/index.d.ts.map +1 -1
  19. package/dist/integrations/base/request-body.d.ts +18 -10
  20. package/dist/integrations/base/request-body.d.ts.map +1 -1
  21. package/dist/integrations/base/request-body.js +131 -215
  22. package/dist/integrations/base/request-body.js.map +1 -1
  23. package/dist/integrations/base/request-body.test.js +306 -164
  24. package/dist/integrations/base/request-body.test.js.map +1 -1
  25. package/dist/integrations/base/rest-api-client-base.d.ts.map +1 -1
  26. package/dist/integrations/base/rest-api-client-base.js +13 -26
  27. package/dist/integrations/base/rest-api-client-base.js.map +1 -1
  28. package/dist/integrations/base/rest-api-integration-client.d.ts.map +1 -1
  29. package/dist/integrations/base/rest-api-integration-client.js +2 -5
  30. package/dist/integrations/base/rest-api-integration-client.js.map +1 -1
  31. package/dist/integrations/base/types.d.ts +0 -8
  32. package/dist/integrations/base/types.d.ts.map +1 -1
  33. package/dist/integrations/cosmosdb/client.d.ts.map +1 -1
  34. package/dist/integrations/cosmosdb/client.js +2 -5
  35. package/dist/integrations/cosmosdb/client.js.map +1 -1
  36. package/dist/integrations/documentation-resolver.test.js +88 -2
  37. package/dist/integrations/documentation-resolver.test.js.map +1 -1
  38. package/dist/integrations/documentation.test.js +10 -0
  39. package/dist/integrations/documentation.test.js.map +1 -1
  40. package/dist/integrations/dynamodb/client.d.ts +6 -2
  41. package/dist/integrations/dynamodb/client.d.ts.map +1 -1
  42. package/dist/integrations/dynamodb/client.js +85 -15
  43. package/dist/integrations/dynamodb/client.js.map +1 -1
  44. package/dist/integrations/dynamodb/client.test.d.ts +8 -0
  45. package/dist/integrations/dynamodb/client.test.d.ts.map +1 -0
  46. package/dist/integrations/dynamodb/client.test.js +198 -0
  47. package/dist/integrations/dynamodb/client.test.js.map +1 -0
  48. package/dist/integrations/dynamodb/index.d.ts +1 -1
  49. package/dist/integrations/dynamodb/index.d.ts.map +1 -1
  50. package/dist/integrations/dynamodb/index.js.map +1 -1
  51. package/dist/integrations/dynamodb/types.d.ts +27 -1
  52. package/dist/integrations/dynamodb/types.d.ts.map +1 -1
  53. package/dist/integrations/gcs/client.d.ts.map +1 -1
  54. package/dist/integrations/gcs/client.js +2 -5
  55. package/dist/integrations/gcs/client.js.map +1 -1
  56. package/dist/integrations/gsheets/client.d.ts.map +1 -1
  57. package/dist/integrations/gsheets/client.js +2 -5
  58. package/dist/integrations/gsheets/client.js.map +1 -1
  59. package/dist/integrations/index.d.ts +1 -1
  60. package/dist/integrations/index.d.ts.map +1 -1
  61. package/dist/integrations/index.js.map +1 -1
  62. package/dist/integrations/mongodb/client.d.ts.map +1 -1
  63. package/dist/integrations/mongodb/client.js +2 -5
  64. package/dist/integrations/mongodb/client.js.map +1 -1
  65. package/dist/integrations/restapiintegration/client.body-types.test.js +107 -25
  66. package/dist/integrations/restapiintegration/client.body-types.test.js.map +1 -1
  67. package/dist/integrations/restapiintegration/client.test.js +16 -0
  68. package/dist/integrations/restapiintegration/client.test.js.map +1 -1
  69. package/dist/integrations/s3/client.d.ts.map +1 -1
  70. package/dist/integrations/s3/client.js +2 -5
  71. package/dist/integrations/s3/client.js.map +1 -1
  72. package/dist/integrations/salesforce/client.d.ts.map +1 -1
  73. package/dist/integrations/salesforce/client.js +2 -5
  74. package/dist/integrations/salesforce/client.js.map +1 -1
  75. package/dist/integrations/slack/client.d.ts.map +1 -1
  76. package/dist/integrations/slack/client.js +4 -13
  77. package/dist/integrations/slack/client.js.map +1 -1
  78. package/dist/integrations/slack/client.test.js +2 -5
  79. package/dist/integrations/slack/client.test.js.map +1 -1
  80. package/dist/integrations/utils.d.ts +8 -3
  81. package/dist/integrations/utils.d.ts.map +1 -1
  82. package/dist/integrations/utils.js +42 -1
  83. package/dist/integrations/utils.js.map +1 -1
  84. package/dist/runtime/context.d.ts +6 -0
  85. package/dist/runtime/context.d.ts.map +1 -1
  86. package/dist/runtime/context.js +2 -1
  87. package/dist/runtime/context.js.map +1 -1
  88. package/dist/runtime/executor.d.ts +6 -0
  89. package/dist/runtime/executor.d.ts.map +1 -1
  90. package/dist/runtime/executor.js +1 -0
  91. package/dist/runtime/executor.js.map +1 -1
  92. package/dist/types.d.ts +10 -0
  93. package/dist/types.d.ts.map +1 -1
  94. package/package.json +3 -3
  95. package/src/errors.test.ts +257 -0
  96. package/src/errors.ts +289 -46
  97. package/src/index.ts +1 -0
  98. package/src/integrations/anthropic/README.md +12 -59
  99. package/src/integrations/anthropic/types.ts +1 -1
  100. package/src/integrations/base/decode-worker-binary-response.ts +5 -7
  101. package/src/integrations/base/index.ts +0 -5
  102. package/src/integrations/base/request-body.test.ts +358 -195
  103. package/src/integrations/base/request-body.ts +170 -326
  104. package/src/integrations/base/rest-api-client-base.ts +22 -31
  105. package/src/integrations/base/rest-api-integration-client.ts +8 -7
  106. package/src/integrations/base/types.ts +0 -18
  107. package/src/integrations/box/README.md +4 -60
  108. package/src/integrations/cosmosdb/client.ts +8 -7
  109. package/src/integrations/documentation-resolver.test.ts +108 -2
  110. package/src/integrations/documentation.test.ts +12 -0
  111. package/src/integrations/dropbox/README.md +1 -71
  112. package/src/integrations/dropbox/docs.manifest.json +10 -1
  113. package/src/integrations/dropbox/overlays/upload-unsupported.md +3 -0
  114. package/src/integrations/dropbox/overlays/upload.md +89 -0
  115. package/src/integrations/dynamodb/README.md +33 -12
  116. package/src/integrations/dynamodb/client.test.ts +254 -0
  117. package/src/integrations/dynamodb/client.ts +129 -23
  118. package/src/integrations/dynamodb/index.ts +5 -1
  119. package/src/integrations/dynamodb/types.ts +33 -1
  120. package/src/integrations/elasticsearch/README.md +0 -80
  121. package/src/integrations/elasticsearch/docs.manifest.json +10 -1
  122. package/src/integrations/elasticsearch/overlays/bulk-unsupported.md +3 -0
  123. package/src/integrations/elasticsearch/overlays/bulk.md +80 -0
  124. package/src/integrations/gcs/client.ts +8 -7
  125. package/src/integrations/googledrive/README.md +10 -36
  126. package/src/integrations/gsheets/client.ts +8 -7
  127. package/src/integrations/index.ts +1 -0
  128. package/src/integrations/jira/README.md +0 -26
  129. package/src/integrations/jira/docs.manifest.json +10 -1
  130. package/src/integrations/jira/overlays/attachments-unsupported.md +3 -0
  131. package/src/integrations/jira/overlays/attachments.md +30 -0
  132. package/src/integrations/mongodb/client.ts +8 -7
  133. package/src/integrations/restapiintegration/client.body-types.test.ts +135 -26
  134. package/src/integrations/restapiintegration/client.test.ts +23 -0
  135. package/src/integrations/restapiintegration/docs.manifest.json +2 -2
  136. package/src/integrations/restapiintegration/overlays/request-body-types.md +26 -17
  137. package/src/integrations/s3/client.ts +8 -7
  138. package/src/integrations/salesforce/client.ts +9 -7
  139. package/src/integrations/slack/client.test.ts +2 -5
  140. package/src/integrations/slack/client.ts +13 -19
  141. package/src/integrations/stabilityai/README.md +0 -87
  142. package/src/integrations/stabilityai/docs.manifest.json +10 -1
  143. package/src/integrations/stabilityai/overlays/image-uploads-unsupported.md +3 -0
  144. package/src/integrations/stabilityai/overlays/image-uploads.md +120 -0
  145. package/src/integrations/stripe/README.md +0 -201
  146. package/src/integrations/stripe/docs.manifest.json +10 -1
  147. package/src/integrations/stripe/overlays/request-bodies-unsupported.md +3 -0
  148. package/src/integrations/stripe/overlays/request-bodies.md +204 -0
  149. package/src/integrations/utils.ts +51 -1
  150. package/src/runtime/context.ts +9 -0
  151. package/src/runtime/executor.ts +8 -0
  152. package/src/types.ts +11 -0
@@ -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
- return `object with keys [${keys.slice(0, 5).join(", ")}${keys.length > 5 ? ", ..." : ""}]`;
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
+ }
@@ -57,6 +57,13 @@ export interface CreateContextOptions {
57
57
  /** Environment variables */
58
58
  env: Record<string, string>;
59
59
 
60
+ /**
61
+ * Server-resolved data tag key.
62
+ *
63
+ * Optional for compatibility with execution wrappers from older agents.
64
+ */
65
+ dataTag?: string;
66
+
60
67
  /** User information from JWT */
61
68
  user: ApiUser;
62
69
 
@@ -101,6 +108,7 @@ export function createApiContext(
101
108
  executeQuery,
102
109
  executionId,
103
110
  env,
111
+ dataTag,
104
112
  user,
105
113
  logger,
106
114
  } = options;
@@ -172,6 +180,7 @@ export function createApiContext(
172
180
  >["integrations"],
173
181
  log,
174
182
  env: Object.freeze({ ...env }),
183
+ dataTag,
175
184
  user,
176
185
  };
177
186
  }
@@ -36,6 +36,13 @@ export interface ExecuteApiRequest {
36
36
  /** Environment variables available to the API */
37
37
  env: Record<string, string>;
38
38
 
39
+ /**
40
+ * Server-resolved data tag key for this execution.
41
+ *
42
+ * Optional on the low-level request for compatibility with older runtimes.
43
+ */
44
+ dataTag?: string;
45
+
39
46
  /** User information extracted from the Superblocks JWT */
40
47
  user: ApiUser;
41
48
 
@@ -162,6 +169,7 @@ export async function executeApi<TInput = unknown, TOutput = unknown>(
162
169
  executeQuery: request.executeQuery,
163
170
  executionId: request.executionId,
164
171
  env: request.env,
172
+ dataTag: request.dataTag,
165
173
  user: request.user,
166
174
  });
167
175
 
package/src/types.ts CHANGED
@@ -182,6 +182,17 @@ export interface ApiContext<
182
182
  /** Access to environment variables */
183
183
  readonly env: Readonly<Record<string, string>>;
184
184
 
185
+ /**
186
+ * Canonical key of the requested data tag validated for this execution.
187
+ *
188
+ * This identifies the integration configuration in use, not a user's
189
+ * environment entitlement. It is supplied by the Superblocks runtime and
190
+ * cannot be selected through API input. It is undefined when no data tag was
191
+ * resolved or on runtimes that predate data-tag context support;
192
+ * authorization checks must deny access in those cases.
193
+ */
194
+ readonly dataTag?: string;
195
+
185
196
  /** User information from the Superblocks JWT */
186
197
  readonly user: ApiUser;
187
198
  }