alchemy 0.24.0 → 0.25.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/lib/aws/control/client.js +1 -1
- package/lib/aws/control/client.js.map +1 -1
- package/lib/aws/control/resource.d.ts.map +1 -1
- package/lib/aws/control/resource.js +2 -1
- package/lib/aws/control/resource.js.map +1 -1
- package/lib/aws/function.d.ts.map +1 -1
- package/lib/aws/function.js +1 -4
- package/lib/aws/function.js.map +1 -1
- package/lib/cloudflare/ai.d.ts +21 -0
- package/lib/cloudflare/ai.d.ts.map +1 -1
- package/lib/cloudflare/ai.js +21 -0
- package/lib/cloudflare/ai.js.map +1 -1
- package/lib/cloudflare/bindings.d.ts +3 -3
- package/lib/cloudflare/bindings.d.ts.map +1 -1
- package/lib/cloudflare/bindings.js.map +1 -1
- package/lib/cloudflare/bound.d.ts +3 -3
- package/lib/cloudflare/bound.d.ts.map +1 -1
- package/lib/cloudflare/do-state-store/index.d.ts +2 -0
- package/lib/cloudflare/do-state-store/index.d.ts.map +1 -0
- package/lib/cloudflare/do-state-store/index.js +2 -0
- package/lib/cloudflare/do-state-store/index.js.map +1 -0
- package/lib/cloudflare/do-state-store/internal.d.ts +19 -0
- package/lib/cloudflare/do-state-store/internal.d.ts.map +1 -0
- package/lib/cloudflare/do-state-store/internal.js +163 -0
- package/lib/cloudflare/do-state-store/internal.js.map +1 -0
- package/lib/cloudflare/do-state-store/store.d.ts +59 -0
- package/lib/cloudflare/do-state-store/store.d.ts.map +1 -0
- package/lib/cloudflare/do-state-store/store.js +120 -0
- package/lib/cloudflare/do-state-store/store.js.map +1 -0
- package/lib/cloudflare/do-state-store/types.d.ts +82 -0
- package/lib/cloudflare/do-state-store/types.d.ts.map +1 -0
- package/lib/cloudflare/do-state-store/types.js +1 -0
- package/lib/cloudflare/do-state-store/types.js.map +1 -0
- package/lib/cloudflare/do-state-store/worker.d.ts +27 -0
- package/lib/cloudflare/do-state-store/worker.d.ts.map +1 -0
- package/lib/cloudflare/do-state-store/worker.js +170 -0
- package/lib/cloudflare/do-state-store/worker.js.map +1 -0
- package/lib/cloudflare/index.d.ts +1 -0
- package/lib/cloudflare/index.d.ts.map +1 -1
- package/lib/cloudflare/index.js +1 -0
- package/lib/cloudflare/index.js.map +1 -1
- package/lib/cloudflare/pipeline.js +1 -1
- package/lib/cloudflare/pipeline.js.map +1 -1
- package/lib/cloudflare/queue-consumer.d.ts +14 -1
- package/lib/cloudflare/queue-consumer.d.ts.map +1 -1
- package/lib/cloudflare/queue-consumer.js +17 -0
- package/lib/cloudflare/queue-consumer.js.map +1 -1
- package/lib/cloudflare/website.d.ts +30 -1
- package/lib/cloudflare/website.d.ts.map +1 -1
- package/lib/cloudflare/website.js +8 -5
- package/lib/cloudflare/website.js.map +1 -1
- package/lib/cloudflare/worker-assets.d.ts.map +1 -1
- package/lib/cloudflare/worker-assets.js +13 -3
- package/lib/cloudflare/worker-assets.js.map +1 -1
- package/lib/cloudflare/worker-metadata.js +1 -1
- package/lib/cloudflare/worker-metadata.js.map +1 -1
- package/lib/cloudflare/worker.d.ts +40 -1
- package/lib/cloudflare/worker.d.ts.map +1 -1
- package/lib/cloudflare/worker.js +40 -38
- package/lib/cloudflare/worker.js.map +1 -1
- package/lib/cloudflare/wrangler.json.js +1 -1
- package/lib/cloudflare/wrangler.json.js.map +1 -1
- package/lib/cloudflare/zone.d.ts +30 -2
- package/lib/cloudflare/zone.d.ts.map +1 -1
- package/lib/cloudflare/zone.js +53 -0
- package/lib/cloudflare/zone.js.map +1 -1
- package/lib/fs/file-system-state-store.d.ts +3 -1
- package/lib/fs/file-system-state-store.d.ts.map +1 -1
- package/lib/fs/file-system-state-store.js +2 -2
- package/lib/fs/file-system-state-store.js.map +1 -1
- package/lib/stripe/card.d.ts +171 -0
- package/lib/stripe/card.d.ts.map +1 -0
- package/lib/stripe/card.js +148 -0
- package/lib/stripe/card.js.map +1 -0
- package/lib/stripe/client.d.ts +9 -0
- package/lib/stripe/client.d.ts.map +1 -0
- package/lib/stripe/client.js +94 -0
- package/lib/stripe/client.js.map +1 -0
- package/lib/stripe/coupon.d.ts +135 -0
- package/lib/stripe/coupon.d.ts.map +1 -0
- package/lib/stripe/coupon.js +161 -0
- package/lib/stripe/coupon.js.map +1 -0
- package/lib/stripe/customer.d.ts +269 -0
- package/lib/stripe/customer.d.ts.map +1 -0
- package/lib/stripe/customer.js +289 -0
- package/lib/stripe/customer.js.map +1 -0
- package/lib/stripe/entitlements-feature.d.ts +84 -0
- package/lib/stripe/entitlements-feature.d.ts.map +1 -0
- package/lib/stripe/entitlements-feature.js +102 -0
- package/lib/stripe/entitlements-feature.js.map +1 -0
- package/lib/stripe/file.d.ts +143 -0
- package/lib/stripe/file.d.ts.map +1 -0
- package/lib/stripe/file.js +97 -0
- package/lib/stripe/file.js.map +1 -0
- package/lib/stripe/index.d.ts +11 -0
- package/lib/stripe/index.d.ts.map +1 -1
- package/lib/stripe/index.js +11 -0
- package/lib/stripe/index.js.map +1 -1
- package/lib/stripe/meter.d.ts +10 -1
- package/lib/stripe/meter.d.ts.map +1 -1
- package/lib/stripe/meter.js +13 -7
- package/lib/stripe/meter.js.map +1 -1
- package/lib/stripe/portal-configuration.d.ts +286 -0
- package/lib/stripe/portal-configuration.d.ts.map +1 -0
- package/lib/stripe/portal-configuration.js +320 -0
- package/lib/stripe/portal-configuration.js.map +1 -0
- package/lib/stripe/price.d.ts +10 -1
- package/lib/stripe/price.d.ts.map +1 -1
- package/lib/stripe/price.js +34 -13
- package/lib/stripe/price.js.map +1 -1
- package/lib/stripe/product-feature.d.ts +76 -0
- package/lib/stripe/product-feature.d.ts.map +1 -0
- package/lib/stripe/product-feature.js +74 -0
- package/lib/stripe/product-feature.js.map +1 -0
- package/lib/stripe/product.d.ts +10 -1
- package/lib/stripe/product.d.ts.map +1 -1
- package/lib/stripe/product.js +33 -14
- package/lib/stripe/product.js.map +1 -1
- package/lib/stripe/promotion-code.d.ts +138 -0
- package/lib/stripe/promotion-code.d.ts.map +1 -0
- package/lib/stripe/promotion-code.js +150 -0
- package/lib/stripe/promotion-code.js.map +1 -0
- package/lib/stripe/shipping-rate.d.ts +188 -0
- package/lib/stripe/shipping-rate.d.ts.map +1 -0
- package/lib/stripe/shipping-rate.js +198 -0
- package/lib/stripe/shipping-rate.js.map +1 -0
- package/lib/stripe/tax-rate.d.ts +130 -0
- package/lib/stripe/tax-rate.d.ts.map +1 -0
- package/lib/stripe/tax-rate.js +126 -0
- package/lib/stripe/tax-rate.js.map +1 -0
- package/lib/stripe/webhook.d.ts +10 -1
- package/lib/stripe/webhook.d.ts.map +1 -1
- package/lib/stripe/webhook.js +59 -14
- package/lib/stripe/webhook.js.map +1 -1
- package/lib/test/bun.d.ts.map +1 -1
- package/lib/test/bun.js +2 -6
- package/lib/test/bun.js.map +1 -1
- package/lib/test/vitest.d.ts.map +1 -1
- package/lib/test/vitest.js +3 -7
- package/lib/test/vitest.js.map +1 -1
- package/lib/util/retry.d.ts +1 -1
- package/lib/util/retry.d.ts.map +1 -1
- package/lib/util/retry.js.map +1 -1
- package/package.json +3 -2
- package/src/aws/control/client.ts +1 -1
- package/src/aws/control/resource.ts +2 -1
- package/src/aws/function.ts +3 -6
- package/src/cloudflare/ai.ts +21 -0
- package/src/cloudflare/bindings.ts +3 -2
- package/src/cloudflare/bound.ts +3 -3
- package/src/cloudflare/do-state-store/index.ts +1 -0
- package/src/cloudflare/do-state-store/internal.ts +215 -0
- package/src/cloudflare/do-state-store/store.ts +188 -0
- package/src/cloudflare/do-state-store/types.ts +74 -0
- package/src/cloudflare/do-state-store/worker.ts +199 -0
- package/src/cloudflare/index.ts +1 -0
- package/src/cloudflare/pipeline.ts +1 -1
- package/src/cloudflare/queue-consumer.ts +59 -1
- package/src/cloudflare/website.ts +38 -6
- package/src/cloudflare/worker-assets.ts +15 -3
- package/src/cloudflare/worker-metadata.ts +1 -1
- package/src/cloudflare/worker.ts +66 -46
- package/src/cloudflare/wrangler.json.ts +1 -1
- package/src/cloudflare/zone.ts +75 -2
- package/src/fs/file-system-state-store.ts +7 -2
- package/src/stripe/card.ts +320 -0
- package/src/stripe/client.ts +145 -0
- package/src/stripe/coupon.ts +280 -0
- package/src/stripe/customer.ts +528 -0
- package/src/stripe/entitlements-feature.ts +169 -0
- package/src/stripe/file.ts +219 -0
- package/src/stripe/index.ts +11 -0
- package/src/stripe/meter.ts +23 -7
- package/src/stripe/portal-configuration.ts +609 -0
- package/src/stripe/price.ts +47 -14
- package/src/stripe/product-feature.ts +150 -0
- package/src/stripe/product.ts +48 -15
- package/src/stripe/promotion-code.ts +268 -0
- package/src/stripe/shipping-rate.ts +362 -0
- package/src/stripe/tax-rate.ts +218 -0
- package/src/stripe/webhook.ts +82 -15
- package/src/test/bun.ts +2 -7
- package/src/test/vitest.ts +3 -8
- package/src/util/retry.ts +1 -1
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import type Stripe from "stripe";
|
|
2
|
+
import type { Context } from "../context.ts";
|
|
3
|
+
import { Resource } from "../resource.ts";
|
|
4
|
+
import type { Secret } from "../secret.ts";
|
|
5
|
+
import {
|
|
6
|
+
createStripeClient,
|
|
7
|
+
handleStripeDeleteError,
|
|
8
|
+
isStripeConflictError,
|
|
9
|
+
} from "./client.ts";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Properties for creating a Stripe product feature
|
|
13
|
+
*/
|
|
14
|
+
export interface ProductFeatureProps {
|
|
15
|
+
/**
|
|
16
|
+
* The ID of the product that this feature will be attached to
|
|
17
|
+
*/
|
|
18
|
+
product: string;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The ID of the entitlements feature to attach to the product
|
|
22
|
+
*/
|
|
23
|
+
entitlementFeature: string;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* API key to use (overrides environment variable)
|
|
27
|
+
*/
|
|
28
|
+
apiKey?: Secret;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* If true, adopt existing resource if creation fails due to conflict
|
|
32
|
+
*/
|
|
33
|
+
adopt?: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Output from the Stripe product feature
|
|
38
|
+
*/
|
|
39
|
+
export interface ProductFeature
|
|
40
|
+
extends Resource<"stripe::ProductFeature">,
|
|
41
|
+
ProductFeatureProps {
|
|
42
|
+
/**
|
|
43
|
+
* The ID of the product feature
|
|
44
|
+
*/
|
|
45
|
+
id: string;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* String representing the object's type
|
|
49
|
+
*/
|
|
50
|
+
object: "product_feature";
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The entitlement feature object attached to this product
|
|
54
|
+
*/
|
|
55
|
+
entitlementFeatureObject?: {
|
|
56
|
+
id: string;
|
|
57
|
+
name: string;
|
|
58
|
+
lookupKey?: string;
|
|
59
|
+
metadata?: Record<string, string>;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Has the value true if the object exists in live mode or the value false if the object exists in test mode
|
|
64
|
+
*/
|
|
65
|
+
livemode: boolean;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Create and manage Stripe product features
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* // Attach an API access feature to a product
|
|
73
|
+
* const productApiFeature = await ProductFeature("product-api-access", {
|
|
74
|
+
* product: "prod_xyz123",
|
|
75
|
+
* entitlementFeature: "feat_abc456"
|
|
76
|
+
* });
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* // Attach analytics feature to a premium product
|
|
80
|
+
* const productAnalytics = await ProductFeature("premium-analytics", {
|
|
81
|
+
* product: "prod_premium789",
|
|
82
|
+
* entitlementFeature: "feat_analytics123"
|
|
83
|
+
* });
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* // Attach custom integrations to enterprise product
|
|
87
|
+
* const enterpriseIntegrations = await ProductFeature("enterprise-integrations", {
|
|
88
|
+
* product: "prod_enterprise456",
|
|
89
|
+
* entitlementFeature: "feat_integrations789"
|
|
90
|
+
* });
|
|
91
|
+
*/
|
|
92
|
+
export const ProductFeature = Resource(
|
|
93
|
+
"stripe::ProductFeature",
|
|
94
|
+
async function (
|
|
95
|
+
this: Context<ProductFeature>,
|
|
96
|
+
_id: string,
|
|
97
|
+
props: ProductFeatureProps,
|
|
98
|
+
): Promise<ProductFeature> {
|
|
99
|
+
const stripe = createStripeClient({ apiKey: props.apiKey });
|
|
100
|
+
|
|
101
|
+
if (this.phase === "delete") {
|
|
102
|
+
try {
|
|
103
|
+
if (this.output?.id && this.output?.product) {
|
|
104
|
+
await stripe.products.deleteFeature(
|
|
105
|
+
this.output.product,
|
|
106
|
+
this.output.id,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
} catch (error) {
|
|
110
|
+
handleStripeDeleteError(error, "ProductFeature", this.output?.id);
|
|
111
|
+
}
|
|
112
|
+
return this.destroy();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
let productFeature: Stripe.ProductFeature;
|
|
117
|
+
|
|
118
|
+
if (this.phase === "update" && this.output?.id) {
|
|
119
|
+
throw new Error("Product features cannot be updated after creation");
|
|
120
|
+
} else {
|
|
121
|
+
try {
|
|
122
|
+
productFeature = await stripe.products.createFeature(props.product, {
|
|
123
|
+
entitlement_feature: props.entitlementFeature,
|
|
124
|
+
});
|
|
125
|
+
} catch (error) {
|
|
126
|
+
if (isStripeConflictError(error) && props.adopt) {
|
|
127
|
+
throw new Error(
|
|
128
|
+
"ProductFeature adoption is not supported - product features cannot be uniquely identified for adoption",
|
|
129
|
+
);
|
|
130
|
+
} else {
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return this({
|
|
137
|
+
id: productFeature.id,
|
|
138
|
+
object: productFeature.object,
|
|
139
|
+
product: props.product,
|
|
140
|
+
entitlementFeature: props.entitlementFeature,
|
|
141
|
+
entitlementFeatureObject:
|
|
142
|
+
productFeature.entitlement_feature || undefined,
|
|
143
|
+
livemode: productFeature.livemode,
|
|
144
|
+
});
|
|
145
|
+
} catch (error) {
|
|
146
|
+
console.error("Error creating product feature:", error);
|
|
147
|
+
throw error;
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
);
|
package/src/stripe/product.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import Stripe from "stripe";
|
|
1
|
+
import type Stripe from "stripe";
|
|
2
2
|
import type { Context } from "../context.ts";
|
|
3
3
|
import { Resource } from "../resource.ts";
|
|
4
|
+
import type { Secret } from "../secret.ts";
|
|
5
|
+
import { createStripeClient, handleStripeDeleteError } from "./client.ts";
|
|
4
6
|
|
|
5
7
|
type ProductType = Stripe.Product.Type;
|
|
6
8
|
|
|
@@ -62,6 +64,16 @@ export interface ProductProps {
|
|
|
62
64
|
* Default tax code for the product
|
|
63
65
|
*/
|
|
64
66
|
taxCode?: string;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* API key to use (overrides environment variable)
|
|
70
|
+
*/
|
|
71
|
+
apiKey?: Secret;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* If true, adopt existing resource if creation fails due to conflict
|
|
75
|
+
*/
|
|
76
|
+
adopt?: boolean;
|
|
65
77
|
}
|
|
66
78
|
|
|
67
79
|
/**
|
|
@@ -144,14 +156,7 @@ export const Product = Resource(
|
|
|
144
156
|
_id: string,
|
|
145
157
|
props: ProductProps,
|
|
146
158
|
): Promise<Product> {
|
|
147
|
-
|
|
148
|
-
const apiKey = process.env.STRIPE_API_KEY;
|
|
149
|
-
if (!apiKey) {
|
|
150
|
-
throw new Error("STRIPE_API_KEY environment variable is required");
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Initialize Stripe client
|
|
154
|
-
const stripe = new Stripe(apiKey);
|
|
159
|
+
const stripe = createStripeClient({ apiKey: props.apiKey });
|
|
155
160
|
|
|
156
161
|
if (this.phase === "delete") {
|
|
157
162
|
try {
|
|
@@ -159,8 +164,7 @@ export const Product = Resource(
|
|
|
159
164
|
await stripe.products.update(this.output.id, { active: false });
|
|
160
165
|
}
|
|
161
166
|
} catch (error) {
|
|
162
|
-
|
|
163
|
-
console.error("Error deactivating product:", error);
|
|
167
|
+
handleStripeDeleteError(error, "Product", this.output?.id);
|
|
164
168
|
}
|
|
165
169
|
|
|
166
170
|
// Return a minimal output for deleted state
|
|
@@ -171,7 +175,7 @@ export const Product = Resource(
|
|
|
171
175
|
|
|
172
176
|
if (this.phase === "update" && this.output?.id) {
|
|
173
177
|
// Update existing product
|
|
174
|
-
|
|
178
|
+
const updateParams = {
|
|
175
179
|
name: props.name,
|
|
176
180
|
description: props.description,
|
|
177
181
|
active: props.active,
|
|
@@ -180,10 +184,11 @@ export const Product = Resource(
|
|
|
180
184
|
statement_descriptor: props.statementDescriptor,
|
|
181
185
|
metadata: props.metadata,
|
|
182
186
|
tax_code: props.taxCode,
|
|
183
|
-
}
|
|
187
|
+
};
|
|
188
|
+
product = await stripe.products.update(this.output.id, updateParams);
|
|
184
189
|
} else {
|
|
185
190
|
// Create new product
|
|
186
|
-
|
|
191
|
+
const createParams = {
|
|
187
192
|
name: props.name,
|
|
188
193
|
description: props.description,
|
|
189
194
|
active: props.active,
|
|
@@ -195,7 +200,35 @@ export const Product = Resource(
|
|
|
195
200
|
statement_descriptor: props.statementDescriptor,
|
|
196
201
|
metadata: props.metadata,
|
|
197
202
|
tax_code: props.taxCode,
|
|
198
|
-
}
|
|
203
|
+
};
|
|
204
|
+
if (props.adopt) {
|
|
205
|
+
const existingProducts = await stripe.products.list({
|
|
206
|
+
limit: 100,
|
|
207
|
+
});
|
|
208
|
+
const existingProduct = existingProducts.data.find(
|
|
209
|
+
(p) => p.name === props.name,
|
|
210
|
+
);
|
|
211
|
+
if (existingProduct) {
|
|
212
|
+
const updateParams = {
|
|
213
|
+
name: props.name,
|
|
214
|
+
description: props.description,
|
|
215
|
+
active: props.active,
|
|
216
|
+
images: props.images,
|
|
217
|
+
url: props.url,
|
|
218
|
+
statement_descriptor: props.statementDescriptor,
|
|
219
|
+
metadata: props.metadata,
|
|
220
|
+
tax_code: props.taxCode,
|
|
221
|
+
};
|
|
222
|
+
product = await stripe.products.update(
|
|
223
|
+
existingProduct.id,
|
|
224
|
+
updateParams,
|
|
225
|
+
);
|
|
226
|
+
} else {
|
|
227
|
+
product = await stripe.products.create(createParams);
|
|
228
|
+
}
|
|
229
|
+
} else {
|
|
230
|
+
product = await stripe.products.create(createParams);
|
|
231
|
+
}
|
|
199
232
|
}
|
|
200
233
|
|
|
201
234
|
return this({
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import type Stripe from "stripe";
|
|
2
|
+
import type { Context } from "../context.ts";
|
|
3
|
+
import { Resource } from "../resource.ts";
|
|
4
|
+
import type { Secret } from "../secret.ts";
|
|
5
|
+
import {
|
|
6
|
+
createStripeClient,
|
|
7
|
+
handleStripeDeleteError,
|
|
8
|
+
isStripeConflictError,
|
|
9
|
+
} from "./client.ts";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Restrictions for promotion code usage
|
|
13
|
+
*/
|
|
14
|
+
export interface PromotionCodeRestrictions {
|
|
15
|
+
/**
|
|
16
|
+
* Promotion codes defined with this restriction will only work for Checkout Sessions in payment mode
|
|
17
|
+
*/
|
|
18
|
+
firstTimeTransaction?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Minimum amount required to redeem this promotion code into a coupon
|
|
21
|
+
*/
|
|
22
|
+
minimumAmount?: number;
|
|
23
|
+
/**
|
|
24
|
+
* Three-letter ISO code for minimum_amount
|
|
25
|
+
*/
|
|
26
|
+
minimumAmountCurrency?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Properties for creating a Stripe promotion code
|
|
31
|
+
*/
|
|
32
|
+
export interface PromotionCodeProps {
|
|
33
|
+
/**
|
|
34
|
+
* The coupon for this promotion code
|
|
35
|
+
*/
|
|
36
|
+
coupon: string;
|
|
37
|
+
/**
|
|
38
|
+
* The customer-facing code. Regardless of case, this code must be unique across all active promotion codes for a specific customer
|
|
39
|
+
*/
|
|
40
|
+
code?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Whether the promotion code is currently active
|
|
43
|
+
*/
|
|
44
|
+
active?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* The customer that this promotion code can be used by
|
|
47
|
+
*/
|
|
48
|
+
customer?: string;
|
|
49
|
+
/**
|
|
50
|
+
* The timestamp at which this promotion code will expire
|
|
51
|
+
*/
|
|
52
|
+
expiresAt?: number;
|
|
53
|
+
/**
|
|
54
|
+
* The maximum number of times this promotion code can be redeemed
|
|
55
|
+
*/
|
|
56
|
+
maxRedemptions?: number;
|
|
57
|
+
/**
|
|
58
|
+
* Set of key-value pairs that you can attach to an object
|
|
59
|
+
*/
|
|
60
|
+
metadata?: Record<string, string>;
|
|
61
|
+
/**
|
|
62
|
+
* Settings that restrict the redemption of the promotion code
|
|
63
|
+
*/
|
|
64
|
+
restrictions?: PromotionCodeRestrictions;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* API key to use (overrides environment variable)
|
|
68
|
+
*/
|
|
69
|
+
apiKey?: Secret;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* If true, adopt existing resource if creation fails due to conflict
|
|
73
|
+
*/
|
|
74
|
+
adopt?: boolean;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Output from the Stripe promotion code
|
|
79
|
+
*/
|
|
80
|
+
export interface PromotionCode
|
|
81
|
+
extends Resource<"stripe::PromotionCode">,
|
|
82
|
+
PromotionCodeProps {
|
|
83
|
+
/**
|
|
84
|
+
* The ID of the promotion code
|
|
85
|
+
*/
|
|
86
|
+
id: string;
|
|
87
|
+
/**
|
|
88
|
+
* String representing the object's type
|
|
89
|
+
*/
|
|
90
|
+
object: "promotion_code";
|
|
91
|
+
/**
|
|
92
|
+
* Time at which the object was created
|
|
93
|
+
*/
|
|
94
|
+
created: number;
|
|
95
|
+
/**
|
|
96
|
+
* Has the value true if the object exists in live mode or the value false if the object exists in test mode
|
|
97
|
+
*/
|
|
98
|
+
livemode: boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Number of times this promotion code has been used
|
|
101
|
+
*/
|
|
102
|
+
timesRedeemed: number;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Create and manage Stripe promotion codes for coupons
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* // Create a basic promotion code
|
|
110
|
+
* const basicPromoCode = await PromotionCode("summer-promo", {
|
|
111
|
+
* coupon: "SUMMER25",
|
|
112
|
+
* code: "SAVE25NOW",
|
|
113
|
+
* active: true,
|
|
114
|
+
* metadata: {
|
|
115
|
+
* campaign: "summer_sale",
|
|
116
|
+
* channel: "email"
|
|
117
|
+
* }
|
|
118
|
+
* });
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* // Create a customer-specific promotion code
|
|
122
|
+
* const customerPromoCode = await PromotionCode("vip-discount", {
|
|
123
|
+
* coupon: "VIP15",
|
|
124
|
+
* code: "VIP15OFF",
|
|
125
|
+
* customer: "cus_xyz123",
|
|
126
|
+
* maxRedemptions: 1,
|
|
127
|
+
* expiresAt: Math.floor(Date.now() / 1000) + 86400 * 30,
|
|
128
|
+
* metadata: {
|
|
129
|
+
* type: "vip_exclusive",
|
|
130
|
+
* tier: "gold"
|
|
131
|
+
* }
|
|
132
|
+
* });
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* // Create a promotion code with restrictions
|
|
136
|
+
* const restrictedPromoCode = await PromotionCode("first-time-buyer", {
|
|
137
|
+
* coupon: "WELCOME10",
|
|
138
|
+
* code: "FIRSTTIME10",
|
|
139
|
+
* restrictions: {
|
|
140
|
+
* firstTimeTransaction: true,
|
|
141
|
+
* minimumAmount: 5000,
|
|
142
|
+
* minimumAmountCurrency: "usd"
|
|
143
|
+
* },
|
|
144
|
+
* maxRedemptions: 1000,
|
|
145
|
+
* metadata: {
|
|
146
|
+
* campaign: "new_customer_acquisition",
|
|
147
|
+
* minimum_order: "50_usd"
|
|
148
|
+
* }
|
|
149
|
+
* });
|
|
150
|
+
*/
|
|
151
|
+
export const PromotionCode = Resource(
|
|
152
|
+
"stripe::PromotionCode",
|
|
153
|
+
async function (
|
|
154
|
+
this: Context<PromotionCode>,
|
|
155
|
+
_id: string,
|
|
156
|
+
props: PromotionCodeProps,
|
|
157
|
+
): Promise<PromotionCode> {
|
|
158
|
+
const stripe = createStripeClient({ apiKey: props.apiKey });
|
|
159
|
+
|
|
160
|
+
if (this.phase === "delete") {
|
|
161
|
+
try {
|
|
162
|
+
if (this.output?.id) {
|
|
163
|
+
await stripe.promotionCodes.update(this.output.id, { active: false });
|
|
164
|
+
}
|
|
165
|
+
} catch (error) {
|
|
166
|
+
handleStripeDeleteError(error, "PromotionCode", this.output?.id);
|
|
167
|
+
}
|
|
168
|
+
return this.destroy();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
try {
|
|
172
|
+
let promotionCode: Stripe.PromotionCode;
|
|
173
|
+
|
|
174
|
+
if (this.phase === "update" && this.output?.id) {
|
|
175
|
+
const updateParams: Stripe.PromotionCodeUpdateParams = {
|
|
176
|
+
active: props.active,
|
|
177
|
+
metadata: props.metadata,
|
|
178
|
+
};
|
|
179
|
+
promotionCode = await stripe.promotionCodes.update(
|
|
180
|
+
this.output.id,
|
|
181
|
+
updateParams,
|
|
182
|
+
);
|
|
183
|
+
} else {
|
|
184
|
+
const createParams: Stripe.PromotionCodeCreateParams = {
|
|
185
|
+
coupon: props.coupon,
|
|
186
|
+
code: props.code,
|
|
187
|
+
active: props.active,
|
|
188
|
+
customer: props.customer,
|
|
189
|
+
expires_at: props.expiresAt,
|
|
190
|
+
max_redemptions: props.maxRedemptions,
|
|
191
|
+
metadata: props.metadata,
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
if (props.restrictions) {
|
|
195
|
+
createParams.restrictions = {
|
|
196
|
+
first_time_transaction: props.restrictions.firstTimeTransaction,
|
|
197
|
+
minimum_amount: props.restrictions.minimumAmount,
|
|
198
|
+
minimum_amount_currency: props.restrictions.minimumAmountCurrency,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
promotionCode = await stripe.promotionCodes.create(createParams);
|
|
204
|
+
} catch (error) {
|
|
205
|
+
if (isStripeConflictError(error) && props.adopt) {
|
|
206
|
+
if (props.code) {
|
|
207
|
+
const existingPromotionCodes = await stripe.promotionCodes.list({
|
|
208
|
+
code: props.code,
|
|
209
|
+
limit: 1,
|
|
210
|
+
});
|
|
211
|
+
if (existingPromotionCodes.data.length > 0) {
|
|
212
|
+
const existingPromotionCode = existingPromotionCodes.data[0];
|
|
213
|
+
const updateParams: Stripe.PromotionCodeUpdateParams = {
|
|
214
|
+
active: props.active,
|
|
215
|
+
metadata: props.metadata,
|
|
216
|
+
};
|
|
217
|
+
promotionCode = await stripe.promotionCodes.update(
|
|
218
|
+
existingPromotionCode.id,
|
|
219
|
+
updateParams,
|
|
220
|
+
);
|
|
221
|
+
} else {
|
|
222
|
+
throw error;
|
|
223
|
+
}
|
|
224
|
+
} else {
|
|
225
|
+
throw error;
|
|
226
|
+
}
|
|
227
|
+
} else {
|
|
228
|
+
throw error;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return this({
|
|
234
|
+
id: promotionCode.id,
|
|
235
|
+
object: promotionCode.object,
|
|
236
|
+
coupon:
|
|
237
|
+
typeof promotionCode.coupon === "string"
|
|
238
|
+
? promotionCode.coupon
|
|
239
|
+
: promotionCode.coupon.id,
|
|
240
|
+
code: promotionCode.code,
|
|
241
|
+
active: promotionCode.active,
|
|
242
|
+
customer:
|
|
243
|
+
typeof promotionCode.customer === "string"
|
|
244
|
+
? promotionCode.customer
|
|
245
|
+
: promotionCode.customer?.id,
|
|
246
|
+
expiresAt: promotionCode.expires_at || undefined,
|
|
247
|
+
maxRedemptions: promotionCode.max_redemptions || undefined,
|
|
248
|
+
metadata: promotionCode.metadata || undefined,
|
|
249
|
+
restrictions: promotionCode.restrictions
|
|
250
|
+
? {
|
|
251
|
+
firstTimeTransaction:
|
|
252
|
+
promotionCode.restrictions.first_time_transaction || undefined,
|
|
253
|
+
minimumAmount:
|
|
254
|
+
promotionCode.restrictions.minimum_amount || undefined,
|
|
255
|
+
minimumAmountCurrency:
|
|
256
|
+
promotionCode.restrictions.minimum_amount_currency || undefined,
|
|
257
|
+
}
|
|
258
|
+
: undefined,
|
|
259
|
+
created: promotionCode.created,
|
|
260
|
+
livemode: promotionCode.livemode,
|
|
261
|
+
timesRedeemed: promotionCode.times_redeemed,
|
|
262
|
+
});
|
|
263
|
+
} catch (error) {
|
|
264
|
+
console.error("Error creating/updating promotion code:", error);
|
|
265
|
+
throw error;
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
);
|